EditorIconCache::EditorIconCache(Context* context) : Object(context) { ResourceCache* cache = ui::GetSystemUI()->GetSubsystem<ResourceCache>(); auto* icons = cache->GetResource<XMLFile>("UI/EditorIcons.xml"); if (icons == nullptr) return; XMLElement root = icons->GetRoot(); for (XMLElement element = root.GetChild("element"); element.NotNull(); element = element.GetNext("element")) { ea::string type = element.GetAttribute("type"); if (type.empty()) { URHO3D_LOGERROR("EditorIconCache.xml contains icon entry without a \"type\" attribute."); continue; } XPathResultSet texture = element.SelectPrepared(XPathQuery("attribute[@name=\"Texture\"]")); if (texture.Empty()) { URHO3D_LOGERROR("EditorIconCache.xml contains icon entry without a \"Texture\"."); continue; } XPathResultSet rect = element.SelectPrepared(XPathQuery("attribute[@name=\"Image Rect\"]")); if (rect.Empty()) { URHO3D_LOGERROR("EditorIconCache.xml contains icon entry without a \"Image Rect\"."); continue; } IconData data; data.textureRef_ = texture.FirstResult().GetVariantValue(VAR_RESOURCEREF).GetResourceRef(); data.rect_ = rect.FirstResult().GetVariantValue(VAR_INTRECT).GetIntRect(); iconCache_[type] = data; } }
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 PListFile::LoadDict(PListValueMap& dict, const XMLElement& dictElem) { if (!dictElem) return false; XMLElement keyElem = dictElem.GetChild("key"); XMLElement valueElem = keyElem.GetNext(); while (keyElem && valueElem) { String key = keyElem.GetValue(); valueElem = keyElem.GetNext(); PListValue value; if (!LoadValue(value, valueElem)) return false; dict[key] = value; keyElem = valueElem.GetNext("key"); valueElem = keyElem.GetNext(); } return true; }
void WriteOutput(const String& outputFileName, bool exportAnimations, bool rotationsOnly, bool saveMaterialList) { // Begin serialization { File dest(context_); if (!dest.Open(outputFileName, FILE_WRITE)) ErrorExit("Could not open output file " + outputFileName); // ID dest.WriteFileID("UMDL"); // Vertexbuffers dest.WriteUInt(vertexBuffers_.Size()); for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) vertexBuffers_[i].WriteData(dest); // Indexbuffers dest.WriteUInt(indexBuffers_.Size()); for (unsigned i = 0; i < indexBuffers_.Size(); ++i) indexBuffers_[i].WriteData(dest); // Subgeometries dest.WriteUInt(subGeometries_.Size()); for (unsigned i = 0; i < subGeometries_.Size(); ++i) { // Write bone mapping info from the first LOD level. It does not change for further LODs dest.WriteUInt(subGeometries_[i][0].boneMapping_.Size()); for (unsigned k = 0; k < subGeometries_[i][0].boneMapping_.Size(); ++k) dest.WriteUInt(subGeometries_[i][0].boneMapping_[k]); // Lod levels for this subgeometry dest.WriteUInt(subGeometries_[i].Size()); for (unsigned j = 0; j < subGeometries_[i].Size(); ++j) { dest.WriteFloat(subGeometries_[i][j].distance_); dest.WriteUInt((unsigned)subGeometries_[i][j].primitiveType_); dest.WriteUInt(subGeometries_[i][j].vertexBuffer_); dest.WriteUInt(subGeometries_[i][j].indexBuffer_); dest.WriteUInt(subGeometries_[i][j].indexStart_); dest.WriteUInt(subGeometries_[i][j].indexCount_); } } // Morphs dest.WriteUInt(morphs_.Size()); for (unsigned i = 0; i < morphs_.Size(); ++i) morphs_[i].WriteData(dest); // Skeleton dest.WriteUInt(bones_.Size()); for (unsigned i = 0; i < bones_.Size(); ++i) { dest.WriteString(bones_[i].name_); dest.WriteUInt(bones_[i].parentIndex_); dest.WriteVector3(bones_[i].bindPosition_); dest.WriteQuaternion(bones_[i].bindRotation_); dest.WriteVector3(bones_[i].bindScale_); Matrix3x4 offsetMatrix(bones_[i].derivedPosition_, bones_[i].derivedRotation_, bones_[i].derivedScale_); offsetMatrix = offsetMatrix.Inverse(); dest.Write(offsetMatrix.Data(), sizeof(Matrix3x4)); dest.WriteUByte(bones_[i].collisionMask_); if (bones_[i].collisionMask_ & 1) dest.WriteFloat(bones_[i].radius_); if (bones_[i].collisionMask_ & 2) dest.WriteBoundingBox(bones_[i].boundingBox_); } // Bounding box dest.WriteBoundingBox(boundingBox_); // Geometry centers for (unsigned i = 0; i < subGeometryCenters_.Size(); ++i) dest.WriteVector3(subGeometryCenters_[i]); } if (saveMaterialList) { String materialListName = ReplaceExtension(outputFileName, ".txt"); File listFile(context_); if (listFile.Open(materialListName, FILE_WRITE)) { for (unsigned i = 0; i < materialNames_.Size(); ++i) { // Assume the materials will be located inside the standard Materials subdirectory listFile.WriteLine("Materials/" + ReplaceExtension(SanitateAssetName(materialNames_[i]), ".xml")); } } else PrintLine("Warning: could not write material list file " + materialListName); } XMLElement skeletonRoot = skelFile_->GetRoot("skeleton"); if (skeletonRoot && exportAnimations) { // Go through animations XMLElement animationsRoot = skeletonRoot.GetChild("animations"); if (animationsRoot) { XMLElement animation = animationsRoot.GetChild("animation"); while (animation) { ModelAnimation newAnimation; newAnimation.name_ = animation.GetAttribute("name"); newAnimation.length_ = animation.GetFloat("length"); XMLElement tracksRoot = animation.GetChild("tracks"); XMLElement track = tracksRoot.GetChild("track"); while (track) { String trackName = track.GetAttribute("bone"); ModelBone* bone = 0; for (unsigned i = 0; i < bones_.Size(); ++i) { if (bones_[i].name_ == trackName) { bone = &bones_[i]; break; } } if (!bone) ErrorExit("Found animation track for unknown bone " + trackName); AnimationTrack newAnimationTrack; newAnimationTrack.name_ = trackName; if (!rotationsOnly) newAnimationTrack.channelMask_ = CHANNEL_POSITION | CHANNEL_ROTATION; else newAnimationTrack.channelMask_ = CHANNEL_ROTATION; XMLElement keyFramesRoot = track.GetChild("keyframes"); XMLElement keyFrame = keyFramesRoot.GetChild("keyframe"); while (keyFrame) { AnimationKeyFrame newKeyFrame; // Convert from right- to left-handed XMLElement position = keyFrame.GetChild("translate"); float x = position.GetFloat("x"); float y = position.GetFloat("y"); float z = position.GetFloat("z"); Vector3 pos(x, y, -z); XMLElement rotation = keyFrame.GetChild("rotate"); 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); // Transform from bind-pose relative into absolute pos = bone->bindPosition_ + bone->bindRotation_ * pos; rot = bone->bindRotation_ * rot; newKeyFrame.time_ = keyFrame.GetFloat("time"); newKeyFrame.position_ = pos; newKeyFrame.rotation_ = rot; newAnimationTrack.keyFrames_.Push(newKeyFrame); keyFrame = keyFrame.GetNext("keyframe"); } // Make sure keyframes are sorted from beginning to end Sort(newAnimationTrack.keyFrames_.Begin(), newAnimationTrack.keyFrames_.End(), CompareKeyFrames); // Do not add tracks with no keyframes if (newAnimationTrack.keyFrames_.Size()) newAnimation.tracks_.Push(newAnimationTrack); track = track.GetNext("track"); } // Write each animation into a separate file String animationFileName = outputFileName.Replaced(".mdl", ""); animationFileName += "_" + newAnimation.name_ + ".ani"; File dest(context_); if (!dest.Open(animationFileName, FILE_WRITE)) ErrorExit("Could not open output file " + animationFileName); dest.WriteFileID("UANI"); dest.WriteString(newAnimation.name_); dest.WriteFloat(newAnimation.length_); dest.WriteUInt(newAnimation.tracks_.Size()); for (unsigned i = 0; i < newAnimation.tracks_.Size(); ++i) { AnimationTrack& track = newAnimation.tracks_[i]; dest.WriteString(track.name_); dest.WriteUByte(track.channelMask_); dest.WriteUInt(track.keyFrames_.Size()); for (unsigned j = 0; j < track.keyFrames_.Size(); ++j) { AnimationKeyFrame& keyFrame = track.keyFrames_[j]; dest.WriteFloat(keyFrame.time_); if (track.channelMask_ & CHANNEL_POSITION) dest.WriteVector3(keyFrame.position_); if (track.channelMask_ & CHANNEL_ROTATION) dest.WriteQuaternion(keyFrame.rotation_); if (track.channelMask_ & CHANNEL_SCALE) dest.WriteVector3(keyFrame.scale_); } } animation = animation.GetNext("animation"); PrintLine("Processed animation " + newAnimation.name_); } } } }
bool TextureCube::BeginLoad(Deserializer& source) { ResourceCache* cache = context_->resourceCache(); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } cache->ResetDependencies(this); QString texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); loadParameters_ = (new XMLFile(context_)); if (!loadParameters_->Load(source)) { loadParameters_.Reset(); return false; } loadImages_.clear(); XMLElement textureElem = loadParameters_->GetRoot(); XMLElement imageElem = textureElem.GetChild("image"); // Single image and multiple faces with layout if (imageElem) { QString name = imageElem.GetAttribute("name"); // If path is empty, add the XML file path if (GetPath(name).isEmpty()) name = texPath + name; SharedPtr<Image> image = cache->GetTempResource<Image>(name); if (!image) return false; int faceWidth, faceHeight; loadImages_.resize(MAX_CUBEMAP_FACES); if (image->IsCubemap()) { loadImages_[FACE_POSITIVE_X] = image; loadImages_[FACE_NEGATIVE_X] = loadImages_[FACE_POSITIVE_X]->GetNextSibling(); loadImages_[FACE_POSITIVE_Y] = loadImages_[FACE_NEGATIVE_X]->GetNextSibling(); loadImages_[FACE_NEGATIVE_Y] = loadImages_[FACE_POSITIVE_Y]->GetNextSibling(); loadImages_[FACE_POSITIVE_Z] = loadImages_[FACE_NEGATIVE_Y]->GetNextSibling(); loadImages_[FACE_NEGATIVE_Z] = loadImages_[FACE_POSITIVE_Z]->GetNextSibling(); } else { CubeMapLayout layout = (CubeMapLayout)GetStringListIndex(imageElem.GetAttribute("layout"), cubeMapLayoutNames, CML_HORIZONTAL); switch (layout) { case CML_HORIZONTAL: faceWidth = image->GetWidth() / MAX_CUBEMAP_FACES; faceHeight = image->GetHeight(); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 0, 0, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 2, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 3, 0, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 4, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 5, 0, faceWidth, faceHeight); break; case CML_HORIZONTALNVIDIA: faceWidth = image->GetWidth() / MAX_CUBEMAP_FACES; faceHeight = image->GetHeight(); for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) loadImages_[i] = GetTileImage(image, i, 0, faceWidth, faceHeight); break; case CML_HORIZONTALCROSS: faceWidth = image->GetWidth() / 4; faceHeight = image->GetHeight() / 3; loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 0, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 1, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 2, 1, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 3, 1, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 1, 2, faceWidth, faceHeight); break; case CML_VERTICALCROSS: faceWidth = image->GetWidth() / 3; faceHeight = image->GetHeight() / 4; loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 0, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 1, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 2, 1, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 1, 2, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 1, 3, faceWidth, faceHeight); if (loadImages_[FACE_NEGATIVE_Z]) { loadImages_[FACE_NEGATIVE_Z]->FlipVertical(); loadImages_[FACE_NEGATIVE_Z]->FlipHorizontal(); } break; case CML_BLENDER: faceWidth = image->GetWidth() / 3; faceHeight = image->GetHeight() / 2; loadImages_[FACE_NEGATIVE_X] = GetTileImage(image, 0, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 1, 0, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_X] = GetTileImage(image, 2, 0, faceWidth, faceHeight); loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 0, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Y] = GetTileImage(image, 1, 1, faceWidth, faceHeight); loadImages_[FACE_POSITIVE_Z] = GetTileImage(image, 2, 1, faceWidth, faceHeight); break; } } } // Face per image else { XMLElement faceElem = textureElem.GetChild("face"); while (faceElem) { QString name = faceElem.GetAttribute("name"); // If path is empty, add the XML file path if (GetPath(name).isEmpty()) name = texPath + name; loadImages_.push_back(cache->GetTempResource<Image>(name)); cache->StoreResourceDependency(this, name); faceElem = faceElem.GetNext("face"); } } // Precalculate mip levels if async loading if (GetAsyncLoadState() == ASYNC_LOADING) { for (unsigned i = 0; i < loadImages_.size(); ++i) { if (loadImages_[i]) loadImages_[i]->PrecalculateLevels(); } } return true; }
bool 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 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; }
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 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 ParticleEmitter::Load(XMLFile* file) { if (!file) { LOGERROR("Null particle emitter parameter file"); return false; } XMLElement rootElem = file->GetRoot(); if (!rootElem) { LOGERROR("Particle emitter parameter file does not have a valid root element"); return false; } if (rootElem.HasChild("material")) SetMaterial(GetSubsystem<ResourceCache>()->GetResource<Material>(rootElem.GetChild("material").GetAttribute("name"))); if (rootElem.HasChild("numparticles")) SetNumParticles(rootElem.GetChild("numparticles").GetInt("value")); if (rootElem.HasChild("updateinvisible")) updateInvisible_ = rootElem.GetChild("updateinvisible").GetBool("enable"); if (rootElem.HasChild("relative")) relative_ = rootElem.GetChild("relative").GetBool("enable"); if (rootElem.HasChild("scaled")) scaled_ = rootElem.GetChild("scaled").GetBool("enable"); if (rootElem.HasChild("sorted")) sorted_ = rootElem.GetChild("sorted").GetBool("enable"); if (rootElem.HasChild("animlodbias")) SetAnimationLodBias(rootElem.GetChild("relative").GetFloat("value")); if (rootElem.HasChild("emittertype")) { String type = rootElem.GetChild("emittertype").GetAttributeLower("value"); if (type == "point") { // Point emitter type is deprecated, handled as zero sized sphere emitterType_ = EMITTER_SPHERE; emitterSize_ = Vector3::ZERO; } else if (type == "box") emitterType_ = EMITTER_BOX; else if (type == "sphere") emitterType_ = EMITTER_SPHERE; else LOGERROR("Unknown particle emitter type " + type); } if (rootElem.HasChild("emittersize")) emitterSize_ = rootElem.GetChild("emittersize").GetVector3("value"); if (rootElem.HasChild("emitterradius")) emitterSize_.x_ = emitterSize_.y_ = emitterSize_.z_ = rootElem.GetChild("emitterradius").GetFloat("value"); if (rootElem.HasChild("direction")) GetVector3MinMax(rootElem.GetChild("direction"), directionMin_, directionMax_); if (rootElem.HasChild("constantforce")) constantForce_ = rootElem.GetChild("constantforce").GetVector3("value"); if (rootElem.HasChild("dampingforce")) dampingForce_ = rootElem.GetChild("dampingforce").GetFloat("value"); if (rootElem.HasChild("activetime")) activeTime_ = rootElem.GetChild("activetime").GetFloat("value"); if (activeTime_ < 0.0f) activeTime_ = M_INFINITY; if (rootElem.HasChild("inactivetime")) inactiveTime_ = rootElem.GetChild("inactivetime").GetFloat("value"); if (inactiveTime_ < 0.0f) inactiveTime_ = M_INFINITY; if (rootElem.HasChild("emissionrate")) GetFloatMinMax(rootElem.GetChild("emissionrate"), emissionRateMin_, emissionRateMax_); if (rootElem.HasChild("interval")) { float intervalMin = 0.0f; float intervalMax = 0.0f; GetFloatMinMax(rootElem.GetChild("interval"), intervalMin, intervalMax); emissionRateMax_ = 1.0f / intervalMin; emissionRateMin_ = 1.0f / intervalMax; } if (rootElem.HasChild("particlesize")) GetVector2MinMax(rootElem.GetChild("particlesize"), sizeMin_, sizeMax_); if (rootElem.HasChild("timetolive")) GetFloatMinMax(rootElem.GetChild("timetolive"), timeToLiveMin_, timeToLiveMax_); if (rootElem.HasChild("velocity")) GetFloatMinMax(rootElem.GetChild("velocity"), velocityMin_, velocityMax_); if (rootElem.HasChild("rotation")) GetFloatMinMax(rootElem.GetChild("rotation"), rotationMin_, rotationMax_); if (rootElem.HasChild("rotationspeed")) GetFloatMinMax(rootElem.GetChild("rotationspeed"), rotationSpeedMin_, rotationSpeedMax_); if (rootElem.HasChild("sizedelta")) { XMLElement deltaElem = rootElem.GetChild("sizedelta"); if (deltaElem.HasAttribute("add")) sizeAdd_ = deltaElem.GetFloat("add"); if (deltaElem.HasAttribute("mul")) sizeMul_ = deltaElem.GetFloat("mul"); } if (rootElem.HasChild("color")) SetColor(rootElem.GetChild("color").GetColor("value")); if (rootElem.HasChild("colorfade")) { Vector<ColorFrame> fades; XMLElement colorFadeElem = rootElem.GetChild("colorfade"); while (colorFadeElem) { fades.Push(ColorFrame(colorFadeElem.GetColor("color"), colorFadeElem.GetFloat("time"))); colorFadeElem = colorFadeElem.GetNext("colorfade"); } SetColors(fades); } if (rootElem.HasChild("texanim")) { Vector<TextureFrame> animations; XMLElement animElem = rootElem.GetChild("texanim"); while (animElem) { TextureFrame animation; animation.uv_ = animElem.GetRect("uv"); animation.time_ = animElem.GetFloat("time"); animations.Push(animation); animElem = animElem.GetNext("texanim"); } textureFrames_ = animations; } MarkNetworkUpdate(); 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 Texture3D::Load(Deserializer& source) { PROFILE(LoadTexture3D); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } // If over the texture budget, see if materials can be freed to allow textures to be freed CheckTextureBudget(GetTypeStatic()); // Before actually loading the texture, get optional parameters from an XML description file LoadParameters(); String texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); SharedPtr<XMLFile> xml(new XMLFile(context_)); if (!xml->Load(source)) return false; XMLElement textureElem = xml->GetRoot(); XMLElement volumeElem = textureElem.GetChild("volume"); XMLElement colorlutElem = textureElem.GetChild("colorlut"); if (volumeElem) { String name = volumeElem.GetAttribute("name"); String volumeTexPath, volumeTexName, volumeTexExt; SplitPath(name, volumeTexPath, volumeTexName, volumeTexExt); // If path is empty, add the XML file path if (volumeTexPath.Empty()) name = texPath + name; SharedPtr<Image> image(GetSubsystem<ResourceCache>()->GetResource<Image>(name)); return Load(image); } else if (colorlutElem) { String name = colorlutElem.GetAttribute("name"); String colorlutTexPath, colorlutTexName, colorlutTexExt; SplitPath(name, colorlutTexPath, colorlutTexName, colorlutTexExt); // If path is empty, add the XML file path if (colorlutTexPath.Empty()) name = texPath + name; SharedPtr<File> file = GetSubsystem<ResourceCache>()->GetFile(name); SharedPtr<Image> image(new Image(context_)); if (!image->LoadColorLUT(*(file.Get()))) return false; return Load(image); } return false; }
Node* TerrySpawner::LoadSprite(String name) { //Vector3 startPos = terrySpawns_->GetChild(Random(0,terrySpawns_->GetNumChildren()))->GetPosition(); Vector3 startPos = spawnPoint_; XMLFile* xmlFile = main_->cache_->GetResource<XMLFile>("Objects/terriesNode.xml"); Node* spriteNode = scene_->InstantiateXML(xmlFile->GetRoot(), startPos, Quaternion::IDENTITY, LOCAL); spriteNode->RemoveChild(spriteNode->GetChild("camera")); spriteNode->SetName(name); spriteNode->AddComponent(new Gravity(context_, main_), 0, LOCAL); spriteNode->AddComponent(new Speed(context_, main_), 0, LOCAL); //spriteNode->AddComponent(new RotateTo(context_, main_), 0, LOCAL); spriteNode->AddComponent(new MoveByTouch(context_, main_), 0, LOCAL); spriteNode->AddComponent(new Health(context_, main_), 0, LOCAL); spriteNode->GetComponent<MoveByTouch>()->UnsubscribeFromEvent(E_HUDBUTT); StaticSprite2D* sprite = spriteNode->CreateComponent<StaticSprite2D>(); sprite->SetCustomMaterial(SharedPtr<Material>(main_->cache_->GetResource<Material>("Materials/" + name + "Mat.xml"))); AnimatedSpriteSheet* animatedSpriteSheet = new AnimatedSpriteSheet(); animatedSpriteSheet->sheet_ = main_->cache_->GetResource<SpriteSheet2D>("Urho2D/" + name + "/" + name + "Sheet.xml"); animatedSpriteSheet->staticSprite_ = sprite; animatedSpriteSheet->playing_ = false; animatedSpriteSheet->spriteID_ = spriteIDCount_; animatedSpriteSheet->noed_ = spriteNode; animatedSpriteSheet->flipX_ = false; sprites_.Push(animatedSpriteSheet); spriteIDCount_++; Vector<String> files; files.Push("attackF.xml"); files.Push("attackM.xml"); files.Push("dieF.xml"); files.Push("dieM.xml"); files.Push("gestureF.xml"); files.Push("gestureM.xml"); files.Push("idleF.xml"); files.Push("idleM.xml"); files.Push("runF.xml"); files.Push("runM.xml"); /*main_->filesystem_->ScanDir(files, main_->filesystem_->GetProgramDir() + "Data/Urho2D/" + name + "/animations/", "*.xml", SCAN_FILES, false);*/ for (int x = 0; x < files.Size(); x++) { XMLElement ani = main_->cache_->GetResource<XMLFile>("Urho2D/" + name + "/animations/" + files[x])->GetRoot(); SpriteSheetAnimation* spriteSheetAni = new SpriteSheetAnimation(); animatedSpriteSheet->animations_.Push(spriteSheetAni); spriteSheetAni->name_ = ani.GetChild("Name").GetAttribute("name"); spriteSheetAni->loop_ = ani.GetChild("Loop").GetBool("loop"); int frameCount = ani.GetChild("FrameCount").GetInt("frameCount"); for (int x = 0; x < frameCount; x++) { SpriteSheetAnimationFrame* frame = new SpriteSheetAnimationFrame(); spriteSheetAni->frames_.Push(frame); String child = "Frame" + String(x); frame->duration_ = ani.GetChild(child).GetFloat("duration"); frame->sprite_ = ani.GetChild(child).GetAttribute("sprite"); } } bool sex = Random(0,2); animatedSpriteSheet->noed_->SetVar("sex",sex); VariantMap vm; vm[AnimateSpriteSheet::P_NODE] = node_; vm[AnimateSpriteSheet::P_SPRITEID] = animatedSpriteSheet->spriteID_; if (sex) { vm[AnimateSpriteSheet::P_ANIMATION] = "idleF"; } else { vm[AnimateSpriteSheet::P_ANIMATION] = "idleM"; } vm[AnimateSpriteSheet::P_FLIPX] = 0; SendEvent(E_ANIMATESPRITESHEET, vm); animatedSpriteSheet->noed_->SetVar("collisionCount",0); animatedSpriteSheet->noed_->SetVar("attack",1); animatedSpriteSheet->noed_->SetVar("attackInterval",1.0f); animatedSpriteSheet->noed_->SetVar("attackElapsedTime",0.0f); animatedSpriteSheet->noed_->SetVar("canAttack",false); animatedSpriteSheet->noed_->SetVar("npcType",1);//0 = hero, 1 = terry return spriteNode; }
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 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; }
void GameEconomicGameClient::LoadConfiguration(Configuration &configuration) { /// Grab resources FileSystem * fileSystem = GetSubsystem<FileSystem>(); /// Set all defaults bool success=false; configuration.GameModeForceTablet=false; configuration.VideoBloomParam1=0.9f; configuration.VideoBloomParam2=0.6f; /// Create String String configFileName; /// Set directory and path for network file configFileName.Append(fileSystem->GetProgramDir().CString()); configFileName.Append(""); configFileName.Append("Configuration.xml"); /// If file does not exist exit function with null structure if (!fileSystem->FileExists(configFileName)) { cout << "Configuration file not found.. Using defaults.. " << endl; return; } /// Flag file for loading and load File loadFile(context_, configFileName, FILE_READ); XMLFile * configurationXML = new XMLFile(context_); configurationXML -> Load(loadFile); XMLElement configElem = configurationXML->GetRoot(); /// If no configuration is set or no root if (configElem.IsNull()) { cout << "Configuration file not found.. Using defaults.. " << endl; return; } /// Basic Config XMLElement GameModeConfigurationElem = configElem.GetChild("GameModeConfiguration"); /// If no network server element return false; if (!GameModeConfigurationElem.IsNull()) { if (GameModeConfigurationElem.HasAttribute("GameModeForceTablet")) configuration.GameModeForceTablet = GameModeConfigurationElem.GetBool("GameModeForceTablet"); } /// Basic Config XMLElement VideoConfigurationElem = configElem.GetChild("VideoConfiguration"); /// If no network server element return false; if (!VideoConfigurationElem.IsNull()) { if (VideoConfigurationElem.HasAttribute("BloomParam1")) configuration.VideoBloomParam1= VideoConfigurationElem.GetFloat("BloomParam1"); if (VideoConfigurationElem.HasAttribute("BloomParam2")) configuration.VideoBloomParam2= VideoConfigurationElem.GetFloat("BloomParam2"); } return; }
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 Texture3D::BeginLoad(Deserializer& source) { auto* cache = GetSubsystem<ResourceCache>(); // In headless mode, do not actually load the texture, just return success if (!graphics_) return true; // If device is lost, retry later if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture load while device is lost"); dataPending_ = true; return true; } String texPath, texName, texExt; SplitPath(GetName(), texPath, texName, texExt); cache->ResetDependencies(this); loadParameters_ = new XMLFile(context_); if (!loadParameters_->Load(source)) { loadParameters_.Reset(); return false; } XMLElement textureElem = loadParameters_->GetRoot(); XMLElement volumeElem = textureElem.GetChild("volume"); XMLElement colorlutElem = textureElem.GetChild("colorlut"); if (volumeElem) { String name = volumeElem.GetAttribute("name"); String volumeTexPath, volumeTexName, volumeTexExt; SplitPath(name, volumeTexPath, volumeTexName, volumeTexExt); // If path is empty, add the XML file path if (volumeTexPath.Empty()) name = texPath + name; loadImage_ = cache->GetTempResource<Image>(name); // Precalculate mip levels if async loading if (loadImage_ && GetAsyncLoadState() == ASYNC_LOADING) loadImage_->PrecalculateLevels(); cache->StoreResourceDependency(this, name); return true; } else if (colorlutElem) { String name = colorlutElem.GetAttribute("name"); String colorlutTexPath, colorlutTexName, colorlutTexExt; SplitPath(name, colorlutTexPath, colorlutTexName, colorlutTexExt); // If path is empty, add the XML file path if (colorlutTexPath.Empty()) name = texPath + name; SharedPtr<File> file = GetSubsystem<ResourceCache>()->GetFile(name); loadImage_ = new Image(context_); if (!loadImage_->LoadColorLUT(*(file.Get()))) { loadParameters_.Reset(); loadImage_.Reset(); return false; } // Precalculate mip levels if async loading if (loadImage_ && GetAsyncLoadState() == ASYNC_LOADING) loadImage_->PrecalculateLevels(); cache->StoreResourceDependency(this, name); return true; } URHO3D_LOGERROR("Texture3D XML data for " + GetName() + " did not contain either volume or colorlut element"); return false; }
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 Menu::LoadXML(const XMLElement& source, XMLFile* styleFile, bool setInstanceDefault) { // Get style override if defined String styleName = source.GetAttribute("style"); // Apply the style first, if the style file is available if (styleFile) { // If not defined, use type name if (styleName.Empty()) styleName = GetTypeName(); SetStyle(styleName, styleFile); } // The 'style' attribute value in the style file cannot be equals to original's applied style to prevent infinite loop else if (!styleName.Empty() && styleName != appliedStyle_) { // Attempt to use the default style file styleFile = GetDefaultStyle(); if (styleFile) { // Remember the original applied style String appliedStyle(appliedStyle_); SetStyle(styleName, styleFile); appliedStyle_ = appliedStyle; } } // Then load rest of the attributes from the source if (!Serializable::LoadXML(source, setInstanceDefault)) return false; unsigned nextInternalChild = 0; // Load child elements. Internal elements are not to be created as they already exist XMLElement childElem = source.GetChild("element"); while (childElem) { bool internalElem = childElem.GetBool("internal"); bool popupElem = childElem.GetBool("popup"); String typeName = childElem.GetAttribute("type"); if (typeName.Empty()) typeName = "UIElement"; unsigned index = childElem.HasAttribute("index") ? childElem.GetUInt("index") : M_MAX_UNSIGNED; UIElement* child = 0; if (!internalElem) { if (!popupElem) child = CreateChild(typeName, String::EMPTY, index); else { // Do not add the popup element as a child even temporarily, as that can break layouts SharedPtr<UIElement> popup = DynamicCast<UIElement>(context_->CreateObject(typeName)); if (!popup) URHO3D_LOGERROR("Could not create popup element type " + typeName); else { child = popup; SetPopup(popup); } } } else { // An internal popup element should already exist if (popupElem) child = popup_; else { for (unsigned i = nextInternalChild; i < children_.Size(); ++i) { if (children_[i]->IsInternal() && children_[i]->GetTypeName() == typeName) { child = children_[i]; nextInternalChild = i + 1; break; } } if (!child) URHO3D_LOGWARNING("Could not find matching internal child element of type " + typeName + " in " + GetTypeName()); } } if (child) { if (!styleFile) styleFile = GetDefaultStyle(); // As popup is not a child element in itself, the parental chain to acquire the default style file is broken for popup's child elements // To recover from this, popup needs to have the default style set in its own instance so the popup's child elements can find it later if (popupElem) child->SetDefaultStyle(styleFile); if (!child->LoadXML(childElem, styleFile, setInstanceDefault)) return false; } childElem = childElem.GetNext("element"); } ApplyAttributes(); return true; }
bool Menu::LoadXML(const XMLElement& source, XMLFile* styleFile) { // Apply the style first, but only for non-internal elements if (!internal_ && styleFile) { // Use style override if defined, otherwise type name String styleName = source.GetAttribute("style"); if (styleName.Empty()) styleName = GetTypeName(); SetStyle(styleFile, styleName); } // Then load rest of the attributes from the source if (!Serializable::LoadXML(source)) return false; unsigned nextInternalChild = 0; // Load child elements. Internal elements are not to be created as they already exist XMLElement childElem = source.GetChild("element"); while (childElem) { bool internalElem = childElem.GetBool("internal"); bool popupElem = childElem.GetBool("popup"); String typeName = childElem.GetAttribute("type"); if (typeName.Empty()) typeName = "UIElement"; UIElement* child = 0; if (!internalElem) { if (!popupElem) child = CreateChild(ShortStringHash(typeName)); else { // Do not add the popup element as a child even temporarily, as that can break layouts SharedPtr<UIElement> popup = DynamicCast<UIElement>(context_->CreateObject(ShortStringHash(typeName))); if (!popup) LOGERROR("Could not create popup element type " + ShortStringHash(typeName).ToString()); else { child = popup; SetPopup(popup); } } } else { // An internal popup element should already exist if (popupElem) child = popup_; else { for (unsigned i = nextInternalChild; i < children_.Size(); ++i) { if (children_[i]->IsInternal() && children_[i]->GetTypeName() == typeName) { child = children_[i]; nextInternalChild = i + 1; break; } } if (!child) LOGWARNING("Could not find matching internal child element of type " + typeName + " in " + GetTypeName()); } } if (child) { if (!child->LoadXML(childElem, styleFile)) return false; } childElem = childElem.GetNext("element"); } ApplyAttributes(); 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; }
void PropertySet2D::Load(const XMLElement& element) { assert(element.GetName() == "properties"); for (XMLElement propertyElem = element.GetChild("property"); propertyElem; propertyElem = propertyElem.GetNext("property")) nameToValueMapping_[propertyElem.GetAttribute("name")] = propertyElem.GetAttribute("value"); }
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 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 ParticleEffect::Load(const XMLElement& source) { // Reset to defaults first so that missing parameters in case of a live reload behave as expected material_.Reset(); numParticles_ = DEFAULT_NUM_PARTICLES; updateInvisible_ = false; relative_ = true; scaled_ = true; sorted_ = false; fixedScreenSize_ = false; animationLodBias_ = 0.0f; emitterType_ = EMITTER_SPHERE; emitterSize_ = Vector3::ZERO; directionMin_ = DEFAULT_DIRECTION_MIN; directionMax_ = DEFAULT_DIRECTION_MAX; constantForce_ = Vector3::ZERO; dampingForce_ = 0.0f; activeTime_ = 0.0f; inactiveTime_ = 0.0; emissionRateMin_ = DEFAULT_EMISSION_RATE; emissionRateMax_ = DEFAULT_EMISSION_RATE; sizeMin_ = DEFAULT_PARTICLE_SIZE; sizeMax_ = DEFAULT_PARTICLE_SIZE; timeToLiveMin_ = DEFAULT_TIME_TO_LIVE; timeToLiveMax_ = DEFAULT_TIME_TO_LIVE; velocityMin_ = DEFAULT_VELOCITY; velocityMax_ = DEFAULT_VELOCITY; rotationMin_ = 0.0f; rotationMax_ = 0.0f; rotationSpeedMin_ = 0.0f; rotationSpeedMax_ = 0.0f; sizeAdd_ = 0.0f; sizeMul_ = 1.0f; colorFrames_.Clear(); textureFrames_.Clear(); faceCameraMode_ = FC_ROTATE_XYZ; if (source.IsNull()) { URHO3D_LOGERROR("Can not load particle effect from null XML element"); return false; } if (source.HasChild("material")) { loadMaterialName_ = source.GetChild("material").GetAttribute("name"); // If async loading, can not GetResource() the material. But can do a background request for it if (GetAsyncLoadState() == ASYNC_LOADING) GetSubsystem<ResourceCache>()->BackgroundLoadResource<Material>(loadMaterialName_, true, this); } if (source.HasChild("numparticles")) SetNumParticles((unsigned)source.GetChild("numparticles").GetInt("value")); if (source.HasChild("updateinvisible")) updateInvisible_ = source.GetChild("updateinvisible").GetBool("enable"); if (source.HasChild("relative")) relative_ = source.GetChild("relative").GetBool("enable"); if (source.HasChild("scaled")) scaled_ = source.GetChild("scaled").GetBool("enable"); if (source.HasChild("sorted")) sorted_ = source.GetChild("sorted").GetBool("enable"); if (source.HasChild("fixedscreensize")) fixedScreenSize_ = source.GetChild("fixedscreensize").GetBool("enable"); if (source.HasChild("animlodbias")) SetAnimationLodBias(source.GetChild("animlodbias").GetFloat("value")); if (source.HasChild("emittertype")) { String type = source.GetChild("emittertype").GetAttributeLower("value"); if (type == "point") { // Point emitter type is deprecated, handled as zero sized sphere emitterType_ = EMITTER_SPHERE; emitterSize_ = Vector3::ZERO; } else emitterType_ = (EmitterType)GetStringListIndex(type.CString(), emitterTypeNames, EMITTER_SPHERE); } if (source.HasChild("emittersize")) emitterSize_ = source.GetChild("emittersize").GetVector3("value"); if (source.HasChild("emitterradius")) emitterSize_.x_ = emitterSize_.y_ = emitterSize_.z_ = source.GetChild("emitterradius").GetFloat("value"); if (source.HasChild("direction")) GetVector3MinMax(source.GetChild("direction"), directionMin_, directionMax_); if (source.HasChild("constantforce")) constantForce_ = source.GetChild("constantforce").GetVector3("value"); if (source.HasChild("dampingforce")) dampingForce_ = source.GetChild("dampingforce").GetFloat("value"); if (source.HasChild("activetime")) activeTime_ = source.GetChild("activetime").GetFloat("value"); if (activeTime_ < 0.0f) activeTime_ = M_INFINITY; if (source.HasChild("inactivetime")) inactiveTime_ = source.GetChild("inactivetime").GetFloat("value"); if (inactiveTime_ < 0.0f) inactiveTime_ = M_INFINITY; if (source.HasChild("emissionrate")) GetFloatMinMax(source.GetChild("emissionrate"), emissionRateMin_, emissionRateMax_); if (source.HasChild("interval")) { float intervalMin = 0.0f; float intervalMax = 0.0f; GetFloatMinMax(source.GetChild("interval"), intervalMin, intervalMax); emissionRateMax_ = 1.0f / intervalMin; emissionRateMin_ = 1.0f / intervalMax; } if (source.HasChild("particlesize")) GetVector2MinMax(source.GetChild("particlesize"), sizeMin_, sizeMax_); if (source.HasChild("timetolive")) GetFloatMinMax(source.GetChild("timetolive"), timeToLiveMin_, timeToLiveMax_); if (source.HasChild("velocity")) GetFloatMinMax(source.GetChild("velocity"), velocityMin_, velocityMax_); if (source.HasChild("rotation")) GetFloatMinMax(source.GetChild("rotation"), rotationMin_, rotationMax_); if (source.HasChild("rotationspeed")) GetFloatMinMax(source.GetChild("rotationspeed"), rotationSpeedMin_, rotationSpeedMax_); if (source.HasChild("faceCameraMode")) { String type = source.GetChild("faceCameraMode").GetAttributeLower("value"); faceCameraMode_ = (FaceCameraMode)GetStringListIndex(type.CString(), faceCameraModeNames, FC_ROTATE_XYZ); } if (source.HasChild("sizedelta")) { XMLElement deltaElem = source.GetChild("sizedelta"); if (deltaElem.HasAttribute("add")) sizeAdd_ = deltaElem.GetFloat("add"); if (deltaElem.HasAttribute("mul")) sizeMul_ = deltaElem.GetFloat("mul"); } if (source.HasChild("color")) { ColorFrame colorFrame(source.GetChild("color").GetColor("value")); SetColorFrame(0, colorFrame); } if (source.HasChild("colorfade")) { Vector<ColorFrame> fades; for (XMLElement colorFadeElem = source.GetChild("colorfade"); colorFadeElem; colorFadeElem = colorFadeElem.GetNext("colorfade")) fades.Push(ColorFrame(colorFadeElem.GetColor("color"), colorFadeElem.GetFloat("time"))); SetColorFrames(fades); } if (colorFrames_.Empty()) colorFrames_.Push(ColorFrame(Color::WHITE)); if (source.HasChild("texanim")) { Vector<TextureFrame> animations; for (XMLElement animElem = source.GetChild("texanim"); animElem; animElem = animElem.GetNext("texanim")) { TextureFrame animation; animation.uv_ = animElem.GetRect("uv"); animation.time_ = animElem.GetFloat("time"); animations.Push(animation); } SetTextureFrames(animations); } 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 ParticleEffect2D::Load(Deserializer& source) { 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"); ResourceCache* cache = GetSubsystem<ResourceCache>(); sprite_= cache->GetResource<Sprite2D>(texture, false); // If sprite not found, try get in current directory if (!sprite_) sprite_= cache->GetResource<Sprite2D>(GetParentPath(GetName()) + texture); if (!sprite_) return false; sourcePositionVariance_ = ReadVector2(rootElem.GetChild("sourcePositionVariance")); speed_ = rootElem.GetChild("speed").GetFloat("value"); speedVariance_ = rootElem.GetChild("speedVariance").GetFloat("value"); particleLifeSpan_ = Max(0.01f, rootElem.GetChild("particleLifeSpan").GetFloat("value")); particleLifespanVariance_ = rootElem.GetChild("particleLifespanVariance").GetFloat("value"); angle_ = rootElem.GetChild("angle").GetFloat("value"); angleVariance_ = rootElem.GetChild("angleVariance").GetFloat("value"); gravity_ = ReadVector2(rootElem.GetChild("gravity")); radialAcceleration_ = rootElem.GetChild("radialAcceleration").GetFloat("value"); tangentialAcceleration_ = rootElem.GetChild("tangentialAcceleration").GetFloat("value"); radialAccelVariance_ = rootElem.GetChild("radialAccelVariance").GetFloat("value"); tangentialAccelVariance_ = rootElem.GetChild("tangentialAccelVariance").GetFloat("value"); startColor_ = ReadColor(rootElem.GetChild("startColor")); startColorVariance_ = ReadColor(rootElem.GetChild("startColorVariance")); finishColor_ = ReadColor(rootElem.GetChild("finishColor")); finishColorVariance_ = ReadColor(rootElem.GetChild("finishColorVariance")); maxParticles_ = rootElem.GetChild("maxParticles").GetInt("value"); startParticleSize_ = rootElem.GetChild("startParticleSize").GetFloat("value"); startParticleSizeVariance_ = rootElem.GetChild("startParticleSizeVariance").GetFloat("value"); finishParticleSize_ = rootElem.GetChild("finishParticleSize").GetFloat("value"); FinishParticleSizeVariance_ = rootElem.GetChild("FinishParticleSizeVariance").GetFloat("value"); duration_ = M_INFINITY; if (rootElem.HasChild("duration")) { float duration = rootElem.GetChild("duration").GetFloat("value"); if (duration > 0.0f) duration_ = duration; } emitterType_ = (EmitterType2D)rootElem.GetChild("emitterType").GetInt("value"); maxRadius_ = rootElem.GetChild("maxRadius").GetFloat("value"); maxRadiusVariance_ = rootElem.GetChild("maxRadiusVariance").GetFloat("value"); minRadius_ = rootElem.GetChild("minRadius").GetFloat("value"); rotatePerSecond_ = rootElem.GetChild("rotatePerSecond").GetFloat("value"); rotatePerSecondVariance_ = rootElem.GetChild("rotatePerSecondVariance").GetFloat("value"); int blendFuncSource = rootElem.GetChild("blendFuncSource").GetInt("value"); int blendFuncDestination = rootElem.GetChild("blendFuncDestination").GetInt("value"); blendMode_ = BLEND_ALPHA; for (int i = 0; i < MAX_BLENDMODES; ++i) { if (blendFuncSource == srcBlendFuncs[i] && blendFuncDestination == destBlendFuncs[i]) { blendMode_ = (BlendMode)i; break; } } rotationStart_ = rootElem.GetChild("rotationStart").GetFloat("value"); rotationStartVariance_ = rootElem.GetChild("rotationStartVariance").GetFloat("value"); rotationEnd_ = rootElem.GetChild("rotationEnd").GetFloat("value"); rotationEndVariance_ = rootElem.GetChild("rotationEndVariance").GetFloat("value"); 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"); } } } }