2010-07-31 09:53:02 +00:00
|
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
|
*
|
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
|
*
|
|
|
|
|
* 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; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* $URL$
|
|
|
|
|
* $Id$
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
/*
|
2010-07-31 09:53:02 +00:00
|
|
|
|
* This code is based on Broken Sword 2.5 engine
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
|
|
|
|
*
|
|
|
|
|
* Licensed under GNU GPL v2
|
|
|
|
|
*
|
|
|
|
|
*/
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Includes
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-07-30 09:02:39 +00:00
|
|
|
|
#include "sword25/gfx/animationresource.h"
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-07-30 09:02:39 +00:00
|
|
|
|
#include "sword25/kernel/kernel.h"
|
|
|
|
|
#include "sword25/kernel/string.h"
|
|
|
|
|
#include "sword25/package/packagemanager.h"
|
2010-08-14 19:52:01 +00:00
|
|
|
|
#include "sword25/util/tinyxml/tinyxml.h"
|
2010-07-30 09:02:39 +00:00
|
|
|
|
#include "sword25/gfx/bitmapresource.h"
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-05 12:48:19 +00:00
|
|
|
|
namespace Sword25 {
|
|
|
|
|
|
2010-07-29 19:53:02 +00:00
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
#define BS_LOG_PREFIX "ANIMATIONRESOURCE"
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Constants
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
namespace {
|
|
|
|
|
const int DEFAULT_FPS = 10;
|
|
|
|
|
const int MIN_FPS = 1;
|
|
|
|
|
const int MAX_FPS = 200;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Construction / Destruction
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
BS_AnimationResource::BS_AnimationResource(const Common::String &FileName) :
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_Resource(FileName, BS_Resource::TYPE_ANIMATION),
|
2010-08-06 13:13:25 +00:00
|
|
|
|
m_Valid(false) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
// Pointer auf den Package-Manager bekommen
|
2010-08-06 13:13:25 +00:00
|
|
|
|
BS_PackageManager *PackagePtr = BS_Kernel::GetInstance()->GetPackage();
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_ASSERT(PackagePtr);
|
|
|
|
|
|
|
|
|
|
// Animations-XML laden
|
|
|
|
|
TiXmlDocument Doc;
|
|
|
|
|
{
|
2010-08-06 13:13:25 +00:00
|
|
|
|
// Die Daten werden zun<75>chst <20>ber den Package-Manager gelesen und dann in einen um ein Byte gr<67><72>eren Buffer kopiert und
|
2010-07-29 19:53:02 +00:00
|
|
|
|
// NULL-Terminiert, da TinyXML NULL-Terminierte Daten ben<65>tigt.
|
|
|
|
|
unsigned int FileSize;
|
2010-08-06 13:13:25 +00:00
|
|
|
|
char *LoadBuffer = (char *) PackagePtr->GetFile(GetFileName(), &FileSize);
|
|
|
|
|
if (!LoadBuffer) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("Could not read \"%s\".", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-08-06 10:59:50 +00:00
|
|
|
|
char *WorkBuffer;
|
|
|
|
|
WorkBuffer = (char *)malloc(FileSize + 1);
|
2010-07-29 19:53:02 +00:00
|
|
|
|
memcpy(&WorkBuffer[0], LoadBuffer, FileSize);
|
|
|
|
|
delete LoadBuffer;
|
|
|
|
|
WorkBuffer[FileSize] = '\0';
|
|
|
|
|
|
|
|
|
|
// Datei parsen
|
|
|
|
|
Doc.Parse(&WorkBuffer[0]);
|
2010-08-06 10:59:50 +00:00
|
|
|
|
free(WorkBuffer);
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (Doc.Error()) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("The following TinyXML-Error occured while parsing \"%s\": %s", GetFileName().c_str(), Doc.ErrorDesc());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wurzelknoten des Animations-Tags finden, pr<70>fen und Attribute auslesen.
|
2010-08-06 13:13:25 +00:00
|
|
|
|
TiXmlElement *pElement;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
{
|
2010-08-06 13:13:25 +00:00
|
|
|
|
TiXmlNode *pNode = Doc.FirstChild("animation");
|
|
|
|
|
if (!pNode || pNode->Type() != TiXmlNode::ELEMENT) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("No <animation> tag found in \"%s\".", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pElement = pNode->ToElement();
|
|
|
|
|
|
|
|
|
|
// Animation-Tag parsen
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (!ParseAnimationTag(*pElement, m_FPS, m_AnimationType)) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("An error occurred while parsing <animation> tag in \"%s\".", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Zeit (in Millisekunden) bestimmen f<>r die ein einzelner Frame angezeigt wird
|
|
|
|
|
m_MillisPerFrame = 1000000 / m_FPS;
|
|
|
|
|
|
|
|
|
|
// In das Verzeichnis der Eingabedatei wechseln, da die Dateiverweise innerhalb der XML-Datei relativ zu diesem Verzeichnis sind.
|
2010-08-06 10:59:35 +00:00
|
|
|
|
Common::String OldDirectory = PackagePtr->GetCurrentDirectory();
|
2010-08-06 10:59:50 +00:00
|
|
|
|
if (GetFileName().contains('/')) {
|
|
|
|
|
Common::String Dir = Common::String(GetFileName().c_str(), strrchr(GetFileName().c_str(), '/'));
|
2010-07-29 19:53:02 +00:00
|
|
|
|
PackagePtr->ChangeDirectory(Dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Nacheinander alle Frames-Informationen erstellen.
|
2010-08-06 13:13:25 +00:00
|
|
|
|
TiXmlElement *pFrameElement = pElement->FirstChild("frame")->ToElement();
|
|
|
|
|
while (pFrameElement) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
Frame CurFrame;
|
2010-08-06 13:13:25 +00:00
|
|
|
|
|
|
|
|
|
if (!ParseFrameTag(*pFrameElement, CurFrame, *PackagePtr)) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("An error occurred in \"%s\" while parsing <frame> tag.", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-08-06 13:13:25 +00:00
|
|
|
|
|
2010-07-29 19:53:02 +00:00
|
|
|
|
m_Frames.push_back(CurFrame);
|
|
|
|
|
pFrameElement = pFrameElement->NextSiblingElement("frame");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ursprungsverzeichnis wieder herstellen
|
|
|
|
|
PackagePtr->ChangeDirectory(OldDirectory);
|
|
|
|
|
|
|
|
|
|
// Sicherstellen, dass die Animation mindestens einen Frame besitzt
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (m_Frames.empty()) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("\"%s\" does not have any frames.", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Alle Frame-Dateien werden vorgecached
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (!PrecacheAllFrames()) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("Could not precache all frames of \"%s\".", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Feststellen, ob die Animation skalierbar ist
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (!ComputeFeatures()) {
|
|
|
|
|
BS_LOG_ERRORLN("Could not determine the features of \"%s\".", GetFileName().c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
m_Valid = true;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Dokument-Parsermethoden
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
bool BS_AnimationResource::ParseAnimationTag(TiXmlElement &AnimationTag, int &FPS, BS_Animation::ANIMATION_TYPES &AnimationType) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
// FPS einlesen
|
2010-08-06 13:13:25 +00:00
|
|
|
|
const char *FPSString;
|
2010-08-16 20:23:53 +00:00
|
|
|
|
if ((FPSString = AnimationTag.Attribute("fps"))) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
int TempFPS;
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (!BS_String::ToInt(Common::String(FPSString), TempFPS) || TempFPS < MIN_FPS || TempFPS > MAX_FPS) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_WARNINGLN("Illegal fps value (\"%s\") in <animation> tag in \"%s\". Assuming default (\"%d\"). "
|
2010-08-06 13:13:25 +00:00
|
|
|
|
"The fps value has to be between %d and %d.",
|
|
|
|
|
FPSString, GetFileName().c_str(), DEFAULT_FPS, MIN_FPS, MAX_FPS);
|
|
|
|
|
} else
|
2010-07-29 19:53:02 +00:00
|
|
|
|
FPS = TempFPS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loop-Typ einlesen
|
2010-08-06 13:13:25 +00:00
|
|
|
|
const char *LoopTypeString;
|
2010-08-16 20:23:53 +00:00
|
|
|
|
if ((LoopTypeString = AnimationTag.Attribute("type"))) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
if (strcmp(LoopTypeString, "oneshot") == 0)
|
|
|
|
|
AnimationType = BS_Animation::AT_ONESHOT;
|
|
|
|
|
else if (strcmp(LoopTypeString, "loop") == 0)
|
|
|
|
|
AnimationType = BS_Animation::AT_LOOP;
|
|
|
|
|
else if (strcmp(LoopTypeString, "jojo") == 0)
|
|
|
|
|
AnimationType = BS_Animation::AT_JOJO;
|
|
|
|
|
else
|
|
|
|
|
BS_LOG_WARNINGLN("Illegal type value (\"%s\") in <animation> tag in \"%s\". Assuming default (\"loop\").",
|
2010-08-06 13:13:25 +00:00
|
|
|
|
LoopTypeString, GetFileName().c_str());
|
2010-07-29 19:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
bool BS_AnimationResource::ParseFrameTag(TiXmlElement &FrameTag, Frame &Frame_, BS_PackageManager &PackageManager) {
|
|
|
|
|
const char *FileString = FrameTag.Attribute("file");
|
|
|
|
|
if (!FileString) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("<frame> tag without file attribute occurred in \"%s\".", GetFileName().c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.FileName = PackageManager.GetAbsolutePath(FileString);
|
2010-08-06 13:13:25 +00:00
|
|
|
|
if (Frame_.FileName == "") {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("Could not create absolute path for file specified in <frame> tag in \"%s\": \"%s\".", GetFileName().c_str(), FileString);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
const char *ActionString = FrameTag.Attribute("action");
|
2010-07-29 19:53:02 +00:00
|
|
|
|
if (ActionString)
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.Action = ActionString;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
const char *HotspotxString = FrameTag.Attribute("hotspotx");
|
|
|
|
|
const char *HotspotyString = FrameTag.Attribute("hotspoty");
|
2010-07-29 19:53:02 +00:00
|
|
|
|
if ((!HotspotxString && HotspotyString) ||
|
2010-08-06 13:13:25 +00:00
|
|
|
|
(HotspotxString && !HotspotyString))
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_WARNINGLN("%s attribute occurred without %s attribute in <frame> tag in \"%s\". Assuming default (\"0\").",
|
2010-08-06 13:13:25 +00:00
|
|
|
|
HotspotxString ? "hotspotx" : "hotspoty",
|
|
|
|
|
!HotspotyString ? "hotspoty" : "hotspotx",
|
|
|
|
|
GetFileName().c_str());
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.HotspotX = 0;
|
|
|
|
|
if (HotspotxString && !BS_String::ToInt(Common::String(HotspotxString), Frame_.HotspotX))
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_WARNINGLN("Illegal hotspotx value (\"%s\") in frame tag in \"%s\". Assuming default (\"%s\").",
|
2010-08-06 13:13:25 +00:00
|
|
|
|
HotspotxString, GetFileName().c_str(), Frame_.HotspotX);
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.HotspotY = 0;
|
|
|
|
|
if (HotspotyString && !BS_String::ToInt(Common::String(HotspotyString), Frame_.HotspotY))
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_WARNINGLN("Illegal hotspoty value (\"%s\") in frame tag in \"%s\". Assuming default (\"%s\").",
|
2010-08-06 13:13:25 +00:00
|
|
|
|
HotspotyString, GetFileName().c_str(), Frame_.HotspotY);
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
const char *FlipVString = FrameTag.Attribute("flipv");
|
|
|
|
|
if (FlipVString) {
|
|
|
|
|
if (!BS_String::ToBool(Common::String(FlipVString), Frame_.FlipV)) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_WARNINGLN("Illegal flipv value (\"%s\") in <frame> tag in \"%s\". Assuming default (\"false\").",
|
2010-08-06 13:13:25 +00:00
|
|
|
|
FlipVString, GetFileName().c_str());
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.FlipV = false;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
}
|
2010-08-06 13:13:25 +00:00
|
|
|
|
} else
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.FlipV = false;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
const char *FlipHString = FrameTag.Attribute("fliph");
|
|
|
|
|
if (FlipHString) {
|
|
|
|
|
if (!BS_String::ToBool(FlipHString, Frame_.FlipH)) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_WARNINGLN("Illegal fliph value (\"%s\") in <frame> tag in \"%s\". Assuming default (\"false\").",
|
2010-08-06 13:13:25 +00:00
|
|
|
|
FlipHString, GetFileName().c_str());
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.FlipH = false;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
}
|
2010-08-06 13:13:25 +00:00
|
|
|
|
} else
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Frame_.FlipH = false;
|
2010-07-29 19:53:02 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
BS_AnimationResource::~BS_AnimationResource() {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
bool BS_AnimationResource::PrecacheAllFrames() const {
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Common::Array<Frame>::const_iterator Iter = m_Frames.begin();
|
2010-08-06 13:13:25 +00:00
|
|
|
|
for (; Iter != m_Frames.end(); ++Iter) {
|
|
|
|
|
if (!BS_Kernel::GetInstance()->GetResourceManager()->PrecacheResource((*Iter).FileName)) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("Could not precache \"%s\".", (*Iter).FileName.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
2010-08-06 13:13:25 +00:00
|
|
|
|
bool BS_AnimationResource::ComputeFeatures() {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_ASSERT(m_Frames.size());
|
|
|
|
|
|
|
|
|
|
// Alle Features werden als vorhanden angenommen
|
|
|
|
|
m_ScalingAllowed = true;
|
|
|
|
|
m_AlphaAllowed = true;
|
|
|
|
|
m_ColorModulationAllowed = true;
|
|
|
|
|
|
|
|
|
|
// Alle Frame durchgehen und alle Features deaktivieren, die auch nur von einem Frame nicht unterst<73>tzt werden.
|
2010-08-06 10:59:50 +00:00
|
|
|
|
Common::Array<Frame>::const_iterator Iter = m_Frames.begin();
|
2010-08-06 13:13:25 +00:00
|
|
|
|
for (; Iter != m_Frames.end(); ++Iter) {
|
|
|
|
|
BS_BitmapResource *pBitmap;
|
|
|
|
|
if (!(pBitmap = static_cast<BS_BitmapResource *>(BS_Kernel::GetInstance()->GetResourceManager()->RequestResource((*Iter).FileName)))) {
|
2010-07-29 19:53:02 +00:00
|
|
|
|
BS_LOG_ERRORLN("Could not request \"%s\".", (*Iter).FileName.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pBitmap->IsScalingAllowed())
|
|
|
|
|
m_ScalingAllowed = false;
|
|
|
|
|
if (!pBitmap->IsAlphaAllowed())
|
|
|
|
|
m_AlphaAllowed = false;
|
|
|
|
|
if (!pBitmap->IsColorModulationAllowed())
|
|
|
|
|
m_ColorModulationAllowed = false;
|
|
|
|
|
|
|
|
|
|
pBitmap->Release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-08-05 12:48:19 +00:00
|
|
|
|
|
|
|
|
|
} // End of namespace Sword25
|