bool PListFile::BeginLoad(Deserializer& source) { if (GetName().Empty()) SetName(source.GetName()); XMLFile xmlFile(context_); if (!xmlFile.Load(source)) { URHO3D_LOGERROR("Could not load property list"); return false; } XMLElement plistElem = xmlFile.GetRoot("plist"); if (!plistElem) { URHO3D_LOGERROR("Invalid property list file"); return false; } root_.Clear(); XMLElement dictElem = plistElem.GetChild("dict"); if (!LoadDict(root_, dictElem)) return false; SetMemoryUse(source.GetSize()); return true; }
bool XMLFile::Load(Deserializer& source) { PROFILE(LoadXMLFile); unsigned dataSize = source.GetSize(); if (!dataSize && !source.GetName().Empty()) { 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)) { LOGERROR("Could not parse XML data from " + source.GetName()); return false; } // Note: this probably does not reflect internal data structure size accurately SetMemoryUse(dataSize); return true; }
bool Font::Load(Deserializer& source) { PROFILE(LoadFont); // In headless mode, do not actually load, just return success Graphics* graphics = GetSubsystem<Graphics>(); if (!graphics) return true; faces_.Clear(); fontDataSize_ = source.GetSize(); if (fontDataSize_) { fontData_ = new unsigned char[fontDataSize_]; if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_) return false; } else { fontData_.Reset(); return false; } String ext = GetExtension(GetName()).ToLower(); if (ext == ".ttf") fontType_ = FONT_TTF; else if (ext == ".xml" || ext == ".fnt") fontType_ = FONT_BITMAP; SetMemoryUse(fontDataSize_); return true; }
bool Sound::LoadOggVorbis(Deserializer& source) { unsigned dataSize = source.GetSize(); SharedArrayPtr<signed char> data(new signed char[dataSize]); source.Read(data.Get(), dataSize); // Check for validity of data int error; stb_vorbis* vorbis = stb_vorbis_open_memory((unsigned char*)data.Get(), dataSize, &error, 0); if (!vorbis) { LOGERROR("Could not read Ogg Vorbis data from " + source.GetName()); return false; } // Store length, frequency and stereo flag stb_vorbis_info info = stb_vorbis_get_info(vorbis); compressedLength_ = stb_vorbis_stream_length_in_seconds(vorbis); frequency_ = info.sample_rate; stereo_ = info.channels > 1; stb_vorbis_close(vorbis); data_ = data; dataSize_ = dataSize; sixteenBit_ = true; compressed_ = true; SetMemoryUse(dataSize); return true; }
bool SpriteSheet2D::BeginLoadFromXMLFile(Deserializer& source) { loadXMLFile_ = new XMLFile(context_); if (!loadXMLFile_->Load(source)) { URHO3D_LOGERROR("Could not load sprite sheet"); loadXMLFile_.Reset(); return false; } SetMemoryUse(source.GetSize()); XMLElement rootElem = loadXMLFile_->GetRoot("TextureAtlas"); if (!rootElem) { URHO3D_LOGERROR("Invalid sprite sheet"); loadXMLFile_.Reset(); return false; } // If we're async loading, request the texture now. Finish during EndLoad(). loadTextureName_ = GetParentPath(GetName()) + rootElem.GetAttribute("imagePath"); if (GetAsyncLoadState() == ASYNC_LOADING) GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(loadTextureName_, true, this); return true; }
bool JSONFile::BeginLoad(Deserializer& source) { unsigned dataSize = source.GetSize(); if (!dataSize && !source.GetName().Empty()) { LOGERROR("Zero sized JSON data in " + source.GetName()); return false; } SharedArrayPtr<char> buffer(new char[dataSize + 1]); if (source.Read(buffer.Get(), dataSize) != dataSize) return false; buffer[dataSize] = '\0'; rapidjson::Document document; if (document.Parse<0>(buffer).HasParseError()) { LOGERROR("Could not parse JSON data from " + source.GetName()); return false; } ToJSONValue(root_, document); SetMemoryUse(dataSize); return true; }
void ScriptFile::ReleaseModule() { if (scriptModule_) { script_->ClearObjectTypeCache(); // Clear search caches and event handlers includeFiles_.Clear(); validClasses_.Clear(); functions_.Clear(); methods_.Clear(); UnsubscribeFromAllEventsExcept(PODVector<StringHash>(), true); // Remove the module scriptModule_->SetUserData(0); asIScriptEngine* engine = script_->GetScriptEngine(); engine->DiscardModule(GetName().CString()); scriptModule_ = 0; compiled_ = false; SetMemoryUse(0); ResourceCache* cache = GetSubsystem<ResourceCache>(); if (cache) cache->ResetDependencies(this); } }
void Material::RefreshMemoryUse() { unsigned memoryUse = sizeof(Material); memoryUse += techniques_.Size() * sizeof(TechniqueEntry); memoryUse += MAX_TEXTURE_UNITS * sizeof(SharedPtr<Texture>); memoryUse += shaderParameters_.Size() * sizeof(MaterialShaderParameter); SetMemoryUse(memoryUse); }
void Technique::RemovePass(const String& name) { HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower()); if (i == passIndices.End()) return; else if (i->second_ < passes_.Size() && passes_[i->second_].Get()) { passes_[i->second_].Reset(); SetMemoryUse((unsigned)(sizeof(Technique) + GetNumPasses() * sizeof(Pass))); } }
void Technique::RemovePass(const ea::string& name) { auto i = passIndices.find(name.to_lower()); if (i == passIndices.end()) return; else if (i->second < passes_.size() && passes_[i->second].get()) { passes_[i->second].reset(); SetMemoryUse((unsigned)(sizeof(Technique) + GetNumPasses() * sizeof(Pass))); } }
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; }
void Sound::SetSize(unsigned dataSize) { if (!dataSize) return; data_ = new signed char[dataSize + IP_SAFETY]; dataSize_ = dataSize; compressed_ = false; SetLooped(false); SetMemoryUse(dataSize + IP_SAFETY); }
bool LuaFile::BeginLoad(Deserializer& source) { size_ = source.GetSize(); if (size_ == 0) return false; // Read all data. data_ = new char[size_]; if (source.Read(data_, size_) != size_) return false; SetMemoryUse(size_); return true; }
void Image::SetSize(int width, int height, unsigned components) { if (width == width_ && height == height_ && components == components_) return; if (width <= 0 || height <= 0) return; data_ = new unsigned char[width * height * components]; width_ = width; height_ = height; components_ = components; compressedFormat_ = CF_NONE; numCompressedLevels_ = 0; SetMemoryUse(width * height * components); }
Pass* Technique::CreatePass(const ea::string& name) { Pass* oldPass = GetPass(name); if (oldPass) return oldPass; ea::shared_ptr<Pass> newPass(new Pass(name)); unsigned passIndex = newPass->GetIndex(); if (passIndex >= passes_.size()) passes_.resize(passIndex + 1); passes_[passIndex] = newPass; // Calculate memory use now SetMemoryUse((unsigned)(sizeof(Technique) + GetNumPasses() * sizeof(Pass))); return newPass; }
bool ParticleEffect::BeginLoad(Deserializer& source) { loadMaterialName_.Clear(); XMLFile file(context_); if (!file.Load(source)) { URHO3D_LOGERROR("Load particle effect file failed"); return false; } XMLElement rootElem = file.GetRoot(); bool success = Load(rootElem); if (success) SetMemoryUse(source.GetSize()); return success; }
bool SpriteSheet2D::BeginLoadFromPListFile(Deserializer& source) { loadPListFile_ = new PListFile(context_); if (!loadPListFile_->Load(source)) { URHO3D_LOGERROR("Could not load sprite sheet"); loadPListFile_.Reset(); return false; } SetMemoryUse(source.GetSize()); const PListValueMap& root = loadPListFile_->GetRoot(); const PListValueMap& metadata = root["metadata"]->GetValueMap(); const String& textureFileName = metadata["realTextureFileName"]->GetString(); // If we're async loading, request the texture now. Finish during EndLoad(). loadTextureName_ = GetParentPath(GetName()) + textureFileName; if (GetAsyncLoadState() == ASYNC_LOADING) GetSubsystem<ResourceCache>()->BackgroundLoadResource<Texture2D>(loadTextureName_, true, this); return true; }
bool Font::BeginLoad(Deserializer& source) { // In headless mode, do not actually load, just return success Graphics* graphics = GetSubsystem<Graphics>(); if (!graphics) return true; fontType_ = FONT_NONE; faces_.Clear(); fontDataSize_ = source.GetSize(); if (fontDataSize_) { fontData_ = new unsigned char[fontDataSize_]; if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_) return false; } else { fontData_.Reset(); return false; } String ext = GetExtension(GetName()); if (ext == ".ttf" || ext == ".otf" || ext == ".woff") { fontType_ = FONT_FREETYPE; LoadParameters(); } else if (ext == ".xml" || ext == ".fnt" || ext == ".sdf") fontType_ = FONT_BITMAP; sdfFont_ = ext == ".sdf"; SetMemoryUse(fontDataSize_); return true; }
bool Technique::BeginLoad(Deserializer& source) { passes_.clear(); cloneTechniques_.clear(); SetMemoryUse(sizeof(Technique)); ea::shared_ptr<XMLFile> xml(context_->CreateObject<XMLFile>()); if (!xml->Load(source)) return false; XMLElement rootElem = xml->GetRoot(); if (rootElem.HasAttribute("desktop")) isDesktop_ = rootElem.GetBool("desktop"); ea::string globalVS = rootElem.GetAttribute("vs"); ea::string globalPS = rootElem.GetAttribute("ps"); ea::string globalVSDefines = rootElem.GetAttribute("vsdefines"); ea::string globalPSDefines = rootElem.GetAttribute("psdefines"); // End with space so that the pass-specific defines can be appended if (!globalVSDefines.empty()) globalVSDefines += ' '; if (!globalPSDefines.empty()) globalPSDefines += ' '; XMLElement passElem = rootElem.GetChild("pass"); while (passElem) { if (passElem.HasAttribute("name")) { Pass* newPass = CreatePass(passElem.GetAttribute("name")); if (passElem.HasAttribute("desktop")) newPass->SetIsDesktop(passElem.GetBool("desktop")); // Append global defines only when pass does not redefine the shader if (passElem.HasAttribute("vs")) { newPass->SetVertexShader(passElem.GetAttribute("vs")); newPass->SetVertexShaderDefines(passElem.GetAttribute("vsdefines")); } else { newPass->SetVertexShader(globalVS); newPass->SetVertexShaderDefines(globalVSDefines + passElem.GetAttribute("vsdefines")); } if (passElem.HasAttribute("ps")) { newPass->SetPixelShader(passElem.GetAttribute("ps")); newPass->SetPixelShaderDefines(passElem.GetAttribute("psdefines")); } else { newPass->SetPixelShader(globalPS); newPass->SetPixelShaderDefines(globalPSDefines + passElem.GetAttribute("psdefines")); } newPass->SetVertexShaderDefineExcludes(passElem.GetAttribute("vsexcludes")); newPass->SetPixelShaderDefineExcludes(passElem.GetAttribute("psexcludes")); if (passElem.HasAttribute("lighting")) { ea::string lighting = passElem.GetAttributeLower("lighting"); newPass->SetLightingMode((PassLightingMode)GetStringListIndex(lighting.c_str(), lightingModeNames, LIGHTING_UNLIT)); } if (passElem.HasAttribute("blend")) { ea::string blend = passElem.GetAttributeLower("blend"); newPass->SetBlendMode((BlendMode)GetStringListIndex(blend.c_str(), blendModeNames, BLEND_REPLACE)); } if (passElem.HasAttribute("cull")) { ea::string cull = passElem.GetAttributeLower("cull"); newPass->SetCullMode((CullMode)GetStringListIndex(cull.c_str(), cullModeNames, MAX_CULLMODES)); } if (passElem.HasAttribute("depthtest")) { ea::string depthTest = passElem.GetAttributeLower("depthtest"); if (depthTest == "false") newPass->SetDepthTestMode(CMP_ALWAYS); else newPass->SetDepthTestMode((CompareMode)GetStringListIndex(depthTest.c_str(), compareModeNames, CMP_LESS)); } if (passElem.HasAttribute("depthwrite")) newPass->SetDepthWrite(passElem.GetBool("depthwrite")); if (passElem.HasAttribute("alphatocoverage")) newPass->SetAlphaToCoverage(passElem.GetBool("alphatocoverage")); } else URHO3D_LOGERROR("Missing pass name"); passElem = passElem.GetNext("pass"); } return true; }
bool TextureCube::Load(CubeMapFace face, SharedPtr<Image> image, bool useAlpha) { if (!image) { LOGERROR("Null image, can not load texture"); return false; } unsigned memoryUse = 0; int quality = QUALITY_HIGH; Renderer* renderer = GetSubsystem<Renderer>(); if (renderer) quality = renderer->GetTextureQuality(); if (!image->IsCompressed()) { unsigned char* levelData = image->GetData(); int levelWidth = image->GetWidth(); int levelHeight = image->GetHeight(); unsigned components = image->GetComponents(); unsigned format = 0; if (levelWidth != levelHeight) { LOGERROR("Cube texture width not equal to height"); return false; } // Discard unnecessary mip levels for (unsigned i = 0; i < mipsToSkip_[quality]; ++i) { image = image->GetNextLevel(); levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } switch (components) { case 1: format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat(); break; case 2: format = Graphics::GetLuminanceAlphaFormat(); break; case 3: format = Graphics::GetRGBFormat(); break; case 4: format = Graphics::GetRGBAFormat(); break; } // Create the texture when face 0 is being loaded, check that rest of the faces are same size & format if (!face) { // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size if (IsCompressed() && requestedLevels_ > 1) requestedLevels_ = 0; SetSize(levelWidth, format); } else { if (!object_) { LOGERROR("Cube texture face 0 must be loaded first"); return false; } if (levelWidth != width_ || format != format_) { LOGERROR("Cube texture face does not match size or format of face 0"); return false; } } for (unsigned i = 0; i < levels_; ++i) { SetData(face, i, 0, 0, levelWidth, levelHeight, levelData); memoryUse += levelWidth * levelHeight * components; if (i < levels_ - 1) { image = image->GetNextLevel(); levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } } } else { int width = image->GetWidth(); int height = image->GetHeight(); unsigned levels = image->GetNumCompressedLevels(); unsigned format = graphics_->GetFormat(image->GetCompressedFormat()); bool needDecompress = false; if (width != height) { LOGERROR("Cube texture width not equal to height"); return false; } if (!format) { format = Graphics::GetRGBAFormat(); needDecompress = true; } unsigned mipsToSkip = mipsToSkip_[quality]; if (mipsToSkip >= levels) mipsToSkip = levels - 1; while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4)) --mipsToSkip; width /= (1 << mipsToSkip); height /= (1 << mipsToSkip); // Create the texture when face 0 is being loaded, assume rest of the faces are same size & format if (!face) { SetNumLevels(Max((int)(levels - mipsToSkip), 1)); SetSize(width, format); } else { if (!object_) { LOGERROR("Cube texture face 0 must be loaded first"); return false; } if (width != width_ || format != format_) { LOGERROR("Cube texture face does not match size or format of face 0"); return false; } } for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i) { CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip); if (!needDecompress) { SetData(face, i, 0, 0, level.width_, level.height_, level.data_); memoryUse += level.rows_ * level.rowSize_; } else { unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4]; level.Decompress(rgbaData); SetData(face, i, 0, 0, level.width_, level.height_, rgbaData); memoryUse += level.width_ * level.height_ * 4; delete[] rgbaData; } } } faceMemoryUse_[face] = memoryUse; unsigned totalMemoryUse = sizeof(TextureCube); for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) totalMemoryUse += faceMemoryUse_[i]; SetMemoryUse(totalMemoryUse); return true; }
bool SpriteSheet2D::Load(Deserializer& source) { spriteMapping_.Clear(); SharedPtr<XMLFile> xmlFile(new XMLFile(context_)); if(!xmlFile->Load(source)) { LOGERROR("Could not load sprite sheet"); return false; } SetMemoryUse(source.GetSize()); XMLElement rootElem = xmlFile->GetRoot(); if (!rootElem) { LOGERROR("Invalid sprite sheet"); return false; } if (rootElem.GetName() == "spritesheet") { ResourceCache* cache = GetSubsystem<ResourceCache>(); String textureFileName = rootElem.GetAttribute("texture"); texture_ = cache->GetResource<Texture2D>(textureFileName, false); // If texture not found, try get in current directory if (!texture_) texture_ = cache->GetResource<Texture2D>(GetParentPath(GetName()) + textureFileName); if (!texture_) { LOGERROR("Cound not load texture"); return false; } XMLElement spriteElem = rootElem.GetChild("sprite"); while (spriteElem) { String name = spriteElem.GetAttribute("name"); IntRect rectangle = spriteElem.GetIntRect("rectangle"); Vector2 hotSpot(0.5f, 0.5f); if (spriteElem.HasAttribute("hotspot")) hotSpot = spriteElem.GetVector2("hotspot"); DefineSprite(name, rectangle, hotSpot); spriteElem = spriteElem.GetNext("sprite"); } } // Sparrow Starling texture atlas else if (rootElem.GetName() == "TextureAtlas") { String textureFileName = rootElem.GetAttribute("imagePath"); ResourceCache* cache = GetSubsystem<ResourceCache>(); texture_ = cache->GetResource<Texture2D>(textureFileName, false); // If texture not found, try get in current directory if (!texture_) texture_ = cache->GetResource<Texture2D>(GetParentPath(GetName()) + textureFileName); if (!texture_) { LOGERROR("Cound not load texture"); return false; } XMLElement subTextureElem = rootElem.GetChild("SubTexture"); while (subTextureElem) { String name = subTextureElem.GetAttribute("name"); int x = subTextureElem.GetInt("x"); int y = subTextureElem.GetInt("y"); int width = subTextureElem.GetInt("width"); int height = subTextureElem.GetInt("height"); IntRect rectangle(x, y, x + width, y + height); Vector2 hotSpot(0.5f, 0.5f); if (subTextureElem.HasAttribute("frameWidth") && subTextureElem.HasAttribute("frameHeight")) { int frameX = subTextureElem.GetInt("frameX"); int frameY = subTextureElem.GetInt("frameY"); int frameWidth = subTextureElem.GetInt("frameWidth"); int frameHeight = subTextureElem.GetInt("frameHeight"); hotSpot.x_ = ((float)frameX + frameWidth / 2) / width; hotSpot.y_ = 1.0f - ((float)frameY + frameHeight / 2) / height; } DefineSprite(name, rectangle, hotSpot); subTextureElem = subTextureElem.GetNext("SubTexture"); } } else { LOGERROR("Invalid sprite sheet file"); return false; } return true; }
bool Technique::BeginLoad(Deserializer& source) { passes_.Clear(); SetMemoryUse(sizeof(Technique)); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(source)) return false; XMLElement rootElem = xml->GetRoot(); if (rootElem.HasAttribute("sm3")) isSM3_ = rootElem.GetBool("sm3"); String globalVS = rootElem.GetAttribute("vs"); String globalPS = rootElem.GetAttribute("ps"); String globalVSDefines = rootElem.GetAttribute("vsdefines"); String globalPSDefines = rootElem.GetAttribute("psdefines"); // End with space so that the pass-specific defines can be appended if (!globalVSDefines.Empty()) globalVSDefines += ' '; if (!globalPSDefines.Empty()) globalPSDefines += ' '; bool globalAlphaMask = false; if (rootElem.HasAttribute("alphamask")) globalAlphaMask = rootElem.GetBool("alphamask"); unsigned numPasses = 0; XMLElement passElem = rootElem.GetChild("pass"); while (passElem) { if (passElem.HasAttribute("name")) { StringHash nameHash(passElem.GetAttribute("name")); Pass* newPass = CreatePass(nameHash); ++numPasses; if (passElem.HasAttribute("sm3")) newPass->SetIsSM3(passElem.GetBool("sm3")); // Append global defines only when pass does not redefine the shader if (passElem.HasAttribute("vs")) { newPass->SetVertexShader(passElem.GetAttribute("vs")); newPass->SetVertexShaderDefines(passElem.GetAttribute("vsdefines")); } else { newPass->SetVertexShader(globalVS); newPass->SetVertexShaderDefines(globalVSDefines + passElem.GetAttribute("vsdefines")); } if (passElem.HasAttribute("ps")) { newPass->SetPixelShader(passElem.GetAttribute("ps")); newPass->SetPixelShaderDefines(passElem.GetAttribute("psdefines")); } else { newPass->SetPixelShader(globalPS); newPass->SetPixelShaderDefines(globalPSDefines + passElem.GetAttribute("psdefines")); } if (passElem.HasAttribute("lighting")) { String lighting = passElem.GetAttributeLower("lighting"); newPass->SetLightingMode((PassLightingMode)GetStringListIndex(lighting.CString(), lightingModeNames, LIGHTING_UNLIT)); } if (passElem.HasAttribute("blend")) { String blend = passElem.GetAttributeLower("blend"); newPass->SetBlendMode((BlendMode)GetStringListIndex(blend.CString(), blendModeNames, BLEND_REPLACE)); } if (passElem.HasAttribute("depthtest")) { String depthTest = passElem.GetAttributeLower("depthtest"); if (depthTest == "false") newPass->SetDepthTestMode(CMP_ALWAYS); else newPass->SetDepthTestMode((CompareMode)GetStringListIndex(depthTest.CString(), compareModeNames, CMP_LESS)); } if (passElem.HasAttribute("depthwrite")) newPass->SetDepthWrite(passElem.GetBool("depthwrite")); if (passElem.HasAttribute("alphamask")) newPass->SetAlphaMask(passElem.GetBool("alphamask")); else newPass->SetAlphaMask(globalAlphaMask); } else LOGERROR("Missing pass name"); passElem = passElem.GetNext("pass"); } // Calculate memory use now SetMemoryUse(sizeof(Technique) + numPasses * sizeof(Pass)); return true; }
bool Technique::Load(Deserializer& source) { PROFILE(LoadTechnique); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(source)) return false; XMLElement rootElem = xml->GetRoot(); if (rootElem.HasAttribute("sm3")) isSM3_ = rootElem.GetBool("sm3"); unsigned numPasses = 0; XMLElement passElem = rootElem.GetChild("pass"); while (passElem) { if (passElem.HasAttribute("name")) { StringHash nameHash(passElem.GetAttribute("name")); Pass* newPass = CreatePass(nameHash); ++numPasses; if (passElem.HasAttribute("vs")) newPass->SetVertexShader(passElem.GetAttribute("vs")); if (passElem.HasAttribute("ps")) newPass->SetPixelShader(passElem.GetAttribute("ps")); if (passElem.HasAttribute("lighting")) { String lighting = passElem.GetAttributeLower("lighting"); newPass->SetLightingMode((PassLightingMode)GetStringListIndex(lighting.CString(), lightingModeNames, LIGHTING_UNLIT)); } if (passElem.HasAttribute("blend")) { String blend = passElem.GetAttributeLower("blend"); newPass->SetBlendMode((BlendMode)GetStringListIndex(blend.CString(), blendModeNames, BLEND_REPLACE)); } if (passElem.HasAttribute("depthtest")) { String depthTest = passElem.GetAttributeLower("depthtest"); if (depthTest == "false") newPass->SetDepthTestMode(CMP_ALWAYS); else newPass->SetDepthTestMode((CompareMode)GetStringListIndex(depthTest.CString(), compareModeNames, CMP_LESS)); } if (passElem.HasAttribute("depthwrite")) newPass->SetDepthWrite(passElem.GetBool("depthwrite")); if (passElem.HasAttribute("alphamask")) newPass->SetAlphaMask(passElem.GetBool("alphamask")); } else LOGERROR("Missing pass name"); passElem = passElem.GetNext("pass"); } // Calculate memory use unsigned memoryUse = sizeof(Technique) + numPasses * sizeof(Pass); SetMemoryUse(memoryUse); return true; }
bool Texture2D::SetData(SharedPtr<Image> image, bool useAlpha) { if (!image) { URHO3D_LOGERROR("Null image, can not set data"); return false; } unsigned memoryUse = sizeof(Texture2D); int quality = QUALITY_HIGH; Renderer* renderer = GetSubsystem<Renderer>(); if (renderer) quality = renderer->GetTextureQuality(); if (!image->IsCompressed()) { // Convert unsuitable formats to RGBA unsigned components = image->GetComponents(); if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2)) { image = image->ConvertToRGBA(); if (!image) return false; components = image->GetComponents(); } unsigned char* levelData = image->GetData(); int levelWidth = image->GetWidth(); int levelHeight = image->GetHeight(); unsigned format = 0; // Discard unnecessary mip levels for (unsigned i = 0; i < mipsToSkip_[quality]; ++i) { image = image->GetNextLevel(); levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } switch (components) { case 1: format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat(); break; case 2: format = Graphics::GetLuminanceAlphaFormat(); break; case 3: format = Graphics::GetRGBFormat(); break; case 4: format = Graphics::GetRGBAFormat(); break; default: assert(false); // Should not reach here break; } // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size if (IsCompressed() && requestedLevels_ > 1) requestedLevels_ = 0; SetSize(levelWidth, levelHeight, format); if (!object_) return false; for (unsigned i = 0; i < levels_; ++i) { SetData(i, 0, 0, levelWidth, levelHeight, levelData); memoryUse += levelWidth * levelHeight * components; if (i < levels_ - 1) { image = image->GetNextLevel(); levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } } } else { int width = image->GetWidth(); int height = image->GetHeight(); unsigned levels = image->GetNumCompressedLevels(); unsigned format = graphics_->GetFormat(image->GetCompressedFormat()); bool needDecompress = false; if (!format) { format = Graphics::GetRGBAFormat(); needDecompress = true; } unsigned mipsToSkip = mipsToSkip_[quality]; if (mipsToSkip >= levels) mipsToSkip = levels - 1; while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4)) --mipsToSkip; width /= (1 << mipsToSkip); height /= (1 << mipsToSkip); SetNumLevels((unsigned)Max((int)(levels - mipsToSkip), 1)); SetSize(width, height, format); for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i) { CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip); if (!needDecompress) { SetData(i, 0, 0, level.width_, level.height_, level.data_); memoryUse += level.rows_ * level.rowSize_; } else { unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4]; level.Decompress(rgbaData); SetData(i, 0, 0, level.width_, level.height_, rgbaData); memoryUse += level.width_ * level.height_ * 4; delete[] rgbaData; } } } SetMemoryUse(memoryUse); return true; }
bool Animation::Load(Deserializer& source) { PROFILE(LoadAnimation); unsigned memoryUse = sizeof(Animation); // Check ID if (source.ReadFileID() != "UANI") { LOGERROR(source.GetName() + " is not a valid animation file"); return false; } // Read name and length animationName_ = source.ReadString(); animationNameHash_ = animationName_; length_ = source.ReadFloat(); tracks_.Clear(); unsigned tracks = source.ReadUInt(); tracks_.Resize(tracks); memoryUse += tracks * sizeof(AnimationTrack); // Read tracks for (unsigned i = 0; i < tracks; ++i) { AnimationTrack& newTrack = tracks_[i]; newTrack.name_ = source.ReadString(); newTrack.nameHash_ = newTrack.name_; newTrack.channelMask_ = source.ReadUByte(); unsigned keyFrames = source.ReadUInt(); newTrack.keyFrames_.Resize(keyFrames); memoryUse += keyFrames * sizeof(AnimationKeyFrame); // Read keyframes of the track for (unsigned j = 0; j < keyFrames; ++j) { AnimationKeyFrame& newKeyFrame = newTrack.keyFrames_[j]; newKeyFrame.time_ = source.ReadFloat(); if (newTrack.channelMask_ & CHANNEL_POSITION) newKeyFrame.position_ = source.ReadVector3(); if (newTrack.channelMask_ & CHANNEL_ROTATION) newKeyFrame.rotation_ = source.ReadQuaternion(); if (newTrack.channelMask_ & CHANNEL_SCALE) newKeyFrame.scale_ = source.ReadVector3(); } } // Optionally read triggers from an XML file ResourceCache* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); if (cache->Exists(xmlName)) { XMLFile* file = cache->GetResource<XMLFile>(xmlName); if (file) { XMLElement rootElem = file->GetRoot(); XMLElement triggerElem = rootElem.GetChild("trigger"); while (triggerElem) { if (triggerElem.HasAttribute("normalizedtime")) AddTrigger(triggerElem.GetFloat("normalizedtime"), true, triggerElem.GetVariant()); else if (triggerElem.HasAttribute("time")) AddTrigger(triggerElem.GetFloat("time"), false, triggerElem.GetVariant()); triggerElem = triggerElem.GetNext("trigger"); } memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint); } } SetMemoryUse(memoryUse); return true; }
bool Animation::BeginLoad(Deserializer& source) { unsigned memoryUse = sizeof(Animation); // Check ID if (source.ReadFileID() != "UANI") { URHO3D_LOGERROR(source.GetName() + " is not a valid animation file"); return false; } // Read name and length animationName_ = source.ReadString(); animationNameHash_ = animationName_; length_ = source.ReadFloat(); tracks_.Clear(); unsigned tracks = source.ReadUInt(); memoryUse += tracks * sizeof(AnimationTrack); // Read tracks for (unsigned i = 0; i < tracks; ++i) { AnimationTrack* newTrack = CreateTrack(source.ReadString()); newTrack->channelMask_ = source.ReadUByte(); unsigned keyFrames = source.ReadUInt(); newTrack->keyFrames_.Resize(keyFrames); memoryUse += keyFrames * sizeof(AnimationKeyFrame); // Read keyframes of the track for (unsigned j = 0; j < keyFrames; ++j) { AnimationKeyFrame& newKeyFrame = newTrack->keyFrames_[j]; newKeyFrame.time_ = source.ReadFloat(); if (newTrack->channelMask_ & CHANNEL_POSITION) newKeyFrame.position_ = source.ReadVector3(); if (newTrack->channelMask_ & CHANNEL_ROTATION) newKeyFrame.rotation_ = source.ReadQuaternion(); if (newTrack->channelMask_ & CHANNEL_SCALE) newKeyFrame.scale_ = source.ReadVector3(); } } // Optionally read triggers from an XML file ResourceCache* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); SharedPtr<XMLFile> file(cache->GetTempResource<XMLFile>(xmlName, false)); if (file) { XMLElement rootElem = file->GetRoot(); XMLElement triggerElem = rootElem.GetChild("trigger"); while (triggerElem) { if (triggerElem.HasAttribute("normalizedtime")) AddTrigger(triggerElem.GetFloat("normalizedtime"), true, triggerElem.GetVariant()); else if (triggerElem.HasAttribute("time")) AddTrigger(triggerElem.GetFloat("time"), false, triggerElem.GetVariant()); triggerElem = triggerElem.GetNext("trigger"); } memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint); SetMemoryUse(memoryUse); return true; } // Optionally read triggers from a JSON file String jsonName = ReplaceExtension(GetName(), ".json"); SharedPtr<JSONFile> jsonFile(cache->GetTempResource<JSONFile>(jsonName, false)); if (jsonFile) { const JSONValue& rootVal = jsonFile->GetRoot(); JSONArray triggerArray = rootVal.Get("triggers").GetArray(); for (unsigned i = 0; i < triggerArray.Size(); i++) { const JSONValue& triggerValue = triggerArray.At(i); JSONValue normalizedTimeValue = triggerValue.Get("normalizedTime"); if (!normalizedTimeValue.IsNull()) AddTrigger(normalizedTimeValue.GetFloat(), true, triggerValue.GetVariant()); else { JSONValue timeVal = triggerValue.Get("time"); if (!timeVal.IsNull()) AddTrigger(timeVal.GetFloat(), false, triggerValue.GetVariant()); } } memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint); SetMemoryUse(memoryUse); return true; } SetMemoryUse(memoryUse); return true; }
bool Shader::Load(Deserializer& source) { PROFILE(LoadShader); Graphics* graphics = GetSubsystem<Graphics>(); if (!graphics) return false; vsSourceCodeLength_ = 0; psSourceCodeLength_ = 0; SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(source)) return false; XMLElement shaders = xml->GetRoot("shaders"); if (!shaders) { LOGERROR("No shaders element in " + source.GetName()); return false; } { PROFILE(ParseShaderDefinition); if (!vsParser_.Parse(VS, shaders)) { LOGERROR("VS: " + vsParser_.GetErrorMessage()); return false; } if (!psParser_.Parse(PS, shaders)) { LOGERROR("PS: " + psParser_.GetErrorMessage()); return false; } } String path, fileName, extension; SplitPath(GetName(), path, fileName, extension); { PROFILE(LoadShaderSource); if (!ProcessSource(vsSourceCode_, vsSourceCodeLength_, path + fileName + ".vert")) return false; if (!ProcessSource(psSourceCode_, psSourceCodeLength_, path + fileName + ".frag")) return false; } // If variations had already been created, release them and set new source code /// \todo Should also update defines for (HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = vsVariations_.Begin(); i != vsVariations_.End(); ++i) { i->second_->Release(); i->second_->SetSourceCode(vsSourceCode_, vsSourceCodeLength_); } for (HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = psVariations_.Begin(); i != psVariations_.End(); ++i) { i->second_->Release(); i->second_->SetSourceCode(psSourceCode_, psSourceCodeLength_); } SetMemoryUse(sizeof(Shader) + 2 * sizeof(ShaderParser) + (vsVariations_.Size() + psVariations_.Size()) * sizeof(ShaderVariation)); return true; }
ShaderVariation* Shader::GetVariation(ShaderType type, const String& name) { StringHash nameHash(name); if (type == VS) { if (vsParser_.HasCombination(name)) { HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = vsVariations_.Find(nameHash); // Create the shader variation now if not created yet if (i == vsVariations_.End()) { ShaderCombination combination = vsParser_.GetCombination(name); i = vsVariations_.Insert(MakePair(nameHash, SharedPtr<ShaderVariation>(new ShaderVariation(this, VS)))); String path, fileName, extension; SplitPath(GetName(), path, fileName, extension); String fullName = path + fileName + "_" + name; if (fullName.EndsWith("_")) fullName.Resize(fullName.Length() - 1); i->second_->SetName(fullName); i->second_->SetSourceCode(vsSourceCode_, vsSourceCodeLength_); i->second_->SetDefines(combination.defines_, combination.defineValues_); SetMemoryUse(GetMemoryUse() + sizeof(ShaderVariation)); } return i->second_; } else return 0; } else { if (psParser_.HasCombination(name)) { HashMap<StringHash, SharedPtr<ShaderVariation> >::Iterator i = psVariations_.Find(nameHash); // Create the shader variation now if not created yet if (i == psVariations_.End()) { ShaderCombination combination = psParser_.GetCombination(name); i = psVariations_.Insert(MakePair(nameHash, SharedPtr<ShaderVariation>(new ShaderVariation(this, PS)))); String path, fileName, extension; SplitPath(GetName(), path, fileName, extension); String fullName = path + fileName + "_" + name; if (fullName.EndsWith("_")) fullName.Resize(fullName.Length() - 1); i->second_->SetName(fullName); i->second_->SetSourceCode(psSourceCode_, psSourceCodeLength_); i->second_->SetDefines(combination.defines_, combination.defineValues_); SetMemoryUse(GetMemoryUse() + sizeof(ShaderVariation)); } return i->second_; } else return 0; } }
bool Texture2DArray::SetData(unsigned layer, Image* image, bool useAlpha) { if (!image) { URHO3D_LOGERROR("Null image, can not set data"); return false; } if (!layers_) { URHO3D_LOGERROR("Number of layers in the array must be set first"); return false; } if (layer >= layers_) { URHO3D_LOGERROR("Illegal layer for setting data"); return false; } // Use a shared ptr for managing the temporary mip images created during this function SharedPtr<Image> mipImage; unsigned memoryUse = 0; int quality = QUALITY_HIGH; Renderer* renderer = GetSubsystem<Renderer>(); if (renderer) quality = renderer->GetTextureQuality(); if (!image->IsCompressed()) { unsigned char* levelData = image->GetData(); int levelWidth = image->GetWidth(); int levelHeight = image->GetHeight(); unsigned components = image->GetComponents(); unsigned format = 0; // Discard unnecessary mip levels for (unsigned i = 0; i < mipsToSkip_[quality]; ++i) { mipImage = image->GetNextLevel(); image = mipImage; levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } switch (components) { case 1: format = Graphics::GetAlphaFormat(); break; case 4: format = Graphics::GetRGBAFormat(); break; default: break; } // Create the texture array when layer 0 is being loaded, check that rest of the layers are same size & format if (!layer) { // If image was previously compressed, reset number of requested levels to avoid error if level count is too high for new size if (IsCompressed() && requestedLevels_ > 1) requestedLevels_ = 0; // Create the texture array (the number of layers must have been already set) SetSize(0, levelWidth, levelHeight, format); } else { if (!object_.ptr_) { // Do not spam this error on D3D9 //URHO3D_LOGERROR("Texture array layer 0 must be loaded first"); return false; } if (levelWidth != width_ || levelHeight != height_ || format != format_) { URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0"); return false; } } for (unsigned i = 0; i < levels_; ++i) { SetData(layer, i, 0, 0, levelWidth, levelHeight, levelData); memoryUse += levelWidth * levelHeight * components; if (i < levels_ - 1) { mipImage = image->GetNextLevel(); image = mipImage; levelData = image->GetData(); levelWidth = image->GetWidth(); levelHeight = image->GetHeight(); } } } else { int width = image->GetWidth(); int height = image->GetHeight(); unsigned levels = image->GetNumCompressedLevels(); unsigned format = graphics_->GetFormat(image->GetCompressedFormat()); bool needDecompress = false; if (!format) { format = Graphics::GetRGBAFormat(); needDecompress = true; } unsigned mipsToSkip = mipsToSkip_[quality]; if (mipsToSkip >= levels) mipsToSkip = levels - 1; while (mipsToSkip && (width / (1 << mipsToSkip) < 4 || height / (1 << mipsToSkip) < 4)) --mipsToSkip; width /= (1 << mipsToSkip); height /= (1 << mipsToSkip); // Create the texture array when layer 0 is being loaded, assume rest of the layers are same size & format if (!layer) { SetNumLevels(Max((levels - mipsToSkip), 1U)); SetSize(0, width, height, format); } else { if (!object_.ptr_) { //URHO3D_LOGERROR("Texture array layer 0 must be loaded first"); return false; } if (width != width_ || height != height_ || format != format_) { URHO3D_LOGERROR("Texture array layer does not match size or format of layer 0"); return false; } } for (unsigned i = 0; i < levels_ && i < levels - mipsToSkip; ++i) { CompressedLevel level = image->GetCompressedLevel(i + mipsToSkip); if (!needDecompress) { SetData(layer, i, 0, 0, level.width_, level.height_, level.data_); memoryUse += level.rows_ * level.rowSize_; } else { unsigned char* rgbaData = new unsigned char[level.width_ * level.height_ * 4]; level.Decompress(rgbaData); SetData(layer, i, 0, 0, level.width_, level.height_, rgbaData); memoryUse += level.width_ * level.height_ * 4; delete[] rgbaData; } } } layerMemoryUse_[layer] = memoryUse; unsigned totalMemoryUse = sizeof(Texture2DArray) + layerMemoryUse_.Capacity() * sizeof(unsigned); for (unsigned i = 0; i < layers_; ++i) totalMemoryUse += layerMemoryUse_[i]; SetMemoryUse(totalMemoryUse); return true; }
bool Material::Load(const XMLElement& source) { ResetToDefaults(); if (source.IsNull()) { LOGERROR("Can not load material from null XML element"); return false; } ResourceCache* cache = GetSubsystem<ResourceCache>(); XMLElement techniqueElem = source.GetChild("technique"); techniques_.Clear(); while (techniqueElem) { Technique* tech = cache->GetResource<Technique>(techniqueElem.GetAttribute("name")); if (tech) { TechniqueEntry newTechnique; newTechnique.technique_ = tech; if (techniqueElem.HasAttribute("quality")) newTechnique.qualityLevel_ = techniqueElem.GetInt("quality"); if (techniqueElem.HasAttribute("loddistance")) newTechnique.lodDistance_ = techniqueElem.GetFloat("loddistance"); techniques_.Push(newTechnique); } techniqueElem = techniqueElem.GetNext("technique"); } SortTechniques(); XMLElement textureElem = source.GetChild("texture"); while (textureElem) { TextureUnit unit = TU_DIFFUSE; if (textureElem.HasAttribute("unit")) { String unitName = textureElem.GetAttributeLower("unit"); if (unitName.Length() > 1) { unit = ParseTextureUnitName(unitName); if (unit >= MAX_MATERIAL_TEXTURE_UNITS) LOGERROR("Unknown or illegal texture unit " + unitName); } else unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_MATERIAL_TEXTURE_UNITS - 1); } if (unit != MAX_MATERIAL_TEXTURE_UNITS) { String name = textureElem.GetAttribute("name"); // Detect cube maps by file extension: they are defined by an XML file if (GetExtension(name) == ".xml") SetTexture(unit, cache->GetResource<TextureCube>(name)); else SetTexture(unit, cache->GetResource<Texture2D>(name)); } textureElem = textureElem.GetNext("texture"); } XMLElement parameterElem = source.GetChild("parameter"); while (parameterElem) { String name = parameterElem.GetAttribute("name"); SetShaderParameter(name, ParseShaderParameterValue(parameterElem.GetAttribute("value"))); parameterElem = parameterElem.GetNext("parameter"); } XMLElement cullElem = source.GetChild("cull"); if (cullElem) SetCullMode((CullMode)GetStringListIndex(cullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW)); XMLElement shadowCullElem = source.GetChild("shadowcull"); if (shadowCullElem) SetShadowCullMode((CullMode)GetStringListIndex(shadowCullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW)); XMLElement depthBiasElem = source.GetChild("depthbias"); if (depthBiasElem) SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled"))); // Calculate memory use unsigned memoryUse = sizeof(Material); memoryUse += techniques_.Size() * sizeof(TechniqueEntry); memoryUse += MAX_MATERIAL_TEXTURE_UNITS * sizeof(SharedPtr<Texture>); memoryUse += shaderParameters_.Size() * sizeof(MaterialShaderParameter); SetMemoryUse(memoryUse); CheckOcclusion(); return true; }