scummvm/engines/sword25/gfx/renderobject.cpp
Eugene Sandulenko 3fb0e9383b SWORD25: Removed last traces of STL
svn-id: r53262
2010-10-12 23:07:29 +00:00

542 lines
15 KiB
C++
Raw Blame History

/* 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$
*
*/
/*
* This code is based on Broken Sword 2.5 engine
*
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
*
* Licensed under GNU GPL v2
*
*/
#include "sword25/gfx/renderobject.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/gfx/renderobjectregistry.h"
#include "sword25/gfx/renderobjectmanager.h"
#include "sword25/gfx/graphicengine.h"
#include "sword25/gfx/bitmap.h"
#include "sword25/gfx/staticbitmap.h"
#include "sword25/gfx/dynamicbitmap.h"
#include "sword25/gfx/animation.h"
#include "sword25/gfx/panel.h"
#include "sword25/gfx/text.h"
#include "sword25/gfx/animationtemplate.h"
namespace Sword25 {
#define BS_LOG_PREFIX "RENDEROBJECT"
// Konstruktion / Destruktion
// --------------------------
RenderObject::RenderObject(RenderObjectPtr<RenderObject> ParentPtr, TYPES Type, unsigned int Handle) :
m_ManagerPtr(0),
m_ParentPtr(ParentPtr),
m_X(0),
m_Y(0),
m_Z(0),
m_OldX(-1),
m_OldY(-1),
m_OldZ(-1),
m_Width(0),
m_Height(0),
m_Visible(true),
m_OldVisible(false),
m_ChildChanged(true),
m_Type(Type),
m_InitSuccess(false),
m_RefreshForced(true),
m_Handle(0) {
// Renderobject registrieren, abh<62>ngig vom Handle-Parameter entweder mit beliebigem oder vorgegebenen Handle.
if (Handle == 0)
m_Handle = RenderObjectRegistry::GetInstance().RegisterObject(this);
else
m_Handle = RenderObjectRegistry::GetInstance().RegisterObject(this, Handle);
if (m_Handle == 0) return;
UpdateAbsolutePos();
// Dieses Objekt zu den Kindern der Elternobjektes hinzuf<75>gen, falls nicht Wurzel (ParentPtr ung<6E>ltig) und dem
// selben RenderObjektManager zuweisen.
if (m_ParentPtr.IsValid()) {
m_ManagerPtr = m_ParentPtr->GetManager();
m_ParentPtr->AddObject(this->GetHandle());
} else {
if (GetType() != TYPE_ROOT) {
BS_LOG_ERRORLN("Tried to create a non-root render object and has no parent. All non-root render objects have to have a parent.");
return;
}
}
UpdateObjectState();
m_InitSuccess = true;
}
RenderObject::~RenderObject() {
// Objekt aus dem Elternobjekt entfernen.
if (m_ParentPtr.IsValid()) m_ParentPtr->DetatchChildren(this->GetHandle());
DeleteAllChildren();
// Objekt deregistrieren.
RenderObjectRegistry::GetInstance().DeregisterObject(this);
}
// Rendern
// -------
bool RenderObject::Render() {
// Objekt<6B>nderungen validieren
ValidateObject();
// Falls das Objekt nicht sichtbar ist, muss gar nichts gezeichnet werden
if (!m_Visible) return true;
// Falls notwendig, wird die Renderreihenfolge der Kinderobjekte aktualisiert.
if (m_ChildChanged) {
SortRenderObjects();
m_ChildChanged = false;
}
// Objekt zeichnen.
DoRender();
// Dann m<>ssen die Kinder gezeichnet werden
RENDEROBJECT_ITER it = m_Children.begin();
for (; it != m_Children.end(); ++it)
if (!(*it)->Render())
return false;
return true;
}
// Objektverwaltung
// ----------------
void RenderObject::ValidateObject() {
// Die Ver<65>nderungen in den Objektvariablen aufheben
m_OldBBox = m_BBox;
m_OldVisible = m_Visible;
m_OldX = m_X;
m_OldY = m_Y;
m_OldZ = m_Z;
m_RefreshForced = false;
}
bool RenderObject::UpdateObjectState() {
// Falls sich das Objekt ver<65>ndert hat, muss der interne Zustand neu berechnet werden und evtl. Update-Regions f<>r den n<>chsten Frame
// registriert werden.
if ((CalcBoundingBox() != m_OldBBox) ||
(m_Visible != m_OldVisible) ||
(m_X != m_OldX) ||
(m_Y != m_OldY) ||
(m_Z != m_OldZ) ||
m_RefreshForced) {
// Renderrang des Objektes neu bestimmen, da sich dieser ver<65>ndert haben k<>nnte
if (m_ParentPtr.IsValid()) m_ParentPtr->SignalChildChange();
// Die Bounding-Box neu berechnen und Update-Regions registrieren.
UpdateBoxes();
// <20>nderungen Validieren
ValidateObject();
}
// Dann muss der Objektstatus der Kinder aktualisiert werden.
RENDEROBJECT_ITER it = m_Children.begin();
for (; it != m_Children.end(); ++it)
if (!(*it)->UpdateObjectState()) return false;
return true;
}
void RenderObject::UpdateBoxes() {
// Bounding-Box aktualisieren
m_BBox = CalcBoundingBox();
}
BS_Rect RenderObject::CalcBoundingBox() const {
// Die Bounding-Box mit der Objektgr<67><72>e initialisieren.
BS_Rect BBox(0, 0, m_Width, m_Height);
// Die absolute Position der Bounding-Box berechnen.
BBox.Move(m_AbsoluteX, m_AbsoluteY);
// Die Bounding-Box am Elternobjekt clippen.
if (m_ParentPtr.IsValid()) BBox.Intersect(m_ParentPtr->GetBBox(), BBox);
return BBox;
}
void RenderObject::CalcAbsolutePos(int &X, int &Y) const {
X = CalcAbsoluteX();
Y = CalcAbsoluteY();
}
int RenderObject::CalcAbsoluteX() const {
if (m_ParentPtr.IsValid())
return m_ParentPtr->GetAbsoluteX() + m_X;
else
return m_X;
}
int RenderObject::CalcAbsoluteY() const {
if (m_ParentPtr.IsValid())
return m_ParentPtr->GetAbsoluteY() + m_Y;
else
return m_Y;
}
// Baumverwaltung
// --------------
void RenderObject::DeleteAllChildren() {
// Es ist nicht notwendig die Liste zu iterieren, da jedes Kind f<>r sich DetatchChildren an diesem Objekt aufruft und sich somit
// selber entfernt. Daher muss immer nur ein beliebiges Element (hier das letzte) gel<65>scht werden, bis die Liste leer ist.
while (!m_Children.empty()) {
RenderObjectPtr<RenderObject> CurPtr = m_Children.back();
CurPtr.Erase();
}
}
bool RenderObject::AddObject(RenderObjectPtr<RenderObject> pObject) {
if (!pObject.IsValid()) {
BS_LOG_ERRORLN("Tried to add a null object to a renderobject.");
return false;
}
// Objekt in die Kinderliste einf<6E>gen.
m_Children.push_back(pObject);
// Sicherstellen, dass vor dem n<>chsten Rendern die Renderreihenfolge aktualisiert wird.
if (m_ParentPtr.IsValid()) m_ParentPtr->SignalChildChange();
return true;
}
bool RenderObject::DetatchChildren(RenderObjectPtr<RenderObject> pObject) {
// Kinderliste durchgehen und Objekt entfernen falls vorhanden
RENDEROBJECT_ITER it = m_Children.begin();
for (; it != m_Children.end(); ++it)
if (*it == pObject) {
m_Children.erase(it);
return true;
}
BS_LOG_ERRORLN("Tried to detach children from a render object that isn't its parent.");
return false;
}
void RenderObject::SortRenderObjects() {
Common::sort(m_Children.begin(), m_Children.end(), Greater);
}
void RenderObject::UpdateAbsolutePos() {
CalcAbsolutePos(m_AbsoluteX, m_AbsoluteY);
RENDEROBJECT_ITER it = m_Children.begin();
for (; it != m_Children.end(); ++it)
(*it)->UpdateAbsolutePos();
}
// Get-Methoden
// ------------
bool RenderObject::GetObjectIntersection(RenderObjectPtr<RenderObject> pObject, BS_Rect &Result) {
return m_BBox.Intersect(pObject->GetBBox(), Result);
}
// Set-Methoden
// ------------
void RenderObject::SetPos(int X, int Y) {
m_X = X;
m_Y = Y;
UpdateAbsolutePos();
}
void RenderObject::SetX(int X) {
m_X = X;
UpdateAbsolutePos();
}
void RenderObject::SetY(int Y) {
m_Y = Y;
UpdateAbsolutePos();
}
void RenderObject::SetZ(int Z) {
if (Z < 0)
BS_LOG_ERRORLN("Tried to set a negative Z value (%d).", Z);
else
m_Z = Z;
}
void RenderObject::SetVisible(bool Visible) {
m_Visible = Visible;
}
// -----------------------------------------------------------------------------
// Objekterzeuger
// -----------------------------------------------------------------------------
RenderObjectPtr<Animation> RenderObject::AddAnimation(const Common::String &Filename) {
RenderObjectPtr<Animation> AniPtr((new Animation(this->GetHandle(), Filename))->GetHandle());
if (AniPtr.IsValid() && AniPtr->GetInitSuccess())
return AniPtr;
else {
if (AniPtr.IsValid()) AniPtr.Erase();
return RenderObjectPtr<Animation>();
}
}
// -----------------------------------------------------------------------------
RenderObjectPtr<Animation> RenderObject::AddAnimation(const AnimationTemplate &AnimationTemplate) {
Animation *AniPtr = new Animation(this->GetHandle(), AnimationTemplate);
if (AniPtr && AniPtr->GetInitSuccess())
return AniPtr->GetHandle();
else {
delete AniPtr;
return RenderObjectPtr<Animation>();
}
}
// -----------------------------------------------------------------------------
RenderObjectPtr<Bitmap> RenderObject::AddBitmap(const Common::String &Filename) {
RenderObjectPtr<Bitmap> BitmapPtr((new StaticBitmap(this->GetHandle(), Filename))->GetHandle());
if (BitmapPtr.IsValid() && BitmapPtr->GetInitSuccess())
return RenderObjectPtr<Bitmap>(BitmapPtr);
else {
if (BitmapPtr.IsValid()) BitmapPtr.Erase();
return RenderObjectPtr<Bitmap>();
}
}
// -----------------------------------------------------------------------------
RenderObjectPtr<Bitmap> RenderObject::AddDynamicBitmap(unsigned int Width, unsigned int Height) {
RenderObjectPtr<Bitmap> BitmapPtr((new DynamicBitmap(this->GetHandle(), Width, Height))->GetHandle());
if (BitmapPtr.IsValid() && BitmapPtr->GetInitSuccess())
return BitmapPtr;
else {
if (BitmapPtr.IsValid()) BitmapPtr.Erase();
return RenderObjectPtr<Bitmap>();
}
}
// -----------------------------------------------------------------------------
RenderObjectPtr<Panel> RenderObject::AddPanel(int Width, int Height, unsigned int Color) {
RenderObjectPtr<Panel> PanelPtr((new Panel(this->GetHandle(), Width, Height, Color))->GetHandle());
if (PanelPtr.IsValid() && PanelPtr->GetInitSuccess())
return PanelPtr;
else {
if (PanelPtr.IsValid()) PanelPtr.Erase();
return RenderObjectPtr<Panel>();
}
}
// -----------------------------------------------------------------------------
RenderObjectPtr<Text> RenderObject::AddText(const Common::String &Font, const Common::String &text) {
RenderObjectPtr<Text> TextPtr((new Text(this->GetHandle()))->GetHandle());
if (TextPtr.IsValid() && TextPtr->GetInitSuccess() && TextPtr->SetFont(Font)) {
TextPtr->SetText(text);
return TextPtr;
} else {
if (TextPtr.IsValid()) TextPtr.Erase();
return RenderObjectPtr<Text>();
}
}
// Persistenz-Methoden
// -------------------
bool RenderObject::Persist(OutputPersistenceBlock &Writer) {
// Typ und Handle werden als erstes gespeichert, damit beim Laden ein Objekt vom richtigen Typ mit dem richtigen Handle erzeugt werden kann.
Writer.Write(static_cast<unsigned int>(m_Type));
Writer.Write(m_Handle);
// Restliche Objekteigenschaften speichern.
Writer.Write(m_X);
Writer.Write(m_Y);
Writer.Write(m_AbsoluteX);
Writer.Write(m_AbsoluteY);
Writer.Write(m_Z);
Writer.Write(m_Width);
Writer.Write(m_Height);
Writer.Write(m_Visible);
Writer.Write(m_ChildChanged);
Writer.Write(m_InitSuccess);
Writer.Write(m_BBox.left);
Writer.Write(m_BBox.top);
Writer.Write(m_BBox.right);
Writer.Write(m_BBox.bottom);
Writer.Write(m_OldBBox.left);
Writer.Write(m_OldBBox.top);
Writer.Write(m_OldBBox.right);
Writer.Write(m_OldBBox.bottom);
Writer.Write(m_OldX);
Writer.Write(m_OldY);
Writer.Write(m_OldZ);
Writer.Write(m_OldVisible);
Writer.Write(m_ParentPtr.IsValid() ? m_ParentPtr->GetHandle() : 0);
Writer.Write(m_RefreshForced);
return true;
}
// -----------------------------------------------------------------------------
bool RenderObject::Unpersist(InputPersistenceBlock &Reader) {
// Typ und Handle wurden schon von RecreatePersistedRenderObject() ausgelesen. Jetzt werden die restlichen Objekteigenschaften ausgelesen.
Reader.Read(m_X);
Reader.Read(m_Y);
Reader.Read(m_AbsoluteX);
Reader.Read(m_AbsoluteY);
Reader.Read(m_Z);
Reader.Read(m_Width);
Reader.Read(m_Height);
Reader.Read(m_Visible);
Reader.Read(m_ChildChanged);
Reader.Read(m_InitSuccess);
Reader.Read(m_BBox.left);
Reader.Read(m_BBox.top);
Reader.Read(m_BBox.right);
Reader.Read(m_BBox.bottom);
Reader.Read(m_OldBBox.left);
Reader.Read(m_OldBBox.top);
Reader.Read(m_OldBBox.right);
Reader.Read(m_OldBBox.bottom);
Reader.Read(m_OldX);
Reader.Read(m_OldY);
Reader.Read(m_OldZ);
Reader.Read(m_OldVisible);
unsigned int ParentHandle;
Reader.Read(ParentHandle);
m_ParentPtr = RenderObjectPtr<RenderObject>(ParentHandle);
Reader.Read(m_RefreshForced);
UpdateAbsolutePos();
UpdateObjectState();
return Reader.IsGood();
}
// -----------------------------------------------------------------------------
bool RenderObject::PersistChildren(OutputPersistenceBlock &Writer) {
bool Result = true;
// Kinderanzahl speichern.
Writer.Write(m_Children.size());
// Rekursiv alle Kinder speichern.
RENDEROBJECT_LIST::iterator It = m_Children.begin();
while (It != m_Children.end()) {
Result &= (*It)->Persist(Writer);
++It;
}
return Result;
}
// -----------------------------------------------------------------------------
bool RenderObject::UnpersistChildren(InputPersistenceBlock &Reader) {
bool Result = true;
// Kinderanzahl einlesen.
unsigned int ChildrenCount;
Reader.Read(ChildrenCount);
if (!Reader.IsGood()) return false;
// Alle Kinder rekursiv wieder herstellen.
for (unsigned int i = 0; i < ChildrenCount; ++i) {
if (!RecreatePersistedRenderObject(Reader).IsValid()) return false;
}
return Result && Reader.IsGood();
}
// -----------------------------------------------------------------------------
RenderObjectPtr<RenderObject> RenderObject::RecreatePersistedRenderObject(InputPersistenceBlock &Reader) {
RenderObjectPtr<RenderObject> Result;
// Typ und Handle auslesen.
unsigned int Type;
unsigned int Handle;
Reader.Read(Type);
Reader.Read(Handle);
if (!Reader.IsGood()) return Result;
switch (Type) {
case TYPE_PANEL:
Result = (new Panel(Reader, this->GetHandle(), Handle))->GetHandle();
break;
case TYPE_STATICBITMAP:
Result = (new StaticBitmap(Reader, this->GetHandle(), Handle))->GetHandle();
break;
case TYPE_DYNAMICBITMAP:
Result = (new DynamicBitmap(Reader, this->GetHandle(), Handle))->GetHandle();
break;
case TYPE_TEXT:
Result = (new Text(Reader, this->GetHandle(), Handle))->GetHandle();
break;
case TYPE_ANIMATION:
Result = (new Animation(Reader, this->GetHandle(), Handle))->GetHandle();
break;
default:
BS_LOG_ERRORLN("Cannot recreate render object of unknown type %d.", Type);
}
return Result;
}
// Hilfs-Methoden
// --------------
bool RenderObject::Greater(const RenderObjectPtr<RenderObject> lhs, const RenderObjectPtr<RenderObject> rhs) {
// Das Objekt mit dem kleinem Z-Wert m<>ssen zuerst gerendert werden.
if (lhs->m_Z != rhs->m_Z)
return lhs->m_Z < rhs->m_Z;
// Falls der Z-Wert gleich ist, wird das weiter oben gelegenen Objekte zuerst gezeichnet.
return lhs->m_Y < rhs->m_Y;
}
} // End of namespace Sword25