static int Deserializer_Read(duk_context* ctx) { duk_int_t magic = duk_get_current_magic(ctx); duk_push_this(ctx); // safe cast based on type check above Deserializer* deserial = CastToDeserializer(ctx, duk_get_top_index(ctx)); duk_pop(ctx); if (!deserial) { duk_push_boolean(ctx, 0); return 1; } char* data; String str; size_t length; IO_MAGIC_TYPE v = (IO_MAGIC_TYPE) magic; bool success = false; switch(v) { case IO_MAGIC_INT: duk_push_number(ctx, (double) deserial->ReadInt()); return 1; case IO_MAGIC_STRING: length = deserial->GetSize() - deserial->GetPosition(); str.Resize(length + 1); deserial->Read(&str[0], length); str[length] = '\0'; duk_push_string(ctx, str.CString()); return 1; case IO_MAGIC_ZEROSTRING: success = duk_push_string(ctx, deserial->ReadString().CString()); return 1; case IO_MAGIC_BINARY: length = deserial->GetSize() - deserial->GetPosition(); duk_push_fixed_buffer(ctx, length); duk_push_buffer_object(ctx, -1, 0, length, DUK_BUFOBJ_UINT8ARRAY); duk_replace(ctx, -2); data = (char*) duk_require_buffer_data(ctx, 0, &length); success = deserial->Read(data, length); return 1; default: break; } duk_push_undefined(ctx); return 1; }
bool CompressStream(Serializer& dest, Deserializer& src) { unsigned srcSize = src.GetSize() - src.GetPosition(); // Prepend the source and dest. data size in the stream so that we know to buffer & uncompress the right amount if (!srcSize) { dest.WriteUInt(0); dest.WriteUInt(0); return true; } unsigned maxDestSize = LZ4_compressBound(srcSize); SharedArrayPtr<unsigned char> srcBuffer(new unsigned char[srcSize]); SharedArrayPtr<unsigned char> destBuffer(new unsigned char[maxDestSize]); if (src.Read(srcBuffer, srcSize) != srcSize) return false; unsigned destSize = LZ4_compressHC((const char*)srcBuffer.Get(), (char*)destBuffer.Get(), srcSize); bool success = true; success &= dest.WriteUInt(srcSize); success &= dest.WriteUInt(destSize); success &= dest.Write(destBuffer, destSize) == destSize; return success; }
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 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 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; }
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 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 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 UnknownComponent::Load(Deserializer& source, bool setInstanceDefault) { useXML_ = false; xmlAttributes_.Clear(); xmlAttributeInfos_.Clear(); // Assume we are reading from a component data buffer, and the type has already been read unsigned dataSize = source.GetSize() - source.GetPosition(); binaryAttributes_.Resize(dataSize); return dataSize ? source.Read(&binaryAttributes_[0], dataSize) == dataSize : 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; }
static int Deserializer_Read(duk_context* ctx) { duk_int_t magic = duk_get_current_magic(ctx); duk_push_this(ctx); // safe cast based on type check above Deserializer* deserial = CastToDeserializer(ctx, duk_get_top_index(ctx)); duk_pop(ctx); if (!deserial) { duk_push_boolean(ctx, 0); return 1; } PODVector<unsigned char> buffer; String str; size_t length; IO_MAGIC_TYPE v = (IO_MAGIC_TYPE) magic; bool success = false; switch(v) { case IO_MAGIC_INT: duk_push_number(ctx, (double) deserial->ReadInt()); return 1; case IO_MAGIC_STRING: length = deserial->GetSize() - deserial->GetPosition(); str.Resize(length + 1); deserial->Read(&str[0], length); str[length] = '\0'; duk_push_string(ctx, str.CString()); return 1; case IO_MAGIC_ZEROSTRING: success = duk_push_string(ctx, deserial->ReadString().CString()); return 1; default: break; } duk_push_undefined(ctx); return 1; }
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; }
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; }
static int Deserializer_GetSize(duk_context* ctx) { duk_push_this(ctx); // safe cast based on type check above Deserializer* deserial = CastToDeserializer(ctx, duk_get_top_index(ctx)); duk_pop(ctx); if (!deserial) { duk_push_boolean(ctx, 0); return 1; } duk_push_number(ctx, (double)deserial->GetSize()); return 1; }
bool DecompressStream(Serializer& dest, Deserializer& src) { if (src.IsEof()) return false; unsigned destSize = src.ReadUInt(); unsigned srcSize = src.ReadUInt(); if (!srcSize || !destSize) return true; // No data if (srcSize > src.GetSize()) return false; // Illegal source (packed data) size reported, possibly not valid data SharedArrayPtr<unsigned char> srcBuffer(new unsigned char[srcSize]); SharedArrayPtr<unsigned char> destBuffer(new unsigned char[destSize]); if (src.Read(srcBuffer, srcSize) != srcSize) return false; LZ4_decompress_fast((const char*)srcBuffer.Get(), (char*)destBuffer.Get(), destSize); return dest.Write(destBuffer, destSize) == destSize; }
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 ScriptFile::BeginLoad(Deserializer& source) { ReleaseModule(); loadByteCode_.Reset(); asIScriptEngine* engine = script_->GetScriptEngine(); { MutexLock lock(script_->GetModuleMutex()); // Create the module. Discard previous module if there was one scriptModule_ = engine->GetModule(GetName().CString(), asGM_ALWAYS_CREATE); if (!scriptModule_) { LOGERROR("Failed to create script module " + GetName()); return false; } } // Check if this file is precompiled bytecode if (source.ReadFileID() == "ASBC") { // Perform actual parsing in EndLoad(); read data now loadByteCodeSize_ = source.GetSize() - source.GetPosition(); loadByteCode_ = new unsigned char[loadByteCodeSize_]; source.Read(loadByteCode_.Get(), loadByteCodeSize_); return true; } else source.Seek(0); // Not bytecode: add the initial section and check for includes. // Perform actual building during EndLoad(), as AngelScript can not multithread module compilation, // and static initializers may access arbitrary engine functionality which may not be thread-safe return AddScriptSection(engine, source); }
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 Animation2D::Load(Deserializer& source) { frameEndTimes_.Clear(); frameSprites_.Clear(); SharedPtr<XMLFile> xmlFile(new XMLFile(context_)); if(!xmlFile->Load(source)) { LOGERROR("Could not load animation"); return false; } SetMemoryUse(source.GetSize()); XMLElement rootElem = xmlFile->GetRoot("Animation"); if (!rootElem) { LOGERROR("Invalid animation"); return false; } ResourceCache* cache = GetSubsystem<ResourceCache>(); XMLElement keyFrameElem = rootElem.GetChild("Frame"); if (!keyFrameElem) { LOGERROR("Could not found key frame"); return false; } float endTime = 0.0f; while (keyFrameElem) { endTime += keyFrameElem.GetFloat("duration"); frameEndTimes_.Push(endTime); SharedPtr<Sprite2D> sprite; Vector<String> names = keyFrameElem.GetAttribute("sprite").Split('@'); if (names.Size() == 1) sprite = cache->GetResource<Sprite2D>(names[0]); else if (names.Size() == 2) { SpriteSheet2D* spriteSheet = cache->GetResource<SpriteSheet2D>(names[0]); if (!spriteSheet) { LOGERROR("Could not get sprite speet"); return false; } sprite = spriteSheet->GetSprite(names[1]); } if (!sprite) { LOGERROR("Could not get sprite"); return false; } frameSprites_.Push(sprite); keyFrameElem = keyFrameElem.GetNext("Frame"); } 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 Sound::LoadWav(Deserializer& source) { WavHeader header; // Try to open memset(&header, 0, sizeof header); source.Read(&header.riffText_, 4); header.totalLength_ = source.ReadUInt(); source.Read(&header.waveText_, 4); if (memcmp("RIFF", header.riffText_, 4) || memcmp("WAVE", header.waveText_, 4)) { LOGERROR("Could not read WAV data from " + source.GetName()); return false; } // Search for the FORMAT chunk for (;;) { source.Read(&header.formatText_, 4); header.formatLength_ = source.ReadUInt(); if (!memcmp("fmt ", &header.formatText_, 4)) break; source.Seek(source.GetPosition() + header.formatLength_); if (!header.formatLength_ || source.GetPosition() >= source.GetSize()) { LOGERROR("Could not read WAV data from " + source.GetName()); return false; } } // Read the FORMAT chunk header.format_ = source.ReadUShort(); header.channels_ = source.ReadUShort(); header.frequency_ = source.ReadUInt(); header.avgBytes_ = source.ReadUInt(); header.blockAlign_ = source.ReadUShort(); header.bits_ = source.ReadUShort(); // Skip data if the format chunk was bigger than what we use source.Seek(source.GetPosition() + header.formatLength_ - 16); // Check for correct format if (header.format_ != 1) { LOGERROR("Could not read WAV data from " + source.GetName()); return false; } // Search for the DATA chunk for (;;) { source.Read(&header.dataText_, 4); header.dataLength_ = source.ReadUInt(); if (!memcmp("data", &header.dataText_, 4)) break; source.Seek(source.GetPosition() + header.dataLength_); if (!header.dataLength_ || source.GetPosition() >= source.GetSize()) { LOGERROR("Could not read WAV data from " + source.GetName()); return false; } } // Allocate sound and load audio data unsigned length = header.dataLength_; SetSize(length); SetFormat(header.frequency_, header.bits_ == 16, header.channels_ == 2); source.Read(data_.Get(), length); // Convert 8-bit audio to signed if (!sixteenBit_) { for (unsigned i = 0; i < length; ++i) data_[i] -= 128; } return true; }
bool Sound::LoadRaw(Deserializer& source) { unsigned dataSize = source.GetSize(); SetSize(dataSize); return source.Read(data_.Get(), dataSize) == dataSize; }
bool ParticleEffect2D::BeginLoad(Deserializer& source) { if (GetName().Empty()) SetName(source.GetName()); loadSpriteName_.Clear(); XMLFile xmlFile(context_); if (!xmlFile.Load(source)) return false; XMLElement rootElem = xmlFile.GetRoot("particleEmitterConfig"); if (!rootElem) return false; String texture = rootElem.GetChild("texture").GetAttribute("name"); loadSpriteName_ = GetParentPath(GetName()) + texture; // If async loading, request the sprite beforehand if (GetAsyncLoadState() == ASYNC_LOADING) GetSubsystem<ResourceCache>()->BackgroundLoadResource<Sprite2D>(loadSpriteName_, true, this); sourcePositionVariance_ = ReadVector2(rootElem, "sourcePositionVariance"); speed_ = ReadFloat(rootElem, "speed"); speedVariance_ = ReadFloat(rootElem, "speedVariance"); particleLifeSpan_ = Max(0.01f, ReadFloat(rootElem, "particleLifeSpan")); particleLifespanVariance_ = ReadFloat(rootElem, "particleLifespanVariance"); angle_ = ReadFloat(rootElem, "angle"); angleVariance_ = ReadFloat(rootElem, "angleVariance"); gravity_ = ReadVector2(rootElem, "gravity"); radialAcceleration_ = ReadFloat(rootElem, "radialAcceleration"); tangentialAcceleration_ = ReadFloat(rootElem, "tangentialAcceleration"); radialAccelVariance_ = ReadFloat(rootElem, "radialAccelVariance"); tangentialAccelVariance_ = ReadFloat(rootElem, "tangentialAccelVariance"); startColor_ = ReadColor(rootElem, "startColor"); startColorVariance_ = ReadColor(rootElem, "startColorVariance"); finishColor_ = ReadColor(rootElem, "finishColor"); finishColorVariance_ = ReadColor(rootElem, "finishColorVariance"); maxParticles_ = ReadInt(rootElem, "maxParticles"); startParticleSize_ = ReadFloat(rootElem, "startParticleSize"); startParticleSizeVariance_ = ReadFloat(rootElem, "startParticleSizeVariance"); finishParticleSize_ = ReadFloat(rootElem, "finishParticleSize"); // Typo in pex file finishParticleSizeVariance_ = ReadFloat(rootElem, "FinishParticleSizeVariance"); duration_ = M_INFINITY; if (rootElem.HasChild("duration")) { float duration = ReadFloat(rootElem, "duration"); if (duration > 0.0f) duration_ = duration; } emitterType_ = (EmitterType2D)ReadInt(rootElem, "emitterType"); maxRadius_ = ReadFloat(rootElem, "maxRadius"); maxRadiusVariance_ = ReadFloat(rootElem, "maxRadiusVariance"); minRadius_ = ReadFloat(rootElem, "minRadius"); minRadiusVariance_ = ReadFloat(rootElem, "minRadiusVariance"); rotatePerSecond_ = ReadFloat(rootElem, "rotatePerSecond"); rotatePerSecondVariance_ = ReadFloat(rootElem, "rotatePerSecondVariance"); int blendFuncSource = ReadInt(rootElem, "blendFuncSource"); int blendFuncDestination = ReadInt(rootElem, "blendFuncDestination"); blendMode_ = BLEND_ALPHA; for (int i = 0; i < MAX_BLENDMODES; ++i) { if (blendFuncSource == srcBlendFuncs[i] && blendFuncDestination == destBlendFuncs[i]) { blendMode_ = (BlendMode)i; break; } } rotationStart_ = ReadFloat(rootElem, "rotationStart"); rotationStartVariance_ = ReadFloat(rootElem, "rotationStartVariance"); rotationEnd_ = ReadFloat(rootElem, "rotationEnd"); rotationEndVariance_ = ReadFloat(rootElem, "rotationEndVariance"); // Note: not accurate SetMemoryUse(source.GetSize()); return true; }