/* * Author: Andrew Robberts * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include #include #include #include #include #include "pseffectmanager.h" #include "pseffect.h" #include "pseffectobj.h" #include "pscelclient.h" #include "util/log.h" #include "util/pscssetup.h" //#define DONT_DO_EFFECTS psEffectManager::psEffectManager() : scfImplementationType(this) { vc = CS_QUERY_REGISTRY (psCSSetup::object_reg, iVirtualClock); psCSSetup::object_reg->Register(this, "PSEffects"); #ifndef DONT_DO_EFFECTS csRef engine = CS_QUERY_REGISTRY (psCSSetup::object_reg, iEngine); region = engine->CreateRegion("effects"); #endif } psEffectManager::~psEffectManager() { #ifndef DONT_DO_EFFECTS region->DeleteAll(); csHash::GlobalIterator it = effectFactories.GetIterator(); while (it.HasNext()) { psEffect * tmpEffect = it.Next(); delete tmpEffect; } effectFactories.DeleteAll(); csHash::GlobalIterator itActual = actualEffects.GetIterator(); while (itActual.HasNext()) { psEffect * tmpEffect = itActual.Next(); delete tmpEffect; } actualEffects.DeleteAll(); #endif } csPtr psEffectManager::Parse(iDocumentNode * node, iStreamSource * istream, iLoaderContext * ldr_context, iBase * context) { #ifndef DONT_DO_EFFECTS csRef xmlbinds; xmlbinds = node->GetNodes("effect"); csRef effectNode; while (xmlbinds->HasNext()) { effectNode = xmlbinds->Next(); psEffect * newEffect = new psEffect(); newEffect->Load(effectNode, view); if (FindEffect(newEffect->GetName())) csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Duplicate effect '%s' found!", newEffect->GetName().GetData()); else effectFactories.Put((const char *)newEffect->GetName(), newEffect); } #endif context->IncRef(); return context; } bool psEffectManager::LoadEffects(const csString & fileName, iView * parentView) { #ifndef DONT_DO_EFFECTS view = parentView; csRef loader = CS_QUERY_REGISTRY (psCSSetup::object_reg, iLoader); loader->LoadLibraryFile(fileName, region, true, true); #endif return true; } bool psEffectManager::LoadFromEffectsList(const csString & fileName, iView * parentView) { #ifndef DONT_DO_EFFECTS csRef vfs = CS_QUERY_REGISTRY (psCSSetup::object_reg, iVFS); assert(vfs); if (!vfs->Exists(fileName)) return false; csRef doc; csRef xmlbinds; csRef xml; const char* error; csRef buff = vfs->ReadFile(fileName); if (buff == 0) { csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Could not find file: %s", fileName.GetData()); return false; } xml = CS_QUERY_REGISTRY (psCSSetup::object_reg, iDocumentSystem); doc = xml->CreateDocument(); assert(doc); error = doc->Parse( buff ); if ( error ) { csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Parse error in %s: %s", fileName.GetData(), error); return false; } if (doc == 0) return false; csRef root = doc->GetRoot(); if (root == 0) { csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "No root in XML"); return false; } bool isSuccess = true; csRef listNode = root->GetNode("effectsFileList"); if (listNode != 0) { xmlbinds = listNode->GetNodes("effectsFile"); csRef fileNode; while (xmlbinds->HasNext()) { fileNode = xmlbinds->Next(); csString effectFile = fileNode->GetAttributeValue("file"); if (vfs->Exists(effectFile)) { if (!LoadEffects(effectFile, parentView)) { csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Failed to load effect: %s\n", effectFile.GetData()); // don't return, because some cases might want it to load the other spells isSuccess = false; } } } } return isSuccess; #endif return true; } bool psEffectManager::LoadFromDirectory(const csString & path, bool includeSubDirs, iView * parentView) { #ifndef DONT_DO_EFFECTS csRef vfs = CS_QUERY_REGISTRY (psCSSetup::object_reg, iVFS); assert(vfs); if (!vfs->Exists(path)) { csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Failed to load effects from directory; %s does not exist", path.GetData()); return false; } if (!vfs->ChDir(path)) { csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Failed to load effects from directory; %s read failed", path.GetData()); return false; } csRef files = vfs->FindFiles("*"); for (size_t a=0; aLength(); ++a) { const char * file = files->Get(a); if (file[0] == '.') continue; if (strcmp(file, path) == 0) continue; size_t len = strlen(file); char lastChar = file[len-1]; if (lastChar == '/' || lastChar == '\\') { if (includeSubDirs) { if (!LoadFromDirectory(file, true, parentView)) return false; } } else if (len > 4 && ((lastChar == 'f' || lastChar == 'F') && (file[len-2] == 'f' || file[len-2] == 'F') && (file[len-3] == 'e' || file[len-3] == 'E') && file[len-4] == '.')) { LoadEffects(files->Get(a), parentView); } } #endif return true; } bool psEffectManager::DeleteEffect(unsigned int effectID) { #ifndef DONT_DO_EFFECTS if (effectID == 0) return true; csArray effects; effects = actualEffects.GetAll(effectID); while (effects.Length()) { delete effects.Pop(); } actualEffects.DeleteAll(effectID); #endif return true; } unsigned int psEffectManager::RenderEffect(const csString & effectName, const csVector3 & offset, iMeshWrapper * attachPos, iMeshWrapper * attachTarget, const csVector3 & up, const unsigned int uniqueIDOverride) { #ifndef DONT_DO_EFFECTS if (!attachPos) return 0; // check if it's a single effect psEffect * currEffect = FindEffect(effectName); if (currEffect != 0) { currEffect = currEffect->Clone(); const unsigned int uniqueID = currEffect->Render(attachPos->GetMovable()->GetSectors(), offset, attachPos, attachTarget, up.Unit(), uniqueIDOverride); actualEffects.Put(uniqueID, currEffect); return uniqueID; } #endif return 0; } unsigned int psEffectManager::RenderEffect(const csString & effectName, iSector * sector, const csVector3 & pos, iMeshWrapper * attachTarget, const csVector3 & up, const unsigned int uniqueIDOverride) { #ifndef DONT_DO_EFFECTS // check if it's a single effect psEffect * currEffect = FindEffect(effectName); if (currEffect != 0) { currEffect = currEffect->Clone(); unsigned int uniqueID = currEffect->Render(sector, pos, 0, attachTarget, up.Unit(), uniqueIDOverride); actualEffects.Put(uniqueID, currEffect); return uniqueID; } #endif return 0; } unsigned int psEffectManager::RenderEffect(const csString & effectName, iSectorList * sectors, const csVector3 & pos, iMeshWrapper * attachTarget, const csVector3 & up, const unsigned int uniqueIDOverride) { #ifndef DONT_DO_EFFECTS // check if it's a single effect psEffect * currEffect = FindEffect(effectName); if (currEffect != 0) { currEffect = currEffect->Clone(); const unsigned int uniqueID = currEffect->Render(sectors, pos, 0, attachTarget, up.Unit(), uniqueIDOverride); actualEffects.Put(uniqueID, currEffect); return uniqueID; } #endif return 0; } void psEffectManager::Update(csTicks elapsed) { #ifndef DONT_DO_EFFECTS unsigned int delId = (unsigned int)-1; if (elapsed == 0) elapsed = vc->GetElapsedTicks(); csHash::GlobalIterator it = actualEffects.GetIterator(); csList ids_to_delete; csList effects_to_delete; while (it.HasNext()) { unsigned int id = 0; psEffect * effect = it.Next(id); if (!effect) continue; // update the effect itself if (!effect->Update(elapsed)) { ids_to_delete.PushBack(id); effects_to_delete.PushBack(effect); } } while (!effects_to_delete.IsEmpty()) { psEffect * effect = effects_to_delete.Front(); actualEffects.Delete(ids_to_delete.Front(),effect); delete effect; effects_to_delete.PopFront(); ids_to_delete.PopFront(); } #endif } bool psEffectManager::Prepare() { #ifndef DONT_DO_EFFECTS if (!region) return false; return region->Prepare(); #endif } void psEffectManager::Clear() { #ifndef DONT_DO_EFFECTS csHash::GlobalIterator it = effectFactories.GetIterator(); while (it.HasNext()) delete it.Next(); effectFactories.DeleteAll(); csHash::GlobalIterator itActual = actualEffects.GetIterator(); while (itActual.HasNext()) delete itActual.Next(); actualEffects.DeleteAll(); region->DeleteAll(); region->Clear(); #endif } psEffect * psEffectManager::FindEffect(unsigned int ID) const { #ifndef DONT_DO_EFFECTS if (ID == 0) return 0; return actualEffects.Get(ID, 0); #endif return 0; } psEffect * psEffectManager::FindEffect(const csString & name) const { #ifndef DONT_DO_EFFECTS return effectFactories.Get((const char *)name, 0); #endif return 0; } csHash::GlobalIterator psEffectManager::GetEffectsIterator() { return effectFactories.GetIterator(); } void psEffectManager::ShowEffect(unsigned int id,bool value) { psEffect* eff = FindEffect(id); if(!eff) return; // No change? if(value == eff->IsVisible()) return; if(value) eff->Show(); else eff->Hide(); }