diff options
author | Eugene Sandulenko | 2010-07-29 19:53:02 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2010-10-12 21:38:20 +0000 |
commit | a683a420a9e43705c972b5e74d55e319729e1a81 (patch) | |
tree | bde6e4abd417bdfaec120aa951da9a19be36b654 /engines/sword25/gfx/renderobject.cpp | |
parent | 7723d91c957d07205c51be32498d45cd0a78568f (diff) | |
download | scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.gz scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.bz2 scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.zip |
SWORD25: Importing original sources
svn-id: r53171
Diffstat (limited to 'engines/sword25/gfx/renderobject.cpp')
-rwxr-xr-x | engines/sword25/gfx/renderobject.cpp | 571 |
1 files changed, 571 insertions, 0 deletions
diff --git a/engines/sword25/gfx/renderobject.cpp b/engines/sword25/gfx/renderobject.cpp new file mode 100755 index 0000000000..427038e477 --- /dev/null +++ b/engines/sword25/gfx/renderobject.cpp @@ -0,0 +1,571 @@ +// ----------------------------------------------------------------------------- +// This file is part of Broken Sword 2.5 +// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer +// +// Broken Sword 2.5 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. +// +// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// ----------------------------------------------------------------------------- + +#include "renderobject.h" + +#include <algorithm> + +#include "kernel/outputpersistenceblock.h" +#include "kernel/inputpersistenceblock.h" + +#include "renderobjectregistry.h" +#include "renderobjectmanager.h" +#include "graphicengine.h" + +#include "bitmap.h" +#include "staticbitmap.h" +#include "dynamicbitmap.h" +#include "animation.h" +#include "panel.h" +#include "text.h" +#include "animationtemplate.h" + +#define BS_LOG_PREFIX "RENDEROBJECT" + +// Konstruktion / Destruktion +// -------------------------- +BS_RenderObject::BS_RenderObject(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, TYPES Type, unsigned int Handle) : + m_ManagerPtr(0), + m_ParentPtr(ParentPtr), + m_X(0), + m_Y(0), + m_Z(0), + m_Width(0), + m_Height(0), + m_Visible(true), + m_ChildChanged(true), + m_Type(Type), + m_InitSuccess(false), + m_RefreshForced(true), + m_Handle(0) +{ + // Renderobject registrieren, abhängig vom Handle-Parameter entweder mit beliebigem oder vorgegebenen Handle. + if (Handle == 0) + m_Handle = BS_RenderObjectRegistry::GetInstance().RegisterObject(this); + else + m_Handle = BS_RenderObjectRegistry::GetInstance().RegisterObject(this, Handle); + if (m_Handle == 0) return; + + UpdateAbsolutePos(); + + // Dieses Objekt zu den Kindern der Elternobjektes hinzufügen, falls nicht Wurzel (ParentPtr ungültig) und dem + // selben RenderObjektManager zuweisen. + if (m_ParentPtr.IsValid()) + { + m_ManagerPtr = m_ParentPtr->GetManager(); + m_ParentPtr->AddObject(this); + } + 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; +} + +BS_RenderObject::~BS_RenderObject() +{ + // Objekt aus dem Elternobjekt entfernen. + if (m_ParentPtr.IsValid()) m_ParentPtr->DetatchChildren(this); + + DeleteAllChildren(); + + // Objekt deregistrieren. + BS_RenderObjectRegistry::GetInstance().DeregisterObject(this); +} + +// Rendern +// ------- +bool BS_RenderObject::Render() +{ + // Objektä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 BS_RenderObject::ValidateObject() +{ + // Die Verä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 BS_RenderObject::UpdateObjectState() +{ + // Falls sich das Objekt verä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ändert haben könnte + if (m_ParentPtr.IsValid()) m_ParentPtr->SignalChildChange(); + + // Die Bounding-Box neu berechnen und Update-Regions registrieren. + UpdateBoxes(); + + // Ä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 BS_RenderObject::UpdateBoxes() +{ + // Bounding-Box aktualisieren + m_BBox = CalcBoundingBox(); +} + +BS_Rect BS_RenderObject::CalcBoundingBox() const +{ + // Die Bounding-Box mit der Objektgröß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 BS_RenderObject::CalcAbsolutePos(int& X, int& Y) const +{ + X = CalcAbsoluteX(); + Y = CalcAbsoluteY(); +} + +int BS_RenderObject::CalcAbsoluteX() const +{ + if (m_ParentPtr.IsValid()) + return m_ParentPtr->GetAbsoluteX() + m_X; + else + return m_X; +} + +int BS_RenderObject::CalcAbsoluteY() const +{ + if (m_ParentPtr.IsValid()) + return m_ParentPtr->GetAbsoluteY() + m_Y; + else + return m_Y; +} + +// Baumverwaltung +// -------------- + +void BS_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öscht werden, bis die Liste leer ist. + while (!m_Children.empty()) + { + BS_RenderObjectPtr<BS_RenderObject> CurPtr = m_Children.back(); + CurPtr.Erase(); + } +} + +bool BS_RenderObject::AddObject(BS_RenderObjectPtr<BS_RenderObject> pObject) +{ + if (!pObject.IsValid()) + { + BS_LOG_ERRORLN("Tried to add a null object to a renderobject."); + return false; + } + + // Objekt in die Kinderliste einfü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 BS_RenderObject::DetatchChildren(BS_RenderObjectPtr<BS_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 BS_RenderObject::SortRenderObjects() +{ + std::sort(m_Children.begin(), m_Children.end(), Greater); +} + +void BS_RenderObject::UpdateAbsolutePos() +{ + CalcAbsolutePos(m_AbsoluteX, m_AbsoluteY); + + RENDEROBJECT_ITER it = m_Children.begin(); + for (; it != m_Children.end(); ++it) + (*it)->UpdateAbsolutePos(); +} + +// Get-Methoden +// ------------ + +bool BS_RenderObject::GetObjectIntersection(BS_RenderObjectPtr<BS_RenderObject> pObject, BS_Rect& Result) +{ + return m_BBox.Intersect(pObject->GetBBox(), Result); +} + +// Set-Methoden +// ------------ +void BS_RenderObject::SetPos(int X, int Y) +{ + m_X = X; + m_Y = Y; + UpdateAbsolutePos(); +} + +void BS_RenderObject::SetX(int X) +{ + m_X = X; + UpdateAbsolutePos(); +} + +void BS_RenderObject::SetY(int Y) +{ + m_Y = Y; + UpdateAbsolutePos(); +} + +void BS_RenderObject::SetZ(int Z) +{ + if (Z < 0) + BS_LOG_ERRORLN("Tried to set a negative Z value (%d).", Z); + else + m_Z = Z; +} + +void BS_RenderObject::SetVisible(bool Visible) +{ + m_Visible = Visible; +} + +// ----------------------------------------------------------------------------- +// Objekterzeuger +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_Animation> BS_RenderObject::AddAnimation(const std::string& Filename) +{ + BS_RenderObjectPtr<BS_Animation> AniPtr(new BS_Animation(this, Filename)); + if (AniPtr.IsValid() && AniPtr->GetInitSuccess()) + return AniPtr; + else + { + if (AniPtr.IsValid()) AniPtr.Erase(); + return BS_RenderObjectPtr<BS_Animation>(); + } +} + + +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_Animation> BS_RenderObject::AddAnimation(const BS_AnimationTemplate & AnimationTemplate) +{ + BS_Animation * AniPtr = new BS_Animation(this, AnimationTemplate); + if (AniPtr && AniPtr->GetInitSuccess()) + return AniPtr; + else + { + delete AniPtr; + return BS_RenderObjectPtr<BS_Animation>(); + } +} + +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_Bitmap> BS_RenderObject::AddBitmap(const std::string& Filename) +{ + BS_RenderObjectPtr<BS_Bitmap> BitmapPtr(new BS_StaticBitmap(this, Filename)); + if (BitmapPtr.IsValid() && BitmapPtr->GetInitSuccess()) + return BS_RenderObjectPtr<BS_Bitmap>(BitmapPtr); + else + { + if (BitmapPtr.IsValid()) BitmapPtr.Erase(); + return BS_RenderObjectPtr<BS_Bitmap>(); + } +} + +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_Bitmap> BS_RenderObject::AddDynamicBitmap(unsigned int Width, unsigned int Height) +{ + BS_RenderObjectPtr<BS_Bitmap> BitmapPtr(new BS_DynamicBitmap(this, Width, Height)); + if (BitmapPtr.IsValid() && BitmapPtr->GetInitSuccess()) + return BitmapPtr; + else + { + if (BitmapPtr.IsValid()) BitmapPtr.Erase(); + return BS_RenderObjectPtr<BS_Bitmap>(); + } +} + +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_Panel> BS_RenderObject::AddPanel(int Width, int Height, unsigned int Color) +{ + BS_RenderObjectPtr<BS_Panel> PanelPtr(new BS_Panel(this, Width, Height, Color)); + if (PanelPtr.IsValid() && PanelPtr->GetInitSuccess()) + return PanelPtr; + else + { + if (PanelPtr.IsValid()) PanelPtr.Erase(); + return BS_RenderObjectPtr<BS_Panel>(); + } +} + +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_Text> BS_RenderObject::AddText(const std::string & Font, const std::string & Text) +{ + BS_RenderObjectPtr<BS_Text> TextPtr(new BS_Text(this)); + if (TextPtr.IsValid() && TextPtr->GetInitSuccess() && TextPtr->SetFont(Font)) + { + TextPtr->SetText(Text); + return TextPtr; + } + else + { + if (TextPtr.IsValid()) TextPtr.Erase(); + return BS_RenderObjectPtr<BS_Text>(); + } +} + +// Persistenz-Methoden +// ------------------- + +bool BS_RenderObject::Persist(BS_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 BS_RenderObject::Unpersist(BS_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 = BS_RenderObjectPtr<BS_RenderObject>(ParentHandle); + Reader.Read(m_RefreshForced); + + UpdateAbsolutePos(); + UpdateObjectState(); + + return Reader.IsGood(); +} + +// ----------------------------------------------------------------------------- + +bool BS_RenderObject::PersistChildren(BS_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 BS_RenderObject::UnpersistChildren(BS_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(); +} + +// ----------------------------------------------------------------------------- + +BS_RenderObjectPtr<BS_RenderObject> BS_RenderObject::RecreatePersistedRenderObject(BS_InputPersistenceBlock & Reader) +{ + BS_RenderObjectPtr<BS_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 BS_Panel(Reader, this, Handle); + break; + + case TYPE_STATICBITMAP: + Result = new BS_StaticBitmap(Reader, this, Handle); + break; + + case TYPE_DYNAMICBITMAP: + Result = new BS_DynamicBitmap(Reader, this, Handle); + break; + + case TYPE_TEXT: + Result = new BS_Text(Reader, this, Handle); + break; + + case TYPE_ANIMATION: + Result = new BS_Animation(Reader, this, Handle); + break; + + default: + BS_LOG_ERRORLN("Cannot recreate render object of unknown type %d.", Type); + } + + return Result; +} + +// Hilfs-Methoden +// -------------- +bool BS_RenderObject::Greater(const BS_RenderObjectPtr<BS_RenderObject> lhs, const BS_RenderObjectPtr<BS_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; +} |