Texture TextureFactory::loadTexture(const std::string& fileName, ObjectsCache& cache, bool async, TextureLoaderDelegate* delegate) { if (fileName.length() == 0) return Texture(); CriticalSectionScope lock(_csTextureLoading); std::string file = application().environment().resolveScalableFileName(fileName, renderContext()->screenScaleFactor()); if (!fileExists(file)) { log::error("Unable to find texture file: %s", file.c_str()); return Texture(); } uint64_t cachedFileProperty = 0; Texture texture = cache.findAnyObject(file, &cachedFileProperty); if (texture.invalid()) { TextureDescription::Pointer desc = async ? et::loadTextureDescription(file, false) : et::loadTexture(file); if (desc.valid()) { bool calledFromAnotherThread = Threading::currentThread() != threading().renderingThread(); texture = Texture(new TextureData(renderContext(), desc, desc->origin(), async || calledFromAnotherThread)); cache.manage(texture, ObjectLoader::Pointer(this)); if (async) _loadingThread->addRequest(desc->origin(), texture, delegate); else if (calledFromAnotherThread) assert(false && "ERROR: Unable to load texture synchronously from non-rendering thread."); } } else { auto newProperty = cache.getFileProperty(file); if (cachedFileProperty != newProperty) reloadObject(texture, cache); if (async && (delegate != nullptr)) { Invocation1 i; i.setTarget(delegate, &TextureLoaderDelegate::textureDidStartLoading, texture); i.invokeInMainRunLoop(); i.setTarget(delegate, &TextureLoaderDelegate::textureDidLoad, texture); i.invokeInMainRunLoop(); } } return texture; }
Program::Pointer ProgramFactory::loadProgram(const std::string& file, ObjectsCache& cache, const StringList& defines) { auto cachedPrograms = cache.findObjects(file); for (Program::Pointer cached : cachedPrograms) { if (cached.valid()) { if (cached->defines().size() == defines.size()) { bool same = true; for (auto& inDefine : defines) { for (auto& cDefine : cached->defines()) { if (inDefine != cDefine) { same = false; break; } if (!same) break; } } if (same) return cached; } } } std::string vertex_shader; std::string geom_shader; std::string frag_shader; StringList sourceFiles = loadProgramSources(file, vertex_shader, geom_shader, frag_shader); if (sourceFiles.empty()) return Program::Pointer::create(renderContext()); std::string workFolder = getFilePath(file); parseSourceCode(ShaderType_Vertex, vertex_shader, defines, workFolder); parseSourceCode(ShaderType_Geometry, geom_shader, defines, workFolder); parseSourceCode(ShaderType_Fragment, frag_shader, defines, workFolder); Program::Pointer program = Program::Pointer::create(renderContext(), vertex_shader, geom_shader, frag_shader, getFileName(file), file, defines); for (auto& s : sourceFiles) program->addOrigin(s); cache.manage(program, _private->loader); return program; }
Texture::Pointer TextureFactory::loadTexture(const std::string& fileName, ObjectsCache& cache, bool async, TextureLoaderDelegate* delegate) { if (fileName.length() == 0) return Texture::Pointer(); CriticalSectionScope lock(_csTextureLoading); auto file = resolveTextureName(fileName); if (!fileExists(file)) return Texture::Pointer(); uint64_t cachedFileProperty = 0; Texture::Pointer texture = cache.findAnyObject(file, &cachedFileProperty); if (texture.invalid()) { TextureDescription::Pointer desc = async ? et::loadTextureDescription(file, false) : et::loadTexture(file); int maxTextureSize = static_cast<int>(RenderingCapabilities::instance().maxTextureSize()); if ((desc->size.x > maxTextureSize) || (desc->size.y > maxTextureSize)) { log::warning("Attempt to load texture with dimensions (%d x %d) larger than max allowed (%d)", desc->size.x, desc->size.y, maxTextureSize); } if (desc.valid()) { bool calledFromAnotherThread = !threading::inMainThread(); texture = Texture::Pointer::create(renderContext(), desc, desc->origin(), async || calledFromAnotherThread); cache.manage(texture, _private->loader); if (async) { _loadingThread->addRequest(desc->origin(), texture, delegate); } else if (calledFromAnotherThread) { ET_FAIL("ERROR: Unable to load texture synchronously from non-rendering thread."); } } } else { auto newProperty = cache.getFileProperty(file); if (cachedFileProperty != newProperty) reloadObject(texture, cache); if (async) { textureDidStartLoading.invokeInMainRunLoop(texture); if (delegate != nullptr) { Invocation1 i; i.setTarget(delegate, &TextureLoaderDelegate::textureDidStartLoading, texture); i.invokeInMainRunLoop(); } textureDidLoad.invokeInMainRunLoop(texture); if (delegate != nullptr) { Invocation1 i; i.setTarget(delegate, &TextureLoaderDelegate::textureDidLoad, texture); i.invokeInMainRunLoop(); } } } return texture; }
Texture::Pointer TextureFactory::loadTexturesToCubemap(const std::string& posx, const std::string& negx, const std::string& posy, const std::string& negy, const std::string& posz, const std::string& negz, ObjectsCache& cache) { TextureDescription::Pointer layers[6] = { et::loadTexture(application().resolveFileName(posx)), et::loadTexture(application().resolveFileName(negx)), et::loadTexture(application().resolveFileName(negy)), et::loadTexture(application().resolveFileName(posy)), et::loadTexture(application().resolveFileName(posz)), et::loadTexture(application().resolveFileName(negz)) }; int maxCubemapSize = static_cast<int>(RenderingCapabilities::instance().maxCubemapTextureSize()); for (size_t l = 0; l < 6; ++l) { if (layers[l].valid()) { if ((layers[l]->size.x > maxCubemapSize) || (layers[l]->size.y > maxCubemapSize)) { log::error("Cubemap %s size of (%d x %d) is larger than allowed %dx%d", layers[l]->origin().c_str(), layers[l]->size.x, layers[l]->size.y, maxCubemapSize, maxCubemapSize); return Texture::Pointer(); } } else { log::error("Unable to load cubemap face."); return Texture::Pointer(); } } std::string texId = layers[0]->origin() + ";"; for (size_t l = 1; l < 6; ++l) { texId += (l < 5) ? layers[l]->origin() + ";" : layers[l]->origin(); if ((layers[l-1]->size != layers[l]->size) || (layers[l-1]->format != layers[l]->format) || (layers[l-1]->internalformat != layers[l]->internalformat) || (layers[l-1]->type != layers[l]->type) || (layers[l-1]->mipMapCount != layers[l]->mipMapCount) || (layers[l-1]->compressed != layers[l]->compressed) || (layers[l-1]->data.size() != layers[l]->data.size())) { log::error("Failed to load cubemap textures. Textures `%s` and `%s` aren't identical", layers[l-1]->origin().c_str(), layers[l]->origin().c_str()); return Texture::Pointer(); } } size_t layerSize = layers[0]->dataSizeForAllMipLevels(); TextureDescription::Pointer desc = TextureDescription::Pointer::create(); desc->target = TextureTarget::Texture_Cube; desc->layersCount = 6; desc->bitsPerPixel = layers[0]->bitsPerPixel; desc->channels = layers[0]->channels; desc->compressed = layers[0]->compressed; desc->format = layers[0]->format; desc->internalformat = layers[0]->internalformat; desc->mipMapCount= layers[0]->mipMapCount; desc->size = layers[0]->size; desc->type = layers[0]->type; desc->data.resize(desc->layersCount * layerSize); for (size_t l = 0; l < desc->layersCount; ++l) etCopyMemory(desc->data.element_ptr(l * layerSize), layers[l]->data.element_ptr(0), layerSize); Texture::Pointer result = Texture::Pointer::create(renderContext(), desc, texId, false); for (size_t i = 0; i < 6; ++i) result->addOrigin(layers[i]->origin()); cache.manage(result, _private->loader); return result; }