bool Texture2DArray::BeginLoad(Deserializer& source) { ResourceCache* cache = context_->resourceCache(); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } cache->ResetDependencies(this); QString texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); loadParameters_ = (new XMLFile(context_)); if (!loadParameters_->Load(source)) { loadParameters_.Reset(); return false; } loadImages_.clear(); XMLElement textureElem = loadParameters_->GetRoot(); XMLElement layerElem = textureElem.GetChild("layer"); while (layerElem) { QString name = layerElem.GetAttribute("name"); // If path is empty, add the XML file path if (GetPath(name).isEmpty()) name = texPath + name; loadImages_.push_back(cache->GetTempResource<Image>(name)); cache->StoreResourceDependency(this, name); layerElem = layerElem.GetNext("layer"); } // Precalculate mip levels if async loading if (GetAsyncLoadState() == ASYNC_LOADING) { for (unsigned i = 0; i < loadImages_.size(); ++i) { if (loadImages_[i]) loadImages_[i]->PrecalculateLevels(); } } return true; }
bool XMLFile::BeginLoad(Deserializer& source) { unsigned dataSize = source.GetSize(); if (!dataSize && !source.GetName().Empty()) { URHO3D_LOGERROR("Zero sized XML data in " + source.GetName()); return false; } SharedArrayPtr<char> buffer(new char[dataSize]); if (source.Read(buffer.Get(), dataSize) != dataSize) return false; if (!document_->load_buffer(buffer.Get(), dataSize)) { URHO3D_LOGERROR("Could not parse XML data from " + source.GetName()); document_->reset(); return false; } XMLElement rootElem = GetRoot(); String inherit = rootElem.GetAttribute("inherit"); if (!inherit.Empty()) { // The existence of this attribute indicates this is an RFC 5261 patch file ResourceCache* cache = GetSubsystem<ResourceCache>(); // If being async loaded, GetResource() is not safe, so use GetTempResource() instead XMLFile* inheritedXMLFile = GetAsyncLoadState() == ASYNC_DONE ? cache->GetResource<XMLFile>(inherit) : cache->GetTempResource<XMLFile>(inherit); if (!inheritedXMLFile) { URHO3D_LOGERRORF("Could not find inherited XML file: %s", inherit.CString()); return false; } // Patch this XMLFile and leave the original inherited XMLFile as it is pugi::xml_document* patchDocument = document_; document_ = new pugi::xml_document(); document_->reset(*inheritedXMLFile->document_); Patch(rootElem); delete patchDocument; // Store resource dependencies so we know when to reload/repatch when the inherited resource changes cache->StoreResourceDependency(this, inherit); // Approximate patched data size dataSize += inheritedXMLFile->GetMemoryUse(); } // Note: this probably does not reflect internal data structure size accurately SetMemoryUse(dataSize); return true; }
bool Shader::ProcessSource(String& code, Deserializer& source) { ResourceCache* cache = GetSubsystem<ResourceCache>(); // If the source if a non-packaged file, store the timestamp File* file = dynamic_cast<File*>(&source); if (file && !file->IsPackaged()) { FileSystem* fileSystem = GetSubsystem<FileSystem>(); String fullName = cache->GetResourceFileName(file->GetName()); unsigned fileTimeStamp = fileSystem->GetLastModifiedTime(fullName); if (fileTimeStamp > timeStamp_) timeStamp_ = fileTimeStamp; } // Store resource dependencies for includes so that we know to reload if any of them changes if (source.GetName() != GetName()) cache->StoreResourceDependency(this, source.GetName()); while (!source.IsEof()) { String line = source.ReadLine(); if (line.StartsWith("#include")) { String includeFileName = GetPath(source.GetName()) + line.Substring(9).Replaced("\"", "").Trimmed(); SharedPtr<File> includeFile = cache->GetFile(includeFileName); if (!includeFile) return false; // Add the include file into the current code recursively if (!ProcessSource(code, *includeFile)) return false; } else { code += line; code += "\n"; } } // Finally insert an empty line to mark the space between files code += "\n"; return true; }
bool ScriptFile::AddScriptSection(asIScriptEngine* engine, Deserializer& source) { ResourceCache* cache = GetSubsystem<ResourceCache>(); unsigned dataSize = source.GetSize(); SharedArrayPtr<char> buffer(new char[dataSize]); source.Read((void*)buffer.Get(), dataSize); // Pre-parse for includes // Adapted from Angelscript's scriptbuilder add-on Vector<String> includeFiles; unsigned pos = 0; while(pos < dataSize) { int len; asETokenClass t = engine->ParseToken(&buffer[pos], dataSize - pos, &len); if (t == asTC_COMMENT || t == asTC_WHITESPACE) { pos += len; continue; } // Is this a preprocessor directive? if (buffer[pos] == '#') { int start = pos++; asETokenClass t = engine->ParseToken(&buffer[pos], dataSize - pos, &len); if (t == asTC_IDENTIFIER) { String token(&buffer[pos], len); if (token == "include") { pos += len; t = engine->ParseToken(&buffer[pos], dataSize - pos, &len); if (t == asTC_WHITESPACE) { pos += len; t = engine->ParseToken(&buffer[pos], dataSize - pos, &len); } if (t == asTC_VALUE && len > 2 && buffer[pos] == '"') { // Get the include file String includeFile(&buffer[pos+1], len - 2); pos += len; // If the file is not found as it is, add the path of current file but only if it is found there if (!cache->Exists(includeFile)) { String prefixedIncludeFile = GetPath(GetName()) + includeFile; if (cache->Exists(prefixedIncludeFile)) includeFile = prefixedIncludeFile; } String includeFileLower = includeFile.ToLower(); // If not included yet, store it for later processing if (!includeFiles_.Contains(includeFileLower)) { includeFiles_.Insert(includeFileLower); includeFiles.Push(includeFile); } // Overwrite the include directive with space characters to avoid compiler error memset(&buffer[start], ' ', pos - start); } } } } // Don't search includes within statement blocks or between tokens in statements else { int len; // Skip until ; or { whichever comes first while (pos < dataSize && buffer[pos] != ';' && buffer[pos] != '{') { engine->ParseToken(&buffer[pos], 0, &len); pos += len; } // Skip entire statement block if (pos < dataSize && buffer[pos] == '{') { ++pos; // Find the end of the statement block int level = 1; while (level > 0 && pos < dataSize) { asETokenClass t = engine->ParseToken(&buffer[pos], 0, &len); if (t == asTC_KEYWORD) { if (buffer[pos] == '{') ++level; else if(buffer[pos] == '}') --level; } pos += len; } } else ++pos; } } // Process includes first for (unsigned i = 0; i < includeFiles.Size(); ++i) { cache->StoreResourceDependency(this, includeFiles[i]); SharedPtr<File> file = cache->GetFile(includeFiles[i]); if (file) { if (!AddScriptSection(engine, *file)) return false; } else { LOGERROR("Could not process all the include directives in " + GetName() + ": missing " + includeFiles[i]); return false; } } // Then add this section if (scriptModule_->AddScriptSection(source.GetName().CString(), (const char*)buffer.Get(), dataSize) < 0) { LOGERROR("Failed to add script section " + source.GetName()); return false; } SetMemoryUse(GetMemoryUse() + dataSize); return true; }
bool Shader::ProcessSource(SharedArrayPtr<char>& dest, unsigned& length, const String& fileName) { ResourceCache* cache = GetSubsystem<ResourceCache>(); if (!cache) return false; // Allow to define only a vertex shader or only a pixel shader if (!cache->Exists(fileName)) return true; cache->StoreResourceDependency(this, fileName); Vector<String> glslCode; // Load the shader source code SharedPtr<File> glslFile = cache->GetFile(fileName); if (!glslFile) return false; while (!glslFile->IsEof()) glslCode.Push(glslFile->ReadLine()); // Process the code for includes for (unsigned i = 0; i < glslCode.Size(); ++i) { if (glslCode[i].StartsWith("#include")) { String includeFileName = GetPath(fileName) + glslCode[i].Substring(9).Replaced("\"", "").Trimmed(); SharedPtr<File> glslIncludeFile = cache->GetFile(includeFileName); if (!glslIncludeFile) return false; // Remove the #include line, then include the code glslCode.Erase(i); unsigned pos = i; while (!glslIncludeFile->IsEof()) { glslCode.Insert(pos, glslIncludeFile->ReadLine()); ++pos; } // Finally insert an empty line to mark the space between files glslCode.Insert(pos, ""); } } // Copy the final code into one memory block length = 0; for (unsigned i = 0; i < glslCode.Size(); ++i) length += glslCode[i].Length() + 1; dest = new char[length]; char* destPtr = dest.Get(); for (unsigned i = 0; i < glslCode.Size(); ++i) { memcpy(destPtr, glslCode[i].CString(), glslCode[i].Length()); destPtr += glslCode[i].Length(); *destPtr++ = '\n'; } return true; }
bool TextureCube::BeginLoad(Deserializer& source) { ResourceCache* cache = context_->resourceCache(); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } cache->ResetDependencies(this); QString texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); loadParameters_ = (new XMLFile(context_)); if (!loadParameters_->Load(source)) { loadParameters_.Reset(); return false; } loadImages_.clear(); XMLElement textureElem = loadParameters_->GetRoot(); XMLElement imageElem = textureElem.GetChild("image"); // Single image and multiple faces with layout if (imageElem) { QString name = imageElem.GetAttribute("name"); // If path is empty, add the XML file path if (GetPath(name).isEmpty()) name = texPath + name; SharedPtr<Image> image = cache->GetTempResource<Image>(name); if (!image) return false; int faceWidth, faceHeight; loadImages_.resize(MAX_CUBEMAP_FACES); if (image->IsCubemap()) { loadImages_[FACE_POSITIVE_X] = image; loadImages_[FACE_NEGATIVE_X] = loadImages_[FACE_POSITIVE_X]->GetNextSibling(); loadImages_[FACE_POSITIVE_Y] = loadImages_[FACE_NEGATIVE_X]->GetNextSibling(); loadImages_[FACE_NEGATIVE_Y] = loadImages_[FACE_POSITIVE_Y]->GetNextSibling(); loadImages_[FACE_POSITIVE_Z] = loadImages_[FACE_NEGATIVE_Y]->GetNextSibling(); loadImages_[FACE_NEGATIVE_Z] = loadImages_[FACE_POSITIVE_Z]->GetNextSibling(); } else { CubeMapLayout layout = (CubeMapLayout)GetStringListIndex(imageElem.GetAttribute("layout"), cubeMapLayoutNames, CML_HORIZONTAL); switch (layout) { case CML_HORIZONTAL: faceWidth = image->GetWidth() / MAX_CUBEMAP_FACES; faceHeight = image->GetHeight(); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 0, 0, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 2, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 3, 0, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 4, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 5, 0, faceWidth, faceHeight); break; case CML_HORIZONTALNVIDIA: faceWidth = image->GetWidth() / MAX_CUBEMAP_FACES; faceHeight = image->GetHeight(); for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) loadImages_[i] = GetTileImage(image, i, 0, faceWidth, faceHeight); break; case CML_HORIZONTALCROSS: faceWidth = image->GetWidth() / 4; faceHeight = image->GetHeight() / 3; loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 0, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 1, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 2, 1, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 3, 1, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 1, 2, faceWidth, faceHeight); break; case CML_VERTICALCROSS: faceWidth = image->GetWidth() / 3; faceHeight = image->GetHeight() / 4; loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 0, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 1, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 2, 1, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 1, 2, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 1, 3, faceWidth, faceHeight); if (loadImages_[FACE_NEGATIVE_Z]) { loadImages_[FACE_NEGATIVE_Z]->FlipVertical(); loadImages_[FACE_NEGATIVE_Z]->FlipHorizontal(); } break; case CML_BLENDER: faceWidth = image->GetWidth() / 3; faceHeight = image->GetHeight() / 2; loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 0, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 2, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 0, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 1, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 2, 1, faceWidth, faceHeight); break; } } } // Face per image else { XMLElement faceElem = textureElem.GetChild("face"); while (faceElem) { QString name = faceElem.GetAttribute("name"); // If path is empty, add the XML file path if (GetPath(name).isEmpty()) name = texPath + name; loadImages_.push_back(cache->GetTempResource<Image>(name)); cache->StoreResourceDependency(this, name); faceElem = faceElem.GetNext("face"); } } // Precalculate mip levels if async loading if (GetAsyncLoadState() == ASYNC_LOADING) { for (unsigned i = 0; i < loadImages_.size(); ++i) { if (loadImages_[i]) loadImages_[i]->PrecalculateLevels(); } } return true; }
bool Texture3D::BeginLoad(Deserializer& source) { ResourceCache* cache = GetSubsystem<ResourceCache>(); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } String texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); cache->ResetDependencies(this); loadParameters_ = new XMLFile(context_); if (!loadParameters_->Load(source)) { loadParameters_.Reset(); return false; } XMLElement textureElem = loadParameters_->GetRoot(); XMLElement volumeElem = textureElem.GetChild("volume"); XMLElement colorlutElem = textureElem.GetChild("colorlut"); if (volumeElem) { String name = volumeElem.GetAttribute("name"); String volumeTexPath, volumeTexName, volumeTexExt; SplitPath(name, volumeTexPath, volumeTexName, volumeTexExt); // If path is empty, add the XML file path if (volumeTexPath.Empty()) name = texPath + name; loadImage_ = cache->GetTempResource<Image>(name); // Precalculate mip levels if async loading if (loadImage_ && GetAsyncLoadState() == ASYNC_LOADING) loadImage_->PrecalculateLevels(); cache->StoreResourceDependency(this, name); return true; } else if (colorlutElem) { String name = colorlutElem.GetAttribute("name"); String colorlutTexPath, colorlutTexName, colorlutTexExt; SplitPath(name, colorlutTexPath, colorlutTexName, colorlutTexExt); // If path is empty, add the XML file path if (colorlutTexPath.Empty()) name = texPath + name; SharedPtr<File> file = GetSubsystem<ResourceCache>()->GetFile(name); loadImage_ = new Image(context_); if (!loadImage_->LoadColorLUT(*(file.Get()))) { loadParameters_.Reset(); loadImage_.Reset(); return false; } // Precalculate mip levels if async loading if (loadImage_ && GetAsyncLoadState() == ASYNC_LOADING) loadImage_->PrecalculateLevels(); cache->StoreResourceDependency(this, name); return true; } URHO3D_LOGERROR("Texture3D XML data for " + GetName() + " did not contain either volume or colorlut element"); return false; }