void RenderTargetInfo::Load(const XMLElement& element) { name_ = element.GetAttribute("name"); tag_ = element.GetAttribute("tag"); if (element.HasAttribute("enabled")) enabled_ = element.GetBool("enabled"); String formatName = element.GetAttribute("format"); format_ = Graphics::GetFormat(formatName); if (element.HasAttribute("filter")) filtered_ = element.GetBool("filter"); if (element.HasAttribute("srgb")) sRGB_ = element.GetBool("srgb"); if (element.HasAttribute("size")) size_ = element.GetIntVector2("size"); if (element.HasAttribute("sizedivisor")) { size_ = element.GetIntVector2("sizedivisor"); sizeMode_ = SIZE_VIEWPORTDIVISOR; } if (element.HasAttribute("rtsizedivisor")) { size_ = element.GetIntVector2("rtsizedivisor"); sizeMode_ = SIZE_RENDERTARGETDIVISOR; } if (element.HasAttribute("width")) size_.x_ = element.GetInt("width"); if (element.HasAttribute("height")) size_.y_ = element.GetInt("height"); }
void TmxLayer2D::LoadInfo(const XMLElement& element) { name_ = element.GetAttribute("name"); width_ = element.GetInt("width"); height_ = element.GetInt("height"); if (element.HasAttribute("visible")) visible_ = element.GetInt("visible") != 0; else visible_ = true; }
void Texture::SetParameters(const XMLElement& element) { XMLElement paramElem = element.GetChild(); while (paramElem) { String name = paramElem.GetName(); if (name == "address") { String coord = paramElem.GetAttributeLower("coord"); if (coord.Length() >= 1) { TextureCoordinate coordIndex = (TextureCoordinate)(coord[0] - 'u'); String mode = paramElem.GetAttributeLower("mode"); SetAddressMode(coordIndex, (TextureAddressMode)GetStringListIndex(mode.CString(), addressModeNames, ADDRESS_WRAP)); } } if (name == "border") SetBorderColor(paramElem.GetColor("color")); if (name == "filter") { String mode = paramElem.GetAttributeLower("mode"); SetFilterMode((TextureFilterMode)GetStringListIndex(mode.CString(), filterModeNames, FILTER_DEFAULT)); } if (name == "mipmap") SetNumLevels(paramElem.GetBool("enable") ? 0 : 1); if (name == "quality") { if (paramElem.HasAttribute("low")) SetMipsToSkip(QUALITY_LOW, paramElem.GetInt("low")); if (paramElem.HasAttribute("med")) SetMipsToSkip(QUALITY_MEDIUM, paramElem.GetInt("med")); if (paramElem.HasAttribute("medium")) SetMipsToSkip(QUALITY_MEDIUM, paramElem.GetInt("medium")); if (paramElem.HasAttribute("high")) SetMipsToSkip(QUALITY_HIGH, paramElem.GetInt("high")); } if (name == "srgb") SetSRGB(paramElem.GetBool("enable")); paramElem = paramElem.GetNext(); } }
void Font::LoadParameters() { ResourceCache* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); SharedPtr<XMLFile> xml = cache->GetTempResource<XMLFile>(xmlName, false); if (!xml) return; XMLElement rootElem = xml->GetRoot(); XMLElement absoluteElem = rootElem.GetChild("absoluteoffset"); if (!absoluteElem) absoluteElem = rootElem.GetChild("absolute"); if (absoluteElem) { absoluteOffset_.x_ = absoluteElem.GetInt("x"); absoluteOffset_.y_ = absoluteElem.GetInt("y"); } XMLElement scaledElem = rootElem.GetChild("scaledoffset"); if (!scaledElem) scaledElem = rootElem.GetChild("scaled"); if (scaledElem) { scaledOffset_.x_ = scaledElem.GetFloat("x"); scaledOffset_.y_ = scaledElem.GetFloat("y"); } }
// ---------------------------------------------------------------------------- bool InputMapping::LoadInputMapping(XMLFile* config) { XMLElement contextElement = config->GetRoot().GetChild("context"); if(!contextElement) return false; while(contextElement) { String contextName = contextElement.GetAttribute("name"); if(contextName == "3rd person controls") { XMLElement mappingElement = contextElement.GetChild("mapping"); while(mappingElement) { String action = mappingElement.GetAttribute("action"); String device = mappingElement.GetAttribute("device"); int value = mappingElement.GetInt("value"); SetMapping(contextName, device, action, value); mappingElement = mappingElement.GetNext("mapping"); } } contextElement = contextElement.GetNext("context"); } return true; }
bool Node::LoadXML(const XMLElement& source, SceneResolver& resolver, bool readChildren, bool rewriteIDs, CreateMode mode) { // Remove all children and components first in case this is not a fresh load RemoveAllChildren(); RemoveAllComponents(); if (!Serializable::LoadXML(source)) return false; XMLElement compElem = source.GetChild("component"); while (compElem) { String typeName = compElem.GetAttribute("type"); unsigned compID = compElem.GetInt("id"); Component* newComponent = CreateComponent(typeName, (mode == REPLICATED && compID < FIRST_LOCAL_ID) ? REPLICATED : LOCAL, rewriteIDs ? 0 : compID); if (newComponent) { resolver.AddComponent(compID, newComponent); if (!newComponent->LoadXML(compElem)) return false; } compElem = compElem.GetNext("component"); } if (!readChildren) return true; XMLElement childElem = source.GetChild("node"); while (childElem) { unsigned nodeID = childElem.GetInt("id"); Node* newNode = CreateChild(rewriteIDs ? 0 : nodeID, (mode == REPLICATED && nodeID < FIRST_LOCAL_ID) ? REPLICATED : LOCAL); resolver.AddNode(nodeID, newNode); if (!newNode->LoadXML(childElem, resolver, readChildren, rewriteIDs, mode)) return false; childElem = childElem.GetNext("node"); } return true; }
void Sound::LoadParameters() { ResourceCache* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); if (!cache->Exists(xmlName)) return; XMLFile* file = cache->GetResource<XMLFile>(xmlName); if (!file) return; XMLElement rootElem = file->GetRoot(); XMLElement paramElem = rootElem.GetChild(); while (paramElem) { String name = paramElem.GetName(); if (name == "format" && !compressed_) { if (paramElem.HasAttribute("frequency")) frequency_ = paramElem.GetInt("frequency"); if (paramElem.HasAttribute("sixteenbit")) sixteenBit_ = paramElem.GetBool("sixteenbit"); if (paramElem.HasAttribute("16bit")) sixteenBit_ = paramElem.GetBool("16bit"); if (paramElem.HasAttribute("stereo")) stereo_ = paramElem.GetBool("stereo"); } if (name == "loop") { if (paramElem.HasAttribute("enable")) SetLooped(paramElem.GetBool("enable")); if (paramElem.HasAttribute("start") && paramElem.HasAttribute("end")) SetLoop(paramElem.GetInt("start"), paramElem.GetInt("end")); } paramElem = paramElem.GetNext(); } }
void Board::LoadRecord() { if (!GetSubsystem<FileSystem>()->FileExists(GetRecordsFileName())) return; XMLFile config(context_); config.Load(File(context_, GetRecordsFileName(), FILE_READ)); XMLElement root = config.GetRoot(); if (root.IsNull()) return; if (root.HasAttribute("_1")) record_ = root.GetInt("_1"); }
void RenderTargetInfo::Load(const XMLElement& element) { name_ = element.GetAttribute("name"); tag_ = element.GetAttribute("tag"); if (element.HasAttribute("enabled")) enabled_ = element.GetBool("enabled"); if (element.HasAttribute("cubemap")) cubemap_ = element.GetBool("cubemap"); String formatName = element.GetAttribute("format"); format_ = Graphics::GetFormat(formatName); if (element.HasAttribute("filter")) filtered_ = element.GetBool("filter"); if (element.HasAttribute("srgb")) sRGB_ = element.GetBool("srgb"); if (element.HasAttribute("persistent")) persistent_ = element.GetBool("persistent"); if (element.HasAttribute("size")) size_ = element.GetVector2("size"); if (element.HasAttribute("sizedivisor")) { size_ = element.GetVector2("sizedivisor"); sizeMode_ = SIZE_VIEWPORTDIVISOR; } else if (element.HasAttribute("rtsizedivisor")) { // Deprecated rtsizedivisor mode, acts the same as sizedivisor mode now URHO3D_LOGWARNING("Deprecated rtsizedivisor mode used in rendertarget definition"); size_ = element.GetVector2("rtsizedivisor"); sizeMode_ = SIZE_VIEWPORTDIVISOR; } else if (element.HasAttribute("sizemultiplier")) { size_ = element.GetVector2("sizemultiplier"); sizeMode_ = SIZE_VIEWPORTMULTIPLIER; } if (element.HasAttribute("width")) size_.x_ = element.GetFloat("width"); if (element.HasAttribute("height")) size_.y_ = element.GetFloat("height"); if (element.HasAttribute("multisample")) multiSample_ = Clamp(element.GetInt("multisample"), 1, 16); if (element.HasAttribute("autoresolve")) autoResolve_ = element.GetBool("autoresolve"); }
VariantMap XMLElement::GetVariantMap() const { VariantMap ret; XMLElement variantElem = GetChild("variant"); while (variantElem) { StringHash key(variantElem.GetInt("hash")); ret[key] = variantElem.GetVariant(); variantElem = variantElem.GetNext("variant"); } return ret; }
void Sound::LoadParameters() { auto* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); SharedPtr<XMLFile> file(cache->GetTempResource<XMLFile>(xmlName, false)); if (!file) return; XMLElement rootElem = file->GetRoot(); LoadMetadataFromXML(rootElem); for (XMLElement paramElem = rootElem.GetChild(); paramElem; paramElem = paramElem.GetNext()) { String name = paramElem.GetName(); if (name == "format" && !compressed_) { if (paramElem.HasAttribute("frequency")) frequency_ = (unsigned)paramElem.GetInt("frequency"); if (paramElem.HasAttribute("sixteenbit")) sixteenBit_ = paramElem.GetBool("sixteenbit"); if (paramElem.HasAttribute("16bit")) sixteenBit_ = paramElem.GetBool("16bit"); if (paramElem.HasAttribute("stereo")) stereo_ = paramElem.GetBool("stereo"); } if (name == "loop") { if (paramElem.HasAttribute("enable")) SetLooped(paramElem.GetBool("enable")); if (paramElem.HasAttribute("start") && paramElem.HasAttribute("end")) SetLoop((unsigned)paramElem.GetInt("start"), (unsigned)paramElem.GetInt("end")); } } }
bool Scene::LoadAsyncXML(File* file) { if (!file) { LOGERROR("Null file for async loading"); return false; } StopAsyncLoading(); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(*file)) return false; LOGINFO("Loading scene from " + file->GetName()); Clear(); XMLElement rootElement = xml->GetRoot(); // Store own old ID for resolving possible root node references unsigned nodeID = rootElement.GetInt("id"); resolver_.AddNode(nodeID, this); // Load the root level components first if (!Node::LoadXML(rootElement, resolver_, false)) return false; // Then prepare for loading all root level child nodes in the async update XMLElement childNodeElement = rootElement.GetChild("node"); asyncLoading_ = true; asyncProgress_.file_ = file; asyncProgress_.xmlFile_ = xml; asyncProgress_.xmlElement_ = childNodeElement; asyncProgress_.loadedNodes_ = 0; asyncProgress_.totalNodes_ = 0; // Count the amount of child nodes while (childNodeElement) { ++asyncProgress_.totalNodes_; childNodeElement = childNodeElement.GetNext("node"); } return true; }
bool TmxTileLayer2D::Load(const XMLElement& element, const TileMapInfo2D& info) { LoadInfo(element); XMLElement dataElem = element.GetChild("data"); if (!dataElem) { URHO3D_LOGERROR("Could not find data in layer"); return false; } if (dataElem.HasAttribute("encoding") && dataElem.GetAttribute("encoding") != "xml") { URHO3D_LOGERROR("Encoding not support now"); return false; } XMLElement tileElem = dataElem.GetChild("tile"); tiles_.Resize((unsigned)(width_ * height_)); for (int y = 0; y < height_; ++y) { for (int x = 0; x < width_; ++x) { if (!tileElem) return false; int gid = tileElem.GetInt("gid"); if (gid > 0) { SharedPtr<Tile2D> tile(new Tile2D()); tile->gid_ = gid; tile->sprite_ = tmxFile_->GetTileSprite(gid); tile->propertySet_ = tmxFile_->GetTilePropertySet(gid); tiles_[y * width_ + x] = tile; } tileElem = tileElem.GetNext("tile"); } } if (element.HasChild("properties")) LoadPropertySet(element.GetChild("properties")); return true; }
bool Node::LoadXML(const XMLElement& source, bool setInstanceDefault) { SceneResolver resolver; // Read own ID. Will not be applied, only stored for resolving possible references unsigned nodeID = source.GetInt("id"); resolver.AddNode(nodeID, this); // Read attributes, components and child nodes bool success = LoadXML(source, resolver); if (success) { resolver.Resolve(); ApplyAttributes(); } return success; }
bool SpriteSheet2D::EndLoadFromXMLFile() { ResourceCache* cache = GetSubsystem<ResourceCache>(); texture_ = cache->GetResource<Texture2D>(loadTextureName_); if (!texture_) { URHO3D_LOGERROR("Could not load texture " + loadTextureName_); loadXMLFile_.Reset(); loadTextureName_.Clear(); return false; } XMLElement rootElem = loadXMLFile_->GetRoot("TextureAtlas"); 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); IntVector2 offset(0, 0); if (subTextureElem.HasAttribute("frameWidth") && subTextureElem.HasAttribute("frameHeight")) { offset.x_ = subTextureElem.GetInt("frameX"); offset.y_ = subTextureElem.GetInt("frameY"); int frameWidth = subTextureElem.GetInt("frameWidth"); int frameHeight = subTextureElem.GetInt("frameHeight"); hotSpot.x_ = ((float)offset.x_ + frameWidth / 2) / width; hotSpot.y_ = 1.0f - ((float)offset.y_ + frameHeight / 2) / height; } DefineSprite(name, rectangle, hotSpot, offset); subTextureElem = subTextureElem.GetNext("SubTexture"); } loadXMLFile_.Reset(); loadTextureName_.Clear(); return true; }
bool AnimationSet2D::LoadAnimation(const XMLElement& animationElem) { SharedPtr<Animation2D> animation(new Animation2D(this)); String name = animationElem.GetAttribute("name"); animation->SetName(name); float length = animationElem.GetFloat("length") * 0.001f; animation->SetLength(length); bool looped = true; if (animationElem.HasAttribute("looping")) looped = animationElem.GetBool("looping"); animation->SetLooped(looped); // Load timelines for (XMLElement timelineElem = animationElem.GetChild("timeline"); timelineElem; timelineElem = timelineElem.GetNext("timeline")) { Timeline2D timeline; timeline.name_ = timelineElem.GetAttribute("name"); if (timelineElem.GetAttribute("object_type") == "bone") timeline.type_ = OT_BONE; else timeline.type_ = OT_SPRITE; for (XMLElement keyElem = timelineElem.GetChild("key"); keyElem; keyElem = keyElem.GetNext("key")) { TimelineKey2D key; key.time_ = keyElem.GetFloat("time") * 0.001f; key.spin_ = 1; if (keyElem.HasAttribute("spin")) key.spin_ = keyElem.GetInt("spin"); XMLElement childElem = keyElem.GetChild(); Vector2 position; position.x_ = childElem.GetFloat("x"); position.y_ = childElem.GetFloat("y"); float angle = childElem.GetFloat("angle"); Vector2 scale(Vector2::ONE); if (childElem.HasAttribute("scale_x")) scale.x_ = childElem.GetFloat("scale_x"); if (childElem.HasAttribute("scale_y")) scale.y_ = childElem.GetFloat("scale_y"); key.transform_ = Transform2D(position, angle, scale); if (timeline.type_ == OT_SPRITE) { int folder = childElem.GetUInt("folder"); int file = childElem.GetUInt("file"); key.sprite_ = GetSprite(folder, file); if (!key.sprite_) { LOGERROR("Could not find sprite"); return false; } if (childElem.HasAttribute("pivot_x")) key.hotSpot_.x_ = childElem.GetFloat("pivot_x"); else key.hotSpot_.x_ = key.sprite_->GetHotSpot().x_; if (childElem.HasAttribute("pivot_y")) key.hotSpot_.y_ = childElem.GetFloat("pivot_y"); else key.hotSpot_.y_ = key.sprite_->GetHotSpot().y_; if (childElem.HasAttribute("a")) key.alpha_ = childElem.GetFloat("a"); } timeline.timelineKeys_.Push(key); } // Add end key for looped animation if (looped && timeline.timelineKeys_.Back().time_ != length) { TimelineKey2D key = timeline.timelineKeys_.Front(); key.time_ = length; timeline.timelineKeys_.Push(key); } animation->AddTimeline(timeline); } // Load main line XMLElement mainlineElem = animationElem.GetChild("mainline"); for (XMLElement keyElem = mainlineElem.GetChild("key"); keyElem; keyElem = keyElem.GetNext("key")) { MainlineKey2D mainlineKey; int id = keyElem.GetInt("id"); mainlineKey.time_ = keyElem.GetFloat("time") * 0.001f; for (XMLElement refElem = keyElem.GetChild(); refElem; refElem = refElem.GetNext()) { Reference2D ref; int refId = refElem.GetInt("id"); if (refElem.GetName() == "bone_ref") ref.type_ = OT_BONE; else ref.type_ = OT_SPRITE; ref.timeline_ = refElem.GetInt("timeline"); if (refElem.HasAttribute("parent")) { int parent = refElem.GetInt("parent"); int parentTimeline = mainlineKey.references_[parent].timeline_; animation->SetTimelineParent(ref.timeline_, parentTimeline); } if (refElem.GetName() == "object_ref") ref.zIndex_ = refElem.GetInt("z_index"); mainlineKey.references_.Push(ref); } animation->AddMainlineKey(mainlineKey); } animations_.Push(animation); 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; }
void LoadMesh(const String& inputFileName, bool generateTangents, bool splitSubMeshes, bool exportMorphs) { File meshFileSource(context_); meshFileSource.Open(inputFileName); if (!meshFile_->Load(meshFileSource)) ErrorExit("Could not load input file " + inputFileName); XMLElement root = meshFile_->GetRoot("mesh"); XMLElement subMeshes = root.GetChild("submeshes"); XMLElement skeletonLink = root.GetChild("skeletonlink"); if (root.IsNull()) ErrorExit("Could not load input file " + inputFileName); String skeletonName = skeletonLink.GetAttribute("name"); if (!skeletonName.Empty()) LoadSkeleton(GetPath(inputFileName) + GetFileName(skeletonName) + ".skeleton.xml"); // Check whether there's benefit of avoiding 32bit indices by splitting each submesh into own buffer XMLElement subMesh = subMeshes.GetChild("submesh"); unsigned totalVertices = 0; unsigned maxSubMeshVertices = 0; while (subMesh) { materialNames_.Push(subMesh.GetAttribute("material")); XMLElement geometry = subMesh.GetChild("geometry"); if (geometry) { unsigned vertices = geometry.GetInt("vertexcount"); totalVertices += vertices; if (maxSubMeshVertices < vertices) maxSubMeshVertices = vertices; } ++numSubMeshes_; subMesh = subMesh.GetNext("submesh"); } XMLElement sharedGeometry = root.GetChild("sharedgeometry"); if (sharedGeometry) { unsigned vertices = sharedGeometry.GetInt("vertexcount"); totalVertices += vertices; if (maxSubMeshVertices < vertices) maxSubMeshVertices = vertices; } if (!sharedGeometry && (splitSubMeshes || (totalVertices > 65535 && maxSubMeshVertices <= 65535))) { useOneBuffer_ = false; vertexBuffers_.Resize(numSubMeshes_); indexBuffers_.Resize(numSubMeshes_); } else { vertexBuffers_.Resize(1); indexBuffers_.Resize(1); } subMesh = subMeshes.GetChild("submesh"); unsigned indexStart = 0; unsigned vertexStart = 0; unsigned subMeshIndex = 0; PODVector<unsigned> vertexStarts; vertexStarts.Resize(numSubMeshes_); while (subMesh) { XMLElement geometry = subMesh.GetChild("geometry"); XMLElement faces = subMesh.GetChild("faces"); // If no submesh vertexbuffer, process the shared geometry, but do it only once unsigned vertices = 0; if (!geometry) { vertexStart = 0; if (!subMeshIndex) geometry = root.GetChild("sharedgeometry"); } if (geometry) vertices = geometry.GetInt("vertexcount"); ModelSubGeometryLodLevel subGeometryLodLevel; ModelVertexBuffer* vBuf; ModelIndexBuffer* iBuf; if (useOneBuffer_) { vBuf = &vertexBuffers_[0]; if (vertices) vBuf->vertices_.Resize(vertexStart + vertices); iBuf = &indexBuffers_[0]; subGeometryLodLevel.vertexBuffer_ = 0; subGeometryLodLevel.indexBuffer_ = 0; } else { vertexStart = 0; indexStart = 0; vBuf = &vertexBuffers_[subMeshIndex]; vBuf->vertices_.Resize(vertices); iBuf = &indexBuffers_[subMeshIndex]; subGeometryLodLevel.vertexBuffer_ = subMeshIndex; subGeometryLodLevel.indexBuffer_ = subMeshIndex; } // Store the start vertex for later use vertexStarts[subMeshIndex] = vertexStart; // Ogre may have multiple buffers in one submesh. These will be merged into one XMLElement bufferDef; if (geometry) bufferDef = geometry.GetChild("vertexbuffer"); while (bufferDef) { if (bufferDef.HasAttribute("positions")) vBuf->elementMask_ |= MASK_POSITION; if (bufferDef.HasAttribute("normals")) vBuf->elementMask_ |= MASK_NORMAL; if (bufferDef.HasAttribute("texture_coords")) { vBuf->elementMask_ |= MASK_TEXCOORD1; if (bufferDef.GetInt("texture_coords") > 1) vBuf->elementMask_ |= MASK_TEXCOORD2; } unsigned vertexNum = vertexStart; if (vertices) { XMLElement vertex = bufferDef.GetChild("vertex"); while (vertex) { XMLElement position = vertex.GetChild("position"); if (position) { // Convert from right- to left-handed float x = position.GetFloat("x"); float y = position.GetFloat("y"); float z = position.GetFloat("z"); Vector3 vec(x, y, -z); vBuf->vertices_[vertexNum].position_ = vec; boundingBox_.Merge(vec); } XMLElement normal = vertex.GetChild("normal"); if (normal) { // Convert from right- to left-handed float x = normal.GetFloat("x"); float y = normal.GetFloat("y"); float z = normal.GetFloat("z"); Vector3 vec(x, y, -z); vBuf->vertices_[vertexNum].normal_ = vec; } XMLElement uv = vertex.GetChild("texcoord"); if (uv) { float x = uv.GetFloat("u"); float y = uv.GetFloat("v"); Vector2 vec(x, y); vBuf->vertices_[vertexNum].texCoord1_ = vec; if (vBuf->elementMask_ & MASK_TEXCOORD2) { uv = uv.GetNext("texcoord"); if (uv) { float x = uv.GetFloat("u"); float y = uv.GetFloat("v"); Vector2 vec(x, y); vBuf->vertices_[vertexNum].texCoord2_ = vec; } } } vertexNum++; vertex = vertex.GetNext("vertex"); } } bufferDef = bufferDef.GetNext("vertexbuffer"); } unsigned triangles = faces.GetInt("count"); unsigned indices = triangles * 3; XMLElement triangle = faces.GetChild("face"); while (triangle) { unsigned v1 = triangle.GetInt("v1"); unsigned v2 = triangle.GetInt("v2"); unsigned v3 = triangle.GetInt("v3"); iBuf->indices_.Push(v3 + vertexStart); iBuf->indices_.Push(v2 + vertexStart); iBuf->indices_.Push(v1 + vertexStart); triangle = triangle.GetNext("face"); } subGeometryLodLevel.indexStart_ = indexStart; subGeometryLodLevel.indexCount_ = indices; if (vertexStart + vertices > 65535) iBuf->indexSize_ = sizeof(unsigned); XMLElement boneAssignments = subMesh.GetChild("boneassignments"); if (bones_.Size()) { if (boneAssignments) { XMLElement boneAssignment = boneAssignments.GetChild("vertexboneassignment"); while (boneAssignment) { unsigned vertex = boneAssignment.GetInt("vertexindex") + vertexStart; unsigned bone = boneAssignment.GetInt("boneindex"); float weight = boneAssignment.GetFloat("weight"); BoneWeightAssignment assign; assign.boneIndex_ = bone; assign.weight_ = weight; // Source data might have 0 weights. Disregard these if (assign.weight_ > 0.0f) { subGeometryLodLevel.boneWeights_[vertex].Push(assign); // Require skinning weight to be sufficiently large before vertex contributes to bone hitbox if (assign.weight_ > 0.33f) { // Check distance of vertex from bone to get bone max. radius information Vector3 bonePos = bones_[bone].derivedPosition_; Vector3 vertexPos = vBuf->vertices_[vertex].position_; float distance = (bonePos - vertexPos).Length(); if (distance > bones_[bone].radius_) { bones_[bone].collisionMask_ |= 1; bones_[bone].radius_ = distance; } // Build the hitbox for the bone bones_[bone].boundingBox_.Merge(bones_[bone].inverseWorldTransform_ * (vertexPos)); bones_[bone].collisionMask_ |= 2; } } boneAssignment = boneAssignment.GetNext("vertexboneassignment"); } } if ((subGeometryLodLevel.boneWeights_.Size()) && bones_.Size()) { vBuf->elementMask_ |= MASK_BLENDWEIGHTS | MASK_BLENDINDICES; bool sorted = false; // If amount of bones is larger than supported by HW skinning, must remap per submesh if (bones_.Size() > maxBones_) { HashMap<unsigned, unsigned> usedBoneMap; unsigned remapIndex = 0; for (HashMap<unsigned, PODVector<BoneWeightAssignment> >::Iterator i = subGeometryLodLevel.boneWeights_.Begin(); i != subGeometryLodLevel.boneWeights_.End(); ++i) { // Sort the bone assigns by weight Sort(i->second_.Begin(), i->second_.End(), CompareWeights); // Use only the first 4 weights for (unsigned j = 0; j < i->second_.Size() && j < 4; ++j) { unsigned originalIndex = i->second_[j].boneIndex_; if (!usedBoneMap.Contains(originalIndex)) { usedBoneMap[originalIndex] = remapIndex; remapIndex++; } i->second_[j].boneIndex_ = usedBoneMap[originalIndex]; } } // If still too many bones in one subgeometry, error if (usedBoneMap.Size() > maxBones_) ErrorExit("Too many bones (limit " + String(maxBones_) + ") in submesh " + String(subMeshIndex + 1)); // Write mapping of vertex buffer bone indices to original bone indices subGeometryLodLevel.boneMapping_.Resize(usedBoneMap.Size()); for (HashMap<unsigned, unsigned>::Iterator j = usedBoneMap.Begin(); j != usedBoneMap.End(); ++j) subGeometryLodLevel.boneMapping_[j->second_] = j->first_; sorted = true; } for (HashMap<unsigned, PODVector<BoneWeightAssignment> >::Iterator i = subGeometryLodLevel.boneWeights_.Begin(); i != subGeometryLodLevel.boneWeights_.End(); ++i) { // Sort the bone assigns by weight, if not sorted yet in bone remapping pass if (!sorted) Sort(i->second_.Begin(), i->second_.End(), CompareWeights); float totalWeight = 0.0f; float normalizationFactor = 0.0f; // Calculate normalization factor in case there are more than 4 blend weights, or they do not add up to 1 for (unsigned j = 0; j < i->second_.Size() && j < 4; ++j) totalWeight += i->second_[j].weight_; if (totalWeight > 0.0f) normalizationFactor = 1.0f / totalWeight; for (unsigned j = 0; j < i->second_.Size() && j < 4; ++j) { vBuf->vertices_[i->first_].blendIndices_[j] = i->second_[j].boneIndex_; vBuf->vertices_[i->first_].blendWeights_[j] = i->second_[j].weight_ * normalizationFactor; } // If there are less than 4 blend weights, fill rest with zero for (unsigned j = i->second_.Size(); j < 4; ++j) { vBuf->vertices_[i->first_].blendIndices_[j] = 0; vBuf->vertices_[i->first_].blendWeights_[j] = 0.0f; } vBuf->vertices_[i->first_].hasBlendWeights_ = true; } } } else if (boneAssignments) PrintLine("No skeleton loaded, skipping skinning information"); // Calculate center for the subgeometry Vector3 center = Vector3::ZERO; for (unsigned i = 0; i < iBuf->indices_.Size(); i += 3) { center += vBuf->vertices_[iBuf->indices_[i]].position_; center += vBuf->vertices_[iBuf->indices_[i + 1]].position_; center += vBuf->vertices_[iBuf->indices_[i + 2]].position_; } if (iBuf->indices_.Size()) center /= (float)iBuf->indices_.Size(); subGeometryCenters_.Push(center); indexStart += indices; vertexStart += vertices; OptimizeIndices(&subGeometryLodLevel, vBuf, iBuf); PrintLine("Processed submesh " + String(subMeshIndex + 1) + ": " + String(vertices) + " vertices " + String(triangles) + " triangles"); Vector<ModelSubGeometryLodLevel> thisSubGeometry; thisSubGeometry.Push(subGeometryLodLevel); subGeometries_.Push(thisSubGeometry); subMesh = subMesh.GetNext("submesh"); subMeshIndex++; } // Process LOD levels, if any XMLElement lods = root.GetChild("levelofdetail"); if (lods) { try { // For now, support only generated LODs, where the vertices are the same XMLElement lod = lods.GetChild("lodgenerated"); while (lod) { float distance = M_EPSILON; if (lod.HasAttribute("fromdepthsquared")) distance = sqrtf(lod.GetFloat("fromdepthsquared")); if (lod.HasAttribute("value")) distance = lod.GetFloat("value"); XMLElement lodSubMesh = lod.GetChild("lodfacelist"); while (lodSubMesh) { unsigned subMeshIndex = lodSubMesh.GetInt("submeshindex"); unsigned triangles = lodSubMesh.GetInt("numfaces"); ModelSubGeometryLodLevel newLodLevel; ModelSubGeometryLodLevel& originalLodLevel = subGeometries_[subMeshIndex][0]; // Copy all initial values newLodLevel = originalLodLevel; ModelVertexBuffer* vBuf; ModelIndexBuffer* iBuf; if (useOneBuffer_) { vBuf = &vertexBuffers_[0]; iBuf = &indexBuffers_[0]; } else { vBuf = &vertexBuffers_[subMeshIndex]; iBuf = &indexBuffers_[subMeshIndex]; } unsigned indexStart = iBuf->indices_.Size(); unsigned indexCount = triangles * 3; unsigned vertexStart = vertexStarts[subMeshIndex]; newLodLevel.distance_ = distance; newLodLevel.indexStart_ = indexStart; newLodLevel.indexCount_ = indexCount; // Append indices to the original index buffer XMLElement triangle = lodSubMesh.GetChild("face"); while (triangle) { unsigned v1 = triangle.GetInt("v1"); unsigned v2 = triangle.GetInt("v2"); unsigned v3 = triangle.GetInt("v3"); iBuf->indices_.Push(v3 + vertexStart); iBuf->indices_.Push(v2 + vertexStart); iBuf->indices_.Push(v1 + vertexStart); triangle = triangle.GetNext("face"); } OptimizeIndices(&newLodLevel, vBuf, iBuf); subGeometries_[subMeshIndex].Push(newLodLevel); PrintLine("Processed LOD level for submesh " + String(subMeshIndex + 1) + ": distance " + String(distance)); lodSubMesh = lodSubMesh.GetNext("lodfacelist"); } lod = lod.GetNext("lodgenerated"); } } catch (...) {} } // Process poses/morphs // First find out all pose definitions if (exportMorphs) { try { Vector<XMLElement> poses; XMLElement posesRoot = root.GetChild("poses"); if (posesRoot) { XMLElement pose = posesRoot.GetChild("pose"); while (pose) { poses.Push(pose); pose = pose.GetNext("pose"); } } // Then process animations using the poses XMLElement animsRoot = root.GetChild("animations"); if (animsRoot) { XMLElement anim = animsRoot.GetChild("animation"); while (anim) { String name = anim.GetAttribute("name"); float length = anim.GetFloat("length"); HashSet<unsigned> usedPoses; XMLElement tracks = anim.GetChild("tracks"); if (tracks) { XMLElement track = tracks.GetChild("track"); while (track) { XMLElement keyframes = track.GetChild("keyframes"); if (keyframes) { XMLElement keyframe = keyframes.GetChild("keyframe"); while (keyframe) { float time = keyframe.GetFloat("time"); XMLElement poseref = keyframe.GetChild("poseref"); // Get only the end pose if (poseref && time == length) usedPoses.Insert(poseref.GetInt("poseindex")); keyframe = keyframe.GetNext("keyframe"); } } track = track.GetNext("track"); } } if (usedPoses.Size()) { ModelMorph newMorph; newMorph.name_ = name; if (useOneBuffer_) newMorph.buffers_.Resize(1); else newMorph.buffers_.Resize(usedPoses.Size()); unsigned bufIndex = 0; for (HashSet<unsigned>::Iterator i = usedPoses.Begin(); i != usedPoses.End(); ++i) { XMLElement pose = poses[*i]; unsigned targetSubMesh = pose.GetInt("index"); XMLElement poseOffset = pose.GetChild("poseoffset"); if (useOneBuffer_) newMorph.buffers_[bufIndex].vertexBuffer_ = 0; else newMorph.buffers_[bufIndex].vertexBuffer_ = targetSubMesh; newMorph.buffers_[bufIndex].elementMask_ = MASK_POSITION; ModelVertexBuffer* vBuf = &vertexBuffers_[newMorph.buffers_[bufIndex].vertexBuffer_]; while (poseOffset) { // Convert from right- to left-handed unsigned vertexIndex = poseOffset.GetInt("index") + vertexStarts[targetSubMesh]; float x = poseOffset.GetFloat("x"); float y = poseOffset.GetFloat("y"); float z = poseOffset.GetFloat("z"); Vector3 vec(x, y, -z); if (vBuf->morphCount_ == 0) { vBuf->morphStart_ = vertexIndex; vBuf->morphCount_ = 1; } else { unsigned first = vBuf->morphStart_; unsigned last = first + vBuf->morphCount_ - 1; if (vertexIndex < first) first = vertexIndex; if (vertexIndex > last) last = vertexIndex; vBuf->morphStart_ = first; vBuf->morphCount_ = last - first + 1; } ModelVertex newVertex; newVertex.position_ = vec; newMorph.buffers_[bufIndex].vertices_.Push(MakePair(vertexIndex, newVertex)); poseOffset = poseOffset.GetNext("poseoffset"); } if (!useOneBuffer_) ++bufIndex; } morphs_.Push(newMorph); PrintLine("Processed morph " + name + " with " + String(usedPoses.Size()) + " sub-poses"); } anim = anim.GetNext("animation"); } } } catch (...) {} } // Check any of the buffers for vertices with missing blend weight assignments for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { if (vertexBuffers_[i].elementMask_ & MASK_BLENDWEIGHTS) { for (unsigned j = 0; j < vertexBuffers_[i].vertices_.Size(); ++j) if (!vertexBuffers_[i].vertices_[j].hasBlendWeights_) ErrorExit("Found a vertex with missing skinning information"); } } // Tangent generation if (generateTangents) { for (unsigned i = 0; i < subGeometries_.Size(); ++i) { for (unsigned j = 0; j < subGeometries_[i].Size(); ++j) { ModelVertexBuffer& vBuf = vertexBuffers_[subGeometries_[i][j].vertexBuffer_]; ModelIndexBuffer& iBuf = indexBuffers_[subGeometries_[i][j].indexBuffer_]; unsigned indexStart = subGeometries_[i][j].indexStart_; unsigned indexCount = subGeometries_[i][j].indexCount_; // If already has tangents, do not regenerate if (vBuf.elementMask_ & MASK_TANGENT || vBuf.vertices_.Empty() || iBuf.indices_.Empty()) continue; vBuf.elementMask_ |= MASK_TANGENT; if ((vBuf.elementMask_ & (MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1)) != (MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1)) ErrorExit("To generate tangents, positions normals and texcoords are required"); GenerateTangents(&vBuf.vertices_[0], sizeof(ModelVertex), &iBuf.indices_[0], sizeof(unsigned), indexStart, indexCount, offsetof(ModelVertex, normal_), offsetof(ModelVertex, texCoord1_), offsetof(ModelVertex, tangent_)); PrintLine("Generated tangents"); } } } }
void RenderPathCommand::Load(const XMLElement& element) { type_ = (RenderCommandType)GetStringListIndex(element.GetAttributeLower("type").CString(), commandTypeNames, CMD_NONE); tag_ = element.GetAttribute("tag"); if (element.HasAttribute("enabled")) enabled_ = element.GetBool("enabled"); if (element.HasAttribute("metadata")) metadata_ = element.GetAttribute("metadata"); switch (type_) { case CMD_CLEAR: if (element.HasAttribute("color")) { clearFlags_ |= CLEAR_COLOR; if (element.GetAttributeLower("color") == "fog") useFogColor_ = true; else clearColor_ = element.GetColor("color"); } if (element.HasAttribute("depth")) { clearFlags_ |= CLEAR_DEPTH; clearDepth_ = element.GetFloat("depth"); } if (element.HasAttribute("stencil")) { clearFlags_ |= CLEAR_STENCIL; clearStencil_ = (unsigned)element.GetInt("stencil"); } break; case CMD_SCENEPASS: pass_ = element.GetAttribute("pass"); sortMode_ = (RenderCommandSortMode)GetStringListIndex(element.GetAttributeLower("sort").CString(), sortModeNames, SORT_FRONTTOBACK); if (element.HasAttribute("marktostencil")) markToStencil_ = element.GetBool("marktostencil"); if (element.HasAttribute("vertexlights")) vertexLights_ = element.GetBool("vertexlights"); break; case CMD_FORWARDLIGHTS: pass_ = element.GetAttribute("pass"); if (element.HasAttribute("uselitbase")) useLitBase_ = element.GetBool("uselitbase"); break; case CMD_LIGHTVOLUMES: case CMD_QUAD: vertexShaderName_ = element.GetAttribute("vs"); pixelShaderName_ = element.GetAttribute("ps"); vertexShaderDefines_ = element.GetAttribute("vsdefines"); pixelShaderDefines_ = element.GetAttribute("psdefines"); if (type_ == CMD_QUAD) { if (element.HasAttribute("blend")) { String blend = element.GetAttributeLower("blend"); blendMode_ = ((BlendMode)GetStringListIndex(blend.CString(), blendModeNames, BLEND_REPLACE)); } XMLElement parameterElem = element.GetChild("parameter"); while (parameterElem) { String name = parameterElem.GetAttribute("name"); shaderParameters_[name] = Material::ParseShaderParameterValue(parameterElem.GetAttribute("value")); parameterElem = parameterElem.GetNext("parameter"); } } break; default: break; } // By default use 1 output, which is the viewport outputs_.Resize(1); outputs_[0] = MakePair(String("viewport"), FACE_POSITIVE_X); if (element.HasAttribute("output")) outputs_[0].first_ = element.GetAttribute("output"); if (element.HasAttribute("face")) outputs_[0].second_ = (CubeMapFace)element.GetInt("face"); if (element.HasAttribute("depthstencil")) depthStencilName_ = element.GetAttribute("depthstencil"); // Check for defining multiple outputs XMLElement outputElem = element.GetChild("output"); while (outputElem) { unsigned index = (unsigned)outputElem.GetInt("index"); if (index < MAX_RENDERTARGETS) { if (index >= outputs_.Size()) outputs_.Resize(index + 1); outputs_[index].first_ = outputElem.GetAttribute("name"); outputs_[index].second_ = outputElem.HasAttribute("face") ? (CubeMapFace)outputElem.GetInt("face") : FACE_POSITIVE_X; } outputElem = outputElem.GetNext("output"); } XMLElement textureElem = element.GetChild("texture"); while (textureElem) { TextureUnit unit = TU_DIFFUSE; if (textureElem.HasAttribute("unit")) unit = ParseTextureUnitName(textureElem.GetAttribute("unit")); if (unit < MAX_TEXTURE_UNITS) { String name = textureElem.GetAttribute("name"); textureNames_[unit] = name; } textureElem = textureElem.GetNext("texture"); } }
bool Scene::LoadAsyncXML(File* file, LoadMode mode) { if (!file) { LOGERROR("Null file for async loading"); return false; } StopAsyncLoading(); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(*file)) return false; if (mode > LOAD_RESOURCES_ONLY) { LOGINFO("Loading scene from " + file->GetName()); Clear(); } asyncLoading_ = true; asyncProgress_.xmlFile_ = xml; asyncProgress_.file_ = file; asyncProgress_.mode_ = mode; asyncProgress_.loadedNodes_ = asyncProgress_.totalNodes_ = asyncProgress_.loadedResources_ = asyncProgress_.totalResources_ = 0; asyncProgress_.resources_.Clear(); if (mode > LOAD_RESOURCES_ONLY) { XMLElement rootElement = xml->GetRoot(); // Preload resources if appropriate if (mode != LOAD_SCENE) { PROFILE(FindResourcesToPreload); PreloadResourcesXML(rootElement); } // Store own old ID for resolving possible root node references unsigned nodeID = rootElement.GetInt("id"); resolver_.AddNode(nodeID, this); // Load the root level components first if (!Node::LoadXML(rootElement, resolver_, false)) return false; // Then prepare for loading all root level child nodes in the async update XMLElement childNodeElement = rootElement.GetChild("node"); asyncProgress_.xmlElement_ = childNodeElement; // Count the amount of child nodes while (childNodeElement) { ++asyncProgress_.totalNodes_; childNodeElement = childNodeElement.GetNext("node"); } } else { PROFILE(FindResourcesToPreload); LOGINFO("Preloading resources from " + file->GetName()); PreloadResourcesXML(xml->GetRoot()); } return true; }
void LoadSkeleton(const String& skeletonFileName) { // Process skeleton first (if found) XMLElement skeletonRoot; File skeletonFileSource(context_); skeletonFileSource.Open(skeletonFileName); if (!skelFile_->Load(skeletonFileSource)) PrintLine("Failed to load skeleton " + skeletonFileName); skeletonRoot = skelFile_->GetRoot(); if (skeletonRoot) { XMLElement bonesRoot = skeletonRoot.GetChild("bones"); XMLElement bone = bonesRoot.GetChild("bone"); while (bone) { unsigned index = bone.GetInt("id"); String name = bone.GetAttribute("name"); if (index >= bones_.Size()) bones_.Resize(index + 1); // Convert from right- to left-handed XMLElement position = bone.GetChild("position"); float x = position.GetFloat("x"); float y = position.GetFloat("y"); float z = position.GetFloat("z"); Vector3 pos(x, y, -z); XMLElement rotation = bone.GetChild("rotation"); XMLElement axis = rotation.GetChild("axis"); float angle = -rotation.GetFloat("angle") * M_RADTODEG; x = axis.GetFloat("x"); y = axis.GetFloat("y"); z = axis.GetFloat("z"); Vector3 axisVec(x, y, -z); Quaternion rot(angle, axisVec); bones_[index].name_ = name; bones_[index].parentIndex_ = index; // Fill in the correct parent later bones_[index].bindPosition_ = pos; bones_[index].bindRotation_ = rot; bones_[index].bindScale_ = Vector3::ONE; bones_[index].collisionMask_ = 0; bones_[index].radius_ = 0.0f; bone = bone.GetNext("bone"); } // Go through the bone hierarchy XMLElement boneHierarchy = skeletonRoot.GetChild("bonehierarchy"); XMLElement boneParent = boneHierarchy.GetChild("boneparent"); while (boneParent) { String bone = boneParent.GetAttribute("bone"); String parent = boneParent.GetAttribute("parent"); unsigned i = 0, j = 0; for (i = 0; i < bones_.Size() && bones_[i].name_ != bone; ++i); for (j = 0; j < bones_.Size() && bones_[j].name_ != parent; ++j); if (i >= bones_.Size() || j >= bones_.Size()) ErrorExit("Found indeterminate parent bone assignment"); bones_[i].parentIndex_ = j; boneParent = boneParent.GetNext("boneparent"); } // Calculate bone derived positions for (unsigned i = 0; i < bones_.Size(); ++i) { Vector3 derivedPosition = bones_[i].bindPosition_; Quaternion derivedRotation = bones_[i].bindRotation_; Vector3 derivedScale = bones_[i].bindScale_; unsigned index = bones_[i].parentIndex_; if (index != i) { for (;;) { derivedPosition = bones_[index].bindPosition_ + (bones_[index].bindRotation_ * (bones_[index].bindScale_ * derivedPosition)); derivedRotation = bones_[index].bindRotation_ * derivedRotation; derivedScale = bones_[index].bindScale_ * derivedScale; if (bones_[index].parentIndex_ != index) index = bones_[index].parentIndex_; else break; } } bones_[i].derivedPosition_ = derivedPosition; bones_[i].derivedRotation_ = derivedRotation; bones_[i].derivedScale_ = derivedScale; bones_[i].worldTransform_ = Matrix3x4(derivedPosition, derivedRotation, derivedScale); bones_[i].inverseWorldTransform_ = bones_[i].worldTransform_.Inverse(); } PrintLine("Processed skeleton"); } }
bool TmxFile2D::LoadTileSet(const XMLElement& element) { int firstgid = element.GetInt("firstgid"); XMLElement tileSetElem; if (element.HasAttribute("source")) { String source = element.GetAttribute("source"); HashMap<String, SharedPtr<XMLFile> >::Iterator i = tsxXMLFiles_.Find(source); if (i == tsxXMLFiles_.End()) { SharedPtr<XMLFile> tsxXMLFile = LoadTSXFile(source); if (!tsxXMLFile) return false; // Add to napping to avoid release tsxXMLFiles_[source] = tsxXMLFile; tileSetElem = tsxXMLFile->GetRoot("tileset"); } else tileSetElem = i->second_->GetRoot("tileset"); } else tileSetElem = element; XMLElement imageElem = tileSetElem.GetChild("image"); String textureFilePath = GetParentPath(GetName()) + imageElem.GetAttribute("source"); ResourceCache* cache = GetSubsystem<ResourceCache>(); SharedPtr<Texture2D> texture(cache->GetResource<Texture2D>(textureFilePath)); if (!texture) { URHO3D_LOGERROR("Could not load texture " + textureFilePath); return false; } tileSetTextures_.Push(texture); int tileWidth = tileSetElem.GetInt("tilewidth"); int tileHeight = tileSetElem.GetInt("tileheight"); int spacing = tileSetElem.GetInt("spacing"); int margin = tileSetElem.GetInt("margin"); int imageWidth = imageElem.GetInt("width"); int imageHeight = imageElem.GetInt("height"); // Set hot spot at left bottom Vector2 hotSpot(0.0f, 0.0f); if (tileSetElem.HasChild("tileoffset")) { XMLElement offsetElem = tileSetElem.GetChild("tileoffset"); hotSpot.x_ += offsetElem.GetFloat("x") / (float)tileWidth; hotSpot.y_ += offsetElem.GetFloat("y") / (float)tileHeight; } int gid = firstgid; for (int y = margin; y + tileHeight <= imageHeight - margin; y += tileHeight + spacing) { for (int x = margin; x + tileWidth <= imageWidth - margin; x += tileWidth + spacing) { SharedPtr<Sprite2D> sprite(new Sprite2D(context_)); sprite->SetTexture(texture); sprite->SetRectangle(IntRect(x, y, x + tileWidth, y + tileHeight)); sprite->SetHotSpot(hotSpot); gidToSpriteMapping_[gid++] = sprite; } } for (XMLElement tileElem = tileSetElem.GetChild("tile"); tileElem; tileElem = tileElem.GetNext("tile")) { if (tileElem.HasChild("properties")) { SharedPtr<PropertySet2D> propertySet(new PropertySet2D()); propertySet->Load(tileElem.GetChild("properties")); gidToPropertySetMapping_[firstgid + tileElem.GetInt("id")] = propertySet; } } 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; }
bool TmxObjectGroup2D::Load(const XMLElement& element, const TileMapInfo2D& info) { LoadInfo(element); for (XMLElement objectElem = element.GetChild("object"); objectElem; objectElem = objectElem.GetNext("object")) { SharedPtr<TileMapObject2D> object(new TileMapObject2D()); if (objectElem.HasAttribute("name")) object->name_ = objectElem.GetAttribute("name"); if (objectElem.HasAttribute("type")) object->type_ = objectElem.GetAttribute("type"); if (objectElem.HasAttribute("gid")) object->objectType_ = OT_TILE; else if (objectElem.HasChild("polygon")) object->objectType_ = OT_POLYGON; else if (objectElem.HasChild("polyline")) object->objectType_ = OT_POLYLINE; else if (objectElem.HasChild("ellipse")) object->objectType_ = OT_ELLIPSE; else object->objectType_ = OT_RECTANGLE; const Vector2 position(objectElem.GetFloat("x"), objectElem.GetFloat("y")); const Vector2 size(objectElem.GetFloat("width"), objectElem.GetFloat("height")); switch (object->objectType_) { case OT_RECTANGLE: case OT_ELLIPSE: object->position_ = info.ConvertPosition(Vector2(position.x_, position.y_ + size.y_)); object->size_ = Vector2(size.x_ * PIXEL_SIZE, size.y_ * PIXEL_SIZE); break; case OT_TILE: object->position_ = info.ConvertPosition(position); object->gid_ = objectElem.GetInt("gid"); object->sprite_ = tmxFile_->GetTileSprite(object->gid_); if (objectElem.HasAttribute("width") || objectElem.HasAttribute("height")) { object->size_ = Vector2(size.x_ * PIXEL_SIZE, size.y_ * PIXEL_SIZE); } else if (object->sprite_) { IntVector2 spriteSize = object->sprite_->GetRectangle().Size(); object->size_ = Vector2(spriteSize.x_, spriteSize.y_); } break; case OT_POLYGON: case OT_POLYLINE: { Vector<String> points; const char* name = object->objectType_ == OT_POLYGON ? "polygon" : "polyline"; XMLElement polygonElem = objectElem.GetChild(name); points = polygonElem.GetAttribute("points").Split(' '); if (points.Size() <= 1) continue; object->points_.Resize(points.Size()); for (unsigned i = 0; i < points.Size(); ++i) { points[i].Replace(',', ' '); Vector2 point = position + ToVector2(points[i]); object->points_[i] = info.ConvertPosition(point); } } break; default: break; } if (objectElem.HasChild("properties")) { object->propertySet_ = new PropertySet2D(); object->propertySet_->Load(objectElem.GetChild("properties")); } objects_.Push(object); } if (element.HasChild("properties")) LoadPropertySet(element.GetChild("properties")); return true; }
void RenderPathCommand::Load(const XMLElement& element) { type_ = (RenderCommandType)GetStringListIndex(element.GetAttributeLower("type").CString(), commandTypeNames, CMD_NONE); tag_ = element.GetAttribute("tag"); if (element.HasAttribute("enabled")) enabled_ = element.GetBool("enabled"); if (element.HasAttribute("metadata")) metadata_ = element.GetAttribute("metadata"); switch (type_) { case CMD_CLEAR: if (element.HasAttribute("color")) { clearFlags_ |= CLEAR_COLOR; // Mark fog color with negative values if (element.GetAttributeLower("color") == "fog") useFogColor_ = true; else clearColor_ = element.GetColor("color"); } if (element.HasAttribute("depth")) { clearFlags_ |= CLEAR_DEPTH; clearDepth_ = element.GetFloat("depth"); } if (element.HasAttribute("stencil")) { clearFlags_ |= CLEAR_STENCIL; clearStencil_ = element.GetInt("stencil"); } break; case CMD_SCENEPASS: pass_ = element.GetAttribute("pass"); sortMode_ = (RenderCommandSortMode)GetStringListIndex(element.GetAttributeLower("sort").CString(), sortModeNames, SORT_FRONTTOBACK); if (element.HasAttribute("marktostencil")) markToStencil_ = element.GetBool("marktostencil"); if (element.HasAttribute("vertexlights")) vertexLights_ = element.GetBool("vertexlights"); if (element.HasAttribute("usescissor")) useScissor_ = element.GetBool("usescissor"); break; case CMD_FORWARDLIGHTS: pass_ = element.GetAttribute("pass"); if (element.HasAttribute("uselitbase")) useLitBase_ = element.GetBool("uselitbase"); break; case CMD_LIGHTVOLUMES: case CMD_QUAD: vertexShaderName_ = element.GetAttribute("vs"); pixelShaderName_ = element.GetAttribute("ps"); if (type_ == CMD_QUAD) { XMLElement parameterElem = element.GetChild("parameter"); while (parameterElem) { String name = parameterElem.GetAttribute("name"); Variant value = parameterElem.GetVectorVariant("value"); shaderParameters_[name] = value; parameterElem = parameterElem.GetNext("parameter"); } } break; default: break; } // By default use 1 output, which is the viewport outputNames_.Push("viewport"); if (element.HasAttribute("output")) outputNames_[0] = element.GetAttribute("output"); // Check for defining multiple outputs XMLElement outputElem = element.GetChild("output"); while (outputElem) { unsigned index = outputElem.GetInt("index"); if (index < MAX_RENDERTARGETS) { if (index >= outputNames_.Size()) outputNames_.Resize(index + 1); outputNames_[index] = outputElem.GetAttribute("name"); } outputElem = outputElem.GetNext("output"); } XMLElement textureElem = element.GetChild("texture"); while (textureElem) { TextureUnit unit = TU_DIFFUSE; if (textureElem.HasAttribute("unit")) { String unitName = textureElem.GetAttributeLower("unit"); if (unitName.Length() > 1) unit = ParseTextureUnitName(unitName); else unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_TEXTURE_UNITS - 1); } if (unit < MAX_TEXTURE_UNITS) { String name = textureElem.GetAttribute("name"); textureNames_[unit] = name; } textureElem = textureElem.GetNext("texture"); } }
bool Material::Load(Deserializer& source) { PROFILE(LoadMaterial); // In headless mode, do not actually load the material, just return success Graphics* graphics = GetSubsystem<Graphics>(); if (!graphics) return true; ResetToDefaults(); ResourceCache* cache = GetSubsystem<ResourceCache>(); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(source)) return false; XMLElement rootElem = xml->GetRoot(); XMLElement techniqueElem = rootElem.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"); } XMLElement textureElem = rootElem.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 = rootElem.GetChild("parameter"); while (parameterElem) { String name = parameterElem.GetAttribute("name"); Variant value = parameterElem.GetVectorVariant("value"); SetShaderParameter(name, value); parameterElem = parameterElem.GetNext("parameter"); } XMLElement cullElem = rootElem.GetChild("cull"); if (cullElem) SetCullMode((CullMode)GetStringListIndex(cullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW)); XMLElement shadowCullElem = rootElem.GetChild("shadowcull"); if (shadowCullElem) SetShadowCullMode((CullMode)GetStringListIndex(shadowCullElem.GetAttribute("value").CString(), cullModeNames, CULL_CCW)); XMLElement depthBiasElem = rootElem.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; }
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")) unit = ParseTextureUnitName(textureElem.GetAttribute("unit")); if (unit < MAX_TEXTURE_UNITS) { String name = textureElem.GetAttribute("name"); // Detect cube maps by file extension: they are defined by an XML file /// \todo Differentiate with 3D textures by actually reading the XML content if (GetExtension(name) == ".xml") { #ifdef DESKTOP_GRAPHICS if (unit == TU_VOLUMEMAP) SetTexture(unit, cache->GetResource<Texture3D>(name)); else #endif SetTexture(unit, cache->GetResource<TextureCube>(name)); } else SetTexture(unit, cache->GetResource<Texture2D>(name)); } textureElem = textureElem.GetNext("texture"); } batchedParameterUpdate_ = true; XMLElement parameterElem = source.GetChild("parameter"); while (parameterElem) { String name = parameterElem.GetAttribute("name"); SetShaderParameter(name, ParseShaderParameterValue(parameterElem.GetAttribute("value"))); parameterElem = parameterElem.GetNext("parameter"); } batchedParameterUpdate_ = false; XMLElement parameterAnimationElem = source.GetChild("parameteranimation"); while (parameterAnimationElem) { String name = parameterAnimationElem.GetAttribute("name"); SharedPtr<ValueAnimation> animation(new ValueAnimation(context_)); if (!animation->LoadXML(parameterAnimationElem)) { LOGERROR("Could not load parameter animation"); return false; } String wrapModeString = parameterAnimationElem.GetAttribute("wrapmode"); WrapMode wrapMode = WM_LOOP; for (int i = 0; i <= WM_CLAMP; ++i) { if (wrapModeString == wrapModeNames[i]) { wrapMode = (WrapMode)i; break; } } float speed = parameterAnimationElem.GetFloat("speed"); SetShaderParameterAnimation(name, animation, wrapMode, speed); parameterAnimationElem = parameterAnimationElem.GetNext("parameteranimation"); } 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 fillElem = source.GetChild("fill"); if (fillElem) SetFillMode((FillMode)GetStringListIndex(fillElem.GetAttribute("value").CString(), fillModeNames, FILL_SOLID)); XMLElement depthBiasElem = source.GetChild("depthbias"); if (depthBiasElem) SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled"))); RefreshShaderParameterHash(); RefreshMemoryUse(); CheckOcclusion(); return true; }
bool TmxFile2D::EndLoad() { if (!loadXMLFile_) return false; XMLElement rootElem = loadXMLFile_->GetRoot("map"); String version = rootElem.GetAttribute("version"); if (version != "1.0") { URHO3D_LOGERROR("Invalid version"); return false; } String orientation = rootElem.GetAttribute("orientation"); if (orientation == "orthogonal") info_.orientation_ = O_ORTHOGONAL; else if (orientation == "isometric") info_.orientation_ = O_ISOMETRIC; else if (orientation == "staggered") info_.orientation_ = O_STAGGERED; else if (orientation == "hexagonal") info_.orientation_ = O_HEXAGONAL; else { URHO3D_LOGERROR("Unsupported orientation type " + orientation); return false; } info_.width_ = rootElem.GetInt("width"); info_.height_ = rootElem.GetInt("height"); info_.tileWidth_ = rootElem.GetFloat("tilewidth") * PIXEL_SIZE; info_.tileHeight_ = rootElem.GetFloat("tileheight") * PIXEL_SIZE; for (unsigned i = 0; i < layers_.Size(); ++i) delete layers_[i]; layers_.Clear(); for (XMLElement childElement = rootElem.GetChild(); childElement; childElement = childElement.GetNext()) { bool ret = true; String name = childElement.GetName(); if (name == "tileset") ret = LoadTileSet(childElement); else if (name == "layer") { TmxTileLayer2D* tileLayer = new TmxTileLayer2D(this); ret = tileLayer->Load(childElement, info_); layers_.Push(tileLayer); } else if (name == "objectgroup") { TmxObjectGroup2D* objectGroup = new TmxObjectGroup2D(this); ret = objectGroup->Load(childElement, info_); layers_.Push(objectGroup); } else if (name == "imagelayer") { TmxImageLayer2D* imageLayer = new TmxImageLayer2D(this); ret = imageLayer->Load(childElement, info_); layers_.Push(imageLayer); } if (!ret) { loadXMLFile_.Reset(); tsxXMLFiles_.Clear(); return false; } } loadXMLFile_.Reset(); tsxXMLFiles_.Clear(); return true; }
/// Load Communication Logs bool GameEconomicGameClient::LoadCommunicationLogs(LogFormatType LogType, Vector<CommunicationLog> * TargetLogs) { /// Grab resources FileSystem * fileSystem = GetSubsystem<FileSystem>(); bool success=false; /// Create String String configFileName; /// Set directory and path for network file configFileName.Append(fileSystem->GetProgramDir().CString()); configFileName.Append("CommunicationLogs/DefaultLogs.xml"); /// If file does not exist exit function with null structure if (!fileSystem->FileExists(configFileName)) { cout << "No file found communication log" << endl; return false; } /// Flag file for loading and load File loadFile(context_, configFileName, FILE_READ); XMLFile * communicationXML = new XMLFile(context_); communicationXML -> Load(loadFile); XMLElement communicationRootElement = communicationXML->GetRoot(); /// If no configuration is set or no root if (communicationRootElement.IsNull()) { return false; } /// Setupload data XMLElement TempLogElement; String FormatText; /// Log log format Personal if(LogType == LogFormat_Personal) { FormatText.Append(String("PersonalLog")); TempLogElement = communicationRootElement.GetChild(FormatText); } else { return false; } /// If no network server element return false; while(!TempLogElement.IsNull()) { /// Create a temporary log CommunicationLog TempLog; if (TempLogElement.HasAttribute("LogCreation")) TempLog.Creation= TempLogElement.GetInt("LogCreation"); if (TempLogElement.HasAttribute("LogTitle")) TempLog.Title = TempLogElement.GetAttribute("LogTitle"); if (TempLogElement.HasAttribute("LogText")) TempLog.Text = TempLogElement.GetAttribute("LogText"); TargetLogs->Push(TempLog); cout << "Adding" << TempLog.Title.CString()<<endl; /// Get next TempLogElement=communicationRootElement.GetNext(FormatText); } return success; }
bool AnimationSet2D::LoadFolders(const XMLElement& rootElem) { ResourceCache* cache = GetSubsystem<ResourceCache>(); bool async = GetAsyncLoadState() == ASYNC_LOADING; String parentPath = GetParentPath(GetName()); String spriteSheetFilePath = parentPath + GetFileName(GetName()) + ".xml"; SpriteSheet2D* spriteSheet = 0; bool hasSpriteSheet = false; // When async loading, request the sprite sheet for background loading but do not actually get it if (!async) spriteSheet = cache->GetResource<SpriteSheet2D>(spriteSheetFilePath, false); else { hasSpriteSheet = cache->Exists(spriteSheetFilePath); if (hasSpriteSheet) cache->BackgroundLoadResource<SpriteSheet2D>(spriteSheetFilePath, false, this); } for (XMLElement folderElem = rootElem.GetChild("folder"); folderElem; folderElem = folderElem.GetNext("folder")) { unsigned folderId = folderElem.GetUInt("id"); for (XMLElement fileElem = folderElem.GetChild("file"); fileElem; fileElem = fileElem.GetNext("file")) { unsigned fileId = fileElem.GetUInt("id"); String fileName = fileElem.GetAttribute("name"); // When async loading, request the sprites for background loading but do not actually get them if (!async) { SharedPtr<Sprite2D> sprite; if (spriteSheet) sprite = spriteSheet->GetSprite(GetFileName(fileName)); else sprite = (cache->GetResource<Sprite2D>(parentPath + fileName)); if (!sprite) { LOGERROR("Could not load sprite " + fileName); return false; } Vector2 hotSpot(0.0f, 1.0f); if (fileElem.HasAttribute("pivot_x")) hotSpot.x_ = fileElem.GetFloat("pivot_x"); if (fileElem.HasAttribute("pivot_y")) hotSpot.y_ = fileElem.GetFloat("pivot_y"); // If sprite is trimmed, recalculate hot spot const IntVector2& offset = sprite->GetOffset(); if (offset != IntVector2::ZERO) { int width = fileElem.GetInt("width"); int height = fileElem.GetInt("height"); float pivotX = width * hotSpot.x_; float pivotY = height * (1.0f - hotSpot.y_); const IntRect& rectangle = sprite->GetRectangle(); hotSpot.x_ = (offset.x_ + pivotX) / rectangle.Width(); hotSpot.y_ = 1.0f - (offset.y_ + pivotY) / rectangle.Height(); } sprite->SetHotSpot(hotSpot); sprites_[(folderId << 16) + fileId] = sprite; } else if (!hasSpriteSheet) cache->BackgroundLoadResource<Sprite2D>(parentPath + fileName, true, this); } } return true; }