aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/gfx
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/gfx')
-rwxr-xr-xengines/sword25/gfx/animation.cpp878
-rwxr-xr-xengines/sword25/gfx/animation.h209
-rwxr-xr-xengines/sword25/gfx/animationdescription.cpp58
-rwxr-xr-xengines/sword25/gfx/animationdescription.h90
-rwxr-xr-xengines/sword25/gfx/animationresource.cpp323
-rwxr-xr-xengines/sword25/gfx/animationresource.h83
-rwxr-xr-xengines/sword25/gfx/animationtemplate.cpp293
-rwxr-xr-xengines/sword25/gfx/animationtemplate.h108
-rwxr-xr-xengines/sword25/gfx/animationtemplateregistry.cpp111
-rwxr-xr-xengines/sword25/gfx/animationtemplateregistry.h64
-rwxr-xr-xengines/sword25/gfx/bitmap.cpp214
-rwxr-xr-xengines/sword25/gfx/bitmap.h167
-rwxr-xr-xengines/sword25/gfx/bitmapresource.cpp54
-rwxr-xr-xengines/sword25/gfx/bitmapresource.h177
-rwxr-xr-xengines/sword25/gfx/dynamicbitmap.cpp191
-rwxr-xr-xengines/sword25/gfx/dynamicbitmap.h71
-rwxr-xr-xengines/sword25/gfx/fontresource.cpp243
-rwxr-xr-xengines/sword25/gfx/fontresource.h104
-rwxr-xr-xengines/sword25/gfx/framecounter.cpp53
-rwxr-xr-xengines/sword25/gfx/framecounter.h76
-rwxr-xr-xengines/sword25/gfx/graphicengine.cpp218
-rwxr-xr-xengines/sword25/gfx/graphicengine.h401
-rwxr-xr-xengines/sword25/gfx/graphicengine_script.cpp1722
-rwxr-xr-xengines/sword25/gfx/image/b25sloader.cpp101
-rwxr-xr-xengines/sword25/gfx/image/b25sloader.h52
-rwxr-xr-xengines/sword25/gfx/image/image.h208
-rwxr-xr-xengines/sword25/gfx/image/imageloader.cpp120
-rwxr-xr-xengines/sword25/gfx/image/imageloader.h358
-rwxr-xr-xengines/sword25/gfx/image/imageloader_ids.h44
-rwxr-xr-xengines/sword25/gfx/image/pngloader.cpp389
-rwxr-xr-xengines/sword25/gfx/image/pngloader.h64
-rwxr-xr-xengines/sword25/gfx/image/vectorimage.cpp571
-rwxr-xr-xengines/sword25/gfx/image/vectorimage.h167
-rwxr-xr-xengines/sword25/gfx/image/vectorimagerenderer.cpp198
-rwxr-xr-xengines/sword25/gfx/image/vectorimagerenderer.h76
-rwxr-xr-xengines/sword25/gfx/opengl/glimage.cpp208
-rwxr-xr-xengines/sword25/gfx/opengl/glimage.h85
-rwxr-xr-xengines/sword25/gfx/opengl/glvectorimageblit.cpp133
-rwxr-xr-xengines/sword25/gfx/opengl/openglgfx.cpp505
-rwxr-xr-xengines/sword25/gfx/opengl/openglgfx.h114
-rwxr-xr-xengines/sword25/gfx/opengl/swimage.cpp125
-rwxr-xr-xengines/sword25/gfx/opengl/swimage.h69
-rwxr-xr-xengines/sword25/gfx/panel.cpp123
-rwxr-xr-xengines/sword25/gfx/panel.h58
-rwxr-xr-xengines/sword25/gfx/renderobject.cpp571
-rwxr-xr-xengines/sword25/gfx/renderobject.h477
-rwxr-xr-xengines/sword25/gfx/renderobjectmanager.cpp163
-rwxr-xr-xengines/sword25/gfx/renderobjectmanager.h115
-rwxr-xr-xengines/sword25/gfx/renderobjectptr.h80
-rwxr-xr-xengines/sword25/gfx/renderobjectregistry.cpp50
-rwxr-xr-xengines/sword25/gfx/renderobjectregistry.h60
-rwxr-xr-xengines/sword25/gfx/rootrenderobject.h53
-rwxr-xr-xengines/sword25/gfx/screenshot.cpp202
-rwxr-xr-xengines/sword25/gfx/screenshot.h44
-rwxr-xr-xengines/sword25/gfx/staticbitmap.cpp218
-rwxr-xr-xengines/sword25/gfx/staticbitmap.h69
-rwxr-xr-xengines/sword25/gfx/text.cpp404
-rwxr-xr-xengines/sword25/gfx/text.h156
-rwxr-xr-xengines/sword25/gfx/timedrenderobject.cpp39
-rwxr-xr-xengines/sword25/gfx/timedrenderobject.h57
60 files changed, 12434 insertions, 0 deletions
diff --git a/engines/sword25/gfx/animation.cpp b/engines/sword25/gfx/animation.cpp
new file mode 100755
index 0000000000..a4511454ed
--- /dev/null
+++ b/engines/sword25/gfx/animation.cpp
@@ -0,0 +1,878 @@
+// -----------------------------------------------------------------------------
+// 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 <memory>
+
+#include "animation.h"
+
+#include "kernel/kernel.h"
+#include "kernel/resmanager.h"
+#include "kernel/inputpersistenceblock.h"
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/callbackregistry.h"
+#include "package/packagemanager.h"
+#include "util/tinyxml/tinyxml.h"
+#include "image/image.h"
+#include "animationtemplate.h"
+#include "animationtemplateregistry.h"
+#include "animationresource.h"
+#include "bitmapresource.h"
+#include "graphicengine.h"
+
+#define BS_LOG_PREFIX "ANIMATION"
+
+// Konstruktion / Destruktion
+// --------------------------
+
+BS_Animation::BS_Animation(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, const std::string & FileName) :
+ BS_TimedRenderObject(ParentPtr, BS_RenderObject::TYPE_ANIMATION)
+{
+ // Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
+ if (!m_InitSuccess) return;
+
+ InitMembers();
+
+ // Vom negativen Fall ausgehen.
+ m_InitSuccess = false;
+
+ InitializeAnimationResource(FileName);
+
+ // Erfolg signalisieren.
+ m_InitSuccess = true;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Animation::BS_Animation(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, const BS_AnimationTemplate & Template) :
+ BS_TimedRenderObject(ParentPtr, BS_RenderObject::TYPE_ANIMATION)
+{
+ // Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
+ if (!m_InitSuccess) return;
+
+ InitMembers();
+
+ // Vom negativen Fall ausgehen.
+ m_InitSuccess = false;
+
+ m_AnimationTemplateHandle = BS_AnimationTemplate::Create(Template);
+
+ // Erfolg signalisieren.
+ m_InitSuccess = true;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Animation::BS_Animation(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle) :
+ BS_TimedRenderObject(ParentPtr, BS_RenderObject::TYPE_ANIMATION, Handle)
+{
+ // Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
+ if (!m_InitSuccess) return;
+
+ InitMembers();
+
+ // Objekt vom Stream laden.
+ m_InitSuccess = Unpersist(Reader);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::InitializeAnimationResource(const std::string &FileName)
+{
+ // Die Resource wird für die gesamte Lebensdauer des Animations-Objektes gelockt.
+ BS_Resource * ResourcePtr = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(FileName);
+ if (ResourcePtr && ResourcePtr->GetType() == BS_Resource::TYPE_ANIMATION)
+ m_AnimationResourcePtr = static_cast<BS_AnimationResource *>(ResourcePtr);
+ else
+ {
+ BS_LOG_ERRORLN("The resource \"%s\" could not be requested. The Animation can't be created.", FileName.c_str());
+ return;
+ }
+
+ // Größe und Position der Animation anhand des aktuellen Frames bestimmen.
+ ComputeCurrentCharacteristics();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::InitMembers()
+{
+ m_CurrentFrame = 0;
+ m_CurrentFrameTime = 0;
+ m_Direction = FORWARD;
+ m_Running = false;
+ m_Finished = false;
+ m_RelX = 0;
+ m_RelY = 0;
+ m_ScaleFactorX = 1.0f;
+ m_ScaleFactorY = 1.0f;
+ m_ModulationColor = 0xffffffff;
+ m_AnimationResourcePtr = 0;
+ m_AnimationTemplateHandle = 0;
+ m_FramesLocked = false;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Animation::~BS_Animation()
+{
+ if (GetAnimationDescription())
+ {
+ Stop();
+ GetAnimationDescription()->Unlock();
+ }
+
+ // Delete Callbacks
+ std::vector<ANIMATION_CALLBACK_DATA>::iterator it = m_DeleteCallbacks.begin();
+ for (; it != m_DeleteCallbacks.end(); it++) ((*it).Callback)((*it).Data);
+
+}
+
+// -----------------------------------------------------------------------------
+// Steuermethoden
+// -----------------------------------------------------------------------------
+
+void BS_Animation::Play()
+{
+ // Wenn die Animation zuvor komplett durchgelaufen ist, wird sie wieder von Anfang abgespielt
+ if (m_Finished) Stop();
+
+ m_Running = true;
+ LockAllFrames();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::Pause()
+{
+ m_Running = false;
+ UnlockAllFrames();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::Stop()
+{
+ m_CurrentFrame = 0;
+ m_CurrentFrameTime = 0;
+ m_Direction = FORWARD;
+ Pause();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetFrame(unsigned int Nr)
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+
+ if (Nr >= animationDescriptionPtr->GetFrameCount())
+ {
+ BS_LOG_ERRORLN("Tried to set animation to illegal frame (%d). Value must be between 0 and %d.",
+ Nr, animationDescriptionPtr->GetFrameCount());
+ return;
+ }
+
+ m_CurrentFrame = Nr;
+ m_CurrentFrameTime = 0;
+ ComputeCurrentCharacteristics();
+ ForceRefresh();
+}
+
+// -----------------------------------------------------------------------------
+// Rendern
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::DoRender()
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ BS_ASSERT(m_CurrentFrame < animationDescriptionPtr->GetFrameCount());
+
+ // Bitmap des aktuellen Frames holen
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(animationDescriptionPtr->GetFrame(m_CurrentFrame).FileName);
+ BS_ASSERT(pResource);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ BS_BitmapResource * pBitmapResource = static_cast<BS_BitmapResource*>(pResource);
+
+ // Framebufferobjekt holen
+ BS_GraphicEngine * pGfx = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
+ BS_ASSERT(pGfx);
+
+ // Bitmap zeichnen
+ bool Result;
+ if (IsScalingAllowed() && (m_Width != pBitmapResource->GetWidth() || m_Height != pBitmapResource->GetHeight()))
+ {
+ Result = pBitmapResource->Blit(m_AbsoluteX, m_AbsoluteY,
+ (animationDescriptionPtr->GetFrame(m_CurrentFrame).FlipV ? BS_BitmapResource::FLIP_V : 0) |
+ (animationDescriptionPtr->GetFrame(m_CurrentFrame).FlipH ? BS_BitmapResource::FLIP_H : 0),
+ 0, m_ModulationColor, m_Width, m_Height);
+ }
+ else
+ {
+ Result = pBitmapResource->Blit(m_AbsoluteX, m_AbsoluteY,
+ (animationDescriptionPtr->GetFrame(m_CurrentFrame).FlipV ? BS_BitmapResource::FLIP_V : 0) |
+ (animationDescriptionPtr->GetFrame(m_CurrentFrame).FlipH ? BS_BitmapResource::FLIP_H : 0),
+ 0, m_ModulationColor, -1, -1);
+ }
+
+ // Resource freigeben
+ pBitmapResource->Release();
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+// Frame Notifikation
+// -----------------------------------------------------------------------------
+
+void BS_Animation::FrameNotification(int TimeElapsed)
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ BS_ASSERT(TimeElapsed >= 0);
+
+ // Nur wenn die Animation läuft wird sie auch weiterbewegt
+ if (m_Running)
+ {
+ int OldFrame = m_CurrentFrame;
+
+ // Gesamte vergangene Zeit bestimmen (inkl. Restzeit des aktuellen Frames)
+ m_CurrentFrameTime += TimeElapsed;
+
+ // Anzahl an zu überpringenden Frames bestimmen
+ int SkipFrames = animationDescriptionPtr->GetMillisPerFrame() == 0 ? 0 : m_CurrentFrameTime / animationDescriptionPtr->GetMillisPerFrame();
+
+ // Neue Frame-Restzeit bestimmen
+ m_CurrentFrameTime -= animationDescriptionPtr->GetMillisPerFrame() * SkipFrames;
+
+ // Neuen Frame bestimmen (je nach aktuellener Abspielrichtung wird addiert oder subtrahiert)
+ int TmpCurFrame = m_CurrentFrame;
+ switch (m_Direction)
+ {
+ case FORWARD:
+ TmpCurFrame += SkipFrames;
+ break;
+
+ case BACKWARD:
+ TmpCurFrame -= SkipFrames;
+ break;
+
+ default:
+ BS_ASSERT(0);
+ }
+
+ // Überläufe behandeln
+ if (TmpCurFrame < 0)
+ {
+ // Loop-Point Callbacks
+ std::vector<ANIMATION_CALLBACK_DATA>::iterator it = m_LoopPointCallbacks.begin();
+ while (it != m_LoopPointCallbacks.end())
+ {
+ if (((*it).Callback)((*it).Data) == false)
+ {
+ it = m_LoopPointCallbacks.erase(it);
+ }
+ else
+ it++;
+ }
+
+ // Ein Unterlauf darf nur auftreten, wenn der Animationstyp JOJO ist.
+ BS_ASSERT(animationDescriptionPtr->GetAnimationType() == AT_JOJO);
+ TmpCurFrame = - TmpCurFrame;
+ m_Direction = FORWARD;
+ }
+ else if (static_cast<unsigned int>(TmpCurFrame) >= animationDescriptionPtr->GetFrameCount())
+ {
+ // Loop-Point Callbacks
+ std::vector<ANIMATION_CALLBACK_DATA>::iterator it = m_LoopPointCallbacks.begin();
+ while (it != m_LoopPointCallbacks.end())
+ {
+ if (((*it).Callback)((*it).Data) == false)
+ it = m_LoopPointCallbacks.erase(it);
+ else
+ it++;
+ }
+
+ switch (animationDescriptionPtr->GetAnimationType())
+ {
+ case AT_ONESHOT:
+ TmpCurFrame = animationDescriptionPtr->GetFrameCount() - 1;
+ m_Finished = true;
+ Pause();
+ break;
+
+ case AT_LOOP:
+ TmpCurFrame = TmpCurFrame % animationDescriptionPtr->GetFrameCount();
+ break;
+
+ case AT_JOJO:
+ TmpCurFrame = animationDescriptionPtr->GetFrameCount() - (TmpCurFrame % animationDescriptionPtr->GetFrameCount()) - 1;
+ m_Direction = BACKWARD;
+ break;
+
+ default:
+ BS_ASSERT(0);
+ }
+ }
+
+ if (m_CurrentFrame != TmpCurFrame)
+ {
+ ForceRefresh();
+
+ if (animationDescriptionPtr->GetFrame(m_CurrentFrame).Action != "")
+ {
+ // Action Callbacks
+ std::vector<ANIMATION_CALLBACK_DATA>::iterator it = m_ActionCallbacks.begin();
+ while (it != m_ActionCallbacks.end())
+ {
+ if (((*it).Callback)((*it).Data) == false)
+ it = m_ActionCallbacks.erase(it);
+ else
+ it++;
+ }
+ }
+ }
+
+ m_CurrentFrame = static_cast<unsigned int>(TmpCurFrame);
+ }
+
+ // Größe und Position der Animation anhand des aktuellen Frames bestimmen
+ ComputeCurrentCharacteristics();
+
+ BS_ASSERT(m_CurrentFrame < animationDescriptionPtr->GetFrameCount());
+ BS_ASSERT(m_CurrentFrameTime >= 0);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::ComputeCurrentCharacteristics()
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ const BS_AnimationResource::Frame & CurFrame = animationDescriptionPtr->GetFrame(m_CurrentFrame);
+
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(CurFrame.FileName);
+ BS_ASSERT(pResource);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ BS_BitmapResource* pBitmap = static_cast<BS_BitmapResource *>(pResource);
+
+ // Größe des Bitmaps auf die Animation übertragen
+ m_Width = static_cast<int>(pBitmap->GetWidth() * m_ScaleFactorX);
+ m_Height = static_cast<int>(pBitmap->GetHeight() * m_ScaleFactorY);
+
+ // Position anhand des Hotspots berechnen und setzen
+ int PosX = m_RelX + ComputeXModifier();
+ int PosY = m_RelY + ComputeYModifier();
+
+ BS_RenderObject::SetPos(PosX, PosY);
+
+ pBitmap->Release();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::LockAllFrames()
+{
+ if (!m_FramesLocked)
+ {
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ for (unsigned int i = 0; i < animationDescriptionPtr->GetFrameCount(); ++i)
+ {
+ if (!BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(animationDescriptionPtr->GetFrame(i).FileName))
+ {
+ BS_LOG_ERRORLN("Could not lock all animation frames.");
+ return false;
+ }
+ }
+
+ m_FramesLocked = true;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::UnlockAllFrames()
+{
+ if (m_FramesLocked)
+ {
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ for (unsigned int i = 0; i < animationDescriptionPtr->GetFrameCount(); ++i)
+ {
+ BS_Resource* pResource;
+ if (!(pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(animationDescriptionPtr->GetFrame(i).FileName)))
+ {
+ BS_LOG_ERRORLN("Could not unlock all animation frames.");
+ return false;
+ }
+
+ // Zwei mal freigeben um den Request von LockAllFrames() und den jetzigen Request aufzuheben
+ pResource->Release();
+ if (pResource->GetLockCount()) pResource->Release();
+ }
+
+ m_FramesLocked = false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// Getter
+// -----------------------------------------------------------------------------
+
+BS_Animation::ANIMATION_TYPES BS_Animation::GetAnimationType() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->GetAnimationType();
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::GetFPS() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->GetFPS();
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::GetFrameCount() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->GetFrameCount();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::IsScalingAllowed() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->IsScalingAllowed();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::IsAlphaAllowed() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->IsAlphaAllowed();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::IsColorModulationAllowed() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->IsColorModulationAllowed();
+}
+
+// -----------------------------------------------------------------------------
+// Positionieren
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetPos(int RelX, int RelY)
+{
+ m_RelX = RelX;
+ m_RelY = RelY;
+
+ ComputeCurrentCharacteristics();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetX(int RelX)
+{
+ m_RelX = RelX;
+
+ ComputeCurrentCharacteristics();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetY(int RelY)
+{
+ m_RelY = RelY;
+
+ ComputeCurrentCharacteristics();
+}
+
+// -----------------------------------------------------------------------------
+// Darstellungsart festlegen
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetAlpha(int Alpha)
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ if (!animationDescriptionPtr->IsAlphaAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set alpha value on an animation that does not support alpha. Call was ignored.");
+ return;
+ }
+
+ unsigned int NewModulationColor = (m_ModulationColor & 0x00ffffff) | Alpha << 24;
+ if (NewModulationColor != m_ModulationColor)
+ {
+ m_ModulationColor = NewModulationColor;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetModulationColor(unsigned int ModulationColor)
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ if (!animationDescriptionPtr->IsColorModulationAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set modulation color on an animation that does not support color modulation. Call was ignored");
+ return;
+ }
+
+ unsigned int NewModulationColor = (ModulationColor & 0x00ffffff) | (m_ModulationColor & 0xff000000);
+ if (NewModulationColor != m_ModulationColor)
+ {
+ m_ModulationColor = NewModulationColor;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetScaleFactor(float ScaleFactor)
+{
+ SetScaleFactorX(ScaleFactor);
+ SetScaleFactorY(ScaleFactor);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetScaleFactorX(float ScaleFactorX)
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ if (!animationDescriptionPtr->IsScalingAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set x scale factor on an animation that does not support scaling. Call was ignored");
+ return;
+ }
+
+ if (ScaleFactorX != m_ScaleFactorX)
+ {
+ m_ScaleFactorX = ScaleFactorX;
+ if (m_ScaleFactorX <= 0.0f) m_ScaleFactorX = 0.001f;
+ ForceRefresh();
+ ComputeCurrentCharacteristics();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::SetScaleFactorY(float ScaleFactorY)
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ if (!animationDescriptionPtr->IsScalingAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set y scale factor on an animation that does not support scaling. Call was ignored");
+ return;
+ }
+
+ if (ScaleFactorY != m_ScaleFactorY)
+ {
+ m_ScaleFactorY = ScaleFactorY;
+ if (m_ScaleFactorY <= 0.0f) m_ScaleFactorY = 0.001f;
+ ForceRefresh();
+ ComputeCurrentCharacteristics();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+const std::string & BS_Animation::GetCurrentAction() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ return animationDescriptionPtr->GetFrame(m_CurrentFrame).Action;
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::GetX() const
+{
+ return m_RelX;
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::GetY() const
+{
+ return m_RelY;
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::GetAbsoluteX() const
+{
+ return m_AbsoluteX + (m_RelX - m_X);
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::GetAbsoluteY() const
+{
+ return m_AbsoluteY + (m_RelY - m_Y);
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::ComputeXModifier() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ const BS_AnimationResource::Frame & CurFrame = animationDescriptionPtr->GetFrame(m_CurrentFrame);
+
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(CurFrame.FileName);
+ BS_ASSERT(pResource);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ BS_BitmapResource* pBitmap = static_cast<BS_BitmapResource *>(pResource);
+
+ int Result = CurFrame.FlipV ? - static_cast<int>((pBitmap->GetWidth() - 1 - CurFrame.HotspotX) * m_ScaleFactorX) :
+ - static_cast<int>(CurFrame.HotspotX * m_ScaleFactorX);
+
+ pBitmap->Release();
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Animation::ComputeYModifier() const
+{
+ BS_AnimationDescription * animationDescriptionPtr = GetAnimationDescription();
+ BS_ASSERT(animationDescriptionPtr);
+ const BS_AnimationResource::Frame & CurFrame = animationDescriptionPtr->GetFrame(m_CurrentFrame);
+
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(CurFrame.FileName);
+ BS_ASSERT(pResource);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ BS_BitmapResource* pBitmap = static_cast<BS_BitmapResource *>(pResource);
+
+ int Result = CurFrame.FlipH ? - static_cast<int>((pBitmap->GetHeight() - 1 - CurFrame.HotspotY) * m_ScaleFactorY) :
+ - static_cast<int>(CurFrame.HotspotY * m_ScaleFactorY);
+
+ pBitmap->Release();
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::RegisterActionCallback(ANIMATION_CALLBACK Callback, unsigned int Data)
+{
+ ANIMATION_CALLBACK_DATA CD;
+ CD.Callback = Callback;
+ CD.Data = Data;
+ m_ActionCallbacks.push_back(CD);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::RegisterLoopPointCallback(ANIMATION_CALLBACK Callback, unsigned int Data)
+{
+ ANIMATION_CALLBACK_DATA CD;
+ CD.Callback = Callback;
+ CD.Data = Data;
+ m_LoopPointCallbacks.push_back(CD);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::RegisterDeleteCallback(ANIMATION_CALLBACK Callback, unsigned int Data)
+{
+ ANIMATION_CALLBACK_DATA CD;
+ CD.Callback = Callback;
+ CD.Data = Data;
+ m_DeleteCallbacks.push_back(CD);
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+void BS_Animation::PersistCallbackVector(BS_OutputPersistenceBlock & Writer, const std::vector<ANIMATION_CALLBACK_DATA> & Vector)
+{
+ // Anzahl an Callbacks persistieren.
+ Writer.Write(Vector.size());
+
+ // Alle Callbacks einzeln persistieren.
+ std::vector<ANIMATION_CALLBACK_DATA>::const_iterator It = Vector.begin();
+ while (It != Vector.end())
+ {
+ Writer.Write(BS_CallbackRegistry::GetInstance().ResolveCallbackPointer(It->Callback));
+ Writer.Write(It->Data);
+
+ ++It;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Animation::UnpersistCallbackVector(BS_InputPersistenceBlock & Reader, std::vector<ANIMATION_CALLBACK_DATA> & Vector)
+{
+ // Callbackvector leeren.
+ Vector.resize(0);
+
+ // Anzahl an Callbacks einlesen.
+ unsigned int CallbackCount;
+ Reader.Read(CallbackCount);
+
+ // Alle Callbacks einzeln wieder herstellen.
+ for (unsigned int i = 0; i < CallbackCount; ++i)
+ {
+ ANIMATION_CALLBACK_DATA CallbackData;
+
+ std::string CallbackFunctionName;
+ Reader.Read(CallbackFunctionName);
+ CallbackData.Callback = reinterpret_cast<ANIMATION_CALLBACK>(BS_CallbackRegistry::GetInstance().ResolveCallbackFunction(CallbackFunctionName));
+
+ Reader.Read(CallbackData.Data);
+
+ Vector.push_back(CallbackData);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Persist(Writer);
+
+ Writer.Write(m_RelX);
+ Writer.Write(m_RelY);
+ Writer.Write(m_ScaleFactorX);
+ Writer.Write(m_ScaleFactorY);
+ Writer.Write(m_ModulationColor);
+ Writer.Write(m_CurrentFrame);
+ Writer.Write(m_CurrentFrameTime);
+ Writer.Write(m_Running);
+ Writer.Write(m_Finished);
+ Writer.Write(static_cast<unsigned int>(m_Direction));
+
+ // Je nach Animationstyp entweder das Template oder die Ressource speichern.
+ if (m_AnimationResourcePtr)
+ {
+ unsigned int Marker = 0;
+ Writer.Write(Marker);
+ Writer.Write(m_AnimationResourcePtr->GetFileName());
+ }
+ else if (m_AnimationTemplateHandle)
+ {
+ unsigned int Marker = 1;
+ Writer.Write(Marker);
+ Writer.Write(m_AnimationTemplateHandle);
+ }
+ else
+ {
+ BS_ASSERT(false);
+ }
+
+ //Writer.Write(m_AnimationDescriptionPtr);
+
+ Writer.Write(m_FramesLocked);
+ PersistCallbackVector(Writer, m_LoopPointCallbacks);
+ PersistCallbackVector(Writer, m_ActionCallbacks);
+ PersistCallbackVector(Writer, m_DeleteCallbacks);
+
+ Result &= BS_RenderObject::PersistChildren(Writer);
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Animation::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Unpersist(Reader);
+
+ Reader.Read(m_RelX);
+ Reader.Read(m_RelY);
+ Reader.Read(m_ScaleFactorX);
+ Reader.Read(m_ScaleFactorY);
+ Reader.Read(m_ModulationColor);
+ Reader.Read(m_CurrentFrame);
+ Reader.Read(m_CurrentFrameTime);
+ Reader.Read(m_Running);
+ Reader.Read(m_Finished);
+ unsigned int Direction;
+ Reader.Read(Direction);
+ m_Direction = static_cast<DIRECTION>(Direction);
+
+ // Animationstyp einlesen.
+ unsigned int Marker;
+ Reader.Read(Marker);
+ if (Marker == 0)
+ {
+ std::string ResourceFilename;
+ Reader.Read(ResourceFilename);
+ InitializeAnimationResource(ResourceFilename);
+ }
+ else if (Marker == 1)
+ {
+ Reader.Read(m_AnimationTemplateHandle);
+ }
+ else
+ {
+ BS_ASSERT(false);
+ }
+
+ Reader.Read(m_FramesLocked);
+ if (m_FramesLocked) LockAllFrames();
+
+ UnpersistCallbackVector(Reader, m_LoopPointCallbacks);
+ UnpersistCallbackVector(Reader, m_ActionCallbacks);
+ UnpersistCallbackVector(Reader, m_DeleteCallbacks);
+
+ Result &= BS_RenderObject::UnpersistChildren(Reader);
+
+ return Reader.IsGood() && Result;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationDescription * BS_Animation::GetAnimationDescription() const
+{
+ if (m_AnimationResourcePtr) return m_AnimationResourcePtr;
+ else return BS_AnimationTemplateRegistry::GetInstance().ResolveHandle(m_AnimationTemplateHandle);
+}
diff --git a/engines/sword25/gfx/animation.h b/engines/sword25/gfx/animation.h
new file mode 100755
index 0000000000..37380f27a9
--- /dev/null
+++ b/engines/sword25/gfx/animation.h
@@ -0,0 +1,209 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_ANIMATION_H
+#define BS_ANIMATION_H
+
+// Includes
+#include "kernel/common.h"
+#include "timedrenderobject.h"
+
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+// Forward declarations
+class BS_Kernel;
+class BS_PackageManager;
+class BS_AnimationResource;
+class BS_AnimationTemplate;
+class BS_AnimationDescription;
+class BS_InputPersistenceBlock;
+
+class BS_Animation : public BS_TimedRenderObject
+{
+friend BS_RenderObject;
+
+private:
+ BS_Animation(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, const std::string & FileName);
+ BS_Animation(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, const BS_AnimationTemplate & Template);
+ BS_Animation(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle);
+
+public:
+ enum ANIMATION_TYPES
+ {
+ AT_ONESHOT,
+ AT_LOOP,
+ AT_JOJO,
+ };
+
+ virtual ~BS_Animation();
+
+ void Play();
+ void Pause();
+ void Stop();
+ void SetFrame(unsigned int Nr);
+
+ virtual void SetPos(int X, int Y);
+ virtual void SetX(int X);
+ virtual void SetY(int Y);
+
+ virtual int GetX() const;
+ virtual int GetY() const;
+ virtual int GetAbsoluteX() const;
+ virtual int GetAbsoluteY() const;
+
+ /**
+ @brief Setzt den Alphawert der Animation.
+ @param Alpha der neue Alphawert der Animation (0 = keine Deckung, 255 = volle Deckung).
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsAlphaAllowed() true zurückgibt.
+ */
+ void SetAlpha(int Alpha);
+
+ /**
+ @brief Setzt die Modulationfarbe der Animation.
+ @param Color eine 24-Bit Farbe, die die Modulationsfarbe der Animation festlegt.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsColorModulationAllowed() true zurückgibt.
+ */
+ void SetModulationColor(unsigned int ModulationColor);
+
+ /**
+ @brief Setzt den Skalierungsfaktor der Animation.
+ @param ScaleFactor der Faktor um den die Animation in beide Richtungen gestreckt werden soll.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ void SetScaleFactor(float ScaleFactor);
+
+ /**
+ @brief Setzt den Skalierungsfaktor der Animation auf der X-Achse.
+ @param ScaleFactor der Faktor um den die Animation in Richtungen der X-Achse gestreckt werden soll.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ void SetScaleFactorX(float ScaleFactorX);
+
+ /**
+ @brief Setzt den Skalierungsfaktor der Animation auf der Y-Achse.
+ @param ScaleFactor der Faktor um den die Animation in Richtungen der Y-Achse gestreckt werden soll.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ void SetScaleFactorY(float ScaleFactorY);
+
+ /**
+ @brief Gibt den Skalierungsfakter der Animation auf der X-Achse zurück.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ float GetScaleFactorX() const { return m_ScaleFactorX; }
+
+ /**
+ @brief Gibt den Skalierungsfakter der Animation auf der Y-Achse zurück.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ float GetScaleFactorY() const { return m_ScaleFactorY; }
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+ virtual void FrameNotification(int TimeElapsed);
+
+ ANIMATION_TYPES GetAnimationType() const;
+ int GetFPS() const;
+ int GetFrameCount() const;
+ bool IsScalingAllowed() const;
+ bool IsAlphaAllowed() const;
+ bool IsColorModulationAllowed() const;
+ unsigned int GetCurrentFrame() const { return m_CurrentFrame; }
+ const std::string & GetCurrentAction() const ;
+ bool IsRunning() const { return m_Running; }
+
+ typedef bool (*ANIMATION_CALLBACK)(unsigned int);
+
+ void RegisterLoopPointCallback(ANIMATION_CALLBACK Callback, unsigned int Data = 0);
+ void RegisterActionCallback(ANIMATION_CALLBACK Callback, unsigned int Data = 0);
+ void RegisterDeleteCallback(ANIMATION_CALLBACK Callback, unsigned int Data = 0);
+
+protected:
+ virtual bool DoRender();
+
+private:
+ enum DIRECTION
+ {
+ FORWARD,
+ BACKWARD
+ };
+
+ int m_RelX;
+ int m_RelY;
+ float m_ScaleFactorX;
+ float m_ScaleFactorY;
+ unsigned int m_ModulationColor;
+ unsigned int m_CurrentFrame;
+ int m_CurrentFrameTime;
+ bool m_Running;
+ bool m_Finished;
+ DIRECTION m_Direction;
+ BS_AnimationResource * m_AnimationResourcePtr;
+ unsigned int m_AnimationTemplateHandle;
+ bool m_FramesLocked;
+
+ struct ANIMATION_CALLBACK_DATA
+ {
+ ANIMATION_CALLBACK Callback;
+ unsigned int Data;
+ };
+ std::vector<ANIMATION_CALLBACK_DATA> m_LoopPointCallbacks;
+ std::vector<ANIMATION_CALLBACK_DATA> m_ActionCallbacks;
+ std::vector<ANIMATION_CALLBACK_DATA> m_DeleteCallbacks;
+
+ /**
+ @brief Lockt alle Frames.
+ @return Gibt false zurück, falls nicht alle Frames gelockt werden konnten.
+ */
+ bool LockAllFrames();
+
+ /**
+ @brief Unlockt alle Frames.
+ @return Gibt false zurück, falls nicht alles Frames freigegeben werden konnten.
+ */
+ bool UnlockAllFrames();
+
+ /**
+ @brief Diese Methode aktualisiert die Parameter (Größe, Position) der Animation anhand des aktuellen Frames.
+
+ Diese Methode muss bei jedem Framewechsel aufgerufen werden damit der RenderObject-Manager immer aktuelle Daten hat.
+ */
+ void ComputeCurrentCharacteristics();
+
+ /**
+ @brief Berechnet den Abstand zwischen dem linken Rand und dem Hotspot auf X-Achse in der aktuellen Darstellung.
+ */
+ int ComputeXModifier() const;
+
+ /**
+ @brief Berechnet den Abstand zwischen dem linken Rand und dem Hotspot auf X-Achse in der aktuellen Darstellung.
+ */
+ int ComputeYModifier() const;
+
+ void InitMembers();
+ void PersistCallbackVector(BS_OutputPersistenceBlock & Writer, const std::vector<ANIMATION_CALLBACK_DATA> & Vector);
+ void UnpersistCallbackVector(BS_InputPersistenceBlock & Reader, std::vector<ANIMATION_CALLBACK_DATA> & Vector);
+ BS_AnimationDescription * GetAnimationDescription() const;
+ void InitializeAnimationResource(const std::string &FileName);
+};
+
+#endif
diff --git a/engines/sword25/gfx/animationdescription.cpp b/engines/sword25/gfx/animationdescription.cpp
new file mode 100755
index 0000000000..3bd5c05c0b
--- /dev/null
+++ b/engines/sword25/gfx/animationdescription.cpp
@@ -0,0 +1,58 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/inputpersistenceblock.h"
+#include "animationdescription.h"
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationDescription::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ Writer.Write(static_cast<unsigned int>(m_AnimationType));
+ Writer.Write(m_FPS);
+ Writer.Write(m_MillisPerFrame);
+ Writer.Write(m_ScalingAllowed);
+ Writer.Write(m_AlphaAllowed);
+ Writer.Write(m_ColorModulationAllowed);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationDescription::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ unsigned int AnimationType;
+ Reader.Read(AnimationType);
+ m_AnimationType = static_cast<BS_Animation::ANIMATION_TYPES>(AnimationType);
+ Reader.Read(m_FPS);
+ Reader.Read(m_MillisPerFrame);
+ Reader.Read(m_ScalingAllowed);
+ Reader.Read(m_AlphaAllowed);
+ Reader.Read(m_ColorModulationAllowed);
+
+ return Reader.IsGood();
+}
diff --git a/engines/sword25/gfx/animationdescription.h b/engines/sword25/gfx/animationdescription.h
new file mode 100755
index 0000000000..16bde6d101
--- /dev/null
+++ b/engines/sword25/gfx/animationdescription.h
@@ -0,0 +1,90 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_ANIMATIONDESCRIPTION_H
+#define BS_ANIMATIONDESCRIPTION_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/persistable.h"
+#include "animation.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_AnimationDescription : public BS_Persistable
+{
+protected:
+ BS_AnimationDescription() :
+ m_AnimationType(BS_Animation::AT_LOOP),
+ m_FPS(10),
+ m_MillisPerFrame(0),
+ m_ScalingAllowed(true),
+ m_AlphaAllowed(true),
+ m_ColorModulationAllowed(true)
+ {};
+
+public:
+ struct Frame
+ {
+ // Die Hotspot-Angabe bezieht sich auf das ungeflippte Bild!!
+ int HotspotX;
+ int HotspotY;
+ bool FlipV;
+ bool FlipH;
+ std::string FileName;
+ std::string Action;
+ };
+
+ // -----------------------------------------------------------------------------
+ // Abstrakte Methoden
+ // -----------------------------------------------------------------------------
+
+ virtual const Frame & GetFrame(unsigned int Index) const = 0;
+ virtual unsigned int GetFrameCount() const = 0;
+ virtual void Unlock() = 0;
+
+ // -----------------------------------------------------------------------------
+ // Getter Methoden
+ // -----------------------------------------------------------------------------
+
+ BS_Animation::ANIMATION_TYPES GetAnimationType() const { return m_AnimationType; }
+ int GetFPS() const { return m_FPS; }
+ int GetMillisPerFrame() const { return m_MillisPerFrame; }
+ bool IsScalingAllowed() const { return m_ScalingAllowed; }
+ bool IsAlphaAllowed() const { return m_AlphaAllowed; }
+ bool IsColorModulationAllowed() const { return m_ColorModulationAllowed; }
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+protected:
+ BS_Animation::ANIMATION_TYPES m_AnimationType;
+ int m_FPS;
+ int m_MillisPerFrame;
+ bool m_ScalingAllowed;
+ bool m_AlphaAllowed;
+ bool m_ColorModulationAllowed;
+};
+
+#endif
diff --git a/engines/sword25/gfx/animationresource.cpp b/engines/sword25/gfx/animationresource.cpp
new file mode 100755
index 0000000000..f1f88eaf2f
--- /dev/null
+++ b/engines/sword25/gfx/animationresource.cpp
@@ -0,0 +1,323 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "animationresource.h"
+
+#include "kernel/kernel.h"
+#include "kernel/string.h"
+#include "package/packagemanager.h"
+#include "util/tinyxml/tinyxml.h"
+#include "bitmapresource.h"
+
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "ANIMATIONRESOURCE"
+
+// -----------------------------------------------------------------------------
+// Constants
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const int DEFAULT_FPS = 10;
+ const int MIN_FPS = 1;
+ const int MAX_FPS = 200;
+}
+
+// -----------------------------------------------------------------------------
+// Construction / Destruction
+// -----------------------------------------------------------------------------
+
+BS_AnimationResource::BS_AnimationResource(const std::string& FileName) :
+ BS_Resource(FileName, BS_Resource::TYPE_ANIMATION),
+ m_Valid(false)
+{
+ // Pointer auf den Package-Manager bekommen
+ BS_PackageManager* PackagePtr = BS_Kernel::GetInstance()->GetPackage();
+ BS_ASSERT(PackagePtr);
+
+ // Animations-XML laden
+ TiXmlDocument Doc;
+ {
+ // Die Daten werden zunächst über den Package-Manager gelesen und dann in einen um ein Byte größeren Buffer kopiert und
+ // NULL-Terminiert, da TinyXML NULL-Terminierte Daten benötigt.
+ unsigned int FileSize;
+ char * LoadBuffer = (char *) PackagePtr->GetFile(GetFileName(), &FileSize);
+ if (!LoadBuffer)
+ {
+ BS_LOG_ERRORLN("Could not read \"%s\".", GetFileName().c_str());
+ return;
+ }
+ std::vector<char> WorkBuffer(FileSize + 1);
+ memcpy(&WorkBuffer[0], LoadBuffer, FileSize);
+ delete LoadBuffer;
+ WorkBuffer[FileSize] = '\0';
+
+ // Datei parsen
+ Doc.Parse(&WorkBuffer[0]);
+ if (Doc.Error())
+ {
+ BS_LOG_ERRORLN("The following TinyXML-Error occured while parsing \"%s\": %s", GetFileName().c_str(), Doc.ErrorDesc());
+ return;
+ }
+ }
+
+ // Wurzelknoten des Animations-Tags finden, prüfen und Attribute auslesen.
+ TiXmlElement* pElement;
+ {
+ TiXmlNode* pNode = Doc.FirstChild("animation");
+ if (!pNode || pNode->Type() != TiXmlNode::ELEMENT)
+ {
+ BS_LOG_ERRORLN("No <animation> tag found in \"%s\".", GetFileName().c_str());
+ return;
+ }
+ pElement = pNode->ToElement();
+
+ // Animation-Tag parsen
+ if (!ParseAnimationTag(*pElement, m_FPS, m_AnimationType))
+ {
+ 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.
+ std::string OldDirectory = PackagePtr->GetCurrentDirectory();
+ int LastSlash = GetFileName().rfind('/');
+ if (LastSlash != std::string::npos)
+ {
+ std::string Dir = GetFileName().substr(0, LastSlash);
+ PackagePtr->ChangeDirectory(Dir);
+ }
+
+ // Nacheinander alle Frames-Informationen erstellen.
+ TiXmlElement* pFrameElement = pElement->FirstChild("frame")->ToElement();
+ while (pFrameElement)
+ {
+ Frame CurFrame;
+
+ if (!ParseFrameTag(*pFrameElement, CurFrame, *PackagePtr))
+ {
+ BS_LOG_ERRORLN("An error occurred in \"%s\" while parsing <frame> tag.", GetFileName().c_str());
+ return;
+ }
+
+ m_Frames.push_back(CurFrame);
+ pFrameElement = pFrameElement->NextSiblingElement("frame");
+ }
+
+ // Ursprungsverzeichnis wieder herstellen
+ PackagePtr->ChangeDirectory(OldDirectory);
+
+ // Sicherstellen, dass die Animation mindestens einen Frame besitzt
+ if (m_Frames.empty())
+ {
+ BS_LOG_ERRORLN("\"%s\" does not have any frames.", GetFileName().c_str());
+ return;
+ }
+
+ // Alle Frame-Dateien werden vorgecached
+ if (!PrecacheAllFrames())
+ {
+ BS_LOG_ERRORLN("Could not precache all frames of \"%s\".", GetFileName().c_str());
+ return;
+ }
+
+ // Feststellen, ob die Animation skalierbar ist
+ if (!ComputeFeatures())
+ {
+ BS_LOG_ERRORLN("Could not determine the features of \"%s\".", GetFileName().c_str());
+ return;
+ }
+
+ m_Valid = true;
+}
+
+// -----------------------------------------------------------------------------
+// Dokument-Parsermethoden
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationResource::ParseAnimationTag(TiXmlElement& AnimationTag, int& FPS, BS_Animation::ANIMATION_TYPES & AnimationType)
+{
+ // FPS einlesen
+ const char* FPSString;
+ if (FPSString = AnimationTag.Attribute("fps"))
+ {
+ int TempFPS;
+ if (!BS_String::ToInt(std::string(FPSString), TempFPS) || TempFPS < MIN_FPS || TempFPS > MAX_FPS)
+ {
+ BS_LOG_WARNINGLN("Illegal fps value (\"%s\") in <animation> tag in \"%s\". Assuming default (\"%d\"). "
+ "The fps value has to be between %d and %d.",
+ FPSString, GetFileName().c_str(), DEFAULT_FPS, MIN_FPS, MAX_FPS);
+ }
+ else
+ FPS = TempFPS;
+ }
+
+ // Loop-Typ einlesen
+ const char* LoopTypeString;
+ if (LoopTypeString = AnimationTag.Attribute("type"))
+ {
+ 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\").",
+ LoopTypeString, GetFileName().c_str());
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationResource::ParseFrameTag(TiXmlElement& FrameTag, Frame& Frame, BS_PackageManager& PackageManager)
+{
+ const char* FileString = FrameTag.Attribute("file");
+ if (!FileString)
+ {
+ BS_LOG_ERRORLN("<frame> tag without file attribute occurred in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+ Frame.FileName = PackageManager.GetAbsolutePath(FileString);
+ if (Frame.FileName == "")
+ {
+ BS_LOG_ERRORLN("Could not create absolute path for file specified in <frame> tag in \"%s\": \"%s\".", GetFileName().c_str(), FileString);
+ return false;
+ }
+
+ const char* ActionString = FrameTag.Attribute("action");
+ if (ActionString)
+ Frame.Action = ActionString;
+
+ const char* HotspotxString = FrameTag.Attribute("hotspotx");
+ const char* HotspotyString = FrameTag.Attribute("hotspoty");
+ if ((!HotspotxString && HotspotyString) ||
+ (HotspotxString && !HotspotyString))
+ BS_LOG_WARNINGLN("%s attribute occurred without %s attribute in <frame> tag in \"%s\". Assuming default (\"0\").",
+ HotspotxString ? "hotspotx" : "hotspoty",
+ !HotspotyString ? "hotspoty" : "hotspotx",
+ GetFileName().c_str());
+
+ Frame.HotspotX = 0;
+ if (HotspotxString && !BS_String::ToInt(std::string(HotspotxString), Frame.HotspotX))
+ BS_LOG_WARNINGLN("Illegal hotspotx value (\"%s\") in frame tag in \"%s\". Assuming default (\"%s\").",
+ HotspotxString,GetFileName().c_str(), Frame.HotspotX);
+
+ Frame.HotspotY = 0;
+ if (HotspotyString && !BS_String::ToInt(std::string(HotspotyString), Frame.HotspotY))
+ BS_LOG_WARNINGLN("Illegal hotspoty value (\"%s\") in frame tag in \"%s\". Assuming default (\"%s\").",
+ HotspotyString, GetFileName().c_str(), Frame.HotspotY);
+
+ const char* FlipVString = FrameTag.Attribute("flipv");
+ if (FlipVString)
+ {
+ if (!BS_String::ToBool(std::string(FlipVString), Frame.FlipV))
+ {
+ BS_LOG_WARNINGLN("Illegal flipv value (\"%s\") in <frame> tag in \"%s\". Assuming default (\"false\").",
+ FlipVString, GetFileName().c_str());
+ Frame.FlipV = false;
+ }
+ }
+ else
+ Frame.FlipV = false;
+
+ const char* FlipHString = FrameTag.Attribute("fliph");
+ if (FlipHString)
+ {
+ if (!BS_String::ToBool(FlipHString, Frame.FlipH))
+ {
+ BS_LOG_WARNINGLN("Illegal fliph value (\"%s\") in <frame> tag in \"%s\". Assuming default (\"false\").",
+ FlipHString, GetFileName().c_str());
+ Frame.FlipH = false;
+ }
+ }
+ else
+ Frame.FlipH = false;
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationResource::~BS_AnimationResource()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationResource::PrecacheAllFrames() const
+{
+ std::vector<Frame>::const_iterator Iter = m_Frames.begin();
+ for (; Iter != m_Frames.end(); ++Iter)
+ {
+ if (!BS_Kernel::GetInstance()->GetResourceManager()->PrecacheResource((*Iter).FileName))
+ {
+ BS_LOG_ERRORLN("Could not precache \"%s\".", (*Iter).FileName.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationResource::ComputeFeatures()
+{
+ 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ützt werden.
+ std::vector<Frame>::const_iterator Iter = m_Frames.begin();
+ for (; Iter != m_Frames.end(); ++Iter)
+ {
+ BS_BitmapResource* pBitmap;
+ if (!(pBitmap = static_cast<BS_BitmapResource*> (BS_Kernel::GetInstance()->GetResourceManager()->RequestResource((*Iter).FileName))))
+ {
+ 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;
+}
diff --git a/engines/sword25/gfx/animationresource.h b/engines/sword25/gfx/animationresource.h
new file mode 100755
index 0000000000..ebb374f87a
--- /dev/null
+++ b/engines/sword25/gfx/animationresource.h
@@ -0,0 +1,83 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_ANIMATIONRESOURCE_H
+#define BS_ANIMATIONRESOURCE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/resource.h"
+#include "animationdescription.h"
+#include "animation.h"
+
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_Kernel;
+class BS_PackageManager;
+class TiXmlElement;
+
+// -----------------------------------------------------------------------------
+// Class Definition
+// -----------------------------------------------------------------------------
+
+class BS_AnimationResource : public BS_Resource, public BS_AnimationDescription
+{
+public:
+ BS_AnimationResource(const std::string & FileName);
+ virtual ~BS_AnimationResource();
+
+ virtual const Frame & GetFrame(unsigned int Index) const { BS_ASSERT(Index < m_Frames.size()); return m_Frames[Index]; }
+ virtual unsigned int GetFrameCount() const { return m_Frames.size(); }
+ virtual void Unlock() { Release(); }
+
+ BS_Animation::ANIMATION_TYPES GetAnimationType() const { return m_AnimationType; }
+ int GetFPS() const { return m_FPS; }
+ int GetMillisPerFrame() const { return m_MillisPerFrame; }
+ bool IsScalingAllowed() const { return m_ScalingAllowed; }
+ bool IsAlphaAllowed() const { return m_AlphaAllowed; }
+ bool IsColorModulationAllowed() const { return m_ColorModulationAllowed; }
+ bool IsValid() const { return m_Valid; }
+
+private:
+ bool m_Valid;
+
+ std::vector<Frame> m_Frames;
+
+ //@{
+ /** @name Dokument-Parser Methoden */
+
+ bool ParseAnimationTag(TiXmlElement& AnimationTag, int& FPS, BS_Animation::ANIMATION_TYPES & AnimationType);
+ bool ParseFrameTag(TiXmlElement& FrameTag, Frame& Frame, BS_PackageManager& PackageManager);
+
+ //@}
+
+ bool ComputeFeatures();
+ bool PrecacheAllFrames() const;
+};
+
+#endif
diff --git a/engines/sword25/gfx/animationtemplate.cpp b/engines/sword25/gfx/animationtemplate.cpp
new file mode 100755
index 0000000000..72b1e9282b
--- /dev/null
+++ b/engines/sword25/gfx/animationtemplate.cpp
@@ -0,0 +1,293 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "ANIMATIONTEMPLATE"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/kernel.h"
+#include "kernel/resource.h"
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/inputpersistenceblock.h"
+
+#include "animationresource.h"
+#include "animationtemplate.h"
+#include "animationtemplateregistry.h"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+unsigned int BS_AnimationTemplate::Create(const std::string & SourceAnimation)
+{
+ BS_AnimationTemplate * AnimationTemplatePtr = new BS_AnimationTemplate(SourceAnimation);
+
+ if (AnimationTemplatePtr->IsValid())
+ {
+ return BS_AnimationTemplateRegistry::GetInstance().ResolvePtr(AnimationTemplatePtr);
+ }
+ else
+ {
+ delete AnimationTemplatePtr;
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_AnimationTemplate::Create(const BS_AnimationTemplate & Other)
+{
+ BS_AnimationTemplate * AnimationTemplatePtr = new BS_AnimationTemplate(Other);
+
+ if (AnimationTemplatePtr->IsValid())
+ {
+ return BS_AnimationTemplateRegistry::GetInstance().ResolvePtr(AnimationTemplatePtr);
+ }
+ else
+ {
+ delete AnimationTemplatePtr;
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_AnimationTemplate::Create(BS_InputPersistenceBlock & Reader, unsigned int Handle)
+{
+ BS_AnimationTemplate * AnimationTemplatePtr = new BS_AnimationTemplate(Reader, Handle);
+
+ if (AnimationTemplatePtr->IsValid())
+ {
+ return BS_AnimationTemplateRegistry::GetInstance().ResolvePtr(AnimationTemplatePtr);
+ }
+ else
+ {
+ delete AnimationTemplatePtr;
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationTemplate::BS_AnimationTemplate(const std::string & SourceAnimation)
+{
+ // Objekt registrieren.
+ BS_AnimationTemplateRegistry::GetInstance().RegisterObject(this);
+
+ m_Valid = false;
+
+ // Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt
+ m_SourceAnimationPtr = RequestSourceAnimation(SourceAnimation);
+
+ // Erfolg signalisieren
+ m_Valid = (m_SourceAnimationPtr != 0);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationTemplate::BS_AnimationTemplate(const BS_AnimationTemplate & Other)
+{
+ // Objekt registrieren.
+ BS_AnimationTemplateRegistry::GetInstance().RegisterObject(this);
+
+ m_Valid = false;
+
+ // Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt.
+ if (!Other.m_SourceAnimationPtr) return;
+ m_SourceAnimationPtr = RequestSourceAnimation(Other.m_SourceAnimationPtr->GetFileName());
+
+ // Alle Member kopieren.
+ m_AnimationType = Other.m_AnimationType;
+ m_FPS = Other.m_FPS;
+ m_MillisPerFrame = Other.m_MillisPerFrame;
+ m_ScalingAllowed = Other.m_ScalingAllowed;
+ m_AlphaAllowed = Other.m_AlphaAllowed;
+ m_ColorModulationAllowed = Other.m_ColorModulationAllowed;
+ m_Frames = Other.m_Frames;
+ m_SourceAnimationPtr = Other.m_SourceAnimationPtr;
+ m_Valid = Other.m_Valid;
+
+ m_Valid &= (m_SourceAnimationPtr != 0);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationTemplate::BS_AnimationTemplate(BS_InputPersistenceBlock & Reader, unsigned int Handle)
+{
+ // Objekt registrieren.
+ BS_AnimationTemplateRegistry::GetInstance().RegisterObject(this, Handle);
+
+ // Objekt laden.
+ m_Valid = Unpersist(Reader);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationResource * BS_AnimationTemplate::RequestSourceAnimation(const std::string & SourceAnimation) const
+{
+ BS_ResourceManager * RMPtr = BS_Kernel::GetInstance()->GetResourceManager();
+ BS_Resource * ResourcePtr;
+ if (NULL == (ResourcePtr = RMPtr->RequestResource(SourceAnimation)) || ResourcePtr->GetType() != BS_Resource::TYPE_ANIMATION)
+ {
+ BS_LOG_ERRORLN("The resource \"%s\" could not be requested or is has an invalid type. The animation template can't be created.", SourceAnimation.c_str());
+ return 0;
+ }
+ return static_cast<BS_AnimationResource *>(ResourcePtr);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_AnimationTemplate::~BS_AnimationTemplate()
+{
+ // Animations-Resource freigeben
+ if (m_SourceAnimationPtr)
+ {
+ m_SourceAnimationPtr->Release();
+ }
+
+ // Objekt deregistrieren
+ BS_AnimationTemplateRegistry::GetInstance().DeregisterObject(this);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_AnimationTemplate::AddFrame(int Index)
+{
+ if (ValidateSourceIndex(Index))
+ {
+ m_Frames.push_back(m_SourceAnimationPtr->GetFrame(Index));
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_AnimationTemplate::SetFrame(int DestIndex, int SrcIndex)
+{
+ if (ValidateDestIndex(DestIndex) && ValidateSourceIndex(SrcIndex))
+ {
+ m_Frames[DestIndex] = m_SourceAnimationPtr->GetFrame(SrcIndex);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationTemplate::ValidateSourceIndex(unsigned int Index) const
+{
+ if (Index > m_SourceAnimationPtr->GetFrameCount())
+ {
+ BS_LOG_WARNINGLN("Tried to insert a frame (\"%d\") that does not exist in the source animation (\"%s\"). Ignoring call.",
+ Index, m_SourceAnimationPtr->GetFileName().c_str());
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationTemplate::ValidateDestIndex(unsigned int Index) const
+{
+ if (Index > m_Frames.size())
+ {
+ BS_LOG_WARNINGLN("Tried to change a nonexistent frame (\"%d\") in a template animation. Ignoring call.",
+ Index);
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_AnimationTemplate::SetFPS(int FPS)
+{
+ m_FPS = FPS;
+ m_MillisPerFrame = 1000000 / m_FPS;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationTemplate::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ // Parent persistieren.
+ Result &= BS_AnimationDescription::Persist(Writer);
+
+ // Frameanzahl schreiben.
+ Writer.Write(m_Frames.size());
+
+ // Frames einzeln persistieren.
+ std::vector<const Frame>::const_iterator Iter = m_Frames.begin();
+ while (Iter != m_Frames.end())
+ {
+ Writer.Write(Iter->HotspotX);
+ Writer.Write(Iter->HotspotY);
+ Writer.Write(Iter->FlipV);
+ Writer.Write(Iter->FlipH);
+ Writer.Write(Iter->FileName);
+ Writer.Write(Iter->Action);
+ ++Iter;
+ }
+
+ // Restliche Member persistieren.
+ Writer.Write(m_SourceAnimationPtr->GetFileName());
+ Writer.Write(m_Valid);
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationTemplate::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ // Parent wieder herstellen.
+ Result &= BS_AnimationDescription::Unpersist(Reader);
+
+ // Frameanzahl lesen.
+ unsigned int FrameCount;
+ Reader.Read(FrameCount);
+
+ // Frames einzeln wieder herstellen.
+ for (unsigned int i = 0; i < FrameCount; ++i)
+ {
+ Frame frame;
+ Reader.Read(frame.HotspotX);
+ Reader.Read(frame.HotspotY);
+ Reader.Read(frame.FlipV);
+ Reader.Read(frame.FlipH);
+ Reader.Read(frame.FileName);
+ Reader.Read(frame.Action);
+
+ m_Frames.push_back(frame);
+ }
+
+ // Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt
+ std::string SourceAnimation;
+ Reader.Read(SourceAnimation);
+ m_SourceAnimationPtr = RequestSourceAnimation(SourceAnimation);
+
+ Reader.Read(m_Valid);
+
+ return m_SourceAnimationPtr && Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/animationtemplate.h b/engines/sword25/gfx/animationtemplate.h
new file mode 100755
index 0000000000..df63735b2e
--- /dev/null
+++ b/engines/sword25/gfx/animationtemplate.h
@@ -0,0 +1,108 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_ANIMATION_TEMPLATE_H
+#define BS_ANIMATION_TEMPLATE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/persistable.h"
+#include "animationdescription.h"
+
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Forward declarations
+// -----------------------------------------------------------------------------
+
+class BS_AnimationResource;
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_AnimationTemplate : public BS_AnimationDescription
+{
+public:
+ static unsigned int Create(const std::string & SourceAnimation);
+ static unsigned int Create(const BS_AnimationTemplate & Other);
+ static unsigned int Create(BS_InputPersistenceBlock & Reader, unsigned int Handle);
+ BS_AnimationTemplate * ResolveHandle(unsigned int Handle) const;
+
+private:
+ BS_AnimationTemplate(const std::string & SourceAnimation);
+ BS_AnimationTemplate(const BS_AnimationTemplate & Other);
+ BS_AnimationTemplate(BS_InputPersistenceBlock & Reader, unsigned int Handle);
+
+public:
+ ~BS_AnimationTemplate();
+
+ virtual const Frame & GetFrame(unsigned int Index) const { BS_ASSERT(Index < m_Frames.size()); return m_Frames[Index]; }
+ virtual unsigned int GetFrameCount() const { return m_Frames.size(); }
+ virtual void Unlock() { delete this; }
+
+ bool IsValid() const { return m_Valid; }
+
+ /**
+ @brief Fügt einen neuen Frame zur Animation hinzu.
+
+ Der Frame wird an das Ende der Animation angehängt.
+
+ @param Index der Index des Frames in der Quellanimation
+ */
+ void AddFrame(int Index);
+
+ /**
+ @brief Ändert einen bereits in der Animation vorhandenen Frame.
+ @param DestIndex der Index des Frames der überschrieben werden soll
+ @param SrcIndex der Index des einzufügenden Frames in der Quellanimation
+ */
+ void SetFrame(int DestIndex, int SrcIndex);
+
+ /**
+ @brief Setzt den Animationstyp.
+ @param Type der Typ der Animation. Muss aus den enum BS_Animation::ANIMATION_TYPES sein.
+ */
+ void SetAnimationType(BS_Animation::ANIMATION_TYPES Type) { m_AnimationType = Type; }
+
+ /**
+ @brief Setzt die Abspielgeschwindigkeit.
+ @param FPS die Abspielgeschwindigkeit in Frames pro Sekunde.
+ */
+ void SetFPS(int FPS);
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+private:
+ std::vector<const Frame> m_Frames;
+ BS_AnimationResource * m_SourceAnimationPtr;
+ bool m_Valid;
+
+ BS_AnimationResource * RequestSourceAnimation(const std::string & SourceAnimation) const;
+ bool ValidateSourceIndex(unsigned int Index) const;
+ bool ValidateDestIndex(unsigned int Index) const;
+};
+
+#endif
diff --git a/engines/sword25/gfx/animationtemplateregistry.cpp b/engines/sword25/gfx/animationtemplateregistry.cpp
new file mode 100755
index 0000000000..aabea41417
--- /dev/null
+++ b/engines/sword25/gfx/animationtemplateregistry.cpp
@@ -0,0 +1,111 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "ANIMATIONTEMPLATEREGISTRY"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/inputpersistenceblock.h"
+#include "animationtemplateregistry.h"
+#include "animationtemplate.h"
+
+// -----------------------------------------------------------------------------
+// Implementation
+// -----------------------------------------------------------------------------
+
+std::auto_ptr<BS_AnimationTemplateRegistry> BS_AnimationTemplateRegistry::m_InstancePtr;
+
+// -----------------------------------------------------------------------------
+
+void BS_AnimationTemplateRegistry::LogErrorLn(const char * Message) const
+{
+ BS_LOG_ERRORLN(Message);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_AnimationTemplateRegistry::LogWarningLn(const char * Message) const
+{
+ BS_LOG_WARNINGLN(Message);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationTemplateRegistry::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ // Das nächste zu vergebene Handle schreiben.
+ Writer.Write(m_NextHandle);
+
+ // Anzahl an BS_AnimationTemplates schreiben.
+ Writer.Write(m_Handle2PtrMap.size());
+
+ // Alle BS_AnimationTemplates persistieren.
+ HANDLE2PTR_MAP::const_iterator Iter = m_Handle2PtrMap.begin();
+ while (Iter != m_Handle2PtrMap.end())
+ {
+ // Handle persistieren.
+ Writer.Write(Iter->first);
+
+ // Objekt persistieren.
+ Result &= Iter->second->Persist(Writer);
+
+ ++Iter;
+ }
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_AnimationTemplateRegistry::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ // Das nächste zu vergebene Handle wieder herstellen.
+ Reader.Read(m_NextHandle);
+
+ // Alle vorhandenen BS_AnimationTemplates zerstören.
+ while (!m_Handle2PtrMap.empty()) delete m_Handle2PtrMap.begin()->second;
+
+ // Anzahl an BS_AnimationTemplates einlesen.
+ unsigned int AnimationTemplateCount;
+ Reader.Read(AnimationTemplateCount);
+
+ // Alle gespeicherten BS_AnimationTemplates wieder herstellen.
+ for (unsigned int i = 0; i < AnimationTemplateCount; ++i)
+ {
+ // Handle lesen.
+ unsigned int Handle;
+ Reader.Read(Handle);
+
+ // BS_AnimationTemplate wieder herstellen.
+ Result &= (BS_AnimationTemplate::Create(Reader, Handle) != 0);
+ }
+
+ return Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/animationtemplateregistry.h b/engines/sword25/gfx/animationtemplateregistry.h
new file mode 100755
index 0000000000..78c83fd2bb
--- /dev/null
+++ b/engines/sword25/gfx/animationtemplateregistry.h
@@ -0,0 +1,64 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_ANIMATIONTEMPLATEREGISTRY_H
+#define BS_ANIMATIONTEMPLATEREGISTRY_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/persistable.h"
+#include "kernel/objectregistry.h"
+
+#include "kernel/memlog_off.h"
+#include <memory>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Forward Deklarationen
+// -----------------------------------------------------------------------------
+
+class BS_AnimationTemplate;
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_AnimationTemplateRegistry : public BS_ObjectRegistry<BS_AnimationTemplate>, public BS_Persistable
+{
+public:
+ static BS_AnimationTemplateRegistry & GetInstance()
+ {
+ if (!m_InstancePtr.get()) m_InstancePtr.reset(new BS_AnimationTemplateRegistry);
+ return *m_InstancePtr.get();
+ }
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+private:
+ virtual void LogErrorLn(const char * Message) const;
+ virtual void LogWarningLn(const char * Message) const;
+
+ static std::auto_ptr<BS_AnimationTemplateRegistry> m_InstancePtr;
+};
+
+#endif
diff --git a/engines/sword25/gfx/bitmap.cpp b/engines/sword25/gfx/bitmap.cpp
new file mode 100755
index 0000000000..85442a835a
--- /dev/null
+++ b/engines/sword25/gfx/bitmap.cpp
@@ -0,0 +1,214 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "bitmap.h"
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/inputpersistenceblock.h"
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "BITMAP"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_Bitmap::BS_Bitmap(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, TYPES Type, unsigned int Handle) :
+ BS_RenderObject(ParentPtr, Type, Handle),
+ m_ModulationColor(0xffffffff),
+ m_ScaleFactorX(1.0f),
+ m_ScaleFactorY(1.0f),
+ m_FlipH(false),
+ m_FlipV(false)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Bitmap::~BS_Bitmap()
+{
+}
+
+// -----------------------------------------------------------------------------
+// Darstellungsart festlegen
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetAlpha(int Alpha)
+{
+ if (!IsAlphaAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set alpha value on a bitmap that does not support alpha blending. Call was ignored.");
+ return;
+ }
+
+ if (Alpha < 0 || Alpha > 255)
+ {
+ int OldAlpha = Alpha;
+ if (Alpha < 0) Alpha = 0;
+ if (Alpha > 255) Alpha = 255;
+ BS_LOG_WARNINGLN("Tried to set an invalid alpha value (%d) on a bitmap. Value was changed to %d.", OldAlpha, Alpha);
+
+ return;
+ }
+
+ unsigned int NewModulationColor = (m_ModulationColor & 0x00ffffff) | Alpha << 24;
+ if (NewModulationColor != m_ModulationColor)
+ {
+ m_ModulationColor = NewModulationColor;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetModulationColor(unsigned int ModulationColor)
+{
+ if (!IsColorModulationAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set modulation color of a bitmap that does not support color modulation. Call was ignored.");
+ return;
+ }
+
+ unsigned int NewModulationColor = (ModulationColor & 0x00ffffff) | (m_ModulationColor & 0xff000000);
+ if (NewModulationColor != m_ModulationColor)
+ {
+ m_ModulationColor = NewModulationColor;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetScaleFactor(float ScaleFactor)
+{
+ SetScaleFactorX(ScaleFactor);
+ SetScaleFactorY(ScaleFactor);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetScaleFactorX(float ScaleFactorX)
+{
+ if (!IsScalingAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set scale factor of a bitmap that does not support scaling. Call was ignored.");
+ return;
+ }
+
+ if (ScaleFactorX < 0)
+ {
+ BS_LOG_WARNINGLN("Tried to set scale factor of a bitmap to a negative value. Call was ignored.");
+ return;
+ }
+
+ if (ScaleFactorX != m_ScaleFactorX)
+ {
+ m_ScaleFactorX = ScaleFactorX;
+ m_Width = static_cast<int>(m_OriginalWidth * m_ScaleFactorX);
+ if (m_ScaleFactorX <= 0.0f) m_ScaleFactorX = 0.001f;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetScaleFactorY(float ScaleFactorY)
+{
+ if (!IsScalingAllowed())
+ {
+ BS_LOG_WARNINGLN("Tried to set scale factor of a bitmap that does not support scaling. Call was ignored.");
+ return;
+ }
+
+ if (ScaleFactorY < 0)
+ {
+ BS_LOG_WARNINGLN("Tried to set scale factor of a bitmap to a negative value. Call was ignored.");
+ return;
+ }
+
+ if (ScaleFactorY != m_ScaleFactorY)
+ {
+ m_ScaleFactorY = ScaleFactorY;
+ m_Height = static_cast<int>(m_OriginalHeight * ScaleFactorY);
+ if (m_ScaleFactorY <= 0.0f) m_ScaleFactorY = 0.001f;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetFlipH(bool FlipH)
+{
+ m_FlipH = FlipH;
+ ForceRefresh();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Bitmap::SetFlipV(bool FlipV)
+{
+ m_FlipV = FlipV;
+ ForceRefresh();
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_Bitmap::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Persist(Writer);
+ Writer.Write(m_FlipH);
+ Writer.Write(m_FlipV);
+ Writer.Write(m_ScaleFactorX);
+ Writer.Write(m_ScaleFactorY);
+ Writer.Write(m_ModulationColor);
+ Writer.Write(m_OriginalWidth);
+ Writer.Write(m_OriginalHeight);
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Bitmap::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Unpersist(Reader);
+ Reader.Read(m_FlipH);
+ Reader.Read(m_FlipV);
+ Reader.Read(m_ScaleFactorX);
+ Reader.Read(m_ScaleFactorY);
+ Reader.Read(m_ModulationColor);
+ Reader.Read(m_OriginalWidth);
+ Reader.Read(m_OriginalHeight);
+
+ ForceRefresh();
+
+ return Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/bitmap.h b/engines/sword25/gfx/bitmap.h
new file mode 100755
index 0000000000..053dc8b9a1
--- /dev/null
+++ b/engines/sword25/gfx/bitmap.h
@@ -0,0 +1,167 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_BITMAP_H
+#define BS_BITMAP_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "renderobject.h"
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_Bitmap : public BS_RenderObject
+{
+protected:
+ BS_Bitmap(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, TYPES Type, unsigned int Handle = 0);
+
+public:
+
+ virtual ~BS_Bitmap();
+
+ /**
+ @brief Setzt den Alphawert des Bitmaps.
+ @param Alpha der neue Alphawert der Bitmaps (0 = keine Deckung, 255 = volle Deckung).
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsAlphaAllowed() true zurückgibt.
+ */
+ void SetAlpha(int Alpha);
+
+ /**
+ @brief Setzt die Modulationfarbe der Bitmaps.
+ @param Color eine 24-Bit Farbe, die die Modulationsfarbe des Bitmaps festlegt.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsColorModulationAllowed() true zurückgibt.
+ */
+ void SetModulationColor(unsigned int ModulationColor);
+
+ /**
+ @brief Setzt den Skalierungsfaktor des Bitmaps.
+ @param ScaleFactor der Faktor um den das Bitmap in beide Richtungen gestreckt werden soll.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ void SetScaleFactor(float ScaleFactor);
+
+ /**
+ @brief Setzt den Skalierungsfaktor der Bitmap auf der X-Achse.
+ @param ScaleFactor der Faktor um den die Bitmap in Richtungen der X-Achse gestreckt werden soll. Dieser Wert muss positiv sein.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ void SetScaleFactorX(float ScaleFactorX);
+
+ /**
+ @brief Setzt den Skalierungsfaktor der Bitmap auf der Y-Achse.
+ @param ScaleFactor der Faktor um den die Bitmap in Richtungen der Y-Achse gestreckt werden soll. Dieser Wert muss positiv sein.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ void SetScaleFactorY(float ScaleFactorY);
+
+ /**
+ @brief Legt fest, ob das Bild an der X-Achse gespiegelt werden soll.
+ */
+ void SetFlipH(bool FlipH);
+
+ /**
+ @brief Legt fest, ob das Bild an der Y-Achse gespiegelt werden soll.
+ */
+ void SetFlipV(bool FlipV);
+
+ /**
+ @brief Gibt den aktuellen Alphawert des Bildes zurück.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsAlphaAllowed() true zurückgibt.
+ */
+ int GetAlpha() { return m_ModulationColor >> 24; }
+
+ /**
+ @brief Gibt die aktuelle 24bit RGB Modulationsfarde des Bildes zurück.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsColorModulationAllowed() true zurückgibt.
+ */
+ int GetModulationColor() { return m_ModulationColor & 0x00ffffff; }
+
+ /**
+ @brief Gibt den Skalierungsfakter des Bitmaps auf der X-Achse zurück.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ float GetScaleFactorX() const { return m_ScaleFactorX; }
+
+ /**
+ @brief Gibt den Skalierungsfakter des Bitmaps auf der Y-Achse zurück.
+ @remark Diese Methode darf nur aufgerufen werden, wenn die Methode IsScalingAllowed() true zurückgibt.
+ */
+ float GetScaleFactorY() const { return m_ScaleFactorY; }
+
+ /**
+ @brief Gibt zurück, ob das Bild an der X-Achse gespiegelt angezeigt wird.
+ */
+ bool IsFlipH() { return m_FlipH; }
+
+ /**
+ @brief Gibt zurück, ob das Bild an der Y-Achse gespiegelt angezeigt wird.
+ */
+ bool IsFlipV() { return m_FlipV; }
+
+ // -----------------------------------------------------------------------------
+ // Die folgenden Methoden müssen alle BS_Bitmap-Klassen implementieren
+ // -----------------------------------------------------------------------------
+
+ /**
+ @brief Liest einen Pixel des Bildes.
+ @param X die X-Koordinate des Pixels.
+ @param Y die Y-Koordinate des Pixels
+ @return Gibt den 32-Bit Farbwert des Pixels an der übergebenen Koordinate zurück.
+ @remark Diese Methode sollte auf keine Fall benutzt werden um größere Teile des Bildes zu lesen, da sie sehr langsam ist. Sie ist
+ eher dafür gedacht einzelne Pixel des Bildes auszulesen.
+ */
+ virtual unsigned int GetPixel(int X, int Y) const = 0;
+
+ /**
+ @brief Füllt den Inhalt des Bildes mit Pixeldaten.
+ @param Pixeldata ein Vector der die Pixeldaten enthält. Sie müssen in dem Farbformat des Bildes vorliegen und es müssen genügend Daten
+ vorhanden sein, um das ganze Bild zu füllen.
+ @param Offset der Offset in Byte im Pixeldata-Vector an dem sich der erste zu schreibende Pixel befindet.<br>
+ Der Standardwert ist 0.
+ @param Stride der Abstand in Byte zwischen dem Zeilenende und dem Beginn einer neuen Zeile im Pixeldata-Vector.<br>
+ Der Standardwert ist 0.
+ @return Gibt false zurück, falls der Aufruf fehlgeschlagen ist.
+ @remark Ein Aufruf dieser Methode ist nur erlaubt, wenn IsSetContentAllowed() true zurückgibt.
+ */
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset = 0, unsigned int Stride = 0) = 0;
+
+ virtual bool IsScalingAllowed() const = 0;
+ virtual bool IsAlphaAllowed() const = 0;
+ virtual bool IsColorModulationAllowed() const = 0;
+ virtual bool IsSetContentAllowed() const = 0;
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+protected:
+ bool m_FlipH;
+ bool m_FlipV;
+ float m_ScaleFactorX;
+ float m_ScaleFactorY;
+ unsigned int m_ModulationColor;
+ int m_OriginalWidth;
+ int m_OriginalHeight;
+};
+
+#endif
diff --git a/engines/sword25/gfx/bitmapresource.cpp b/engines/sword25/gfx/bitmapresource.cpp
new file mode 100755
index 0000000000..af1638333e
--- /dev/null
+++ b/engines/sword25/gfx/bitmapresource.cpp
@@ -0,0 +1,54 @@
+// -----------------------------------------------------------------------------
+// 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 <memory>
+
+#include "bitmapresource.h"
+#include "kernel/kernel.h"
+#include "graphicengine.h"
+#include "image/imageloader.h"
+#include "package/packagemanager.h"
+
+#define BS_LOG_PREFIX "BITMAP"
+
+// Konstruktion / Destruktion
+// --------------------------
+
+BS_BitmapResource::BS_BitmapResource(const std::string & Filename, BS_Image * pImage) :
+ m_Valid(false),
+ m_pImage(pImage),
+ BS_Resource(Filename, BS_Resource::TYPE_BITMAP)
+{
+ m_Valid = m_pImage != 0;
+}
+
+BS_BitmapResource::~BS_BitmapResource()
+{
+ delete m_pImage;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_BitmapResource::GetPixel(int X, int Y) const
+{
+ BS_ASSERT(X >= 0 && X < m_pImage->GetWidth());
+ BS_ASSERT(Y >= 0 && Y < m_pImage->GetHeight());
+
+ return m_pImage->GetPixel(X, Y);
+}
diff --git a/engines/sword25/gfx/bitmapresource.h b/engines/sword25/gfx/bitmapresource.h
new file mode 100755
index 0000000000..0b0ea6db99
--- /dev/null
+++ b/engines/sword25/gfx/bitmapresource.h
@@ -0,0 +1,177 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_BITMAP_RESOURCE_H
+#define BS_BITMAP_RESOURCE_H
+
+// Includes
+#include "kernel/common.h"
+#include "kernel/resource.h"
+#include "image/image.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_Rect;
+
+class BS_BitmapResource : public BS_Resource
+{
+public:
+ /**
+ @brief Die möglichen Flippingparameter für die Blit-Methode.
+ */
+ enum FLIP_FLAGS
+ {
+ /// Das Bild wird nicht gespiegelt.
+ FLIP_NONE = 0,
+ /// Das Bild wird an der horizontalen Achse gespiegelt.
+ FLIP_H = 1,
+ /// Das Bild wird an der vertikalen Achse gespiegelt.
+ FLIP_V = 2,
+ /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt.
+ FLIP_HV = FLIP_H | FLIP_V,
+ /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt.
+ FLIP_VH = FLIP_H | FLIP_V
+ };
+
+ BS_BitmapResource(const std::string & Filename, BS_Image * pImage);
+ virtual ~BS_BitmapResource();
+
+ /**
+ @brief Gibt zurück, ob das Objekt einen gültigen Zustand hat.
+ */
+ bool IsValid() const { return m_Valid; }
+
+ /**
+ @brief Gibt die Breite des Bitmaps zurück.
+ */
+ int GetWidth() const { BS_ASSERT(m_pImage); return m_pImage->GetWidth(); }
+
+ /**
+ @brief Gibt die Höhe des Bitmaps zurück.
+ */
+ int GetHeight() const { BS_ASSERT(m_pImage); return m_pImage->GetHeight(); }
+
+ /**
+ @brief Rendert das Bild in den Framebuffer.
+ @param PosX die Position auf der X-Achse im Zielbild in Pixeln, an der das Bild gerendert werden soll.<br>
+ Der Standardwert ist 0.
+ @param PosY die Position auf der Y-Achse im Zielbild in Pixeln, an der das Bild gerendert werden soll.<br>
+ Der Standardwert ist 0.
+ @param Flipping gibt an, wie das Bild gespiegelt werden soll.<br>
+ Der Standardwert ist BS_Image::FLIP_NONE (keine Spiegelung)
+ @param pSrcPartRect Pointer auf ein BS_Rect, welches den Ausschnitt des Quellbildes spezifiziert, der gerendert
+ werden soll oder NULL, falls das gesamte Bild gerendert werden soll.<br>
+ Dieser Ausschnitt bezieht sich auf das ungespiegelte und unskalierte Bild.<br>
+ Der Standardwert ist NULL.
+ @param Color ein ARGB Farbwert, der die Parameter für die Farbmodulation und fürs Alphablending festlegt.<br>
+ Die Alpha-Komponente der Farbe bestimmt den Alphablending Parameter (0 = keine Deckung, 255 = volle Deckung).<br>
+ Die Farbkomponenten geben die Farbe für die Farbmodulation an.<br>
+ Der Standardwert is BS_ARGB(255, 255, 255, 255) (volle Deckung, keine Farbmodulation).
+ Zum Erzeugen des Farbwertes können die Makros BS_RGB und BS_ARGB benutzt werden.
+ @param Width gibt die Ausgabebreite des Bildausschnittes an.
+ Falls diese von der Breite des Bildausschnittes abweicht wird
+ das Bild entsprechend Skaliert.<br>
+ Der Wert -1 gibt an, dass das Bild nicht Skaliert werden soll.<br>
+ Der Standardwert ist -1.
+ @param Width gibt die Ausgabehöhe des Bildausschnittes an.
+ Falls diese von der Höhe des Bildauschnittes abweicht, wird
+ das Bild entsprechend Skaliert.<br>
+ Der Wert -1 gibt an, dass das Bild nicht Skaliert werden soll.<br>
+ Der Standardwert ist -1.
+ @return Gibt false zurück, falls das Rendern fehlgeschlagen ist.
+ @remark Er werden nicht alle Blitting-Operationen von allen BS_Image-Klassen unterstützt.<br>
+ Mehr Informationen gibt es in der Klassenbeschreibung von BS_Image und durch folgende Methoden:
+ - IsBlitTarget()
+ - IsScalingAllowed()
+ - IsFillingAllowed()
+ - IsAlphaAllowed()
+ - IsColorModulationAllowed()
+ */
+ bool Blit(int PosX = 0, int PosY = 0,
+ int Flipping = FLIP_NONE,
+ BS_Rect* pSrcPartRect = NULL,
+ unsigned int Color = BS_ARGB(255, 255, 255, 255),
+ int Width = -1, int Height = -1)
+ {
+ BS_ASSERT(m_pImage);
+ return m_pImage->Blit(PosX, PosY, Flipping, pSrcPartRect, Color, Width, Height);
+ }
+
+ /**
+ @brief Füllt einen Rechteckigen Bereich des Bildes mit einer Farbe.
+ @param pFillRect Pointer auf ein BS_Rect, welches den Ausschnitt des Bildes spezifiziert, der gefüllt
+ werden soll oder NULL, falls das gesamte Bild gefüllt werden soll.<br>
+ Der Standardwert ist NULL.
+ @param Color der 32 Bit Farbwert mit dem der Bildbereich gefüllt werden soll.
+ @remark Ein Aufruf dieser Methode ist nur gestattet, wenn IsFillingAllowed() true zurückgibt.
+ @remark Es ist möglich über die Methode transparente Rechtecke darzustellen, indem man eine Farbe mit einem Alphawert ungleich
+ 255 angibt.
+ @remark Unabhängig vom Farbformat des Bildes muss ein 32 Bit Farbwert angegeben werden. Zur Erzeugung, können die Makros
+ BS_RGB und BS_ARGB benutzt werden.
+ @remark Falls das Rechteck nicht völlig innerhalb des Bildschirms ist, wird es automatisch zurechtgestutzt.
+ */
+ bool Fill(const BS_Rect* pFillRect = 0, unsigned int Color = BS_RGB(0, 0, 0)) { BS_ASSERT(m_pImage); return m_pImage->Fill(pFillRect, Color); }
+
+ /**
+ @brief Liest einen Pixel des Bildes.
+ @param X die X-Koordinate des Pixels.
+ @param Y die Y-Koordinate des Pixels
+ @return Gibt den 32-Bit Farbwert des Pixels an der übergebenen Koordinate zurück.
+ @remark Diese Methode sollte auf keine Fall benutzt werden um größere Teile des Bildes zu lesen, da sie sehr langsam ist. Sie ist
+ eher dafür gedacht einzelne Pixel des Bildes auszulesen.
+ */
+ unsigned int GetPixel(int X, int Y) const;
+
+ //@{
+ /** @name Auskunfts-Methoden */
+
+ /**
+ @brief Überprüft, ob das BS_Image ein Zielbild für einen Blit-Aufruf sein kann.
+ @return Gibt false zurück, falls ein Blit-Aufruf mit diesem Objekt als Ziel nicht gestattet ist.
+ */
+ bool IsBlitTarget() { BS_ASSERT(m_pImage); return m_pImage->IsBlitTarget(); }
+
+ /**
+ @brief Gibt true zurück, falls das BS_Image bei einem Aufruf von Blit() skaliert dargestellt werden kann.
+ */
+ bool IsScalingAllowed() { BS_ASSERT(m_pImage); return m_pImage->IsScalingAllowed(); }
+
+ /**
+ @brief Gibt true zurück, wenn das BS_Image mit einem Aufruf von Fill() gefüllt werden kann.
+ */
+ bool IsFillingAllowed() { BS_ASSERT(m_pImage); return m_pImage->IsFillingAllowed(); }
+
+ /**
+ @brief Gibt true zurück, wenn das BS_Image bei einem Aufruf von Blit() mit einem Alphawert dargestellt werden kann.
+ */
+ bool IsAlphaAllowed() { BS_ASSERT(m_pImage); return m_pImage->IsAlphaAllowed(); }
+
+ /**
+ @brief Gibt true zurück, wenn das BS_Image bei einem Aufruf von Blit() mit Farbmodulation dargestellt werden kann.
+ */
+ bool IsColorModulationAllowed() { BS_ASSERT(m_pImage); return m_pImage->IsColorModulationAllowed(); }
+
+private:
+ BS_Image * m_pImage;
+ bool m_Valid;
+};
+
+#endif
diff --git a/engines/sword25/gfx/dynamicbitmap.cpp b/engines/sword25/gfx/dynamicbitmap.cpp
new file mode 100755
index 0000000000..6e2c258641
--- /dev/null
+++ b/engines/sword25/gfx/dynamicbitmap.cpp
@@ -0,0 +1,191 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "dynamicbitmap.h"
+#include "bitmapresource.h"
+#include "package/packagemanager.h"
+#include "kernel/inputpersistenceblock.h"
+
+#include <vector>
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "DYNAMICBITMAP"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_DynamicBitmap::BS_DynamicBitmap(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Width, unsigned int Height) :
+ BS_Bitmap(ParentPtr, TYPE_DYNAMICBITMAP)
+{
+ // Das BS_Bitmap konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
+ if (!m_InitSuccess) return;
+
+ m_InitSuccess = CreateGLImage(Width, Height);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_DynamicBitmap::BS_DynamicBitmap(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle) :
+ BS_Bitmap(ParentPtr, TYPE_DYNAMICBITMAP, Handle)
+{
+ m_InitSuccess = Unpersist(Reader);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::CreateGLImage(unsigned int Width, unsigned int Height)
+{
+ // GLImage mit den gewünschten Maßen erstellen
+ bool Result;
+ m_Image.reset(new BS_GLImage(Width, Height, Result));
+
+ m_OriginalWidth = m_Width = Width;
+ m_OriginalHeight = m_Height = Height;
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_DynamicBitmap::~BS_DynamicBitmap()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_DynamicBitmap::GetPixel(int X, int Y) const
+{
+ BS_ASSERT(X >= 0 && X < m_Width);
+ BS_ASSERT(Y >= 0 && Y < m_Height);
+
+ return m_Image->GetPixel(X, Y);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::DoRender()
+{
+ // Framebufferobjekt holen
+ BS_GraphicEngine * pGfx = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
+ BS_ASSERT(pGfx);
+
+ // Bitmap zeichnen
+ bool Result;
+ if (m_ScaleFactorX == 1.0f && m_ScaleFactorY == 1.0f)
+ {
+ Result = m_Image->Blit(m_AbsoluteX, m_AbsoluteY,
+ (m_FlipV ? BS_BitmapResource::FLIP_V : 0) |
+ (m_FlipH ? BS_BitmapResource::FLIP_H : 0),
+ 0, m_ModulationColor, -1, -1);
+ }
+ else
+ {
+ Result = m_Image->Blit(m_AbsoluteX, m_AbsoluteY,
+ (m_FlipV ? BS_BitmapResource::FLIP_V : 0) |
+ (m_FlipH ? BS_BitmapResource::FLIP_H : 0),
+ 0, m_ModulationColor, m_Width, m_Height);
+ }
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride)
+{
+ return m_Image->SetContent(Pixeldata, Offset, Stride);
+}
+
+// -----------------------------------------------------------------------------
+// Auskunftsmethoden
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::IsScalingAllowed() const
+{
+ return m_Image->IsScalingAllowed();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::IsAlphaAllowed() const
+{
+ return m_Image->IsAlphaAllowed();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::IsColorModulationAllowed() const
+{
+ return m_Image->IsColorModulationAllowed();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::IsSetContentAllowed() const
+{
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_DynamicBitmap::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ Result &= BS_Bitmap::Persist(Writer);
+
+ // Bilddaten werden nicht gespeichert. Dies ist auch nicht weiter von bedeutung, da BS_DynamicBitmap nur vom Videoplayer benutzt wird.
+ // Während ein Video abläuft kann niemals gespeichert werden. BS_DynamicBitmap kann nur der Vollständigkeit halber persistiert werden.
+ BS_LOG_WARNINGLN("Persisting a BS_DynamicBitmap. Bitmap content is not persisted.");
+
+ Result &= BS_RenderObject::PersistChildren(Writer);
+
+ return Result;
+}
+
+bool BS_DynamicBitmap::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ Result &= BS_Bitmap::Unpersist(Reader);
+
+ // Ein BS_GLImage mit den gespeicherten Maßen erstellen.
+ Result &= CreateGLImage(m_Width, m_Height);
+
+ // Bilddaten werden nicht gespeichert (s.o.).
+ BS_LOG_WARNINGLN("Unpersisting a BS_DynamicBitmap. Bitmap contents are missing.");
+
+ // Bild mit durchsichtigen Bilddaten initialisieren.
+ std::vector<unsigned char> TransparentImageData(m_Width * m_Height * 4);
+ m_Image->SetContent(TransparentImageData);
+
+ Result &= BS_RenderObject::UnpersistChildren(Reader);
+
+ return Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/dynamicbitmap.h b/engines/sword25/gfx/dynamicbitmap.h
new file mode 100755
index 0000000000..0eb856ce81
--- /dev/null
+++ b/engines/sword25/gfx/dynamicbitmap.h
@@ -0,0 +1,71 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_DYNAMIC_BITMAP_H
+#define BS_DYNAMIC_BITMAP_H
+
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/memlog_off.h"
+#include <memory>
+#include "kernel/memlog_on.h"
+
+#include "kernel/common.h"
+#include "bitmap.h"
+#include "opengl/glimage.h"
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_DynamicBitmap : public BS_Bitmap
+{
+friend BS_RenderObject;
+
+public:
+ virtual ~BS_DynamicBitmap();
+
+ virtual unsigned int GetPixel(int X, int Y) const;
+
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride);
+
+ virtual bool IsScalingAllowed() const;
+ virtual bool IsAlphaAllowed() const;
+ virtual bool IsColorModulationAllowed() const;
+ virtual bool IsSetContentAllowed() const;
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+protected:
+ virtual bool DoRender();
+
+private:
+ BS_DynamicBitmap(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Width, unsigned int Height);
+ BS_DynamicBitmap(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle);
+
+ bool CreateGLImage(unsigned int Width, unsigned int Height);
+
+ std::auto_ptr<BS_GLImage> m_Image;
+};
+
+#endif
diff --git a/engines/sword25/gfx/fontresource.cpp b/engines/sword25/gfx/fontresource.cpp
new file mode 100755
index 0000000000..3d2d12e992
--- /dev/null
+++ b/engines/sword25/gfx/fontresource.cpp
@@ -0,0 +1,243 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "FONTRESOURCE"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include <memory>
+
+#include "kernel/kernel.h"
+#include "kernel/string.h"
+#include "package/packagemanager.h"
+#include "util/tinyxml/tinyxml.h"
+
+#include "fontresource.h"
+
+// -----------------------------------------------------------------------------
+// Konstanten
+// -----------------------------------------------------------------------------
+
+static const unsigned int DEFAULT_LINEHEIGHT = 20;
+static const unsigned int DEFAULT_GAPWIDTH = 1;
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_FontResource::BS_FontResource(BS_Kernel* pKernel, const std::string& FileName) :
+ _pKernel(pKernel),
+ _Valid(false),
+ BS_Resource(FileName, BS_Resource::TYPE_FONT)
+{
+ // XML Fontdatei parsen
+ TiXmlDocument Doc;
+ if (!_ParseXMLDocument(FileName, Doc))
+ {
+ BS_LOG_ERRORLN("The following TinyXML-Error occured while parsing \"%s\": %s", GetFileName().c_str(), Doc.ErrorDesc());
+ return;
+ }
+
+ // Font-Tag finden
+ TiXmlElement* pElement = Doc.FirstChildElement("font");
+ if (!pElement)
+ {
+ BS_LOG_ERRORLN("No <font> tag found in \"%s\".", GetFileName().c_str());
+ return;
+ }
+
+ // Font-Tag parsen
+ std::string BitmapFileName;
+ if (!_ParseFontTag(*pElement, BitmapFileName, _LineHeight, _GapWidth))
+ {
+ BS_LOG_ERRORLN("An error occurred while parsing <font> tag in \"%s\".", GetFileName().c_str());
+ return;
+ }
+
+ // Absoluten, eindeutigen Pfad zur Bitmapdatei bestimmen und dabei auf vorhandensein prüfen
+ {
+ // Pointer auf den Package-Manager bekommen
+ BS_ASSERT(_pKernel);
+ BS_PackageManager* pPackage = static_cast<BS_PackageManager *>(_pKernel->GetService("package"));
+ BS_ASSERT(pPackage);
+
+ // Absoluten, eindeutigen Pfad bestimmen
+ _BitmapFileName = pPackage->GetAbsolutePath(BitmapFileName);
+ if (_BitmapFileName == "")
+ {
+ BS_LOG_ERRORLN("Image file \"%s\" was specified in <font> tag of \"%s\" but could not be found.",
+ _BitmapFileName.c_str(), GetFileName().c_str());
+ return;
+ }
+
+ // Bitmapdatei cachen
+ if (!_pKernel->GetResourceManager()->PrecacheResource(_BitmapFileName))
+ {
+ BS_LOG_ERRORLN("Could not precache \"%s\".", _BitmapFileName.c_str());
+ return;
+ }
+ }
+
+ // Das Erste Character-Tag finden
+ pElement = pElement->FirstChildElement("character");
+ if (!pElement)
+ {
+ BS_LOG_ERRORLN("No <character> tag found in \"%s\".", GetFileName().c_str());
+ return;
+ }
+
+ // Alle Character-Tags parsen
+ while (pElement)
+ {
+ int CharCode;
+ BS_Rect CharRect;
+
+ // Aktuelles Character-Tag parsen
+ if (!_ParseCharacterTag(*pElement, CharCode, CharRect))
+ {
+ BS_LOG_ERRORLN("An error occured while parsing a <character> tag in \"%s\".", GetFileName().c_str());
+ return;
+ }
+
+ // Ausgelesene Daten in das _CharacterRects-Array eintragen
+ BS_ASSERT(CharCode < 256);
+ _CharacterRects[CharCode] = CharRect;
+
+ // Zum nächsten Character-Tag iterieren
+ pElement = pElement->NextSiblingElement("character");
+ }
+
+ // Erfolg signalisieren
+ _Valid = true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FontResource::_ParseXMLDocument(const std::string & FileName, TiXmlDocument & Doc) const
+{
+ // Pointer auf den Package-Manager bekommen
+ BS_ASSERT(_pKernel);
+ BS_PackageManager* pPackage = static_cast<BS_PackageManager *>(_pKernel->GetService("package"));
+ BS_ASSERT(pPackage);
+
+ // Die Daten werden zunächst über den Package-Manager gelesen und dann in einen um ein Byte größeren Buffer kopiert
+ // und NULL-Terminiert, da TinyXML NULL-Terminierte Daten benötigt.
+ unsigned int FileSize;
+ char * LoadBuffer = (char*) pPackage->GetFile(GetFileName(), &FileSize);
+ if (!LoadBuffer)
+ {
+ BS_LOG_ERRORLN("Could not read \"%s\".", GetFileName().c_str());
+ return false;
+ }
+
+ // Daten kopieren und NULL-terminieren
+ std::vector<char> WorkBuffer(FileSize + 1);
+ memcpy(&WorkBuffer[0], LoadBuffer, FileSize);
+ delete LoadBuffer;
+ WorkBuffer[FileSize] = '\0';
+
+ // Daten parsen
+ Doc.Parse(&WorkBuffer[0]);
+
+ return !Doc.Error();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FontResource::_ParseFontTag(TiXmlElement & Tag, std::string & BitmapFileName, int & Lineheight, int & GapWidth) const
+{
+ // Bitmap Attribut auslesen
+ const char * BitmapString = Tag.Attribute("bitmap");
+ if (!BitmapString)
+ {
+ BS_LOG_ERRORLN("<font> tag without bitmap attribute occurred in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+ BitmapFileName = BitmapString;
+
+ // Lineheight Attribut auslesen
+ const char * LineheightString = Tag.Attribute("lineheight");
+ if (!LineheightString || !BS_String::ToInt(std::string(LineheightString), Lineheight) || Lineheight < 0)
+ {
+ BS_LOG_WARNINGLN("Illegal or missing lineheight attribute in <font> tag in \"%s\". Assuming default (\"%d\").",
+ GetFileName().c_str(), DEFAULT_LINEHEIGHT);
+ Lineheight = DEFAULT_LINEHEIGHT;
+ }
+
+
+ // Gap Attribut auslesen
+ const char * GapString = Tag.Attribute("gap");
+ if (!GapString || !BS_String::ToInt(std::string(GapString), GapWidth) || GapWidth < 0)
+ {
+ BS_LOG_WARNINGLN("Illegal or missing gap attribute in <font> tag in \"%s\". Assuming default (\"%d\").",
+ GetFileName().c_str(), DEFAULT_GAPWIDTH);
+ GapWidth = DEFAULT_GAPWIDTH;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FontResource::_ParseCharacterTag(TiXmlElement & Tag, int & Code, BS_Rect & Rect) const
+{
+ // Code Attribut auslesen
+ const char * CodeString = Tag.Attribute("code");
+ if (!CodeString || !BS_String::ToInt(std::string(CodeString), Code) || Code < 0 || Code >= 256)
+ {
+ BS_LOG_ERRORLN("Illegal or missing code attribute in <character> tag in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+
+ // Left Attribut auslesen
+ const char * LeftString = Tag.Attribute("left");
+ if (!LeftString || !BS_String::ToInt(std::string(LeftString), Rect.left) || Rect.left < 0)
+ {
+ BS_LOG_ERRORLN("Illegal or missing left attribute in <character> tag in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+
+ // Right Attribut auslesen
+ const char * RightString = Tag.Attribute("right");
+ if (!RightString || !BS_String::ToInt(RightString, Rect.right) || Rect.right < 0)
+ {
+ BS_LOG_ERRORLN("Illegal or missing right attribute in <character> tag in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+
+ // Top Attribut auslesen
+ const char * TopString = Tag.Attribute("top");
+ if (!TopString || !BS_String::ToInt(TopString, Rect.top) || Rect.top < 0)
+ {
+ BS_LOG_ERRORLN("Illegal or missing top attribute in <character> tag in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+
+ // Bottom Attribut auslesen
+ const char * BottomString = Tag.Attribute("bottom");
+ if (!BottomString || !BS_String::ToInt(BottomString, Rect.bottom) || Rect.bottom < 0)
+ {
+ BS_LOG_ERRORLN("Illegal or missing bottom attribute in <character> tag in \"%s\".", GetFileName().c_str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/engines/sword25/gfx/fontresource.h b/engines/sword25/gfx/fontresource.h
new file mode 100755
index 0000000000..adb790be6b
--- /dev/null
+++ b/engines/sword25/gfx/fontresource.h
@@ -0,0 +1,104 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_FONTRESOURCE_H
+#define BS_FONTRESOURCE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/resource.h"
+#include "math/rect.h"
+
+// -----------------------------------------------------------------------------
+// Forward declarations
+// -----------------------------------------------------------------------------
+
+class BS_Kernel;
+class TiXmlDocument;
+class TiXmlElement;
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FontResource : public BS_Resource
+{
+public:
+ /**
+ @brief Erzeugt eine neues Exemplar von BS_FontResource
+ @param pKernel ein Pointer auf den Kernel
+ @param FileName der Dateiname der zu ladenen Resource
+ @remark Wenn der Konstruktor erfolgreich ausgeführt werden konnte gibt die Methode IsValid true zurück.
+ */
+ BS_FontResource(BS_Kernel * pKernel, const std::string & FileName);
+
+ /**
+ @brief Gibt true zurück, wenn das Objekt korrekt initialisiert wurde.
+
+ Diese Methode kann dazu benutzt werden um festzustellen, ob der Konstruktor erfolgreich ausgeführt wurde.
+ */
+ bool IsValid() const { return _Valid; }
+
+ /**
+ @brief Gibt die Zeilenhöhe des Fonts in Pixeln zurück.
+
+ Die Zeilenhöhe ist der Wert, der zur Y-Koordinate addiert wird, wenn ein Zeilenumbruch auftritt.
+ */
+ int GetLineHeight() const { return _LineHeight; }
+
+ /**
+ @brief Gibt den Buchstabenabstand der Fonts in Pixeln zurück.
+
+ Der Buchstabenabstand ist der Wert, der zwischen zwei Buchstaben freigelassen wird.
+ */
+ int GetGapWidth() const { return _GapWidth; }
+
+ /**
+ @brief Gibt das Bounding-Rect eines Zeichens auf der Charactermap zurück.
+ @param Character der ASCII-Code des Zeichens
+ @return Das Bounding-Rect des übergebenen Zeichens auf der Charactermap.
+ */
+ const BS_Rect & GetCharacterRect(int Character) const { BS_ASSERT(Character >= 0 && Character < 256); return _CharacterRects[Character]; }
+
+ /**
+ @brief Gibt den Dateinamen der Charactermap zurück.
+ */
+ const std::string & GetCharactermapFileName() const { return _BitmapFileName; }
+
+private:
+ BS_Kernel * _pKernel;
+ bool _Valid;
+ std::string _BitmapFileName;
+ int _LineHeight;
+ int _GapWidth;
+ BS_Rect _CharacterRects[256];
+
+ // -----------------------------------------------------------------------------
+ // Hilfsmethoden
+ // -----------------------------------------------------------------------------
+
+ bool _ParseXMLDocument(const std::string & FileName, TiXmlDocument & Doc) const;
+ bool _ParseFontTag(TiXmlElement & Tag, std::string & BitmapFileName, int & LineHeight, int & GapWidth) const;
+ bool _ParseCharacterTag(TiXmlElement & Tag, int & Code, BS_Rect & Rect) const;
+};
+
+#endif
diff --git a/engines/sword25/gfx/framecounter.cpp b/engines/sword25/gfx/framecounter.cpp
new file mode 100755
index 0000000000..54c844967d
--- /dev/null
+++ b/engines/sword25/gfx/framecounter.cpp
@@ -0,0 +1,53 @@
+// -----------------------------------------------------------------------------
+// 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 "framecounter.h"
+#include "kernel/timer.h"
+
+BS_Framecounter::BS_Framecounter(int UpdateFrequency) :
+ m_FPS(0),
+ m_FPSCount(0),
+ m_LastUpdateTime(-1)
+{
+ SetUpdateFrequency(UpdateFrequency);
+}
+
+void BS_Framecounter::Update()
+{
+ // Aktuellen Systemtimerstand auslesen
+ uint64_t Timer = BS_Timer::GetMicroTicks();
+
+ // Falls m_LastUpdateTime == -1 ist, wird der Frame-Counter zum ersten Mal aufgerufen und der aktuelle Systemtimer als erster
+ // Messzeitpunkt genommen.
+ if (m_LastUpdateTime == -1)
+ m_LastUpdateTime = Timer;
+ else
+ {
+ // Die Anzahl der Frames im aktuellen Messzeitraum wird erhöht.
+ m_FPSCount++;
+
+ // Falls der Messzeitraum verstrichen ist, wird die durchschnittliche Framerate berechnet und ein neuer Messzeitraum begonnen.
+ if (Timer - m_LastUpdateTime >= m_UpdateDelay)
+ {
+ m_FPS = static_cast<int>((1000000 * (uint64_t)m_FPSCount) / (Timer - m_LastUpdateTime));
+ m_LastUpdateTime = Timer;
+ m_FPSCount = 0;
+ }
+ }
+}
diff --git a/engines/sword25/gfx/framecounter.h b/engines/sword25/gfx/framecounter.h
new file mode 100755
index 0000000000..79a2b04df6
--- /dev/null
+++ b/engines/sword25/gfx/framecounter.h
@@ -0,0 +1,76 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef _BS_FRAMECOUNTER_H
+#define _BS_FRAMECOUNTER_H
+
+// Includes
+#include "kernel/common.h"
+#include "kernel/bs_stdint.h"
+
+/**
+ @brief Eine einfache Klasse die einen Framecounter implementiert.
+*/
+class BS_Framecounter
+{
+private:
+ enum
+ {
+ DEFAULT_UPDATE_FREQUENCY = 10
+ };
+
+public:
+ /**
+ @brief Erzeugt ein neues BS_Framecounter Objekt.
+ @param UpdateFrequency gibt an wie oft der Framecounter in einer Sekunde aktualisiert werden soll.<br>
+ Der Standardwert ist 10.
+ */
+ BS_Framecounter(int UpdateFrequency = DEFAULT_UPDATE_FREQUENCY);
+
+ /**
+ @brief Bestimmt wie oft der Framecounter in einer Sekunde aktualisiert werden soll.
+ @param UpdateFrequency gibt an wie oft der Framecounter in einer Sekunde aktualisiert werden soll.
+ */
+ inline void SetUpdateFrequency(int UpdateFrequency);
+
+ /**
+ @brief Diese Methode muss einmal pro Frame aufgerufen werden.
+ */
+ void Update();
+
+ /**
+ @brief Gibt den aktuellen FPS-Wert zurück.
+ */
+ int GetFPS() const { return m_FPS; }
+
+private:
+ int m_FPS;
+ int m_FPSCount;
+ uint64_t m_LastUpdateTime;
+ uint64_t m_UpdateDelay;
+};
+
+// Inlines
+void BS_Framecounter::SetUpdateFrequency(int UpdateFrequency)
+{
+ // Frequenz in Laufzeit (in Microsekunden) umrechnen.
+ m_UpdateDelay = 1000000 / UpdateFrequency;
+}
+
+#endif
diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
new file mode 100755
index 0000000000..b8ad3a04bd
--- /dev/null
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -0,0 +1,218 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "GRAPHICENGINE"
+
+#include "image/image.h"
+#include "screenshot.h"
+#include "kernel/memlog_off.h"
+#include <memory>
+#include <vector>
+#include "kernel/memlog_on.h"
+#include "kernel/inputpersistenceblock.h"
+#include "kernel/outputpersistenceblock.h"
+
+extern "C"
+{
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+using namespace std;
+
+// -----------------------------------------------------------------------------
+// Constants
+// -----------------------------------------------------------------------------
+
+static const unsigned int FRAMETIME_SAMPLE_COUNT = 5; // Anzahl der Framezeiten über die, die Framezeit gemittelt wird
+
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "graphicengine.h"
+
+// -----------------------------------------------------------------------------
+
+BS_GraphicEngine::BS_GraphicEngine(BS_Kernel * pKernel) :
+ m_Width(0),
+ m_Height(0),
+ m_BitDepth(0),
+ m_Windowed(0),
+ m_LastTimeStamp(9223372036854775807), // max. BS_INT64 um beim ersten Aufruf von _UpdateLastFrameDuration() einen Reset zu erzwingen
+ m_LastFrameDuration(0),
+ m_TimerActive(true),
+ m_FrameTimeSamples(FRAMETIME_SAMPLE_COUNT, 0),
+ m_FrameTimeSampleSlot(0),
+ m_RepaintedPixels(0),
+ BS_ResourceService(pKernel)
+{
+ if (!RegisterScriptBindings())
+ BS_LOG_ERRORLN("Script bindings could not be registered.");
+ else
+ BS_LOGLN("Script bindings registered.");
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_GraphicEngine::UpdateLastFrameDuration()
+{
+ // Aktuelle Zeit holen
+ uint64_t CurrentTime = BS_Kernel::GetInstance()->GetMicroTicks();
+
+ // Verstrichene Zeit seit letztem Frame berechnen und zu große Zeitsprünge ( > 250 msek.) unterbinden
+ // (kann vorkommen bei geladenen Spielständen, während des Debuggings oder Hardwareungenauigkeiten)
+ m_FrameTimeSamples[m_FrameTimeSampleSlot] = static_cast<unsigned int>(CurrentTime - m_LastTimeStamp);
+ if (m_FrameTimeSamples[m_FrameTimeSampleSlot] > 250000) m_FrameTimeSamples[m_FrameTimeSampleSlot] = 250000;
+ m_FrameTimeSampleSlot = (m_FrameTimeSampleSlot + 1) % FRAMETIME_SAMPLE_COUNT;
+
+ // Die Framezeit wird über mehrere Frames gemittelt um Ausreisser zu eliminieren
+ std::vector<unsigned int>::const_iterator it = m_FrameTimeSamples.begin();
+ unsigned int Sum = *it;
+ for (it++; it != m_FrameTimeSamples.end(); it++) Sum += *it;
+ m_LastFrameDuration = Sum / FRAMETIME_SAMPLE_COUNT;
+
+ // _LastTimeStamp auf die Zeit des aktuellen Frames setzen
+ m_LastTimeStamp = CurrentTime;
+}
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ bool DoSaveScreenshot(BS_GraphicEngine & GraphicEngine, const std::string & Filename, bool Thumbnail)
+ {
+ unsigned int Width;
+ unsigned int Height;
+ vector<unsigned int> Data;
+ if (!GraphicEngine.GetScreenshot(Width, Height, Data))
+ {
+ BS_LOG_ERRORLN("Call to GetScreenshot() failed. Cannot save screenshot.");
+ return false;
+ }
+
+ unsigned int test = Data.size();
+
+ if (Thumbnail)
+ return BS_Screenshot::SaveThumbnailToFile(Width, Height, Data, Filename);
+ else
+ return BS_Screenshot::SaveToFile(Width, Height, Data, Filename);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GraphicEngine::SaveScreenshot(const std::string & Filename)
+{
+ return DoSaveScreenshot(*this, Filename, false);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GraphicEngine::SaveThumbnailScreenshot( const std::string & Filename )
+{
+ return DoSaveScreenshot(*this, Filename, true);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_GraphicEngine::ARGBColorToLuaColor(lua_State * L, unsigned int Color)
+{
+ lua_Number Components[4] =
+ {
+ (Color >> 16) & 0xff, // Rot
+ (Color >> 8) & 0xff, // Grün
+ Color & 0xff, // Blau
+ Color >> 24, // Alpha
+ };
+
+ lua_newtable(L);
+
+ for (unsigned int i = 1; i <= 4; i++)
+ {
+ lua_pushnumber(L, i);
+ lua_pushnumber(L, Components[i - 1]);
+ lua_settable(L, -3);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_GraphicEngine::LuaColorToARGBColor(lua_State * L, int StackIndex)
+{
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Sicherstellen, dass wir wirklich eine Tabelle betrachten
+ luaL_checktype(L, StackIndex, LUA_TTABLE);
+ // Größe der Tabelle auslesen
+ unsigned int n = luaL_getn(L, StackIndex);
+ // RGB oder RGBA Farben werden unterstützt und sonst keine
+ if (n != 3 && n != 4) luaL_argcheck(L, 0, StackIndex, "at least 3 of the 4 color components have to be specified");
+
+ // Rote Farbkomponente auslesen
+ lua_rawgeti(L, StackIndex, 1);
+ unsigned int Red = static_cast<unsigned int>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || Red >= 256) luaL_argcheck(L, 0, StackIndex, "red color component must be an integer between 0 and 255");
+ lua_pop(L, 1);
+
+ // Grüne Farbkomponente auslesen
+ lua_rawgeti(L, StackIndex, 2);
+ unsigned int Green = static_cast<unsigned int>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || Green >= 256) luaL_argcheck(L, 0, StackIndex, "green color component must be an integer between 0 and 255");
+ lua_pop(L, 1);
+
+ // Blaue Farbkomponente auslesen
+ lua_rawgeti(L, StackIndex, 3);
+ unsigned int Blue = static_cast<unsigned int>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || Blue >= 256) luaL_argcheck(L, 0, StackIndex, "blue color component must be an integer between 0 and 255");
+ lua_pop(L, 1);
+
+ // Alpha Farbkomponente auslesen
+ unsigned int Alpha = 0xff;
+ if (n == 4)
+ {
+ lua_rawgeti(L, StackIndex, 4);
+ Alpha = static_cast<unsigned int>(lua_tonumber(L, -1));
+ if (!lua_isnumber(L, -1) || Alpha >= 256) luaL_argcheck(L, 0, StackIndex, "alpha color component must be an integer between 0 and 255");
+ lua_pop(L, 1);
+ }
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return (Alpha << 24) | (Red << 16) | (Green << 8) | Blue;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GraphicEngine::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ Writer.Write(m_TimerActive);
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GraphicEngine::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ Reader.Read(m_TimerActive);
+ return Reader.IsGood();
+}
diff --git a/engines/sword25/gfx/graphicengine.h b/engines/sword25/gfx/graphicengine.h
new file mode 100755
index 0000000000..9fe8fd93fd
--- /dev/null
+++ b/engines/sword25/gfx/graphicengine.h
@@ -0,0 +1,401 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ BS_GraphicEngine
+ ----------------
+ Dies ist das Graphik-Engine Interface, dass alle Methoden und Klassen enthält, die eine
+ Graphik-Engine implementieren muss.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_GRAPHICENGINE_H
+#define _BS_GRAPHICENGINE_H
+
+// Includes
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+#include "kernel/common.h"
+#include "kernel/bs_stdint.h"
+#include "kernel/resservice.h"
+#include "kernel/persistable.h"
+#include "math/rect.h"
+#include "framecounter.h"
+#include "renderobjectptr.h"
+
+class BS_Kernel;
+class BS_Image;
+class BS_Panel;
+class BS_Screenshot;
+
+// Typen
+typedef unsigned int BS_COLOR;
+
+// Makros
+#define BS_RGB(R,G,B) (0xFF000000 | ((R) << 16) | ((G) << 8) | (B))
+#define BS_ARGB(A,R,G,B) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B))
+
+/**
+ @brief Dies ist das Graphik-Engine Interface, dass alle Methoden und Klassen enthält, die eine Graphik-Engine implementieren muss.
+
+ Hier sind nur wenige Rumpffunktionen realisiert, wie z.B. das Abfragen der Parameter des Ausgabepuffers.
+ Die Hauptfunktionen muss eine Implementation dieses Inferfaces stellen.<br>
+ Die bisher einzige Implementation ist BS_DDrawGfx.
+*/
+
+class BS_GraphicEngine : public BS_ResourceService, public BS_Persistable
+{
+public:
+ // Enums
+ // -----
+
+ // Farbformate
+ /**
+ @brief Die von der Engine benutzten Farbformate
+ */
+ enum COLOR_FORMATS
+ {
+ /// Undefiniertes/unbekanntes Farbformat
+ CF_UNKNOWN = 0,
+ /// 16 Bit Farbformat (5 Bit Rot, 5 Bit Grün, 5 Bit Blau)
+ CF_RGB15,
+ /// 16 Bit Farbformat (5 Bit Rot, 6 Bit Grün, 5 Bit Blau)
+ CF_RGB16,
+ /**
+ Spezielles Alpha-Farbformat der Engine, welches besonders schnelles Darstellen unter Benutzung von MMX-Befehlen unterstützt.<br>
+ Die Pixel sind 16 Bit breit und haben das selbe Format wie #CF_RGB15. Zusätzlich besitzt jeder Pixel noch einen 8 Bit Alphawert.<br>
+ Es werden jeweils 4 Pixel und 4 Alphawerte zu einem 12 Byte großen Datenblock zusammengefasst.<br>
+ Dabei werden die Daten in folgender Reihenfolge abgelegt:
+ Alpha0 Alpha1 Alpha2 Alpha3 Pixel0 Pixel1 Pixel2 Pixel3
+ Falls die Pixelanzahl einer Zeile nicht durch 4 teilbar ist, wird der letzte Pixelblock trotzdem komplett abgespeichert, die
+ nicht verwendeten Pixel- und Alphawerte können beliebige Werte haben.
+ */
+ CF_RGB15_INTERLEAVED,
+ /**
+ Spezielles Alpha-Farbformat der Engine, welches besonders schnelles Darstellen unter Benutzung von MMX-Befehlen unterstützt.<br>
+ Die Pixel sind 16 Bit breit und haben das selbe Format wie #CF_RGB16. Zusätzlich besitzt jeder Pixel noch einen 8 Bit Alphawert.<br>
+ Es werden jeweils 4 Pixel und 4 Alphawerte zu einem 12 Byte großen Datenblock zusammengefasst.<br>
+ Dabei werden die Daten in folgender Reihenfolge abgelegt:
+ Alpha0 Alpha1 Alpha2 Alpha3 Pixel0 Pixel1 Pixel2 Pixel3
+ Falls die Pixelanzahl einer Zeile nicht durch 4 teilbar ist, wird der letzte Pixelblock trotzdem komplett abgespeichert, die
+ nicht verwendeten Pixel- und Alphawerte können beliebige Werte haben.
+ */
+ CF_RGB16_INTERLEAVED,
+ /**
+ 24 Bit Farbformat (8 Bit Rot, 8 Bit Grün, 8 Bit Blau)
+ */
+ CF_RGB24,
+ /**
+ 32 Bit Farbformat (8 Bit Alpha, 8 Bit Rot, 8 Bit Grün, 8 Bit Blau) (little endian)
+ */
+ CF_ARGB32,
+ /**
+ 32 Bit Farbformat (8 Bit Alpha, 8 Bit Blau, 8 Bit Grün, 8 Bit Rot) (little endian)
+ */
+ CF_ABGR32,
+ };
+
+ // Interface
+ // ---------
+
+ /**
+ @brief Initialisiert die Graphikengine und setzt den Bildschirmmodus.
+ @param Width die Breite des Ausgabepuffers in Pixeln.<br>Der Standardwert ist 800.
+ @param Height die Höhe des Ausgabepuffers in Pixeln.<br>Der Standardwert ist 600.
+ @param BitDepth die Bittiefe des gewünschten Ausgabepuffers in Bit.<br>Der Standardwert ist 16.
+ @param BackbufferCount die Anzahl an Backbuffern die erzeugt werden soll.<br>Der Standardwert ist 2.
+ @param Windowed gibt an, ob die Engine im Fenstermodus laufen soll. Falls true angegeben wird, wird ein Fenster geöffnet in das
+ die Ausgaben gerendert werden. Ansonsten wird ein Vollbildmodus gesetzt der den Parametern das Ausgabepuffers
+ entspricht.
+ @return Gibt false zurück, falls die Initialisierung fehlgeschlagen ist.
+ @remark Der Fenstermodus sollte nur zu Debuggingzwecken benutzt werden und ist nicht dafür gedacht im endgültigen Produkt benutzt
+ zu werden.
+ @remark Diese Methode sollte direkt nach der Initialisierung aller Services aufgerufen werden.
+ */
+ virtual bool Init(int Width = 800, int Height = 600, int BitDepth = 16, int BackbufferCount = 2, bool Windowed = false) = 0;
+
+ //@{
+ /** @name Frame-Methoden */
+ /**
+ @brief Beginnt das Rendern eines neuen Frames.
+ @param UpdateAll gibt an, ob der Renderer im nächsten Frame alles neu zeichnen soll.<br>
+ Diese Funktion kann nützlich sein, wenn der Renderer mit Dirty-Rectangles arbeitet, der Benutzer aber gelegentlich
+ darauf angewiesen ist, dass der gesamte Bildschirminhalt neu gezeichnet werden soll.<br>
+ Der Standardwert ist false.
+ Diese Methode muss am Anfang das Main-Loops aufgerufen werden und vor dem Aufruf jeglicher Rendermethoden.
+ @return Gibt false zurück, falls ein Fehler aufgetreten ist.
+ @remark Implementationen dieser Methode müssen _UpdateLastFrameDuration() aufrufen.
+ */
+ virtual bool StartFrame(bool UpdateAll = false) = 0;
+
+ /**
+ @brief Beendet das Rendern des Frames und stellt diesen auf dem Bildschirm dar.
+
+ Diese Methode muss am Ende des Main-Loops aufgerufen werden. Nach dem Aufruf dürfen keine weiteren Rendermethoden mehr aufgerufen
+ werden. Dafür muss erst wieder ein Aufruf von #StartFrame erfolgen.
+ @return Gibt false zurück, falls ein Fehler aufgetreten ist:
+ */
+ virtual bool EndFrame() = 0;
+
+ //@}
+
+ //@{
+ /** @name Debug-Methoden */
+
+ /**
+ @brief Zeichnet eine Line in den Framebuffer.
+
+ Diese Methode muss zwischen StartFrame() und EndFrame() aufgerufen werden und ist nur für Debugzwecke gedacht.
+ Die Linie erscheint nur für einen Frame. Wenn die Linie dauerhaft zu sehen sein soll, muss sie jeden Frame neu
+ gezeichnet werden.
+
+ @param Start der Startpunkt der Linie
+ @param End der Endpunkt der Linie
+ @param Color die Farbe der Linie. Der Standardwert ist BS_RGB(255, 255, 255) (Weiß).
+ */
+ virtual void DrawDebugLine(const BS_Vertex & Start, const BS_Vertex & End, unsigned int Color = BS_RGB(255, 255, 255)) = 0;
+
+ /**
+ @brief Erstellt einen Screenshot.
+
+ Erstellt einen Screenshot vom aktuellen Framebuffer und schreibt ihn in eine Grafikdatei.<br>
+ Das verwendete Dateiformat ist PNG.
+
+ @param Der Dateiname des Screenshots.
+ @return Gibt true zurück, wenn der Screenshot gespeichert werden konnte, ansonsten false.
+ @remark Diese Methode darf erst nach einem Aufruf von EndFrame() und vor dem nächsten Aufruf von StartFrame() aufgerufen werden.
+ */
+ bool SaveScreenshot(const std::string & Filename);
+
+ /**
+ @Brief Erstellt einen kleinen Screenshot.
+
+ Erstellt einen Screenshot mit den Maßen 200x125. Hierfür werden am oberen und unteren Bildschirmrand die Interfaceleisten abgeschnitten und
+ das Bild auf ein 16tel seiner Ursprungsgröße verkleinert.
+
+ @param Der Dateiname des Screenshots.
+ @return Gibt true zurück, wenn der Screenshot gespeichert werden konnte, ansonsten false.
+ @remark Diese Methode darf erst nach einem Aufruf von EndFrame() und vor dem nächsten Aufruf von StartFrame() aufgerufen werden.
+ @remark Der Framebuffer muss eine Auflösung von 800x600 haben.
+ */
+ bool SaveThumbnailScreenshot(const std::string & Filename);
+
+ /**
+ @brief Liest den aktuellen Inhalt des Framebuffer aus.
+ @param Width enthält nach einem erfolgreichen Aufruf die Breite des Framebuffers.
+ @param Height enthält nach einem erfolgreichen Aufruf die Höhe des Framebuffers.
+ @param Data enthält nach einem erfolgreichen Aufruf den Inhalt des Framebuffers als 32-Bit Farbwerte.
+ @return Gibt true zurück, wenn der Aufruf erfolgreich war, ansonsten false.
+ @remark Diese Methode ist für das Erstellen von Screenshots gedacht. Sie muss also nicht sehr effizient sein.
+ @remark Diese Methode darf erst nach einem Aufruf von EndFrame() und vor dem nächsten Aufruf von StartFrame() aufgerufen werden.
+ */
+ virtual bool GetScreenshot(unsigned int & Width, unsigned int & Height, std::vector<unsigned int> & Data) = 0;
+
+ //@}
+
+ virtual BS_RenderObjectPtr<BS_Panel> GetMainPanel() = 0;
+
+ /**
+ @brief Gibt die Zeit (in Microsekunden) zurück die seit dem letzten Frame vergangen ist.
+ */
+ int GetLastFrameDurationMicro() { if (m_TimerActive) return m_LastFrameDuration; else return 0; }
+
+ /**
+ @brief Gibt die Zeit (in Sekunden) zurück die seit dem letzten Frame vergangen ist.
+ */
+ float GetLastFrameDuration() { if (m_TimerActive) return static_cast<float>(m_LastFrameDuration) / 1000000.0f; else return 0; }
+
+ void StopMainTimer() { m_TimerActive = false; }
+ void ResumeMainTimer() { m_TimerActive = true; }
+ float GetSecondaryFrameDuration() { return static_cast<float>(m_LastFrameDuration) / 1000000.0f; }
+
+ //@{
+ /** @name Accessor-Methoden */
+
+ /**
+ @brief Gibt die Breite des Ausgabepuffers in Pixeln zurück.
+ */
+ int GetDisplayWidth() { return m_Width; }
+
+ /**
+ @brief Gibt die Höhe des Ausgabepuffers in Pixeln zurück.
+ */
+ int GetDisplayHeight() { return m_Height; }
+
+ /**
+ @brief Gibt die Bounding-Box des Ausgabepuffers zurück. (0, 0, Width, Height)
+ */
+ BS_Rect& GetDisplayRect() { return m_ScreenRect; }
+
+ /**
+ @brief Gibt die Bittiefe des Ausgabepuffers zurück.
+ */
+ int GetBitDepth() { return m_BitDepth; }
+
+ /**
+ @brief Legt fest ob der Framebufferwechsel mit dem vertikalen Strahlenrücklauf synchronisiert werden soll.<br>
+ Vsync ist standardmäßig eingeschaltet.
+ @param Vsync gibt an, ob der Framebufferwechsel mit dem vertikalen Strahlenrücklauf synchronisiert werden soll.
+ @remark Im Fenstermodus hat diese Einstellung keine Auswirkung.
+ */
+ virtual void SetVsync(bool Vsync) = 0;
+
+ /**
+ @brief Gibt true zurück, wenn V-Sync an ist.
+ @remark Im Fenstermodus hat diese Einstellung keine Auswirkung.
+ */
+ virtual bool GetVsync() const = 0;
+
+ /**
+ @brief Gibt true zurück, falls die Engine im Fenstermodus läuft.
+ */
+ bool IsWindowed() { return m_Windowed; }
+
+ /**
+ @brief Füllt einen Rechteckigen Bereich des Framebuffers mit einer Farbe.
+ @param FillRectPtr Pointer auf ein BS_Rect, welches den Ausschnitt des Framebuffers spezifiziert, der gefüllt
+ werden soll oder 0, falls das gesamte Bild gefüllt werden soll.<br>
+ Der Standardwert ist 0.
+ @param Color der 32 Bit Farbwert mit dem der Bildbereich gefüllt werden soll.<br>
+ Der Standardwert ist BS_RGB(0, 0, 0) (Schwarz).
+ @return Gibt true zurück, wenn der Aufruf erfolgreich war, ansonsten false.
+ @remark Es ist möglich über die Methode transparente Rechtecke darzustellen, indem man eine Farbe mit einem
+ Alphawert ungleich 255 angibt.
+ @remark Falls das Rechteck nicht völlig innerhalb des Bildschirms ist, wird es automatisch zurechtgestutzt.
+ */
+ virtual bool Fill(const BS_Rect * FillRectPtr = 0, unsigned int Color = BS_RGB(0, 0, 0)) = 0;
+
+ //@}
+
+ //@{
+ /** @name Debugging-Methoden */
+
+ int GetFPSCount() const { return m_FPSCounter.GetFPS(); }
+ int GetRepaintedPixels() const { return m_RepaintedPixels; }
+
+ //@}
+
+ //@{
+ /** @name Auskunfts-Methoden */
+
+ /**
+ @brief Gibt die Größe eines Pixeleintrages in Byte für ein bestimmtes Farbformat zurück
+ @param ColorFormat das gewünschte Farbformat. Der Parameter muss vom Typ COLOR_FORMATS sein.
+ @return Gibt die Größe eines Pixeleintrages in Byte des Farbsformates ColorFormat zurück.<br>
+ Falls das Farbformat unbekannt ist, wird -1 zurückgegeben.
+ */
+ static int GetPixelSize(BS_GraphicEngine::COLOR_FORMATS ColorFormat)
+ {
+ switch (ColorFormat)
+ {
+ case BS_GraphicEngine::CF_RGB16:
+ case BS_GraphicEngine::CF_RGB15:
+ return 2;
+
+ case BS_GraphicEngine::CF_RGB16_INTERLEAVED:
+ case BS_GraphicEngine::CF_RGB15_INTERLEAVED:
+ return 3;
+
+ case BS_GraphicEngine::CF_ARGB32:
+ return 4;
+ }
+
+ return -1;
+ }
+
+ /**
+ @brief Berechnet die Länge einer Bildzeile eines Bilder in Byte, abhängig vom Farbformat.
+ @param ColorFormat das Farbformat des Bildes.
+ @param Width die Länge einer Bildzeile in Pixel.
+ @return Gibt die Länge einer Bildzeile in Byte wieder.<br>
+ Falls das Farbformat unbekannt ist, wird -1 zurückgegeben.
+ */
+ static int CalcPitch(BS_GraphicEngine::COLOR_FORMATS ColorFormat, int Width)
+ {
+ switch (ColorFormat)
+ {
+ case BS_GraphicEngine::CF_RGB16:
+ case BS_GraphicEngine::CF_RGB15:
+ return Width * 2;
+
+ case BS_GraphicEngine::CF_RGB16_INTERLEAVED:
+ case BS_GraphicEngine::CF_RGB15_INTERLEAVED:
+ return (Width + 3) / 4 * 12;
+
+ case BS_GraphicEngine::CF_ARGB32:
+ case BS_GraphicEngine::CF_ABGR32:
+ return Width * 4;
+
+ default:
+ BS_ASSERT(false);
+ }
+
+ return -1;
+ }
+
+ //@}
+
+ // Persistenz Methoden
+ // -------------------
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+ static void ARGBColorToLuaColor(lua_State * L, unsigned int Color);
+ static unsigned int LuaColorToARGBColor(lua_State * L, int StackIndex);
+
+protected:
+ // Konstruktor
+ // -----------
+ BS_GraphicEngine(BS_Kernel* pKernel);
+
+ // Display Variablen
+ // -----------------
+ int m_Width;
+ int m_Height;
+ BS_Rect m_ScreenRect;
+ int m_BitDepth;
+ bool m_Windowed;
+
+ // Debugging-Variablen
+ // -------------------
+ BS_Framecounter m_FPSCounter;
+
+ unsigned int m_RepaintedPixels;
+
+ /**
+ @brief Berechnet die Zeit die seit dem letzten Framebeginn vergangen ist.
+ */
+ void UpdateLastFrameDuration();
+
+private:
+ bool RegisterScriptBindings();
+
+ // LastFrameDuration-Variablen
+ // ---------------------------
+ uint64_t m_LastTimeStamp;
+ unsigned int m_LastFrameDuration;
+ bool m_TimerActive;
+ std::vector<unsigned int> m_FrameTimeSamples;
+ unsigned int m_FrameTimeSampleSlot;
+};
+
+#endif
diff --git a/engines/sword25/gfx/graphicengine_script.cpp b/engines/sword25/gfx/graphicengine_script.cpp
new file mode 100755
index 0000000000..5419f09f2c
--- /dev/null
+++ b/engines/sword25/gfx/graphicengine_script.cpp
@@ -0,0 +1,1722 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include <algorithm>
+#include <string>
+
+#include "kernel/common.h"
+#include "kernel/kernel.h"
+#include "kernel/callbackregistry.h"
+#include "script/script.h"
+#include "script/luabindhelper.h"
+#include "script/luacallback.h"
+#include "math/vertex.h"
+
+#include "graphicengine.h"
+#include "renderobject.h"
+#include "bitmap.h"
+#include "animation.h"
+#include "panel.h"
+#include "text.h"
+#include "animationtemplate.h"
+#include "animationtemplateregistry.h"
+
+#define BS_LOG_PREFIX "GRAPHICENGINE"
+
+// -----------------------------------------------------------------------------
+// Callback-Objekte
+// -----------------------------------------------------------------------------
+
+static bool AnimationDeleteCallback(unsigned int Data);
+static bool AnimationActionCallback(unsigned int Data);
+static bool AnimationLoopPointCallback(unsigned int Data);
+
+namespace
+{
+ // -------------------------------------------------------------------------
+
+ class ActionCallback : public BS_LuaCallback
+ {
+ public:
+ ActionCallback(lua_State * L) : BS_LuaCallback(L) {};
+
+ std::string Action;
+
+ protected:
+ virtual int PreFunctionInvokation(lua_State * L)
+ {
+ lua_pushstring(L, Action.c_str());
+ return 1;
+ }
+ };
+
+ std::auto_ptr<BS_LuaCallback> LoopPointCallbackPtr;
+ std::auto_ptr<ActionCallback> ActionCallbackPtr;
+
+ // -------------------------------------------------------------------------
+
+ struct CallbackfunctionRegisterer
+ {
+ CallbackfunctionRegisterer()
+ {
+ BS_CallbackRegistry::GetInstance().RegisterCallbackFunction("LuaLoopPointCB", AnimationLoopPointCallback);
+ BS_CallbackRegistry::GetInstance().RegisterCallbackFunction("LuaActionCB", AnimationActionCallback);
+ BS_CallbackRegistry::GetInstance().RegisterCallbackFunction("LuaDeleteCB", AnimationDeleteCallback);
+ }
+ };
+ static CallbackfunctionRegisterer Instance;
+}
+
+// -----------------------------------------------------------------------------
+// Constants
+// -----------------------------------------------------------------------------
+
+// Die Strings werden als #defines definiert um Stringkomposition zur Compilezeit zu ermöglichen.
+#define RENDEROBJECT_CLASS_NAME "Gfx.RenderObject"
+#define BITMAP_CLASS_NAME "Gfx.Bitmap"
+#define PANEL_CLASS_NAME "Gfx.Panel"
+#define TEXT_CLASS_NAME "Gfx.Text"
+#define ANIMATION_CLASS_NAME "Gfx.Animation"
+#define ANIMATION_TEMPLATE_CLASS_NAME "Gfx.AnimationTemplate"
+static const char * GFX_LIBRARY_NAME = "Gfx";
+
+// -----------------------------------------------------------------------------
+
+// Wie luaL_checkudata, nur ohne dass kein Fehler erzeugt wird.
+static void * my_checkudata (lua_State *L, int ud, const char *tname)
+{
+ int top = lua_gettop(L);
+
+ void * p = lua_touserdata(L, ud);
+ if (p != NULL) /* value is a userdata? */
+ {
+ if (lua_getmetatable(L, ud)) /* does it have a metatable? */
+ {
+ // lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
+ BS_LuaBindhelper::GetMetatable(L, tname);
+ if (lua_rawequal(L, -1, -2)) /* does it have the correct mt? */
+ {
+ lua_settop(L, top);
+ return p;
+ }
+ }
+ }
+
+ lua_settop(L, top);
+ return NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+static void NewUintUserData(lua_State * L, unsigned int Value)
+{
+ void * UserData = lua_newuserdata(L, sizeof(Value));
+ memcpy(UserData, &Value, sizeof(Value));
+}
+
+// -----------------------------------------------------------------------------
+
+static BS_AnimationTemplate * CheckAnimationTemplate(lua_State * L, int idx = 1)
+{
+ // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.AnimationTemplate
+ unsigned int AnimationTemplateHandle;
+ if ((AnimationTemplateHandle = *reinterpret_cast<unsigned int *>(my_checkudata(L, idx, ANIMATION_TEMPLATE_CLASS_NAME))) != 0)
+ {
+ BS_AnimationTemplate * AnimationTemplatePtr = BS_AnimationTemplateRegistry::GetInstance().ResolveHandle(AnimationTemplateHandle);
+ if (!AnimationTemplatePtr)
+ luaL_error(L, "The animation template with the handle %d does no longer exist.", AnimationTemplateHandle);
+ return AnimationTemplatePtr;
+ }
+ else
+ {
+ luaL_argcheck(L, 0, idx, "'" ANIMATION_TEMPLATE_CLASS_NAME "' expected");
+ return 0;
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+
+static int NewAnimationTemplate(lua_State * L)
+{
+ unsigned int AnimationTemplateHandle = BS_AnimationTemplate::Create(luaL_checkstring(L, 1));
+ BS_AnimationTemplate * AnimationTemplatePtr = BS_AnimationTemplateRegistry::GetInstance().ResolveHandle(AnimationTemplateHandle);
+ if (AnimationTemplatePtr && AnimationTemplatePtr->IsValid())
+ {
+ NewUintUserData(L, AnimationTemplateHandle);
+ //luaL_getmetatable(L, ANIMATION_TEMPLATE_CLASS_NAME);
+ BS_LuaBindhelper::GetMetatable(L, ANIMATION_TEMPLATE_CLASS_NAME);
+ BS_ASSERT(!lua_isnil(L, -1));
+ lua_setmetatable(L, -2);
+ }
+ else
+ {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int AT_AddFrame(lua_State * L)
+{
+ BS_AnimationTemplate * pAT = CheckAnimationTemplate(L);
+ pAT->AddFrame(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int AT_SetFrame(lua_State * L)
+{
+ BS_AnimationTemplate * pAT = CheckAnimationTemplate(L);
+ pAT->SetFrame(static_cast<int>(luaL_checknumber(L, 2)), static_cast<int>(luaL_checknumber(L, 3)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static bool AnimationTypeStringToNumber(const char * TypeString, BS_Animation::ANIMATION_TYPES & Result)
+{
+ if (strcmp(TypeString, "jojo") == 0)
+ {
+ Result = BS_Animation::AT_JOJO;
+ return true;
+ }
+ else if (strcmp(TypeString, "loop") == 0)
+ {
+ Result = BS_Animation::AT_LOOP;
+ return true;
+ }
+ else if (strcmp(TypeString, "oneshot") == 0)
+ {
+ Result = BS_Animation::AT_ONESHOT;
+ return true;
+ }
+ else
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+static int AT_SetAnimationType(lua_State * L)
+{
+ BS_AnimationTemplate * pAT = CheckAnimationTemplate(L);
+ BS_Animation::ANIMATION_TYPES AnimationType;
+ if (AnimationTypeStringToNumber(luaL_checkstring(L, 2), AnimationType))
+ {
+ pAT->SetAnimationType(AnimationType);
+ }
+ else
+ {
+ luaL_argcheck(L, 0, 2, "Invalid animation type");
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int AT_SetFPS(lua_State * L)
+{
+ BS_AnimationTemplate * pAT = CheckAnimationTemplate(L);
+ pAT->SetFPS(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int AT_Finalize(lua_State * L)
+{
+ BS_AnimationTemplate * pAT = CheckAnimationTemplate(L);
+ delete pAT;
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg ANIMATION_TEMPLATE_METHODS[] =
+{
+ "AddFrame", AT_AddFrame,
+ "SetFrame", AT_SetFrame,
+ "SetAnimationType", AT_SetAnimationType,
+ "SetFPS", AT_SetFPS,
+ "__gc", AT_Finalize,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static BS_GraphicEngine * GetGE()
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_GraphicEngine * pGE = static_cast<BS_GraphicEngine *>(pKernel->GetService("gfx"));
+ BS_ASSERT(pGE);
+ return pGE;
+}
+
+// -----------------------------------------------------------------------------
+
+static int Init(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ switch (lua_gettop(L))
+ {
+ case 0:
+ lua_pushbooleancpp(L, pGE->Init());
+ break;
+ case 1:
+ lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L, 1))));
+ break;
+ case 2:
+ lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L,1)), static_cast<int>(luaL_checknumber(L, 2))));
+ break;
+ case 3:
+ lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L,1)), static_cast<int>(luaL_checknumber(L, 2)),
+ static_cast<int>(luaL_checknumber(L, 3))));
+ break;
+ case 4:
+ lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L,1)), static_cast<int>(luaL_checknumber(L, 2)),
+ static_cast<int>(luaL_checknumber(L, 3)), static_cast<int>(luaL_checknumber(L, 4))));
+ break;
+ default:
+ lua_pushbooleancpp(L, pGE->Init(static_cast<int>(luaL_checknumber(L,1)), static_cast<int>(luaL_checknumber(L, 2)),
+ static_cast<int>(luaL_checknumber(L, 3)), static_cast<int>(luaL_checknumber(L, 4)),
+ lua_tobooleancpp(L, 5)));
+ }
+
+
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Main-Panel zum Gfx-Modul hinzufügen
+ BS_RenderObjectPtr<BS_Panel> MainPanelPtr(GetGE()->GetMainPanel());
+ BS_ASSERT(MainPanelPtr.IsValid());
+
+ lua_pushstring(L, GFX_LIBRARY_NAME);
+ lua_gettable(L, LUA_GLOBALSINDEX);
+ BS_ASSERT(!lua_isnil(L, -1));
+
+ NewUintUserData(L, MainPanelPtr->GetHandle());
+ BS_ASSERT(!lua_isnil(L, -1));
+ // luaL_getmetatable(L, PANEL_CLASS_NAME);
+ BS_LuaBindhelper::GetMetatable(L, PANEL_CLASS_NAME);
+ BS_ASSERT(!lua_isnil(L, -1));
+ lua_setmetatable(L, -2);
+
+ lua_pushstring(L, "MainPanel");
+ lua_insert(L, -2);
+ lua_settable(L, -3);
+
+ lua_pop(L, 1);
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int StartFrame(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ if (lua_gettop(L) == 0)
+ lua_pushbooleancpp(L, pGE->StartFrame());
+ else
+ lua_pushbooleancpp(L, pGE->StartFrame(lua_tobooleancpp(L, 1)));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int EndFrame(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushbooleancpp(L, pGE->EndFrame());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int DrawDebugLine(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ BS_Vertex Start;
+ BS_Vertex End;
+ BS_Vertex::LuaVertexToVertex(L, 1, Start);
+ BS_Vertex::LuaVertexToVertex(L, 2, End);
+ pGE->DrawDebugLine(Start, End, BS_GraphicEngine::LuaColorToARGBColor(L, 3));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetDisplayWidth(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushnumber(L, pGE->GetDisplayWidth());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetDisplayHeight(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushnumber(L, pGE->GetDisplayHeight());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetBitDepth(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushnumber(L, pGE->GetBitDepth());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetVsync(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ pGE->SetVsync(lua_tobooleancpp(L, 1));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsVsync(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushbooleancpp(L, pGE->GetVsync());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsWindowed(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushbooleancpp(L, pGE->IsWindowed());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetFPSCount(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushnumber(L, pGE->GetFPSCount());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetLastFrameDuration(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushnumber(L, pGE->GetLastFrameDuration());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int StopMainTimer(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+ pGE->StopMainTimer();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ResumeMainTimer(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+ pGE->ResumeMainTimer();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSecondaryFrameDuration(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+
+ lua_pushnumber(L, pGE->GetSecondaryFrameDuration());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SaveScreenshot(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+ lua_pushbooleancpp(L, pGE->SaveScreenshot(luaL_checkstring(L, 1)));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SaveThumbnailScreenshot(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+ lua_pushbooleancpp(L, pGE->SaveThumbnailScreenshot(luaL_checkstring(L, 1)));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetRepaintedPixels(lua_State * L)
+{
+ BS_GraphicEngine * pGE = GetGE();
+ lua_pushnumber(L, static_cast<lua_Number>(pGE->GetRepaintedPixels()));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg GFX_FUNCTIONS[] =
+{
+ "Init", Init,
+ "StartFrame", StartFrame,
+ "EndFrame", EndFrame,
+ "DrawDebugLine", DrawDebugLine,
+ "SetVsync", SetVsync,
+ "GetDisplayWidth", GetDisplayWidth,
+ "GetDisplayHeight", GetDisplayHeight,
+ "GetBitDepth", GetBitDepth,
+ "IsVsync", IsVsync,
+ "IsWindowed", IsWindowed,
+ "GetFPSCount", GetFPSCount,
+ "GetLastFrameDuration", GetLastFrameDuration,
+ "StopMainTimer", StopMainTimer,
+ "ResumeMainTimer", ResumeMainTimer,
+ "GetSecondaryFrameDuration", GetSecondaryFrameDuration,
+ "SaveScreenshot", SaveScreenshot,
+ "NewAnimationTemplate", NewAnimationTemplate,
+ "GetRepaintedPixels", GetRepaintedPixels,
+ "SaveThumbnailScreenshot", SaveThumbnailScreenshot,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static BS_RenderObjectPtr<BS_RenderObject> CheckRenderObject(lua_State * L, bool ErrorIfRemoved = true)
+{
+ // Der erste Parameter muss vom Typ userdata sein und die Metatable einer Klasse haben, die von Gfx.RenderObject "erbt".
+ unsigned int * UserDataPtr;
+ if ((UserDataPtr = (unsigned int *) my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0 ||
+ (UserDataPtr = (unsigned int *) my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0 ||
+ (UserDataPtr = (unsigned int *) my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0 ||
+ (UserDataPtr = (unsigned int *) my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0)
+ {
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr(* UserDataPtr);
+ if (ROPtr.IsValid())
+ return ROPtr;
+ else
+ {
+ if (ErrorIfRemoved)
+ luaL_error(L, "The renderobject with the handle %d does no longer exist.", * UserDataPtr);
+ }
+ }
+ else
+ {
+ luaL_argcheck(L, 0, 1, "'" RENDEROBJECT_CLASS_NAME "' expected");
+ }
+
+ return BS_RenderObjectPtr<BS_RenderObject>();
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_SetPos(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ BS_Vertex Pos;
+ BS_Vertex::LuaVertexToVertex(L, 2, Pos);
+ ROPtr->SetPos(Pos.X, Pos.Y);
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_SetX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ ROPtr->SetX(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_SetY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ ROPtr->SetY(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_SetZ(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ ROPtr->SetZ(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_SetVisible(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ ROPtr->SetVisible(lua_tobooleancpp(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetX());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetY());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetZ(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetZ());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetAbsoluteX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetAbsoluteX());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetAbsoluteY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetAbsoluteY());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetWidth(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetWidth());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_GetHeight(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushnumber(L, ROPtr->GetHeight());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_IsVisible(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ lua_pushbooleancpp(L, ROPtr->IsVisible());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_AddPanel(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ BS_RenderObjectPtr<BS_Panel> PanelPtr = ROPtr->AddPanel(static_cast<int>(luaL_checknumber(L, 2)),
+ static_cast<int>(luaL_checknumber(L, 3)),
+ BS_GraphicEngine::LuaColorToARGBColor(L, 4));
+ if (PanelPtr.IsValid())
+ {
+ NewUintUserData(L, PanelPtr->GetHandle());
+ // luaL_getmetatable(L, PANEL_CLASS_NAME);
+ BS_LuaBindhelper::GetMetatable(L, PANEL_CLASS_NAME);
+ BS_ASSERT(!lua_isnil(L, -1));
+ lua_setmetatable(L, -2);
+ }
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_AddBitmap(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ BS_RenderObjectPtr<BS_Bitmap> BitmaPtr = ROPtr->AddBitmap(luaL_checkstring(L, 2));
+ if (BitmaPtr.IsValid())
+ {
+ NewUintUserData(L, BitmaPtr->GetHandle());
+ // luaL_getmetatable(L, BITMAP_CLASS_NAME);
+ BS_LuaBindhelper::GetMetatable(L, BITMAP_CLASS_NAME);
+ BS_ASSERT(!lua_isnil(L, -1));
+ lua_setmetatable(L, -2);
+ }
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_AddText(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+
+ BS_RenderObjectPtr<BS_Text> TextPtr;
+ if (lua_gettop(L) >= 3) TextPtr = ROPtr->AddText(luaL_checkstring(L, 2), luaL_checkstring(L, 3));
+ else TextPtr = ROPtr->AddText(luaL_checkstring(L, 2));
+
+ if (TextPtr.IsValid())
+ {
+ NewUintUserData(L, TextPtr->GetHandle());
+ // luaL_getmetatable(L, TEXT_CLASS_NAME);
+ BS_LuaBindhelper::GetMetatable(L, TEXT_CLASS_NAME);
+ BS_ASSERT(!lua_isnil(L, -1));
+ lua_setmetatable(L, -2);
+ }
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_AddAnimation(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr;
+ if (lua_type(L, 2) == LUA_TUSERDATA)
+ AnimationPtr = ROPtr->AddAnimation(*CheckAnimationTemplate(L, 2));
+ else
+ AnimationPtr = ROPtr->AddAnimation(luaL_checkstring(L, 2));
+
+ if (AnimationPtr.IsValid())
+ {
+ NewUintUserData(L, AnimationPtr->GetHandle());
+ // luaL_getmetatable(L, ANIMATION_CLASS_NAME);
+ BS_LuaBindhelper::GetMetatable(L, ANIMATION_CLASS_NAME);
+ BS_ASSERT(!lua_isnil(L, -1));
+ lua_setmetatable(L, -2);
+
+ // Alle Animationscallbacks registrieren.
+ AnimationPtr->RegisterDeleteCallback(AnimationDeleteCallback, AnimationPtr->GetHandle());
+ AnimationPtr->RegisterLoopPointCallback(AnimationLoopPointCallback, AnimationPtr->GetHandle());
+ AnimationPtr->RegisterActionCallback(AnimationActionCallback, AnimationPtr->GetHandle());
+ }
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int RO_Remove(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ ROPtr.Erase();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg RENDEROBJECT_METHODS[] =
+{
+ "AddAnimation", RO_AddAnimation,
+ "AddText", RO_AddText,
+ "AddBitmap", RO_AddBitmap,
+ "AddPanel", RO_AddPanel,
+ "SetPos", RO_SetPos,
+ "SetX", RO_SetX,
+ "SetY", RO_SetY,
+ "SetZ", RO_SetZ,
+ "SetVisible", RO_SetVisible,
+ "GetX", RO_GetX,
+ "GetY", RO_GetY,
+ "GetZ", RO_GetZ,
+ "GetAbsoluteX", RO_GetAbsoluteX,
+ "GetAbsoluteY", RO_GetAbsoluteY,
+ "GetWidth", RO_GetWidth,
+ "GetHeight", RO_GetHeight,
+ "IsVisible", RO_IsVisible,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static BS_RenderObjectPtr<BS_Panel> CheckPanel(lua_State * L)
+{
+ // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Panel
+ unsigned int * UserDataPtr;
+ if ((UserDataPtr = (unsigned int *) my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0)
+ {
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr(*UserDataPtr);
+ if (ROPtr.IsValid())
+ {
+ return ROPtr->ToPanel();
+ }
+ else
+ luaL_error(L, "The panel with the handle %d does no longer exist.", *UserDataPtr);
+ }
+ else
+ {
+ luaL_argcheck(L, 0, 1, "'" PANEL_CLASS_NAME "' expected");
+ }
+
+ return BS_RenderObjectPtr<BS_Panel>();
+}
+
+// -----------------------------------------------------------------------------
+
+static int P_GetColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Panel> PanelPtr = CheckPanel(L);
+ BS_ASSERT(PanelPtr.IsValid());
+ BS_GraphicEngine::ARGBColorToLuaColor(L, PanelPtr->GetColor());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int P_SetColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Panel> PanelPtr = CheckPanel(L);
+ BS_ASSERT(PanelPtr.IsValid());
+ PanelPtr->SetColor(BS_GraphicEngine::LuaColorToARGBColor(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int P_Remove(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ ROPtr.Erase();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg PANEL_METHODS[] =
+{
+ "GetColor", P_GetColor,
+ "SetColor", P_SetColor,
+ "Remove", P_Remove,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static BS_RenderObjectPtr<BS_Bitmap> CheckBitmap(lua_State * L)
+{
+ // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Bitmap
+ unsigned int * UserDataPtr;
+ if ((UserDataPtr = (unsigned int *) my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0)
+ {
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr(*UserDataPtr);
+ if (ROPtr.IsValid())
+ {
+ return ROPtr->ToBitmap();
+ }
+ else
+ luaL_error(L, "The bitmap with the handle %d does no longer exist.", *UserDataPtr);
+ }
+ else
+ {
+ luaL_argcheck(L, 0, 1, "'" BITMAP_CLASS_NAME "' expected");
+ }
+
+ return BS_RenderObjectPtr<BS_Bitmap>();
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetAlpha(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetAlpha(static_cast<unsigned int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetTintColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetModulationColor(BS_GraphicEngine::LuaColorToARGBColor(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetScaleFactor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetScaleFactor(static_cast<float>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetScaleFactorX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetScaleFactorX(static_cast<float>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetScaleFactorY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetScaleFactorY(static_cast<float>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetFlipH(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetFlipH(lua_tobooleancpp(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_SetFlipV(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BitmapPtr->SetFlipV(lua_tobooleancpp(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_GetAlpha(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushnumber(L, BitmapPtr->GetAlpha());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_GetTintColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BS_GraphicEngine::ARGBColorToLuaColor(L, BitmapPtr->GetModulationColor());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_GetScaleFactorX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushnumber(L, BitmapPtr->GetScaleFactorX());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_GetScaleFactorY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushnumber(L, BitmapPtr->GetScaleFactorY());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_IsFlipH(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushbooleancpp(L, BitmapPtr->IsFlipH());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_IsFlipV(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushbooleancpp(L, BitmapPtr->IsFlipV());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_GetPixel(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ BS_Vertex Pos;
+ BS_Vertex::LuaVertexToVertex(L, 2, Pos);
+ BS_GraphicEngine::ARGBColorToLuaColor(L, BitmapPtr->GetPixel(Pos.X, Pos.Y));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_IsScalingAllowed(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushbooleancpp(L, BitmapPtr->IsScalingAllowed());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_IsAlphaAllowed(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushbooleancpp(L, BitmapPtr->IsAlphaAllowed());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int B_IsTintingAllowed(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Bitmap> BitmapPtr = CheckBitmap(L);
+ BS_ASSERT(BitmapPtr.IsValid());
+ lua_pushbooleancpp(L, BitmapPtr->IsColorModulationAllowed());
+ return 1;
+}
+// -----------------------------------------------------------------------------
+
+static int B_Remove(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr = CheckRenderObject(L);
+ BS_ASSERT(ROPtr.IsValid());
+ ROPtr.Erase();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg BITMAP_METHODS[] =
+{
+ "SetAlpha", B_SetAlpha,
+ "SetTintColor", B_SetTintColor,
+ "SetScaleFactor", B_SetScaleFactor,
+ "SetScaleFactorX", B_SetScaleFactorX,
+ "SetScaleFactorY", B_SetScaleFactorY,
+ "SetFlipH", B_SetFlipH,
+ "SetFlipV", B_SetFlipV,
+ "GetAlpha", B_GetAlpha,
+ "GetTintColor", B_GetTintColor,
+ "GetScaleFactorX", B_GetScaleFactorX,
+ "GetScaleFactorY", B_GetScaleFactorY,
+ "IsFlipH", B_IsFlipH,
+ "IsFlipV", B_IsFlipV,
+ "GetPixel", B_GetPixel,
+ "IsScalingAllowed", B_IsScalingAllowed,
+ "IsAlphaAllowed", B_IsAlphaAllowed,
+ "IsTintingAllowed", B_IsTintingAllowed,
+ "Remove", B_Remove,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static BS_RenderObjectPtr<BS_Animation> CheckAnimation(lua_State * L)
+{
+ // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Animation
+ unsigned int * UserDataPtr;
+ if ((UserDataPtr = (unsigned int *) my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0)
+ {
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr(*UserDataPtr);
+ if (ROPtr.IsValid())
+ return ROPtr->ToAnimation();
+ else
+ {
+ luaL_error(L, "The animation with the handle %d does no longer exist.", *UserDataPtr);
+ }
+ }
+ else
+ {
+ luaL_argcheck(L, 0, 1, "'" ANIMATION_CLASS_NAME "' expected");
+ }
+
+ return BS_RenderObjectPtr<BS_Animation>();
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_Play(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->Play();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_Pause(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->Pause();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_Stop(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->Stop();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_SetFrame(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->SetFrame(static_cast<unsigned int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_SetAlpha(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->SetAlpha(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+// -----------------------------------------------------------------------------
+
+static int A_SetTintColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->SetModulationColor(BS_GraphicEngine::LuaColorToARGBColor(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_SetScaleFactor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->SetScaleFactor(static_cast<float>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_SetScaleFactorX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->SetScaleFactorX(static_cast<float>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_SetScaleFactorY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr->SetScaleFactorY(static_cast<float>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_GetScaleFactorX(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushnumber(L, AnimationPtr->GetScaleFactorX());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_GetScaleFactorY(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushnumber(L, AnimationPtr->GetScaleFactorY());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_GetAnimationType(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ switch (AnimationPtr->GetAnimationType())
+ {
+ case BS_Animation::AT_JOJO:
+ lua_pushstring(L, "jojo");
+ break;
+ case BS_Animation::AT_LOOP:
+ lua_pushstring(L, "loop");
+ break;
+ case BS_Animation::AT_ONESHOT:
+ lua_pushstring(L, "oneshot");
+ break;
+ default:
+ BS_ASSERT(false);
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_GetFPS(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushnumber(L, AnimationPtr->GetFPS());
+ return 1;
+}
+
+
+// -----------------------------------------------------------------------------
+
+static int A_GetFrameCount(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushnumber(L, AnimationPtr->GetFrameCount());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_IsScalingAllowed(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushbooleancpp(L, AnimationPtr->IsScalingAllowed());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_IsAlphaAllowed(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushbooleancpp(L, AnimationPtr->IsAlphaAllowed());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_IsTintingAllowed(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushbooleancpp(L, AnimationPtr->IsColorModulationAllowed());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_GetCurrentFrame(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushnumber(L, AnimationPtr->GetCurrentFrame());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_GetCurrentAction(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushstring(L, AnimationPtr->GetCurrentAction().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_IsPlaying(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ lua_pushbooleancpp(L, AnimationPtr->IsRunning());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static bool AnimationLoopPointCallback(unsigned int Handle)
+{
+ lua_State * L = static_cast<lua_State *>(BS_Kernel::GetInstance()->GetScript()->GetScriptObject());
+ LoopPointCallbackPtr->InvokeCallbackFunctions(L, Handle);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_RegisterLoopPointCallback(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ lua_pushvalue(L, 2);
+ LoopPointCallbackPtr->RegisterCallbackFunction(L, AnimationPtr->GetHandle());
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_UnregisterLoopPointCallback(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ lua_pushvalue(L, 2);
+ LoopPointCallbackPtr->UnregisterCallbackFunction(L, AnimationPtr->GetHandle());
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static bool AnimationActionCallback(unsigned int Handle)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr(Handle);
+ if (AnimationPtr.IsValid())
+ {
+ ActionCallbackPtr->Action = AnimationPtr->GetCurrentAction();
+ lua_State * L = static_cast<lua_State *>(BS_Kernel::GetInstance()->GetScript()->GetScriptObject());
+ ActionCallbackPtr->InvokeCallbackFunctions(L, AnimationPtr->GetHandle());
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_RegisterActionCallback(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ lua_pushvalue(L, 2);
+ ActionCallbackPtr->RegisterCallbackFunction(L, AnimationPtr->GetHandle());
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_UnregisterActionCallback(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ lua_pushvalue(L, 2);
+ ActionCallbackPtr->UnregisterCallbackFunction(L, AnimationPtr->GetHandle());
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static bool AnimationDeleteCallback(unsigned int Handle)
+{
+ lua_State * L = static_cast<lua_State *>(BS_Kernel::GetInstance()->GetScript()->GetScriptObject());
+ LoopPointCallbackPtr->RemoveAllObjectCallbacks(L, Handle);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+static int A_Remove(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Animation> AnimationPtr = CheckAnimation(L);
+ BS_ASSERT(AnimationPtr.IsValid());
+ AnimationPtr.Erase();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg ANIMATION_METHODS[] =
+{
+ "Play", A_Play,
+ "Pause", A_Pause,
+ "Stop", A_Stop,
+ "SetFrame", A_SetFrame,
+ "SetAlpha", A_SetAlpha,
+ "SetTintColor", A_SetTintColor,
+ "SetScaleFactor", A_SetScaleFactor,
+ "SetScaleFactorX", A_SetScaleFactorX,
+ "SetScaleFactorY", A_SetScaleFactorY,
+ "GetScaleFactorX", A_GetScaleFactorX,
+ "GetScaleFactorY", A_GetScaleFactorY,
+ "GetAnimationType", A_GetAnimationType,
+ "GetFPS", A_GetFPS,
+ "GetFrameCount", A_GetFrameCount,
+ "IsScalingAllowed", A_IsScalingAllowed,
+ "IsAlphaAllowed", A_IsAlphaAllowed,
+ "IsTintingAllowed", A_IsTintingAllowed,
+ "GetCurrentFrame", A_GetCurrentFrame,
+ "GetCurrentAction", A_GetCurrentAction,
+ "IsPlaying", A_IsPlaying,
+ "RegisterLoopPointCallback", A_RegisterLoopPointCallback,
+ "UnregisterLoopPointCallback", A_UnregisterLoopPointCallback,
+ "RegisterActionCallback", A_RegisterActionCallback,
+ "UnregisterActionCallback", A_UnregisterActionCallback,
+ "Remove", A_Remove,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static BS_RenderObjectPtr<BS_Text> CheckText(lua_State * L)
+{
+ // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Text
+ unsigned int * UserDataPtr;
+ if ((UserDataPtr = (unsigned int *) my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0)
+ {
+ BS_RenderObjectPtr<BS_RenderObject> ROPtr(*UserDataPtr);
+ if (ROPtr.IsValid())
+ return ROPtr->ToText();
+ else
+ luaL_error(L, "The text with the handle %d does no longer exist.", *UserDataPtr);
+ }
+ else
+ {
+ luaL_argcheck(L, 0, 1, "'" TEXT_CLASS_NAME "' expected");
+ }
+
+ return BS_RenderObjectPtr<BS_Text>();
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_SetFont(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr->SetFont(luaL_checkstring(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_SetText(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr->SetText(luaL_checkstring(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_SetAlpha(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr->SetAlpha(static_cast<int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_SetColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr->SetColor(BS_GraphicEngine::LuaColorToARGBColor(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_SetAutoWrap(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr->SetAutoWrap(lua_tobooleancpp(L, 2));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_SetAutoWrapThreshold(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr->SetAutoWrapThreshold(static_cast<unsigned int>(luaL_checknumber(L, 2)));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_GetText(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ lua_pushstring(L, TextPtr->GetText().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_GetFont(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ lua_pushstring(L, TextPtr->GetFont().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_GetAlpha(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ lua_pushnumber(L, TextPtr->GetAlpha());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_GetColor(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ lua_pushnumber(L, TextPtr->GetColor());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_IsAutoWrap(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ lua_pushbooleancpp(L, TextPtr->IsAutoWrapActive());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_GetAutoWrapThreshold(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ lua_pushnumber(L, TextPtr->GetAutoWrapThreshold());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int T_Remove(lua_State * L)
+{
+ BS_RenderObjectPtr<BS_Text> TextPtr = CheckText(L);
+ BS_ASSERT(TextPtr.IsValid());
+ TextPtr.Erase();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const luaL_reg TEXT_METHODS[] =
+{
+ "SetFont", T_SetFont,
+ "SetText", T_SetText,
+ "SetAlpha", T_SetAlpha,
+ "SetColor", T_SetColor,
+ "SetAutoWrap", T_SetAutoWrap,
+ "SetAutoWrapThreshold", T_SetAutoWrapThreshold,
+ "GetText", T_GetText,
+ "GetFont", T_GetFont,
+ "GetAlpha", T_GetAlpha,
+ "GetColor", T_GetColor,
+ "IsAutoWrap", T_IsAutoWrap,
+ "GetAutoWrapThreshold", T_GetAutoWrapThreshold,
+ "Remove", T_Remove,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+bool BS_GraphicEngine::RegisterScriptBindings()
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script"));
+ BS_ASSERT(pScript);
+ lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject());
+ BS_ASSERT(L);
+
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, BITMAP_CLASS_NAME, RENDEROBJECT_METHODS)) return false;
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, ANIMATION_CLASS_NAME, RENDEROBJECT_METHODS)) return false;
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, PANEL_CLASS_NAME, RENDEROBJECT_METHODS)) return false;
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, TEXT_CLASS_NAME, RENDEROBJECT_METHODS)) return false;
+
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, PANEL_CLASS_NAME, PANEL_METHODS)) return false;
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, BITMAP_CLASS_NAME, BITMAP_METHODS)) return false;
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, TEXT_CLASS_NAME, TEXT_METHODS)) return false;
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, ANIMATION_CLASS_NAME, ANIMATION_METHODS)) return false;
+
+ if (!BS_LuaBindhelper::AddMethodsToClass(L, ANIMATION_TEMPLATE_CLASS_NAME, ANIMATION_TEMPLATE_METHODS)) return false;
+
+ if (!BS_LuaBindhelper::AddFunctionsToLib(L, GFX_LIBRARY_NAME, GFX_FUNCTIONS)) return false;
+
+ LoopPointCallbackPtr.reset(new BS_LuaCallback(L));
+ ActionCallbackPtr.reset(new ActionCallback(L));
+
+ return true;
+}
diff --git a/engines/sword25/gfx/image/b25sloader.cpp b/engines/sword25/gfx/image/b25sloader.cpp
new file mode 100755
index 0000000000..55aaf7a2c5
--- /dev/null
+++ b/engines/sword25/gfx/image/b25sloader.cpp
@@ -0,0 +1,101 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include <string>
+#include <sstream>
+#include <algorithm>
+using namespace std;
+
+#include "b25sloader.h"
+#include "pngloader.h"
+
+#define BS_LOG_PREFIX "B25SLOADER"
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ unsigned int FindEmbeddedPNG(const char * FileDataPtr, unsigned int FileSize)
+ {
+ // Einen Stringstream mit dem Anfang der Datei intialisieren. 512 Byte sollten hierfür genügen.
+ istringstream StringStream(string(FileDataPtr, FileDataPtr + min(static_cast<unsigned int>(512), FileSize)));
+
+ // Headerinformationen der Spielstandes einlesen.
+ string Marker, VersionID;
+ unsigned int CompressedGamedataSize, UncompressedGamedataSize;
+ StringStream >> Marker >> VersionID >> CompressedGamedataSize >> UncompressedGamedataSize;
+ if (!StringStream.good()) return 0;
+
+ // Testen, ob wir tatsächlich einen Spielstand haben.
+ if (Marker == "BS25SAVEGAME")
+ {
+ // Offset zum PNG innerhalb des Spielstandes berechnen und zurückgeben.
+ return static_cast<unsigned int>(StringStream.tellg()) + CompressedGamedataSize + 1;
+ }
+
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_B25SLoader::IsCorrectImageFormat(const char * FileDataPtr, unsigned int FileSize)
+{
+ // PNG innerhalb des Spielstandes finden und den Methodenaufruf zu BS_PNGLoader weiterreichen.
+ unsigned int PNGOffset = FindEmbeddedPNG(FileDataPtr, FileSize);
+ if (PNGOffset > 0)
+ {
+ return BS_PNGLoader::DoIsCorrectImageFormat(FileDataPtr + PNGOffset, FileSize - PNGOffset);
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_B25SLoader::DecodeImage(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS ColorFormat, char * & UncompressedDataPtr,
+ int & Width, int & Height, int & Pitch)
+{
+ // PNG innerhalb des Spielstandes finden und den Methodenaufruf zu BS_PNGLoader weiterreichen.
+ unsigned int PNGOffset = FindEmbeddedPNG(FileDataPtr, FileSize);
+ if (PNGOffset > 0)
+ {
+ return BS_PNGLoader::DoDecodeImage(FileDataPtr + PNGOffset, FileSize - PNGOffset, ColorFormat, UncompressedDataPtr, Width, Height, Pitch);
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_B25SLoader::ImageProperties(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS & ColorFormat, int & Width, int & Height)
+{
+ // PNG innerhalb des Spielstandes finden und den Methodenaufruf zu BS_PNGLoader weiterreichen.
+ unsigned int PNGOffset = FindEmbeddedPNG(FileDataPtr, FileSize);
+ if (PNGOffset > 0)
+ {
+ return BS_PNGLoader::DoImageProperties(FileDataPtr + PNGOffset, FileSize - PNGOffset, ColorFormat, Width, Height);
+ }
+
+ return false;
+}
diff --git a/engines/sword25/gfx/image/b25sloader.h b/engines/sword25/gfx/image/b25sloader.h
new file mode 100755
index 0000000000..bafea87365
--- /dev/null
+++ b/engines/sword25/gfx/image/b25sloader.h
@@ -0,0 +1,52 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_B25SLOADER_H
+#define BS_B25SLOADER_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "imageloader.h"
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_B25SLoader : public BS_ImageLoader
+{
+public:
+ static BS_ImageLoader * CreateInstance()
+ {
+ #include "kernel/memlog_off.h"
+ return static_cast<BS_ImageLoader *>(new BS_B25SLoader());
+ #include "kernel/memlog_on.h"
+ }
+
+protected:
+ virtual bool IsCorrectImageFormat(const char * FileDataPtr, unsigned int FileSize);
+ virtual bool DecodeImage(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS ColorFormat, char * & UncompressedDataPtr,
+ int & Width, int & Height, int & Pitch);
+ virtual bool ImageProperties(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS & ColorFormat, int & Width, int & Height);
+
+};
+
+#endif
diff --git a/engines/sword25/gfx/image/image.h b/engines/sword25/gfx/image/image.h
new file mode 100755
index 0000000000..8f6fe9cab9
--- /dev/null
+++ b/engines/sword25/gfx/image/image.h
@@ -0,0 +1,208 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ BS_Image
+ --------
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef BS_IMAGE_H
+#define BS_IMAGE_H
+
+// Includes
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+#include "kernel/common.h"
+#include "math/rect.h"
+#include "gfx/graphicengine.h"
+
+class BS_Image
+{
+public:
+ virtual ~BS_Image() {};
+
+ // Enums
+ /**
+ @brief Die möglichen Flippingparameter für die Blit-Methode.
+ */
+ enum FLIP_FLAGS
+ {
+ /// Das Bild wird nicht gespiegelt.
+ FLIP_NONE = 0,
+ /// Das Bild wird an der horizontalen Achse gespiegelt.
+ FLIP_H = 1,
+ /// Das Bild wird an der vertikalen Achse gespiegelt.
+ FLIP_V = 2,
+ /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt.
+ FLIP_HV = FLIP_H | FLIP_V,
+ /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt.
+ FLIP_VH = FLIP_H | FLIP_V
+ };
+
+ //@{
+ /** @name Accessor-Methoden */
+
+ /**
+ @brief Gibt die Breite des Bildes in Pixeln zurück
+ */
+ virtual int GetWidth() const = 0;
+
+ /**
+ @brief Gibt die Höhe des Bildes in Pixeln zurück
+ */
+ virtual int GetHeight() const = 0;
+
+ /**
+ @brief Gibt das Farbformat des Bildes zurück
+ */
+ virtual BS_GraphicEngine::COLOR_FORMATS GetColorFormat() const = 0;
+
+ //@}
+
+ //@{
+ /** @name Render-Methoden */
+
+ /**
+ @brief Rendert das Bild in den Framebuffer.
+ @param pDest ein Pointer auf das Zielbild. In den meisten Fällen ist dies der Framebuffer.
+ @param PosX die Position auf der X-Achse im Zielbild in Pixeln, an der das Bild gerendert werden soll.<br>
+ Der Standardwert ist 0.
+ @param PosY die Position auf der Y-Achse im Zielbild in Pixeln, an der das Bild gerendert werden soll.<br>
+ Der Standardwert ist 0.
+ @param Flipping gibt an, wie das Bild gespiegelt werden soll.<br>
+ Der Standardwert ist BS_Image::FLIP_NONE (keine Spiegelung)
+ @param pSrcPartRect Pointer auf ein BS_Rect, welches den Ausschnitt des Quellbildes spezifiziert, der gerendert
+ werden soll oder NULL, falls das gesamte Bild gerendert werden soll.<br>
+ Dieser Ausschnitt bezieht sich auf das ungespiegelte und unskalierte Bild.<br>
+ Der Standardwert ist NULL.
+ @param Color ein ARGB Farbwert, der die Parameter für die Farbmodulation und fürs Alphablending festlegt.<br>
+ Die Alpha-Komponente der Farbe bestimmt den Alphablending Parameter (0 = keine Deckung, 255 = volle Deckung).<br>
+ Die Farbkomponenten geben die Farbe für die Farbmodulation an.<br>
+ Der Standardwert is BS_ARGB(255, 255, 255, 255) (volle Deckung, keine Farbmodulation).
+ Zum Erzeugen des Farbwertes können die Makros BS_RGB und BS_ARGB benutzt werden.
+ @param Width gibt die Ausgabebreite des Bildausschnittes an.
+ Falls diese von der Breite des Bildausschnittes abweicht wird
+ das Bild entsprechend Skaliert.<br>
+ Der Wert -1 gibt an, dass das Bild nicht Skaliert werden soll.<br>
+ Der Standardwert ist -1.
+ @param Width gibt die Ausgabehöhe des Bildausschnittes an.
+ Falls diese von der Höhe des Bildauschnittes abweicht, wird
+ das Bild entsprechend Skaliert.<br>
+ Der Wert -1 gibt an, dass das Bild nicht Skaliert werden soll.<br>
+ Der Standardwert ist -1.
+ @return Gibt false zurück, falls das Rendern fehlgeschlagen ist.
+ @remark Er werden nicht alle Blitting-Operationen von allen BS_Image-Klassen unterstützt.<br>
+ Mehr Informationen gibt es in der Klassenbeschreibung von BS_Image und durch folgende Methoden:
+ - IsBlitTarget()
+ - IsScalingAllowed()
+ - IsFillingAllowed()
+ - IsAlphaAllowed()
+ - IsColorModulationAllowed()
+ - IsSetContentAllowed()
+ */
+ virtual bool Blit(int PosX = 0, int PosY = 0,
+ int Flipping = FLIP_NONE,
+ BS_Rect* pPartRect = NULL,
+ unsigned int Color = BS_ARGB(255, 255, 255, 255),
+ int Width = -1, int Height = -1) = 0;
+
+ /**
+ @brief Füllt einen Rechteckigen Bereich des Bildes mit einer Farbe.
+ @param pFillRect Pointer auf ein BS_Rect, welches den Ausschnitt des Bildes spezifiziert, der gefüllt
+ werden soll oder NULL, falls das gesamte Bild gefüllt werden soll.<br>
+ Der Standardwert ist NULL.
+ @param Color der 32 Bit Farbwert mit dem der Bildbereich gefüllt werden soll.
+ @remark Es ist möglich über die Methode transparente Rechtecke darzustellen, indem man eine Farbe mit einem Alphawert ungleich
+ 255 angibt.
+ @remark Unabhängig vom Farbformat des Bildes muss ein 32 Bit Farbwert angegeben werden. Zur Erzeugung, können die Makros
+ BS_RGB und BS_ARGB benutzt werden.
+ @remark Falls das Rechteck nicht völlig innerhalb des Bildschirms ist, wird es automatisch zurechtgestutzt.
+ */
+ virtual bool Fill(const BS_Rect* pFillRect = 0, unsigned int Color = BS_RGB(0, 0, 0)) = 0;
+
+ /**
+ @brief Füllt den Inhalt des Bildes mit Pixeldaten.
+ @param Pixeldata ein Vector der die Pixeldaten enthält. Sie müssen in dem Farbformat des Bildes vorliegen und es müssen genügend Daten
+ vorhanden sein, um das ganze Bild zu füllen.
+ @param Offset der Offset in Byte im Pixeldata-Vector an dem sich der erste zu schreibende Pixel befindet.<br>
+ Der Standardwert ist 0.
+ @param Stride der Abstand in Byte zwischen dem Zeilenende und dem Beginn einer neuen Zeile im Pixeldata-Vector.<br>
+ Der Standardwert ist 0.
+ @return Gibt false zurück, falls der Aufruf fehlgeschlagen ist.
+ @remark Ein Aufruf dieser Methode ist nur erlaubt, wenn IsSetContentAllowed() true zurückgibt.
+ */
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride) = 0;
+
+ /**
+ @brief Liest einen Pixel des Bildes.
+ @param X die X-Koordinate des Pixels.
+ @param Y die Y-Koordinate des Pixels
+ @return Gibt den 32-Bit Farbwert des Pixels an der übergebenen Koordinate zurück.
+ @remark Diese Methode sollte auf keine Fall benutzt werden um größere Teile des Bildes zu lesen, da sie sehr langsam ist. Sie ist
+ eher dafür gedacht einzelne Pixel des Bildes auszulesen.
+ */
+ virtual unsigned int GetPixel(int X, int Y) = 0;
+
+ //@{
+ /** @name Auskunfts-Methoden */
+
+ /**
+ @brief Überprüft, ob an dem BS_Image Blit() aufgerufen werden darf.
+ @return Gibt false zurück, falls ein Blit()-Aufruf an diesem Objekt nicht gestattet ist.
+ */
+ virtual bool IsBlitSource() const = 0;
+
+ /**
+ @brief Überprüft, ob das BS_Image ein Zielbild für einen Blit-Aufruf sein kann.
+ @return Gibt false zurück, falls ein Blit-Aufruf mit diesem Objekt als Ziel nicht gestattet ist.
+ */
+ virtual bool IsBlitTarget() const = 0;
+
+ /**
+ @brief Gibt true zurück, falls das BS_Image bei einem Aufruf von Blit() skaliert dargestellt werden kann.
+ */
+ virtual bool IsScalingAllowed() const = 0;
+
+ /**
+ @brief Gibt true zurück, wenn das BS_Image mit einem Aufruf von Fill() gefüllt werden kann.
+ */
+ virtual bool IsFillingAllowed() const = 0;
+
+ /**
+ @brief Gibt true zurück, wenn das BS_Image bei einem Aufruf von Blit() mit einem Alphawert dargestellt werden kann.
+ */
+ virtual bool IsAlphaAllowed() const = 0;
+
+ /**
+ @brief Gibt true zurück, wenn das BS_Image bei einem Aufruf von Blit() mit Farbmodulation dargestellt werden kann.
+ */
+ virtual bool IsColorModulationAllowed() const = 0;
+
+ /**
+ @brief Gibt true zurück, wenn der Inhalt des BS_Image durch eine Aufruf von SetContent() ausgetauscht werden kann.
+ */
+ virtual bool IsSetContentAllowed() const = 0;
+
+ //@}
+};
+
+#endif
diff --git a/engines/sword25/gfx/image/imageloader.cpp b/engines/sword25/gfx/image/imageloader.cpp
new file mode 100755
index 0000000000..18d94a4e21
--- /dev/null
+++ b/engines/sword25/gfx/image/imageloader.cpp
@@ -0,0 +1,120 @@
+// -----------------------------------------------------------------------------
+// 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 "imageloader.h"
+#include "imageloader_ids.h"
+
+#define BS_LOG_PREFIX "IMAGELOADER"
+
+// Statische Elemente der Klasse BS_ImageLoader intialisieren.
+std::list<BS_ImageLoader*> BS_ImageLoader::_ImageLoaderList;
+bool BS_ImageLoader::_ImageLoaderListInitialized = false;
+
+// Lade Methode
+// ------------
+
+bool BS_ImageLoader::LoadImage(const char* pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS ColorFormat,
+ char*& pUncompressedData,
+ int& Width, int& Height,
+ int& Pitch)
+{
+ // Falls die Liste der BS_ImageLoader noch nicht initialisiert wurde, wird dies getan.
+ if (!_ImageLoaderListInitialized)
+ _InitializeLoaderList();
+
+ // Passenden BS_ImageLoader finden und Bild dekodieren
+ BS_ImageLoader* pLoader = _FindSuitableImageLoader(pFileData, FileSize);
+ if (pLoader)
+ {
+ return pLoader->DecodeImage(pFileData, FileSize,
+ ColorFormat,
+ pUncompressedData,
+ Width, Height,
+ Pitch);
+ }
+
+ return false;
+}
+
+// Info Methode
+// ------------
+
+bool BS_ImageLoader::ExtractImageProperties(const char* pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS& ColorFormat,
+ int& Width, int& Height)
+{
+ // Falls die Liste der BS_ImageLoader noch nicht initialisiert wurde, wird dies getan.
+ if (!_ImageLoaderListInitialized)
+ _InitializeLoaderList();
+
+ // Passenden BS_ImageLoader finden und Bildeigenschaften auslesen.
+ BS_ImageLoader* pLoader = _FindSuitableImageLoader(pFileData, FileSize);
+ if (pLoader)
+ {
+ return pLoader->ImageProperties(pFileData, FileSize,
+ ColorFormat,
+ Width, Height);
+ }
+
+ return false;
+}
+
+// Verwaltungs Methoden
+// --------------------
+
+void BS_ImageLoader::_InitializeLoaderList()
+{
+ // Von jedem BS_ImageLoader wird eine Instanz erzeugt, diese fügen sich selbständig in die BS_ImageLoader-Liste ein.
+ for (int i = 0; i < BS_IMAGELOADER_COUNT; i++)
+ BS_IMAGELOADER_IDS[i]();
+
+ // Die Liste als gefüllt markieren.
+ _ImageLoaderListInitialized = true;
+
+ // Sicherstellen, dass beim Beenden alle BS_ImageLoader Instanzen zerstört werden.
+ atexit(BS_ImageLoader::_DeinitializeLoaderList);
+}
+
+void BS_ImageLoader::_DeinitializeLoaderList()
+{
+ while (!_ImageLoaderList.empty())
+ {
+ delete _ImageLoaderList.back();
+ _ImageLoaderList.pop_back();
+ }
+}
+
+BS_ImageLoader* BS_ImageLoader::_FindSuitableImageLoader(const char* pFileData, unsigned int FileSize)
+{
+ // Alle BS_ImageLoader-Objekte durchgehen, bis eins gefunden wurde, dass das Bild laden kann
+ std::list<BS_ImageLoader*>::iterator Iter = _ImageLoaderList.begin();
+ for (; Iter != _ImageLoaderList.end(); ++Iter)
+ {
+ // Falls ein geeigneter BS-ImageLoader gefunden wurde, wird er zurückgegeben.
+ if ((*Iter)->IsCorrectImageFormat(pFileData, FileSize))
+ {
+ return (*Iter);
+ }
+ }
+
+ // Es konnte kein passender BS_ImageLoader gefunden werden.
+ BS_LOG_ERRORLN("Could not find suitable image loader for image data.");
+ return NULL;
+}
diff --git a/engines/sword25/gfx/image/imageloader.h b/engines/sword25/gfx/image/imageloader.h
new file mode 100755
index 0000000000..952c36b093
--- /dev/null
+++ b/engines/sword25/gfx/image/imageloader.h
@@ -0,0 +1,358 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ BS_ImageLoader
+ --------------
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef BS_IMAGELOADER_H
+#define BS_IMAGELOADER_H
+
+// Includes
+#include "kernel/bs_stdint.h"
+#include "kernel/common.h"
+#include "../graphicengine.h"
+
+// Die folgenden Header vertragen sich nicht mit der Memoryleak-Detection, daher wird sie kurzzeitig deaktiviert
+#include "kernel/memlog_off.h"
+#include <list>
+#include "kernel/memlog_on.h"
+
+/**
+ @brief Über die statischen Methoden dieser Klasse werden alle unterstützten Bildformate geladen.
+
+ Zum Laden von Bildern wird die #LoadImage-Methode benutzt.
+
+ Außerdem stellt diese Klasse das Interface da, das alle Klassen implementieren müssen, die Bildformate einlesen.<br>
+ Zur Unterstützung eines neuen Bildformates muss folgendermaßen vorgegangen werden:
+ - Erzeugen einer neuen von #BS_ImageLoader abgeleiteten Klasse, die die Methoden #IsCorrectImageFormat und #DecodeImage impelementiert.
+ - Die Klasse muss eine statische Methode haben, die eine Instanz von ihr erzeugt und einen Pointer darauf zurückgibt.
+ - Diese Methode muss in der Liste in der Datei imageloader_ids.h eingetragen werden.
+ - Die Klasse muss JEDES Eingabebild seines Bildformates in die folgenden Farbformate konvertieren können:
+ - BS_GraphicEngine::CF_RGB16
+ - BS_GraphicEngine::CF_RGB15
+ - BS_GraphicEngine::CF_RGB16_INTERLEAVED
+ - BS_GraphicEngine::CF_RGB15_INTERLEAVED
+ - BS_GraphicEngine::CF_ARGB32
+ - BS_GraphicEngine::CF_BGRA32
+ - Zum Konvertieren der Bilddaten können die Hilfsmethoden dieser Klasse benutzt werden, die ARGB Bilddaten in alle benötigten
+ Farbformate konvertieren.
+*/
+class BS_ImageLoader
+{
+public:
+
+ //@{
+ /** @name Lade Methoden */
+
+ /**
+ @brief Lädt eine Bilddatei.
+
+ Diese Methode kann sämtliche unterstütztem Bildformate lesen. Die Methode erkennt selbstständing um welches Dateiformat es sich
+ bei der vorliegenden Datei handelt.<br>
+ Bisher wird nur PNG unterstützt.
+
+ @param pFileData ein Pointer auf die Bilddaten.
+ @param FileSize die Größe der Bilddaten in Byte.
+ @param ColorFormat gibt das gewünschte Farbformat an, in das die Bilddaten konvertiert werden sollen.<br>
+ Folgende Farbformate werden unterstützt:
+ - BS_GraphicEngine::CF_RGB16
+ - BS_GraphicEngine::CF_RGB15
+ - BS_GraphicEngine::CF_RGB16_INTERLEAVED
+ - BS_GraphicEngine::CF_RGB15_INTERLEAVED
+ - BS_GraphicEngine::CF_ARGB32
+ @param pUncompressedData nach erfolgreichen Laden zeigt dieser Pointer auf die enpackten und konvertierten Bilddaten.
+ @param Width gibt nach erfolgreichen Laden die Breite des geladenen Bildes an.
+ @param Height gibt nach erfolgreichen Laden die Höhe des geladenen Bildes an.
+ @param Pitch gibt nach erfolgreichen Laden die Länge einer Bildzeile in Byte an.
+ @return Gibt false zurück, falls das Laden fehlgeschlagen ist.
+ @remark Die Größe der Ausgabedaten in Bytes kann wie folgt berechnet werden: Pitch * Height.
+ @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
+ */
+ static bool LoadImage(const char* pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS ColorFormat,
+ char*& pUncompressedData,
+ int& Width, int& Height,
+ int& Pitch);
+
+ /**
+ @brief Liest die Bildeigenschaften eines Bildes aus.
+
+ @param pFileData ein Pointer auf die Bilddaten.
+ @param FileSize die Größe des Bilddaten in Byte.
+ @param ColorFormat enthält nach einem erfolgreichem Aufruf das Farbformat des Bildes.
+ @param Width enthält nach einem erfolgreichem Aufruf die Breite des Bildes in Pixeln.
+ @param Height enthält nach einem erfolgreichem Aufruf die Höhe des Bildes in Pixeln.
+ @return Gibt false zurück, wenn die Bildeigenschaften nicht ausgelesen werden konnten.
+ @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
+ */
+ static bool ExtractImageProperties(const char* pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS& ColorFormat,
+ int& Width, int& Height);
+ //@}
+
+protected:
+
+ // Protected Konstruktor, damit Instanzen dieser Klasse nur von BS_ImageLoader-Objekten erstellt werden können
+ /**
+ @brief Der Standardkonstruktor.
+
+ Dieser Konstruktor registriert alle Instanzen von #BS_ImageLoader-Klassen in einer Liste.<br>
+ Diese Liste enthält jeweils eine Instanz jedes #BS_ImageLoader und wird benutzt um beliebige Bilddateien einem Loader zuzuordnen.
+ @remark Dieser Konstruktor ist protected damit nur #BS_ImageLoader-Objekte diese Klasse instanziieren können.
+ */
+ BS_ImageLoader()
+ {
+ // Klasse registrieren
+ _ImageLoaderList.push_front(this);
+ }
+
+ //@{
+ /** @name Abstrakte Methoden */
+
+ /**
+ @brief Gibt an, ob der #BS_ImageLoader ein Bild lesen kann.
+ @param pFileData ein Pointer auf die kompletten Daten des Bildes.
+ @param FileSize die Größe der Daten in Byte.
+ @return Gibt true zurück, wenn der #BS_ImageLoader das Bild lesen kann, ansonsten false.
+ @remark Diese Methode muss von allen BS_ImageLoader Klassen implementiert werden.
+ */
+ virtual bool IsCorrectImageFormat(const char* pFileData, unsigned int FileSize) = 0;
+
+ /**
+ @brief Lädt eine Bilddatei.
+ @param pFileData ein Pointer auf die Bilddaten.
+ @param FileSize die Größe der Bilddaten in Byte.
+ @param ColorFormat gibt das gewünschte Farbformat an, in das die Bilddaten konvertiert werden sollen.<br>
+ Folgende Farbformate werden unterstützt:
+ - BS_GraphicEngine::CF_RGB16
+ - BS_GraphicEngine::CF_RGB15
+ - BS_GraphicEngine::CF_RGB16_INTERLEAVED
+ - BS_GraphicEngine::CF_RGB15_INTERLEAVED
+ - BS_GraphicEngine::CF_ARGB32
+ @param pUncompressedData nach erfolgreichen Laden zeigt dieser Pointer auf die enpackten und konvertierten Bilddaten.
+ @param Width gibt nach erfolgreichen Laden die Breite des geladenen Bildes an.
+ @param Height gibt nach erfolgreichen Laden die Höhe des geladenen Bildes an.
+ @param Pitch gibt nach erfolgreichen Laden die Länge einer Bildzeile in Byte an.
+ @return Gibt false zurück, falls das Laden fehlgeschlagen ist.
+ @remark Die Größe der Ausgabedaten in Bytes kann wie folgt berechnet werden: Pitch * Height.
+ @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
+ @remark Diese Methode muss von allen BS_ImageLoader Klassen implementiert werden.
+ */
+ virtual bool DecodeImage(const char* pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS ColorFormat,
+ char*& pUncompressedData,
+ int& Width, int& Height,
+ int& Pitch) = 0;
+
+ /**
+ @brief Liest die Bildeigenschaften aus.
+ @param pFileData ein Pointer auf die Bilddaten.
+ @param FileSize die Größe des Bilddaten in Byte.
+ @param ColorFormat enthält nach einem erfolgreichem Aufruf das Farbformat des Bildes.
+ @param Width enthält nach einem erfolgreichem Aufruf die Breite des Bildes in Pixeln.
+ @param Height enthält nach einem erfolgreichem Aufruf die Höhe des Bildes in Pixeln.
+ @return Gibt false zurück, wenn die Bildeigenschaften nicht ausgelesen werden konnten.
+ @remark Es darf nicht vergessen werden, die Ausgabedaten nach erfolgter Benutzung mit delete freizugeben.
+ @remark Diese Methode muss von allen BS_ImageLoader Klassen implementiert werden.
+ */
+ virtual bool ImageProperties(const char* pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS& ColorFormat,
+ int& Width, int& Height) = 0;
+
+ //@}
+
+ //@{
+ /** @name Konvertierungsmethoden */
+
+ /**
+ @brief Konvertiert eine Bildzeile mit ARGB Pixeldaten in das BS_GraphicEngine::CF_RGB16 Farbformat.
+ @param pSrcData ein Pointer auf die Quelldaten.
+ @param pDestData ein Pointer auf den Zielpuffern.
+ @param Width die Anzahl der Pixel in der Bildzeile.
+ @remark Es gilt zu beachten, dass der Zielpuffer ausreichend groß ist.<br>
+ Es sind mindestens Width * 2 Byte notwendig.
+ */
+ static void RowARGB32ToRGB16(unsigned char* pSrcData, unsigned char* pDestData, unsigned int Width)
+ {
+ for (unsigned int i = 0; i < Width; i++)
+ {
+ ((uint16_t*)pDestData)[i] = ((pSrcData[2] >> 3) << 11) | ((pSrcData[1] >> 2) << 5) | (pSrcData[0] >> 3);
+ pSrcData += 4;
+ }
+ }
+
+ /**
+ @brief Konvertiert eine Bildzeile mit ARGB Pixeldaten in das BS_GraphicEngine::CF_RGB15 Farbformat.
+ @param pSrcData ein Pointer auf die Quelldaten.
+ @param pDestData ein Pointer auf den Zielpuffern.
+ @param Width die Anzahl der Pixel in der Bildzeile.
+ @remark Es gilt zu beachten, dass der Zielpuffer ausreichend groß ist.<br>
+ Es sind mindestens Width * 2 Byte notwendig.
+ */
+ static void RowARGB32ToRGB15(unsigned char* pSrcData, unsigned char* pDestData, unsigned int Width)
+ {
+ for (unsigned int i = 0; i < Width; i++)
+ {
+ ((uint16_t*)pDestData)[i] = ((pSrcData[2] >> 3) << 10) | ((pSrcData[1] >> 3) << 5) | (pSrcData[0] >> 3);
+ pSrcData += 4;
+ }
+ }
+
+ /**
+ @brief Konvertiert eine Bildzeile mit ARGB Pixeldaten in das BS_GraphicEngine::CF_RGB16_INTERLEAVED Farbformat.
+ @param pSrcData ein Pointer auf die Quelldaten.
+ @param pDestData ein Pointer auf den Zielpuffern.
+ @param Width die Anzahl der Pixel in der Bildzeile.
+ @remark Es gilt zu beachten, dass der Zielpuffer ausreichend groß sein muss.<br>
+ Es sind mindestens ((Width + 3) / 4) * 12 Byte notwendig.
+ */
+ static void RowARGB32ToRGB16_INTERLEAVED(unsigned char* pSrcData, unsigned char* pDestData, unsigned int Width)
+ {
+ // Die Pixelblöcke erstellen, dabei werden immer jeweils 4 Pixel zu einem Block zusammengefasst
+ unsigned int BlockFillCount = 0;
+ unsigned int AlphaBlock = 0;
+ for (unsigned int i = 0; i < Width; i++)
+ {
+ // Alphawert in den Alphablock schreiben
+ AlphaBlock = (AlphaBlock >> 8) | (pSrcData[BlockFillCount * 4 + 3] << 24);
+
+ // Füllstand der Pixelblockes aktualisieren
+ BlockFillCount++;
+
+ // Sobald 4 Alphawerte gesammelt wurden, oder die Zeile zu Ende ist wird der Pixelblock in den Zielpuffer geschrieben
+ if (BlockFillCount == 4 || i == (Width - 1))
+ {
+ // Falls der AlphaBlock nicht ganz gefüllt ist muss geshiftet werden um sicherzustellen, dass die Alphawerte
+ // "left aligned" sind.
+ AlphaBlock >>= (4 - BlockFillCount) * 8;
+
+ // Alphablock schreiben
+ *((unsigned int*)pDestData) = AlphaBlock;
+ pDestData += 4;
+
+ // Pixel konvertieren und schreiben
+ RowARGB32ToRGB16(pSrcData, pDestData, BlockFillCount);
+
+ // Pointer auf den nächsten Platz im Zielpuffer setzen
+ pDestData += 8;
+
+ // Pointer auf die nächsten 4 Pixel im Quellpuffer setzen
+ pSrcData += 16;
+
+ // Neuen Pixelblock beginnen
+ BlockFillCount = 0;
+ }
+ }
+ }
+
+ /**
+ @brief Konvertiert eine Bildzeile mit ARGB Pixeldaten in das BS_GraphicEngine::CF_RGB15_INTERLEAVED Farbformat.
+ @param pSrcData ein Pointer auf die Quelldaten.
+ @param pDestData ein Pointer auf den Zielpuffern.
+ @param Width die Anzahl der Pixel in der Bildzeile.
+ @remark Es gilt zu beachten, dass der Zielpuffer ausreichend groß ist.<br>
+ Es sind mindestens (Width / 4 + Width % 4) * 3 Byte notwendig.
+ */
+ static void RowARGB32ToRGB15_INTERLEAVED(unsigned char* pSrcData, unsigned char* pDestData, unsigned int Width)
+ {
+ // Die Pixelblöcke erstellen, dabei werden immer jeweils 4 Pixel zu einem Block zusammengefasst
+ unsigned int BlockFillCount = 0;
+ unsigned int AlphaBlock = 0;
+ for (unsigned int i = 0; i < Width; i++)
+ {
+ // Alphawert in den Alphablock schreiben
+ AlphaBlock = (AlphaBlock >> 8) | (pSrcData[BlockFillCount * 4 + 3] << 24);
+
+ // Füllstand der Pixelblockes aktualisieren
+ BlockFillCount++;
+
+ // Sobald 4 Alphawerte gesammelt wurden, oder die Zeile zu Ende ist wird der Pixelblock in den Zielpuffer geschrieben
+ if (BlockFillCount == 4 || i == (Width - 1))
+ {
+ // Falls der AlphaBlock nicht ganz gefüllt ist muss geshiftet werden um sicherzustellen, dass die Alphawerte
+ // "left aligned" sind.
+ AlphaBlock >>= (4 - BlockFillCount) * 8;
+
+ // Alphablock schreiben
+ *((unsigned int*)pDestData) = AlphaBlock;
+ pDestData += 4;
+
+ // Pixel konvertieren und schreiben
+ RowARGB32ToRGB15(pSrcData, pDestData, BlockFillCount);
+
+ // Pointer auf den nächsten Platz im Zielpuffer setzen
+ pDestData += 8;
+
+ // Pointer auf die nächsten 4 Pixel im Quellpuffer setzen
+ pSrcData += 16;
+
+ // Neuen Pixelblock beginnen
+ BlockFillCount = 0;
+ }
+ }
+ }
+
+ /**
+ @brief Konvertiert eine Bildzeile mit ARGB Pixeldaten in das BS_GraphicEngine::CF_BGRA32 Farbformat.
+ @param pSrcData ein Pointer auf die Quelldaten.
+ @param pDestData ein Pointer auf den Zielpuffern.
+ @param Width die Anzahl der Pixel in der Bildzeile.
+ */
+ static void RowARGB32ToABGR32(unsigned char* pSrcData, unsigned char* pDestData, unsigned int Width)
+ {
+ for (unsigned int i = 0; i < Width; ++i)
+ {
+ *pDestData++ = pSrcData[2];
+ *pDestData++ = pSrcData[1];
+ *pDestData++ = pSrcData[0];
+ *pDestData++ = pSrcData[3];
+
+ pSrcData += 4;
+ }
+ }
+
+private:
+
+ /**
+ @brief Erzeugt je eine Instanz aller BS_ImageLoader Klassen und fügt diese in eine interne Liste ein. Diese werden dann beim
+ Laden von Bildern benutzt.
+ @remark Die Klassen müssen in der Datei imageloader_ids.h eingetragen sein, damit sie an dieser Stelle berücksichtigt werden.
+ */
+ static void _InitializeLoaderList();
+
+ /**
+ @brief Zerstört alle Instanzen von BS_ImageLoader Klassen, die in dieser Klasse registriert sind.
+ */
+ static void _DeinitializeLoaderList();
+
+ /**
+ @brief Sucht zu Bilddaten ein BS_ImageLoader Objekt, dass die Bilddaten dekodieren kann.
+ @return Gibt einen Pointer auf ein passendes BS_ImageLoader Objekt zurück, oder NULL, wenn kein passendes Objekt gefunden wurde.
+ */
+ static BS_ImageLoader* BS_ImageLoader::_FindSuitableImageLoader(const char* pFileData, unsigned int FileSize);
+
+ static std::list<BS_ImageLoader*> _ImageLoaderList; // Die Liste aller BS_ImageLoader-Objekte
+ static bool _ImageLoaderListInitialized; // Gibt an, ob die Liste schon intialisiert wurde
+};
+
+#endif
diff --git a/engines/sword25/gfx/image/imageloader_ids.h b/engines/sword25/gfx/image/imageloader_ids.h
new file mode 100755
index 0000000000..4564996a0f
--- /dev/null
+++ b/engines/sword25/gfx/image/imageloader_ids.h
@@ -0,0 +1,44 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ imageloader_ids.h
+ -----------------
+ In dieser Datei sind alle ImageLoader verzeichnet.
+ JEDER neuer ImageLoader muss hier eingetragen werden, ansonsten wird er beim Laden eines Bildes nicht berücksichtigt.
+
+ Autor: Malte Thiesen
+*/
+
+#include "imageloader.h"
+
+// Die Headerdateien der ImageLoader müssen hier eingebunden werden
+#include "pngloader.h"
+#include "b25sloader.h"
+
+// Die Tabelle enthält Pointer auf statische Member-Funktionen innerhalb der Klassen, die eine Instanz der Klasse
+// erzeugen
+typedef BS_ImageLoader* (*BS_IMAGELOADER_NEW)();
+const BS_IMAGELOADER_NEW BS_IMAGELOADER_IDS[] =
+{
+ BS_PNGLoader::CreateInstance,
+ BS_B25SLoader::CreateInstance,
+};
+const int BS_IMAGELOADER_COUNT = sizeof(BS_IMAGELOADER_IDS) / sizeof(BS_IMAGELOADER_NEW);
+
diff --git a/engines/sword25/gfx/image/pngloader.cpp b/engines/sword25/gfx/image/pngloader.cpp
new file mode 100755
index 0000000000..3815f4e4ff
--- /dev/null
+++ b/engines/sword25/gfx/image/pngloader.cpp
@@ -0,0 +1,389 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "image.h"
+#include "pngloader.h"
+#include "util/libpng/png.h"
+
+#define BS_LOG_PREFIX "PNGLOADER"
+
+// -----------------------------------------------------------------------------
+// Konstruktor / Destruktor
+// -----------------------------------------------------------------------------
+
+BS_PNGLoader::BS_PNGLoader()
+{
+}
+
+// -----------------------------------------------------------------------------
+// Laden
+// -----------------------------------------------------------------------------
+
+static void png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ memcpy(data, (char*)png_ptr->io_ptr, length);
+ png_ptr->io_ptr = (void*)((png_size_t)png_ptr->io_ptr + length);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PNGLoader::DoDecodeImage(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS ColorFormat, char * & UncompressedDataPtr,
+ int & Width, int & Height, int & Pitch)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_bytep RawDataBuffer = NULL;
+ png_bytep* pRowPtr = NULL;
+
+ int BitDepth;
+ int ColorType;
+ int InterlaceType;
+ int i;
+
+ // Zielfarbformat überprüfen
+ if (ColorFormat != BS_GraphicEngine::CF_RGB16 &&
+ ColorFormat != BS_GraphicEngine::CF_RGB15 &&
+ ColorFormat != BS_GraphicEngine::CF_RGB16_INTERLEAVED &&
+ ColorFormat != BS_GraphicEngine::CF_RGB15_INTERLEAVED &&
+ ColorFormat != BS_GraphicEngine::CF_ARGB32 &&
+ ColorFormat != BS_GraphicEngine::CF_ABGR32)
+ {
+ BS_LOG_ERRORLN("Illegal or unsupported color format.");
+ return false;
+ }
+
+ try
+ {
+ // PNG Signatur überprüfen
+ if (!png_check_sig(reinterpret_cast<png_bytep>(const_cast<char *>(FileDataPtr)), 8))
+ {
+ throw(0);
+ }
+
+ // Die beiden PNG Strukturen erstellen
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ BS_LOG_ERRORLN("Could not create libpng read struct.");
+ throw(0);
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ BS_LOG_ERRORLN("Could not create libpng info struct.");
+ throw(0);
+ }
+
+ // Rücksprungpunkt setzen. Wird im Falle eines Fehlers angesprungen.
+ if (setjmp(png_jmpbuf(png_ptr))) throw(0);
+
+ // Alternative Lesefunktion benutzen
+ png_set_read_fn(png_ptr, (void*)FileDataPtr, png_user_read_data);
+
+ // PNG Header einlesen
+ png_read_info(png_ptr, info_ptr);
+
+ // PNG Informationen auslesen
+ png_get_IHDR(png_ptr, info_ptr, (unsigned long*)&Width, (unsigned long*)&Height, &BitDepth, &ColorType, &InterlaceType, NULL, NULL);
+
+ // Pitch des Ausgabebildes berechnen
+ Pitch = BS_GraphicEngine::CalcPitch(ColorFormat, Width);
+
+ // Speicher für die endgültigen Bilddaten reservieren
+ // Dieses geschieht vor dem reservieren von Speicher für temporäre Bilddaten um die Fragmentierung des Speichers gering zu halten
+ UncompressedDataPtr = new char[Pitch * Height];
+ if (!UncompressedDataPtr)
+ {
+ BS_LOG_ERRORLN("Could not allocate memory for output image.");
+ throw(0);
+ }
+
+ // Bilder jeglicher Farbformate werden zunächst in ARGB Bilder umgewandelt
+ if (BitDepth == 16)
+ png_set_strip_16(png_ptr);
+ if (ColorType == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+ if (BitDepth < 8)
+ png_set_expand(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
+ if (ColorType == PNG_COLOR_TYPE_GRAY ||
+ ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+ png_set_bgr(png_ptr);
+
+ if (ColorType != PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+ // Nachdem die Transformationen registriert wurden, werden die Bilddaten erneut eingelesen
+ png_read_update_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, (unsigned long*)&Width, (unsigned long*)&Height, &BitDepth, &ColorType, NULL, NULL, NULL);
+
+ // PNGs ohne Interlacing werden Zeilenweise eingelesen
+ if (InterlaceType == PNG_INTERLACE_NONE)
+ {
+ // Speicher für eine Bildzeile reservieren
+ RawDataBuffer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
+ if (!RawDataBuffer)
+ {
+ BS_LOG_ERRORLN("Could not allocate memory for row buffer.");
+ throw(0);
+ }
+
+ // Bilddaten zeilenweise einlesen und in das gewünschte Zielformat konvertieren
+ for (i = 0; i < Height; i++)
+ {
+ // Zeile einlesen
+ png_read_row(png_ptr, RawDataBuffer, NULL);
+
+ // Zeile konvertieren
+ switch (ColorFormat)
+ {
+ case BS_GraphicEngine::CF_RGB16:
+ RowARGB32ToRGB16((unsigned char*)RawDataBuffer,
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_RGB15:
+ RowARGB32ToRGB15((unsigned char*)RawDataBuffer,
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_RGB16_INTERLEAVED:
+ RowARGB32ToRGB16_INTERLEAVED((unsigned char*)RawDataBuffer,
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_RGB15_INTERLEAVED:
+ RowARGB32ToRGB15_INTERLEAVED((unsigned char*)RawDataBuffer,
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_ARGB32:
+ memcpy(&UncompressedDataPtr[i * Pitch],
+ RawDataBuffer,
+ Pitch);
+ break;
+
+ case BS_GraphicEngine::CF_ABGR32:
+ RowARGB32ToABGR32((unsigned char*)RawDataBuffer,
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ default:
+ BS_ASSERT(false);
+ }
+ }
+ }
+ // PNGs mit Interlacing werden an einem Stück eingelesen
+ else
+ {
+ // Speicher für das komplette Bild reservieren
+ RawDataBuffer = new png_byte[png_get_rowbytes(png_ptr, info_ptr) * Height];
+ if (!RawDataBuffer)
+ {
+ BS_LOG_ERRORLN("Could not allocate memory for raw image buffer.");
+ throw(0);
+ }
+
+ // Speicher für die Rowpointer reservieren
+ pRowPtr = new png_bytep[Height];
+ if (!pRowPtr)
+ {
+ BS_LOG_ERRORLN("Could not allocate memory for row pointers.");
+ throw(0);
+ }
+
+ // Alle Rowpointer mit den richtigen Offsets initialisieren
+ for (i = 0; i < Height; i++)
+ pRowPtr[i] = RawDataBuffer + i * png_get_rowbytes(png_ptr, info_ptr);
+
+ // Bild einlesen
+ png_read_image(png_ptr, pRowPtr);
+
+ // Bilddaten zeilenweise in das gewünschte Ausgabeformat konvertieren
+ switch (ColorFormat)
+ {
+ case BS_GraphicEngine::CF_RGB16:
+ for (i = 0; i < Height; i++)
+ RowARGB32ToRGB16((unsigned char*)(&RawDataBuffer[i * png_get_rowbytes(png_ptr, info_ptr)]),
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_RGB15:
+ for (i = 0; i < Height; i++)
+ RowARGB32ToRGB15((unsigned char*)(&RawDataBuffer[i * png_get_rowbytes(png_ptr, info_ptr)]),
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_RGB16_INTERLEAVED:
+ for (i = 0; i < Height; i++)
+ RowARGB32ToRGB16_INTERLEAVED((unsigned char*)(&RawDataBuffer[i * png_get_rowbytes(png_ptr, info_ptr)]),
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_RGB15_INTERLEAVED:
+ for (i = 0; i < Height; i++)
+ RowARGB32ToRGB15_INTERLEAVED((unsigned char*)(&RawDataBuffer[i * png_get_rowbytes(png_ptr, info_ptr)]),
+ (unsigned char*)&UncompressedDataPtr[i * Pitch],
+ Width);
+ break;
+
+ case BS_GraphicEngine::CF_ARGB32:
+ for (i = 0; i < Height; i++)
+ memcpy(&UncompressedDataPtr[i * Pitch],
+ &RawDataBuffer[i * png_get_rowbytes(png_ptr, info_ptr)],
+ Pitch);
+ break;
+ }
+ }
+
+ // Die zusätzlichen Daten am Ende des Bildes lesen
+ png_read_end(png_ptr, NULL);
+
+ // Die Strukturen freigeben
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ // Temporäre Buffer freigeben
+ delete[] pRowPtr;
+ delete[] RawDataBuffer;
+ }
+
+ catch(int)
+ {
+ delete[] pRowPtr;
+ delete[] RawDataBuffer;
+ if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL);
+ if (info_ptr) png_destroy_read_struct(NULL, &info_ptr, NULL);
+
+ // Der Funktionsaufruf war nicht erfolgreich
+ return false;
+ }
+
+ // Der Funktionsaufruf war erfolgreich
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PNGLoader::DecodeImage(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS ColorFormat, char * & UncompressedDataPtr,
+ int & Width, int & Height, int & Pitch)
+{
+ return DoDecodeImage(FileDataPtr, FileSize, ColorFormat, UncompressedDataPtr, Width, Height, Pitch);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PNGLoader::DoImageProperties(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS & ColorFormat, int & Width, int & Height)
+{
+ // PNG Signatur überprüfen
+ if (!DoIsCorrectImageFormat(FileDataPtr, FileSize)) return false;
+
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ try
+ {
+ // Die beiden PNG Strukturen erstellen
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ BS_LOG_ERRORLN("Could not create libpng read struct.");
+ throw(0);
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ BS_LOG_ERRORLN("Could not create libpng info struct.");
+ throw(0);
+ }
+
+ // Alternative Lesefunktion benutzen
+ png_set_read_fn(png_ptr, (void*)FileDataPtr, png_user_read_data);
+
+ // PNG Header einlesen
+ png_read_info(png_ptr, info_ptr);
+
+ // PNG Informationen auslesen
+ int BitDepth;
+ int ColorType;
+ png_get_IHDR(png_ptr, info_ptr, (unsigned long*)&Width, (unsigned long*)&Height, &BitDepth, &ColorType, NULL, NULL, NULL);
+
+ // PNG-ColorType in BS ColorFormat konvertieren.
+ if (ColorType & PNG_COLOR_MASK_ALPHA || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ ColorFormat = BS_GraphicEngine::CF_ARGB32;
+ else
+ ColorFormat = BS_GraphicEngine::CF_RGB24;
+
+ // Die Strukturen freigeben
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ }
+
+ catch (int)
+ {
+ if (png_ptr) png_destroy_read_struct(&png_ptr, NULL, NULL);
+ if (info_ptr) png_destroy_read_struct(NULL, &info_ptr, NULL);
+
+ // Der Funktionsaufruf war nicht erfolgreich
+ return false;
+ }
+
+ return true;
+
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PNGLoader::ImageProperties(const char* FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS & ColorFormat, int & Width, int & Height)
+{
+ return DoImageProperties(FileDataPtr, FileSize, ColorFormat, Width, Height);
+}
+
+// -----------------------------------------------------------------------------
+// Header überprüfen
+// -----------------------------------------------------------------------------
+
+bool BS_PNGLoader::DoIsCorrectImageFormat(const char * FileDataPtr, unsigned int FileSize)
+{
+ if (FileSize > 8)
+ return png_check_sig((unsigned char*)FileDataPtr, 8) ? true : false;
+ else
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PNGLoader::IsCorrectImageFormat(const char* FileDataPtr, unsigned int FileSize)
+{
+ return DoIsCorrectImageFormat(FileDataPtr, FileSize);
+}
diff --git a/engines/sword25/gfx/image/pngloader.h b/engines/sword25/gfx/image/pngloader.h
new file mode 100755
index 0000000000..5fdedf49fc
--- /dev/null
+++ b/engines/sword25/gfx/image/pngloader.h
@@ -0,0 +1,64 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ BS_PNGLoader
+ ------------
+ BS_ImageLoader-Klasse zum Laden von PNG-Dateien
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef BS_PNGLOADER2_H
+#define BS_PNGLOADER2_H
+
+// Includes
+#include "kernel/common.h"
+#include "imageloader.h"
+
+// Klassendefinition
+class BS_PNGLoader : public BS_ImageLoader
+{
+public:
+ static BS_ImageLoader* CreateInstance()
+ {
+ #include "kernel/memlog_off.h"
+ return (BS_ImageLoader*) new BS_PNGLoader();
+ #include "kernel/memlog_on.h"
+ }
+
+ // Alle virtuellen Methoden von BS_ImageLoader sind hier als static-Methode implementiert, damit sie von BS_B25SLoader aufgerufen werden können.
+ // Die virtuellen Methoden rufen diese Methoden auf.
+ static bool DoIsCorrectImageFormat(const char * FileDataPtr, unsigned int FileSize);
+ static bool DoDecodeImage(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS ColorFormat, char * & UncompressedDataPtr,
+ int & Width, int & Height, int & Pitch);
+ static bool DoImageProperties(const char * FileDataPtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS & ColorFormat, int & Width, int & Height);
+
+protected:
+ BS_PNGLoader();
+ bool DecodeImage(const char * pFileData, unsigned int FileSize,
+ BS_GraphicEngine::COLOR_FORMATS ColorFormat,
+ char * & pUncompressedData,
+ int & Width, int & Height,
+ int & Pitch);
+ bool IsCorrectImageFormat(const char * FileDataPtr, unsigned int FileSize);
+ bool ImageProperties(const char * FileDatePtr, unsigned int FileSize, BS_GraphicEngine::COLOR_FORMATS & ColorFormat, int & Width, int & Height);
+};
+
+#endif
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
new file mode 100755
index 0000000000..035d572149
--- /dev/null
+++ b/engines/sword25/gfx/image/vectorimage.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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/bs_stdint.h"
+#include "vectorimage.h"
+#include <vector>
+#include <stdexcept>
+
+#include "agg_bounding_rect.h"
+
+using namespace std;
+
+#define BS_LOG_PREFIX "VECTORIMAGE"
+
+
+// -----------------------------------------------------------------------------
+// SWF Datentypen
+// -----------------------------------------------------------------------------
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef int16_t s32;
+
+
+// -----------------------------------------------------------------------------
+// Bitstream Hilfsklasse
+// -----------------------------------------------------------------------------
+// Das Parsen von SWF-Dateien erfordert sowohl bitweises Auslesen als auch an
+// Bytegrenzen ausgerichtetes Lesen.
+// Diese Klasse ist speziell dafür ausgestattet.
+// -----------------------------------------------------------------------------
+
+class BS_VectorImage::SWFBitStream
+{
+public:
+ SWFBitStream(const unsigned char * pData, unsigned int DataSize) :
+ m_Pos(pData), m_End(pData + DataSize), m_WordMask(0)
+ {}
+
+ inline u32 GetBits(unsigned int BitCount)
+ {
+ if (BitCount == 0 || BitCount > 32)
+ {
+ throw(runtime_error("SWFBitStream::GetBits() must read at least 1 and at most 32 bits at a time"));
+ }
+
+ u32 value = 0;
+ while (BitCount)
+ {
+ if (m_WordMask == 0) FlushByte();
+
+ value <<= 1;
+ value |= ((m_Word & m_WordMask) != 0) ? 1 : 0;
+ m_WordMask >>= 1;
+
+ --BitCount;
+ }
+
+ return value;
+ }
+
+ inline s32 GetSignedBits(unsigned int BitCount)
+ {
+ // Bits einlesen
+ u32 Temp = GetBits(BitCount);
+
+ // Falls das Sign-Bit gesetzt ist, den Rest des Rückgabewertes mit 1-Bits auffüllen (Sign Extension)
+ if (Temp & 1 << (BitCount - 1))
+ return (0xffffffff << BitCount) | Temp;
+ else
+ return Temp;
+ }
+
+ inline u32 GetU32()
+ {
+ u32 Byte1 = GetU8();
+ u32 Byte2 = GetU8();
+ u32 Byte3 = GetU8();
+ u32 Byte4 = GetU8();
+
+ return Byte1 | (Byte2 << 8) | (Byte3 << 16) | (Byte4 << 24);
+ }
+
+ inline u16 GetU16()
+ {
+ u32 Byte1 = GetU8();
+ u32 Byte2 = GetU8();
+
+ return Byte1 | (Byte2 << 8);
+ }
+
+ inline u8 GetU8()
+ {
+ FlushByte();
+ u8 Value = m_Word;
+ m_WordMask = 0;
+ FlushByte();
+
+ return Value;
+ }
+
+ inline void FlushByte()
+ {
+ if (m_WordMask != 128)
+ {
+ if (m_Pos >= m_End)
+ {
+ throw(runtime_error("Attempted to read past end of file"));
+ }
+ else
+ {
+ m_Word = *m_Pos++;
+ m_WordMask = 128;
+ }
+ }
+ }
+
+ inline void SkipBytes(unsigned int SkipLength)
+ {
+ FlushByte();
+ if (m_Pos + SkipLength >= m_End)
+ {
+ throw(runtime_error("Attempted to read past end of file"));
+ }
+ else
+ {
+ m_Pos += SkipLength;
+ m_Word = *(m_Pos - 1);
+ }
+ }
+
+private:
+ const unsigned char * m_Pos;
+ const unsigned char * m_End;
+
+ u8 m_Word;
+ unsigned int m_WordMask;
+};
+
+
+// -----------------------------------------------------------------------------
+// Konstanten und Hilfsfunktionen
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ // -----------------------------------------------------------------------------
+ // Konstanten
+ // -----------------------------------------------------------------------------
+
+ const u32 MAX_ACCEPTED_FLASH_VERSION = 3; // Die höchste Flash-Dateiversion, die vom Lader akzeptiert wird
+
+
+ // -----------------------------------------------------------------------------
+ // Konvertiert SWF-Rechteckdaten in einem Bitstrom in BS_Rect-Objekte
+ // -----------------------------------------------------------------------------
+
+ BS_Rect FlashRectToBSRect(BS_VectorImage::SWFBitStream & bs)
+ {
+ bs.FlushByte();
+
+ // Feststellen mit wie vielen Bits die einzelnen Komponenten kodiert sind
+ u32 BitsPerValue = bs.GetBits(5);
+
+ // Die einzelnen Komponenten einlesen
+ s32 XMin = bs.GetSignedBits(BitsPerValue);
+ s32 XMax = bs.GetSignedBits(BitsPerValue);
+ s32 YMin = bs.GetSignedBits(BitsPerValue);
+ s32 YMax = bs.GetSignedBits(BitsPerValue);
+
+ return BS_Rect(XMin, YMin, XMax + 1, YMax + 1);
+ }
+
+
+ // -----------------------------------------------------------------------------
+ // Konvertiert SWF-Farben in AntiGrain Farben
+ // -----------------------------------------------------------------------------
+
+ agg::rgba8 FlashColorToAGGRGBA8(unsigned int FlashColor)
+ {
+ agg::rgba8 ResultColor((FlashColor >> 16) & 0xff, (FlashColor >> 8) & 0xff, FlashColor & 0xff, FlashColor >> 24);
+ ResultColor.premultiply();
+ return ResultColor;
+ }
+
+
+ // -----------------------------------------------------------------------------
+ // Berechnet die Bounding-Box eines BS_VectorImageElement
+ // -----------------------------------------------------------------------------
+
+ struct CBBGetId
+ {
+ CBBGetId(const BS_VectorImageElement & VectorImageElement_) : VectorImageElement(VectorImageElement_) {}
+ unsigned operator [] (unsigned i) const { return VectorImageElement.GetPathInfo(i).GetID(); }
+ const BS_VectorImageElement & VectorImageElement;
+ };
+
+ BS_Rect CalculateBoundingBox(const BS_VectorImageElement & VectorImageElement)
+ {
+ agg::path_storage Path = VectorImageElement.GetPaths();
+ CBBGetId IdSource(VectorImageElement);
+
+ double x1, x2, y1, y2;
+ agg::bounding_rect(Path, IdSource, 0, VectorImageElement.GetPathCount(), &x1, &y1, &x2, &y2);
+
+ return BS_Rect(static_cast<int>(x1), static_cast<int>(y1), static_cast<int>(x2) + 1, static_cast<int>(y2) + 1);
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// Konstruktion
+// -----------------------------------------------------------------------------
+
+BS_VectorImage::BS_VectorImage(const unsigned char * pFileData, unsigned int FileSize, bool & Success)
+{
+ Success = false;
+
+ // Bitstream-Objekt erzeugen
+ // Im Folgenden werden die Dateidaten aus diesem ausgelesen.
+ SWFBitStream bs(pFileData, FileSize);
+
+ try
+ {
+ // SWF-Signatur überprüfen
+ u32 Signature[3];
+ Signature[0] = bs.GetU8();
+ Signature[1] = bs.GetU8();
+ Signature[2] = bs.GetU8();
+ if (Signature[0] != 'F' ||
+ Signature[1] != 'W' ||
+ Signature[2] != 'S')
+ {
+ BS_LOG_ERRORLN("File is not a valid SWF-file");
+ return;
+ }
+
+ // Versionsangabe überprüfen
+ u32 Version = bs.GetU8();
+ if (Version > MAX_ACCEPTED_FLASH_VERSION)
+ {
+ BS_LOG_ERRORLN("File is of version %d. Highest accepted version is %d.", Version, MAX_ACCEPTED_FLASH_VERSION);
+ return;
+ }
+
+ // Dateigröße auslesen und mit der tatsächlichen Größe vergleichen
+ u32 StoredFileSize = bs.GetU32();
+ if (StoredFileSize != FileSize)
+ {
+ BS_LOG_ERRORLN("File is not a valid SWF-file");
+ return;
+ }
+
+ // SWF-Maße auslesen
+ BS_Rect MovieRect = FlashRectToBSRect(bs);
+
+ // Framerate und Frameanzahl auslesen
+ u32 FrameRate = bs.GetU16();
+ u32 FrameCount = bs.GetU16();
+
+ // Tags parsen
+ // Da wir uns nur für das erste DefineShape-Tag interessieren
+ bool KeepParsing = true;
+ while (KeepParsing)
+ {
+ // Tags beginnen immer an Bytegrenzen
+ bs.FlushByte();
+
+ // Tagtyp und Länge auslesen
+ u16 TagTypeAndLength = bs.GetU16();
+ u32 TagType = TagTypeAndLength >> 6;
+ u32 TagLength = TagTypeAndLength & 0x3f;
+ if (TagLength == 0x3f) TagLength = bs.GetU32();
+
+ switch (TagType)
+ {
+ case 2:
+ // DefineShape
+ Success = ParseDefineShape(2, bs);
+ return;
+ case 22:
+ // DefineShape2
+ Success = ParseDefineShape(2, bs);
+ return;
+ case 32:
+ Success = ParseDefineShape(3, bs);
+ return;
+ default:
+ // Unbekannte Tags ignorieren
+ bs.SkipBytes(TagLength);
+ }
+ }
+ }
+
+ catch (runtime_error & e)
+ {
+ // Fehler loggen und Funktion verlassen
+ // Success ist somit "false" und signalisiert dem Programmierer, dass die Konstruktion fehlgeschlagen ist.
+ BS_LOG_ERRORLN("The following exception occured while parsing a SWF-file: %s", e.what());
+ return;
+ }
+
+ // Die Ausführung darf nicht an dieser Stelle ankommen: Entweder es wird ein Shape gefunden, dann wird die Funktion mit vorher verlassen, oder
+ // es wird keines gefunden, dann tritt eine Exception auf sobald über das Ende der Datei hinaus gelesen wird.
+ BS_ASSERT(false);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_VectorImage::ParseDefineShape(unsigned int ShapeType, SWFBitStream & bs)
+{
+ u32 ShapeID = bs.GetU16();
+
+ // Bounding Box auslesen
+ m_BoundingBox = FlashRectToBSRect(bs);
+
+ // Erstes Image-Element erzeugen
+ m_Elements.resize(1);
+
+ // Styles einlesen
+ unsigned int NumFillBits;
+ unsigned int NumLineBits;
+ if (!ParseStyles(ShapeType, bs, NumFillBits, NumLineBits)) return false;
+
+ unsigned int LineStyle = 0;
+ unsigned int FillStyle0 = 0;
+ unsigned int FillStyle1 = 0;
+
+ // Shaperecord parsen
+ // ------------------
+
+ bool EndOfShapeDiscovered = false;
+ while (!EndOfShapeDiscovered)
+ {
+ u32 TypeFlag = bs.GetBits(1);
+
+ // Non-Edge Record
+ if (TypeFlag == 0)
+ {
+ // Feststellen welche Parameter gesetzt werden
+ u32 StateNewStyles = bs.GetBits(1);
+ u32 StateLineStyle = bs.GetBits(1);
+ u32 StateFillStyle1 = bs.GetBits(1);
+ u32 StateFillStyle0 = bs.GetBits(1);
+ u32 StateMoveTo = bs.GetBits(1);
+
+ // End der Shape-Definition erreicht?
+ if (!StateNewStyles && !StateLineStyle && !StateFillStyle0 && !StateFillStyle1 && !StateMoveTo)
+ EndOfShapeDiscovered = true;
+ // Parameter dekodieren
+ else
+ {
+ s32 MoveDeltaX = 0;
+ s32 MoveDeltaY = 0;
+ if (StateMoveTo)
+ {
+ u32 MoveToBits = bs.GetBits(5);
+ MoveDeltaX = bs.GetSignedBits(MoveToBits);
+ MoveDeltaY = bs.GetSignedBits(MoveToBits);
+ }
+
+ if (StateFillStyle0)
+ {
+ if (NumFillBits > 0)
+ FillStyle0 = bs.GetBits(NumFillBits);
+ else
+ FillStyle0 = 0;
+ }
+
+ if (StateFillStyle1)
+ {
+ if (NumFillBits > 0)
+ FillStyle1 = bs.GetBits(NumFillBits);
+ else
+ FillStyle1 = 0;
+ }
+
+ if (StateLineStyle)
+ {
+ if (NumLineBits)
+ LineStyle = bs.GetBits(NumLineBits);
+ else
+ NumLineBits = 0;
+ }
+
+ if (StateNewStyles)
+ {
+ // An dieser Stelle werden in Flash die alten Style-Definitionen verworfen und mit den neuen überschrieben.
+ // Es wird ein neues Element begonnen.
+ m_Elements.resize(m_Elements.size() + 1);
+ if (!ParseStyles(ShapeType, bs, NumFillBits, NumLineBits)) return false;
+ }
+
+ // Ein neuen Pfad erzeugen, es sei denn, es wurden nur neue Styles definiert
+ if (StateLineStyle || StateFillStyle0 || StateFillStyle1 || StateMoveTo)
+ {
+ // Letzte Zeichenposition merken, beim Aufruf von start_new_path() wird die Zeichenpostionen auf 0, 0 zurückgesetzt
+ double LastX = m_Elements.back().m_Paths.last_x();
+ double LastY = m_Elements.back().m_Paths.last_y();
+
+ // Neue Pfadinformation erzeugen
+ m_Elements.back().m_PathInfos.push_back(BS_VectorPathInfo(m_Elements.back().m_Paths.start_new_path(), LineStyle, FillStyle0, FillStyle1));
+
+ // Falls eine Bewegung definiert wurde, wird die Zeichenpositionen an die entsprechende Position gesetzt.
+ // Ansonsten wird die Zeichenposition auf die letzte Zeichenposition gesetzt.
+ if (StateMoveTo)
+ m_Elements.back().m_Paths.move_to(MoveDeltaX, MoveDeltaY);
+ else
+ m_Elements.back().m_Paths.move_to(LastX, LastY);
+ }
+ }
+ }
+ // Edge Record
+ else
+ {
+ u32 EdgeFlag = bs.GetBits(1);
+ u32 NumBits = bs.GetBits(4) + 2;
+
+ // Curved edge
+ if (EdgeFlag == 0)
+ {
+ s32 ControlDeltaX = bs.GetSignedBits(NumBits);
+ s32 ControlDeltaY = bs.GetSignedBits(NumBits);
+ s32 AnchorDeltaX = bs.GetSignedBits(NumBits);
+ s32 AnchorDeltaY = bs.GetSignedBits(NumBits);
+
+ double ControlX = m_Elements.back().m_Paths.last_x() + ControlDeltaX;
+ double ControlY = m_Elements.back().m_Paths.last_y() + ControlDeltaY;
+ double AnchorX = ControlX + AnchorDeltaX;
+ double AnchorY = ControlY + AnchorDeltaY;
+ m_Elements.back().m_Paths.curve3(ControlX, ControlY, AnchorX, AnchorY);
+ }
+ // Staight edge
+ else
+ {
+ s32 DeltaX = 0;
+ s32 DeltaY = 0;
+
+ u32 GeneralLineFlag = bs.GetBits(1);
+ if (GeneralLineFlag)
+ {
+ DeltaX = bs.GetSignedBits(NumBits);
+ DeltaY = bs.GetSignedBits(NumBits);
+ }
+ else
+ {
+ u32 VertLineFlag = bs.GetBits(1);
+ if (VertLineFlag)
+ DeltaY = bs.GetSignedBits(NumBits);
+ else
+ DeltaX = bs.GetSignedBits(NumBits);
+ }
+
+ m_Elements.back().m_Paths.line_rel(DeltaX, DeltaY);
+ }
+ }
+ }
+
+ // Bounding-Boxes der einzelnen Elemente berechnen
+ vector<BS_VectorImageElement>::iterator it = m_Elements.begin();
+ for (; it != m_Elements.end(); ++it) it->m_BoundingBox = CalculateBoundingBox(*it);
+
+ return true;
+}
+
+
+// -----------------------------------------------------------------------------
+
+bool BS_VectorImage::ParseStyles(unsigned int ShapeType, SWFBitStream & bs, unsigned int & NumFillBits, unsigned int & NumLineBits)
+{
+ bs.FlushByte();
+
+ // Fillstyles parsen
+ // -----------------
+
+ // Anzahl an Fillstyles bestimmen
+ unsigned int FillStyleCount = bs.GetU8();
+ if (FillStyleCount == 0xff) FillStyleCount = bs.GetU16();
+
+ // Alle Fillstyles einlesen, falls ein Fillstyle mit Typ != 0 gefunden wird, wird das Parsen abgebrochen.
+ // Es wird nur "solid fill" (Typ 0) unterstützt.
+ m_Elements.back().m_FillStyles.reserve(FillStyleCount);
+ for (unsigned int i = 0; i < FillStyleCount; ++i)
+ {
+ u8 Type = bs.GetU8();
+ u32 Color;
+ if (ShapeType == 3)
+ {
+ Color = (bs.GetU8() << 16) | (bs.GetU8() << 8) | bs.GetU8() | (bs.GetU8() << 24);
+ }
+ else
+ Color = bs.GetBits(24) | (0xff << 24);
+ if (Type != 0) return false;
+
+ m_Elements.back().m_FillStyles.push_back(FlashColorToAGGRGBA8(Color));
+ }
+
+ // Linestyles parsen
+ // -----------------
+
+ // Anzahl an Linestyles bestimmen
+ unsigned int LineStyleCount = bs.GetU8();
+ if (LineStyleCount == 0xff) LineStyleCount = bs.GetU16();
+
+ // Alle Linestyles einlesen
+ m_Elements.back().m_LineStyles.reserve(LineStyleCount);
+ for (unsigned int i = 0; i < LineStyleCount; ++i)
+ {
+ double Width = bs.GetU16();
+ u32 Color;
+ if (ShapeType == 3)
+ Color = (bs.GetU8() << 16) | (bs.GetU8() << 8) | bs.GetU8() | (bs.GetU8() << 24);
+ else
+ Color = bs.GetBits(24) | (0xff << 24);
+
+ m_Elements.back().m_LineStyles.push_back(BS_VectorImageElement::LineStyleType(Width, FlashColorToAGGRGBA8(Color)));
+ }
+
+ // Bitbreite für die folgenden Styleindizes auslesen
+ NumFillBits = bs.GetBits(4);
+ NumLineBits = bs.GetBits(4);
+
+ return true;
+}
+
+
+// -----------------------------------------------------------------------------
+
+bool BS_VectorImage::Fill(const BS_Rect* pFillRect, unsigned int Color)
+{
+ BS_LOG_ERRORLN("Fill() is not supported.");
+ return false;
+}
+
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_VectorImage::GetPixel(int X, int Y)
+{
+ BS_LOG_ERRORLN("GetPixel() is not supported. Returning black.");
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_VectorImage::SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride)
+{
+ BS_LOG_ERRORLN("SetContent() is not supported.");
+ return 0;
+}
diff --git a/engines/sword25/gfx/image/vectorimage.h b/engines/sword25/gfx/image/vectorimage.h
new file mode 100755
index 0000000000..74f6c860d9
--- /dev/null
+++ b/engines/sword25/gfx/image/vectorimage.h
@@ -0,0 +1,167 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_VECTORIMAGE_H
+#define BS_VECTORIMAGE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "gfx/image/image.h"
+#include "math/rect.h"
+
+#include <vector>
+#include "agg_path_storage.h"
+#include "agg_color_rgba.h"
+
+
+class BS_VectorImage;
+
+/**
+ @brief Pfadinformationen zu BS_VectorImageElement Objekten
+
+ Jedes BS_VectorImageElement besteht aus Kantenzügen, oder auch Pfaden. Jeder dieser Pfad hat Eigenschaften, die in Objekten diesen Typs
+ gespeichert werden.
+*/
+
+class BS_VectorPathInfo
+{
+public:
+ BS_VectorPathInfo(unsigned int ID, unsigned int LineStyle, unsigned int FillStyle0, unsigned int FillStyle1) :
+ m_ID(ID), m_LineStyle(LineStyle), m_FillStyle0(FillStyle0), m_FillStyle1(FillStyle1) {};
+
+ unsigned int GetID() const { return m_ID; }
+ unsigned int GetLineStyle() const { return m_LineStyle; }
+ unsigned int GetFillStyle0() const { return m_FillStyle0; }
+ unsigned int GetFillStyle1() const { return m_FillStyle1; }
+
+private:
+ unsigned int m_ID;
+ unsigned int m_LineStyle;
+ unsigned int m_FillStyle0;
+ unsigned int m_FillStyle1;
+};
+
+
+/**
+ @brief Ein Element eines Vektorbild. Ein BS_VectorImage besteht aus diesen Elementen, die jeweils einen Teil der Graphik definieren.
+ Werden alle Elemente eines Vektorbildes übereinandergelegt, ergibt sich das komplette Bild.
+*/
+class BS_VectorImageElement
+{
+friend BS_VectorImage;
+public:
+ const agg::path_storage & GetPaths() const { return m_Paths; }
+ unsigned int GetPathCount() const { return m_PathInfos.size(); }
+ const BS_VectorPathInfo & GetPathInfo(unsigned int PathNr) const { BS_ASSERT(PathNr < GetPathCount()); return m_PathInfos[PathNr]; }
+
+ double GetLineStyleWidth(unsigned int LineStyle) const
+ {
+ BS_ASSERT(LineStyle < m_LineStyles.size());
+ return m_LineStyles[LineStyle].Width;
+ }
+
+ unsigned int GetLineStyleCount() const { return m_LineStyles.size(); }
+
+ const agg::rgba8 & GetLineStyleColor(unsigned int LineStyle) const
+ {
+ BS_ASSERT(LineStyle < m_LineStyles.size());
+ return m_LineStyles[LineStyle].Color;
+ }
+
+ unsigned int GetFillStyleCount() const { return m_FillStyles.size(); }
+
+ const agg::rgba8 & GetFillStyleColor(unsigned int FillStyle) const
+ {
+ BS_ASSERT(FillStyle < m_FillStyles.size());
+ return m_FillStyles[FillStyle];
+ }
+
+ const BS_Rect & GetBoundingBox() const { return m_BoundingBox; }
+
+private:
+ struct LineStyleType
+ {
+ LineStyleType(double Width_, const agg::rgba8 & Color_) : Width(Width_), Color(Color_) {};
+ double Width;
+ agg::rgba8 Color;
+ };
+
+ agg::path_storage m_Paths;
+ std::vector<BS_VectorPathInfo> m_PathInfos;
+ std::vector<LineStyleType> m_LineStyles;
+ std::vector<agg::rgba8> m_FillStyles;
+ BS_Rect m_BoundingBox;
+};
+
+
+/**
+ @brief Eine Vektorgraphik
+
+ Objekte dieser Klasse enthalten die Informationen eines SWF-Shapes.
+*/
+
+class BS_VectorImage : public BS_Image
+{
+public:
+ BS_VectorImage(const unsigned char * pFileData, unsigned int FileSize, bool & Success);
+
+ unsigned int GetElementCount() const { return m_Elements.size(); }
+ const BS_VectorImageElement & GetElement(unsigned int ElementNr) const
+ {
+ BS_ASSERT(ElementNr < m_Elements.size());
+ return m_Elements[ElementNr];
+ }
+ const BS_Rect & GetBoundingBox() const { return m_BoundingBox; }
+
+ //
+ // Die abstrakten Methoden von BS_Image
+ //
+ virtual int GetWidth() const { return m_BoundingBox.GetWidth(); }
+ virtual int GetHeight() const { return m_BoundingBox.GetHeight(); }
+ virtual BS_GraphicEngine::COLOR_FORMATS GetColorFormat() const { return BS_GraphicEngine::CF_ARGB32; }
+ virtual bool Fill(const BS_Rect* pFillRect = 0, unsigned int Color = BS_RGB(0, 0, 0));
+ virtual unsigned int GetPixel(int X, int Y);
+ virtual bool IsBlitSource() const { return true; }
+ virtual bool IsBlitTarget() const { return false; }
+ virtual bool IsScalingAllowed() const { return true; }
+ virtual bool IsFillingAllowed() const { return false; }
+ virtual bool IsAlphaAllowed() const { return true; }
+ virtual bool IsColorModulationAllowed() const { return true; }
+ virtual bool IsSetContentAllowed() const { return false; }
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride);
+ virtual bool Blit(int PosX = 0, int PosY = 0,
+ int Flipping = FLIP_NONE,
+ BS_Rect* pPartRect = NULL,
+ unsigned int Color = BS_ARGB(255, 255, 255, 255),
+ int Width = -1, int Height = -1);
+
+ class SWFBitStream;
+
+private:
+ bool ParseDefineShape(unsigned int ShapeType, SWFBitStream & bs);
+ bool ParseStyles(unsigned int ShapeType, SWFBitStream & bs, unsigned int & NumFillBits, unsigned int & NumLineBits);
+
+ std::vector<BS_VectorImageElement> m_Elements;
+ BS_Rect m_BoundingBox;
+};
+
+#endif
diff --git a/engines/sword25/gfx/image/vectorimagerenderer.cpp b/engines/sword25/gfx/image/vectorimagerenderer.cpp
new file mode 100755
index 0000000000..76f2330a65
--- /dev/null
+++ b/engines/sword25/gfx/image/vectorimagerenderer.cpp
@@ -0,0 +1,198 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "vectorimagerenderer.h"
+#include "vectorimage.h"
+#include "agg_conv_curve.h"
+#include "agg_path_storage.h"
+#include "agg_conv_stroke.h"
+
+
+// -----------------------------------------------------------------------------
+// CompoundShape
+// -----------------------------------------------------------------------------
+
+class CompoundShape
+{
+public:
+ CompoundShape(const BS_VectorImageElement & VectorImageElement) :
+ m_ImageElement(VectorImageElement),
+ m_Path(VectorImageElement.GetPaths()),
+ m_Affine(),
+ m_Curve(m_Path),
+ m_Trans(m_Curve, m_Affine)
+ {}
+
+ unsigned operator [] (unsigned i) const
+ {
+ return m_ImageElement.GetPathInfo(i).GetID();
+ }
+
+ unsigned paths() const { return m_ImageElement.GetPathCount(); }
+
+ void rewind(unsigned path_id)
+ {
+ m_Trans.rewind(path_id);
+ }
+
+ unsigned vertex(double* x, double* y)
+ {
+ return m_Trans.vertex(x, y);
+ }
+
+private:
+ const BS_VectorImageElement & m_ImageElement;
+ agg::path_storage m_Path;
+ agg::trans_affine m_Affine;
+ agg::conv_curve<agg::path_storage> m_Curve;
+ agg::conv_transform< agg::conv_curve<agg::path_storage> > m_Trans;
+};
+
+
+// -----------------------------------------------------------------------------
+// StyleHandler
+// -----------------------------------------------------------------------------
+
+class StyleHandler
+{
+public:
+ StyleHandler(const BS_VectorImageElement & VectorImageElement) : m_ImageElement(VectorImageElement) {}
+
+ bool is_solid(unsigned int style) const
+ {
+ return true;
+ }
+
+ const agg::rgba8 & color(unsigned style) const
+ {
+ return m_ImageElement.GetFillStyleColor(style);
+ }
+
+ void generate_span(agg::rgba8 * span, int x, int y, unsigned len, unsigned style)
+ {
+ // Wird nicht benutzt
+ return;
+ }
+
+private:
+ const BS_VectorImageElement & m_ImageElement;
+};
+
+
+// -----------------------------------------------------------------------------
+// Konstruktion
+// -----------------------------------------------------------------------------
+
+BS_VectorImageRenderer::BS_VectorImageRenderer() :
+ PixelFormat(rbuf)
+{
+
+}
+
+
+// -----------------------------------------------------------------------------
+
+bool BS_VectorImageRenderer::Render(const BS_VectorImage & VectorImage,
+ float ScaleFactorX, float ScaleFactorY,
+ unsigned int & Width, unsigned int & Height,
+ std::vector<char> & ImageData,
+ float LineScaleFactor,
+ bool NoAlphaShapes)
+{
+ Width = static_cast<unsigned int>(VectorImage.GetWidth() * ScaleFactorX);
+ Height = static_cast<unsigned int>(VectorImage.GetHeight() * ScaleFactorY);
+
+ ImageData.resize(Width * Height * 4);
+ memset(&ImageData[0], 0, ImageData.size());
+ rbuf.attach(reinterpret_cast<agg::int8u *>(&ImageData[0]), Width, Height, Width * 4);
+
+ BaseRenderer.attach(PixelFormat);
+ ScanlineRenderer.attach(BaseRenderer);
+
+ // Die SWF-Shapes sind häufig nicht am Ursprung (0, 0) ausgerichtet, daher wird die Shape vor dem Rendern derart verschoben, dass
+ // sich die linke obere Ecke der Bounding-Box im Ursprung befindet. Danach wird die Skalierung angewandt.
+ Scale = agg::trans_affine_translation(- VectorImage.GetBoundingBox().left, - VectorImage.GetBoundingBox().top);
+ Scale *= agg::trans_affine_scaling(ScaleFactorX, ScaleFactorY);
+
+ for (unsigned int element = 0; element < VectorImage.GetElementCount(); ++element)
+ {
+ const BS_VectorImageElement & CurImageElement = VectorImage.GetElement(element);
+
+ CompoundShape ImageCompoundShape(CurImageElement);
+ StyleHandler ImageStyleHandler(CurImageElement);
+ agg::conv_transform<CompoundShape> Shape(ImageCompoundShape, Scale);
+ agg::conv_stroke<agg::conv_transform<CompoundShape> > Stroke(Shape);
+
+ // Fill shape
+ //----------------------
+ CompoundRasterizer.clip_box(0, 0, Width, Height);
+ CompoundRasterizer.reset();
+ for(unsigned int i = 0; i < CurImageElement.GetPathCount(); ++i)
+ {
+ unsigned int FillStyle0 = CurImageElement.GetPathInfo(i).GetFillStyle0();
+ unsigned int FillStyle1 = CurImageElement.GetPathInfo(i).GetFillStyle1();
+
+ if (NoAlphaShapes)
+ {
+ if (FillStyle0 != 0 && CurImageElement.GetFillStyleColor(FillStyle0 - 1).a != 255) FillStyle0 = 0;
+ if (FillStyle1 != 0 && CurImageElement.GetFillStyleColor(FillStyle1 - 1).a != 255) FillStyle1 = 0;
+ }
+
+ if(FillStyle0 != 0 || FillStyle1 != 0)
+ {
+ CompoundRasterizer.styles(FillStyle0 - 1, FillStyle1 - 1);
+ CompoundRasterizer.add_path(Shape, CurImageElement.GetPathInfo(i).GetID());
+ }
+ }
+ agg::render_scanlines_compound_layered(CompoundRasterizer, Scanline, BaseRenderer, Alloc, ImageStyleHandler);
+
+
+ // Draw strokes
+ //----------------------
+ Rasterizer.clip_box(0, 0, Width, Height);
+ Stroke.line_join(agg::round_join);
+ Stroke.line_cap(agg::round_cap);
+ for(unsigned int i = 0; i < CurImageElement.GetPathCount(); ++i)
+ {
+ Rasterizer.reset();
+
+ unsigned int CurrentLineStyle = CurImageElement.GetPathInfo(i).GetLineStyle();
+ if (CurrentLineStyle != 0)
+ {
+ Stroke.width(ScaleFactorX * CurImageElement.GetLineStyleWidth(CurrentLineStyle - 1) * LineScaleFactor);
+ Rasterizer.add_path(Stroke, CurImageElement.GetPathInfo(i).GetID());
+ ScanlineRenderer.color(CurImageElement.GetLineStyleColor(CurrentLineStyle - 1));
+ // HACK
+ // Die SWF-Frames enthalten zum Teil Reste von grünen Linien, die wohl von Bernd als Umriss benutzt wurden.
+ // Damit diese Reste nicht störend auffallen werden grüne Linien schlichtweg ignoriert.
+ if (!(CurImageElement.GetLineStyleColor(CurrentLineStyle - 1).a == 255 &&
+ CurImageElement.GetLineStyleColor(CurrentLineStyle - 1).r == 0 &&
+ CurImageElement.GetLineStyleColor(CurrentLineStyle - 1).g == 255 &&
+ CurImageElement.GetLineStyleColor(CurrentLineStyle - 1).b == 0))
+ agg::render_scanlines(Rasterizer, Scanline, ScanlineRenderer);
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/engines/sword25/gfx/image/vectorimagerenderer.h b/engines/sword25/gfx/image/vectorimagerenderer.h
new file mode 100755
index 0000000000..2dc29c480e
--- /dev/null
+++ b/engines/sword25/gfx/image/vectorimagerenderer.h
@@ -0,0 +1,76 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_VECTORIMAGERENDERER_H
+#define BS_VECTORIMAGERENDERER_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include <vector>
+
+#include "agg_rendering_buffer.h"
+#include "agg_pixfmt_rgba.h"
+#include "agg_renderer_scanline.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_rasterizer_compound_aa.h"
+#include "agg_scanline_u.h"
+#include "agg_scanline_bin.h"
+#include "agg_trans_affine.h"
+#include "agg_span_allocator.h"
+
+class BS_VectorImage;
+
+
+/**
+ @brief Rendert BS_VectorImage Objekte
+*/
+
+class BS_VectorImageRenderer
+{
+public:
+ BS_VectorImageRenderer();
+
+ bool Render(const BS_VectorImage & VectorImage,
+ float ScaleFactorX, float ScaleFactorY,
+ unsigned int & Width, unsigned int & Height,
+ std::vector<char> & ImageData,
+ float LineScaleFactor = 1.0f,
+ bool NoAlphaShapes = false);
+
+private:
+ typedef agg::pixfmt_rgba32_pre PixelFormatType;
+ typedef agg::renderer_base<PixelFormatType> BaseRendererType;
+ typedef agg::renderer_scanline_aa_solid<BaseRendererType> ScanlineRendererType;
+
+ agg::rendering_buffer rbuf;
+ PixelFormatType PixelFormat;
+ BaseRendererType BaseRenderer;
+ ScanlineRendererType ScanlineRenderer;
+ agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> Rasterizer;
+ agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> CompoundRasterizer;
+ agg::scanline_u8 Scanline;
+ agg::scanline_bin ScanlineBin;
+ agg::trans_affine Scale;
+ agg::span_allocator<agg::rgba8> Alloc;
+};
+
+#endif
diff --git a/engines/sword25/gfx/opengl/glimage.cpp b/engines/sword25/gfx/opengl/glimage.cpp
new file mode 100755
index 0000000000..1f5322516b
--- /dev/null
+++ b/engines/sword25/gfx/opengl/glimage.cpp
@@ -0,0 +1,208 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// INCLUDES
+// -----------------------------------------------------------------------------
+
+#include "util/glsprites/glsprites.h"
+#include "package/packagemanager.h"
+#include "gfx/image/imageloader.h"
+#include "openglgfx.h"
+#include "glimage.h"
+
+#define BS_LOG_PREFIX "GLIMAGE"
+
+// -----------------------------------------------------------------------------
+// CONSTRUCTION / DESTRUCTION
+// -----------------------------------------------------------------------------
+
+BS_GLImage::BS_GLImage(const std::string & Filename, bool & Result) :
+ m_Sprite(0),
+ m_Width(0),
+ m_Height(0)
+{
+ Result = false;
+
+ BS_PackageManager * pPackage = static_cast<BS_PackageManager*>(BS_Kernel::GetInstance()->GetService("package"));
+ BS_ASSERT(pPackage);
+
+ // Datei laden
+ char* pFileData;
+ unsigned int FileSize;
+ if (!(pFileData = (char*) pPackage->GetFile(Filename, &FileSize)))
+ {
+ BS_LOG_ERRORLN("File \"%s\" could not be loaded.", Filename.c_str());
+ return;
+ }
+
+ // Bildeigenschaften bestimmen
+ BS_GraphicEngine::COLOR_FORMATS ColorFormat;
+ int Pitch;
+ if (!BS_ImageLoader::ExtractImageProperties(pFileData, FileSize, ColorFormat, m_Width, m_Height))
+ {
+ BS_LOG_ERRORLN("Could not read image properties.");
+ return;
+ }
+
+ // Das Bild dekomprimieren
+ char * pUncompressedData;
+ if (!BS_ImageLoader::LoadImage(pFileData, FileSize, BS_GraphicEngine::CF_ABGR32, pUncompressedData, m_Width, m_Height, Pitch))
+ {
+ BS_LOG_ERRORLN("Could not decode image.");
+ return;
+ }
+
+ // Dateidaten freigeben
+ delete[] pFileData;
+
+ // GLS-Sprite mit den Bilddaten erstellen
+ GLS_Result GLSResult = GLS_NewSprite(m_Width, m_Height,
+ (ColorFormat == BS_GraphicEngine::CF_ARGB32) ? GLS_True : GLS_False,
+ pUncompressedData,
+ &m_Sprite);
+ if (Result != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Could not create GLS_Sprite. Reason: %s", GLS_ResultString(GLSResult));
+ return;
+ }
+
+ // Bilddaten freigeben
+ delete[] pUncompressedData;
+
+ Result = true;
+ return;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_GLImage::BS_GLImage(unsigned int Width, unsigned int Height, bool & Result) :
+ m_Sprite(0),
+ m_Width(Width),
+ m_Height(Height)
+{
+ Result = false;
+
+ // GLS-Sprite mit den Bilddaten erstellen
+ GLS_Result GLSResult = GLS_NewSprite(m_Width, m_Height,
+ GLS_True,
+ 0,
+ &m_Sprite);
+ if (GLSResult != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Could not create GLS_Sprite. Reason: %s", GLS_ResultString(GLSResult));
+ return;
+ }
+
+ Result = true;
+ return;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_GLImage::~BS_GLImage()
+{
+ if (m_Sprite) GLS_DeleteSprite(m_Sprite);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GLImage::Fill(const BS_Rect* pFillRect, unsigned int Color)
+{
+ BS_LOG_ERRORLN("Fill() is not supported.");
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GLImage::SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride)
+{
+ // Überprüfen, ob PixelData ausreichend viele Pixel enthält um ein Bild der Größe Width * Height zu erzeugen
+ if (Pixeldata.size() < static_cast<unsigned int>(m_Width * m_Height * 4))
+ {
+ BS_LOG_ERRORLN("PixelData vector is too small to define a 32 bit %dx%d image.", m_Width, m_Height);
+ return false;
+ }
+
+ // GLS-Sprite mit den Bilddaten füllen
+ GLS_Result GLSResult = GLS_SetSpriteData(m_Sprite, m_Width, m_Height, &Pixeldata[Offset], Stride / 4);
+ if (GLSResult != GLS_OK)
+ {
+ BS_LOG_ERRORLN("CGLS_SetSpriteData() failed. Reason: %s", GLS_ResultString(GLSResult));
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_GLImage::GetPixel(int X, int Y)
+{
+ BS_LOG_ERRORLN("GetPixel() is not supported. Returning black.");
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_GLImage::Blit(int PosX, int PosY,
+ int Flipping,
+ BS_Rect* pPartRect,
+ unsigned int Color,
+ int Width, int Height)
+{
+ // BS_Rect nach GLS_Rect konvertieren
+ GLS_Rect SubImage;
+ if (pPartRect)
+ {
+ SubImage.x1 = pPartRect->left;
+ SubImage.y1 = pPartRect->top;
+ SubImage.x2 = pPartRect->right;
+ SubImage.y2 = pPartRect->bottom;
+ }
+
+ // Farbe nach GLS_Color konvertieren
+ GLS_Color GLSColor;
+ GLSColor.a = Color >> 24;
+ GLSColor.r = (Color >> 16) & 0xff;
+ GLSColor.g = (Color >> 8) & 0xff;
+ GLSColor.b = Color & 0xff;
+
+ // Skalierungen berechnen
+ GLS_Float ScaleX, ScaleY;
+ if (Width == -1) Width = m_Width;
+ ScaleX = (GLS_Float) Width / (GLS_Float) m_Width;
+
+ if (Height == -1) Height = m_Height;
+ ScaleY = (GLS_Float) Height / (GLS_Float) m_Height;
+
+ // Rendern
+ // TODO:
+ // Die Bedeutung von FLIP_V und FLIP_H ist vertauscht. Allerdings glaubt der Rest der Engine auch daran, daher war es einfacher diesen Fehler
+ // weiterzuführen. Bei Gelegenheit ist dieses aber zu ändern.
+ GLS_Result Result = GLS_Blit(m_Sprite,
+ PosX, PosY,
+ pPartRect ? &SubImage : 0, &GLSColor,
+ (Flipping & BS_Image::FLIP_V) ? GLS_True : GLS_False,
+ (Flipping & BS_Image::FLIP_H) ? GLS_True : GLS_False,
+ ScaleX, ScaleY);
+ if (Result != GLS_OK) BS_LOG_ERRORLN("GLS_Blit() failed. Reason: %s", GLS_ResultString(Result));
+
+ return Result == GLS_OK;
+}
diff --git a/engines/sword25/gfx/opengl/glimage.h b/engines/sword25/gfx/opengl/glimage.h
new file mode 100755
index 0000000000..d9c81dc4a5
--- /dev/null
+++ b/engines/sword25/gfx/opengl/glimage.h
@@ -0,0 +1,85 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_GL_IMAGE_H
+#define BS_GL_IMAGE_H
+
+// -----------------------------------------------------------------------------
+// INCLUDES
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "gfx/image/image.h"
+#include "gfx/graphicengine.h"
+
+#include <vector>
+
+// -----------------------------------------------------------------------------
+// FORWARD DECLARATION
+// -----------------------------------------------------------------------------
+
+typedef void * GLS_Sprite;
+
+// -----------------------------------------------------------------------------
+// CLASS DEFINITION
+// -----------------------------------------------------------------------------
+
+class BS_GLImage : public BS_Image
+{
+public:
+ BS_GLImage(const std::string & Filename, bool & Result);
+
+ /**
+ @brief Erzeugt ein leeres BS_GLImage
+
+ @param Width die Breite des zu erzeugenden Bildes.
+ @param Height die Höhe des zu erzeugenden Bildes
+ @param Result gibt dem Aufrufer bekannt, ob der Konstruktor erfolgreich ausgeführt wurde. Wenn es nach dem Aufruf false enthalten sollte,
+ dürfen keine Methoden am Objekt aufgerufen werden und das Objekt ist sofort zu zerstören.
+ */
+ BS_GLImage(unsigned int Width, unsigned int Height, bool & Result);
+ virtual ~BS_GLImage();
+
+ virtual int GetWidth() const { return m_Width; }
+ virtual int GetHeight() const { return m_Height; }
+ virtual BS_GraphicEngine::COLOR_FORMATS GetColorFormat() const { return BS_GraphicEngine::CF_ARGB32; }
+
+ virtual bool Blit(int PosX = 0, int PosY = 0,
+ int Flipping = BS_Image::FLIP_NONE,
+ BS_Rect* pPartRect = NULL,
+ unsigned int Color = BS_ARGB(255, 255, 255, 255),
+ int Width = -1, int Height = -1);
+ virtual bool Fill(const BS_Rect* pFillRect, unsigned int Color);
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset = 0, unsigned int Stride = 0);
+ virtual unsigned int GetPixel(int X, int Y);
+
+ virtual bool IsBlitSource() const { return true; }
+ virtual bool IsBlitTarget() const { return false; }
+ virtual bool IsScalingAllowed() const { return true; }
+ virtual bool IsFillingAllowed() const { return false; }
+ virtual bool IsAlphaAllowed() const { return true; }
+ virtual bool IsColorModulationAllowed() const { return true; }
+ virtual bool IsSetContentAllowed() const { return true; }
+private:
+ GLS_Sprite m_Sprite;
+ int m_Width;
+ int m_Height;
+};
+
+#endif
diff --git a/engines/sword25/gfx/opengl/glvectorimageblit.cpp b/engines/sword25/gfx/opengl/glvectorimageblit.cpp
new file mode 100755
index 0000000000..38cfd9fa85
--- /dev/null
+++ b/engines/sword25/gfx/opengl/glvectorimageblit.cpp
@@ -0,0 +1,133 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "gfx/image/vectorimage.h"
+#include "gfx/image/vectorimagerenderer.h"
+#include "util/glsprites/glsprites.h"
+
+#include <vector>
+using namespace std;
+
+#define BS_LOG_PREFIX "GLVECTORIMAGEBLIT"
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const float LINE_SCALE_FACTOR = 1.0f;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_VectorImage::Blit(int PosX, int PosY,
+ int Flipping,
+ BS_Rect* pPartRect,
+ unsigned int Color,
+ int Width, int Height)
+{
+ static BS_VectorImageRenderer VectorImageRenderer;
+ static vector<char> PixelData;
+ static GLS_Sprite Sprite = 0;
+ static BS_VectorImage * OldThis = 0;
+ static int OldWidth;
+ static int OldHeight;
+ static GLS_Rect OldSubImage;
+
+ // Falls Breite oder Höhe 0 sind, muss nichts dargestellt werden.
+ if (Width == 0 || Height == 0) return true;
+
+ // Sprite erstellen, falls es noch nicht erstellt wurde
+ if (Sprite == 0)
+ {
+ GLS_Result Result = GLS_NewSprite(512, 512, GLS_True, 0, &Sprite);
+ if (Result != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Could not create GLS_Sprite. Reason: %s", GLS_ResultString(Result));
+ return false;
+ }
+ }
+
+ // Feststellen, ob das alte Bild im Cache nicht wiederbenutzt werden kann und neu Berechnet werden muss
+ if (!(OldThis == this && OldWidth == Width && OldHeight == Height && Sprite != 0))
+ {
+ float ScaleFactorX = (Width == - 1) ? 1 : static_cast<float>(Width) / static_cast<float>(GetWidth());
+ float ScaleFactorY = (Height == - 1) ? 1: static_cast<float>(Height) / static_cast<float>(GetHeight());
+
+ unsigned int RenderedWidth;
+ unsigned int RenderedHeight;
+ if (!VectorImageRenderer.Render(*this, ScaleFactorX, ScaleFactorY, RenderedWidth, RenderedHeight, PixelData, LINE_SCALE_FACTOR))
+ {
+ BS_LOG_ERRORLN("Call to BS_VectorImageRenderer::Render() failed.");
+ return false;
+ }
+
+ if (RenderedWidth > 512 || RenderedHeight > 512)
+ {
+ BS_LOG_WARNINGLN("Currently the maximum size for scaled vector images is 512x512.");
+ return true;
+ }
+
+ GLS_Result Result = GLS_SetSpriteData(Sprite, RenderedWidth, RenderedHeight, &PixelData[0], 0);
+ if (Result != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Call to GLS_SetSpriteData() failed. Reason: %s", GLS_ResultString(Result));
+ return false;
+ }
+
+ OldThis = this;
+ OldHeight = Height;
+ OldWidth = Width;
+
+ OldSubImage.x1 = 0;
+ OldSubImage.y1 = 0;
+ OldSubImage.x2 = RenderedWidth;
+ OldSubImage.y2 = RenderedHeight;
+ }
+
+ // Rendern
+ // -------
+
+ // pDest wird ignoriert. Es wird einfach angenommen, dass der Backbuffer gemeint ist, da nur auf den Backbuffer gerendert werden kann.
+ // Ebenso werden pPartRect ignoriert. Es wird immer das gesamte Sprite gerendert.
+
+ // Farbe nach GLS_Color konvertieren
+ GLS_Color GLSColor;
+ GLSColor.a = Color >> 24;
+ GLSColor.r = (Color >> 16) & 0xff;
+ GLSColor.g = (Color >> 8) & 0xff;
+ GLSColor.b = Color & 0xff;
+
+ // Rendern
+ // TODO:
+ // Die Bedeutung von FLIP_V und FLIP_H ist vertauscht. Allerdings glaubt der Rest der Engine auch daran, daher war es einfacher diesen Fehler
+ // weiterzuführen. Bei Gelegenheit ist dieses aber zu ändern.
+ GLS_Result Result = GLS_Blit(Sprite,
+ PosX, PosY,
+ &OldSubImage, &GLSColor,
+ (Flipping & BS_Image::FLIP_V) ? GLS_True : GLS_False,
+ (Flipping & BS_Image::FLIP_H) ? GLS_True : GLS_False,
+ 1.0f, 1.0f);
+ if (Result != GLS_OK) BS_LOG_ERRORLN("GLS_Blit() failed. Reason: %s", GLS_ResultString(Result));
+
+ return Result == GLS_OK;
+}
diff --git a/engines/sword25/gfx/opengl/openglgfx.cpp b/engines/sword25/gfx/opengl/openglgfx.cpp
new file mode 100755
index 0000000000..6131a229a5
--- /dev/null
+++ b/engines/sword25/gfx/opengl/openglgfx.cpp
@@ -0,0 +1,505 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// INCLUDES
+// -----------------------------------------------------------------------------
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <GL/GL.h>
+
+#include "util/glsprites/glsprites.h"
+#include "../bitmapresource.h"
+#include "../animationresource.h"
+#include "../fontresource.h"
+#include "../panel.h"
+#include "../renderobjectmanager.h"
+#include "../image/vectorimage.h"
+#include "package/packagemanager.h"
+#include "kernel/inputpersistenceblock.h"
+#include "kernel/outputpersistenceblock.h"
+
+#include "openglgfx.h"
+#include "glimage.h"
+#include "swimage.h"
+
+#include <algorithm>
+
+using namespace std;
+
+#define BS_LOG_PREFIX "OPENGLGFX"
+
+
+// -----------------------------------------------------------------------------
+// CONSTANTS
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const unsigned int BIT_DEPTH = 32;
+ const unsigned int BACKBUFFER_COUNT = 1;
+ const std::string PNG_EXTENSION(".png");
+ const std::string PNG_S_EXTENSION("_s.png");
+ const std::string ANI_EXTENSION("_ani.xml");
+ const std::string FNT_EXTENSION("_fnt.xml");
+ const std::string SWF_EXTENSION(".swf");
+ const std::string B25S_EXTENSION(".b25s");
+}
+
+
+// -----------------------------------------------------------------------------
+// CONSTRUCTION / DESTRUCTION
+// -----------------------------------------------------------------------------
+
+BS_OpenGLGfx::BS_OpenGLGfx(BS_Kernel * pKernel) :
+ BS_GraphicEngine(pKernel),
+ m_GLspritesInitialized(false)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+BS_OpenGLGfx::~BS_OpenGLGfx()
+{
+ if (m_GLspritesInitialized) GLS_Quit();
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Service * BS_OpenGLGfx_CreateObject(BS_Kernel* pKernel)
+{
+ return new BS_OpenGLGfx(pKernel);
+}
+
+
+// -----------------------------------------------------------------------------
+// INTERFACE
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::Init(int Width, int Height, int BitDepth, int BackbufferCount, bool Windowed)
+{
+ // Warnung ausgeben, wenn eine nicht unterstützte Bittiefe gewählt wurde.
+ if (BitDepth != BIT_DEPTH)
+ {
+ BS_LOG_WARNINGLN("Can't use a bit depth of %d (not supported). Falling back to %d.", BitDepth, BIT_DEPTH);
+ m_BitDepth = BIT_DEPTH;
+ }
+
+ // Warnung ausgeben, wenn nicht genau ein Backbuffer gewählt wurde.
+ if (BackbufferCount != BACKBUFFER_COUNT)
+ {
+ BS_LOG_WARNINGLN("Can't use %d backbuffers (not supported). Falling back to %d.", BackbufferCount, BACKBUFFER_COUNT);
+ BackbufferCount = BACKBUFFER_COUNT;
+ }
+
+ // Parameter in lokale Variablen kopieren
+ m_Width = Width;
+ m_Height = Height;
+ m_BitDepth = BitDepth;
+ m_Windowed = Windowed;
+ m_ScreenRect.left = 0;
+ m_ScreenRect.top = 0;
+ m_ScreenRect.right = m_Width;
+ m_ScreenRect.bottom = m_Height;
+
+ // GLsprites initialisieren
+ HWND hwnd = reinterpret_cast<HWND>(BS_Kernel::GetInstance()->GetWindow()->GetWindowHandle());
+ GLS_Result Result = GLS_InitExternalWindow(Width, Height, Windowed ? GLS_False : GLS_True, hwnd);
+ if (Result != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Could not initialize GLsprites. Reason: %s", GLS_ResultString(Result));
+ return false;
+ }
+ m_GLspritesInitialized = true;
+
+ // Standardmäßig ist Vsync an.
+ SetVsync(true);
+
+ // Layer-Manager initialisieren.
+ m_RenderObjectManagerPtr.reset(new BS_RenderObjectManager(Width, Height, BackbufferCount + 1));
+
+ // Hauptpanel erstellen
+ m_MainPanelPtr = m_RenderObjectManagerPtr->GetTreeRoot()->AddPanel(Width, Height, BS_ARGB(0,0,0,0));
+ if (!m_MainPanelPtr.IsValid()) return false;
+ m_MainPanelPtr->SetVisible(true);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::StartFrame(bool UpdateAll)
+{
+ // Berechnen, wie viel Zeit seit dem letzten Frame vergangen ist.
+ // Dieser Wert kann über GetLastFrameDuration() von Modulen abgefragt werden, die zeitabhängig arbeiten.
+ UpdateLastFrameDuration();
+
+ // Den Layer-Manager auf den nächsten Frame vorbereiten
+ m_RenderObjectManagerPtr->StartFrame();
+
+ // GLsprites bescheidgeben
+ GLS_Result Result = GLS_StartFrame();
+ if (Result != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Call to GLS_StartFrame() failed. Reason: %s", GLS_ResultString(Result));
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::EndFrame()
+{
+ // Scene zeichnen
+ m_RenderObjectManagerPtr->Render();
+
+ // Debug-Lines zeichnen
+ if (!m_DebugLines.empty())
+ {
+ glEnable(GL_LINE_SMOOTH);
+ glBegin(GL_LINES);
+
+ std::vector<DebugLine>::const_iterator iter = m_DebugLines.begin();
+ for (; iter != m_DebugLines.end(); ++iter)
+ {
+ const unsigned int & Color = (*iter).Color;
+ const BS_Vertex & Start = (*iter).Start;
+ const BS_Vertex & End = (*iter).End;
+
+ glColor4ub((Color >> 16) & 0xff, (Color >> 8) & 0xff, Color & 0xff, Color >> 24);
+ glVertex2d(Start.X, Start.Y);
+ glVertex2d(End.X, End.Y);
+ }
+
+ glEnd();
+ glDisable(GL_LINE_SMOOTH);
+
+ m_DebugLines.clear();
+ }
+
+ // Flippen
+ GLS_Result Result = GLS_EndFrame();
+ if (Result != GLS_OK)
+ {
+ BS_LOG_ERRORLN("Call to GLS_EndFrame() failed. Reason: %s", GLS_ResultString(Result));
+ return false;
+ }
+
+ // Framecounter aktualisieren
+ m_FPSCounter.Update();
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_RenderObjectPtr<BS_Panel> BS_OpenGLGfx::GetMainPanel()
+{
+ return m_MainPanelPtr;
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OpenGLGfx::SetVsync(bool Vsync)
+{
+ GLS_Result Result = GLS_SetVSync(Vsync ? GLS_True : GLS_False);
+ if (Result != GLS_OK) BS_LOG_WARNINGLN("Could not set vsync status. Reason: %s", GLS_ResultString(Result));
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::GetVsync() const
+{
+ GLS_Bool Status;
+ GLS_Result Result = GLS_IsVsync(&Status);
+ if (Result != GLS_OK)
+ {
+ BS_LOG_WARNINGLN("Could not get vsync status. Returning false. Reason: %s", GLS_ResultString(Result));
+ return false;
+ }
+
+ return Status == GLS_True ? true : false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::Fill(const BS_Rect* FillRectPtr, unsigned int Color)
+{
+ BS_Rect Rect;
+
+ if (!FillRectPtr)
+ {
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = m_Width;
+ Rect.bottom = m_Height;
+ FillRectPtr = &Rect;
+ }
+
+ glBegin(GL_QUADS);
+ glColor4ub((Color >> 16) & 0xff, (Color >> 8) & 0xff, Color & 0xff, Color >> 24);
+
+ glVertex2i(FillRectPtr->left, FillRectPtr->top);
+ glVertex2i(FillRectPtr->right, FillRectPtr->top);
+ glVertex2i(FillRectPtr->right, FillRectPtr->bottom);
+ glVertex2i(FillRectPtr->left, FillRectPtr->bottom);
+ glEnd();
+
+ return glGetError() == 0;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::GetScreenshot(unsigned int & Width, unsigned int & Height, vector<unsigned int> & Data)
+{
+ if (!ReadFramebufferContents(m_Width, m_Height, Data)) return false;
+
+ // Die Größe des Framebuffers zurückgeben.
+ Width = m_Width;
+ Height = m_Height;
+
+ // Bilddaten vom OpenGL-Format in unser eigenes Format umwandeln.
+ ReverseRGBAComponentOrder(Data);
+ FlipImagedataVertical(Width, Height, Data);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::ReadFramebufferContents(unsigned int Width, unsigned int Height, std::vector<unsigned int> & Data)
+{
+ Data.resize(Width * Height);
+ glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, &Data[0]);
+
+ if (glGetError() == 0)
+ return true;
+ else
+ {
+ Data.clear();
+ return false;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OpenGLGfx::ReverseRGBAComponentOrder(vector<unsigned int> & Data)
+{
+ vector<unsigned int>::iterator It = Data.begin();
+ while (It != Data.end())
+ {
+ unsigned int Pixel = *It;
+ *It = (Pixel & 0xff00ff00) | ((Pixel >> 16) & 0xff) | ((Pixel & 0xff) << 16);
+ ++It;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OpenGLGfx::FlipImagedataVertical(unsigned int Width, unsigned int Height, vector<unsigned int> & Data)
+{
+ vector<unsigned int> LineBuffer(Width);
+
+ for (unsigned int Y = 0; Y < Height / 2; ++Y)
+ {
+ vector<unsigned int>::iterator Line1It = Data.begin() + Y * Width;
+ vector<unsigned int>::iterator Line2It = Data.begin() + (Height - 1 - Y) * Width;
+ copy(Line1It, Line1It + Width, LineBuffer.begin());
+ copy(Line2It, Line2It + Width, Line1It);
+ copy(LineBuffer.begin(), LineBuffer.end(), Line2It);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// RESOURCE MANAGING
+// -----------------------------------------------------------------------------
+
+static bool DoesStringEndWith(const std::string & String, const std::string & OtherString)
+{
+ std::string::size_type StringPos = String.rfind(OtherString);
+ if (StringPos == std::string::npos) return false;
+
+ return StringPos + OtherString.size() == String.size();
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Resource * BS_OpenGLGfx::LoadResource(const std::string& FileName)
+{
+ BS_ASSERT(CanLoadResource(FileName));
+
+ // Bild für den Softwarebuffer laden
+ if (DoesStringEndWith(FileName, PNG_S_EXTENSION))
+ {
+ bool Result;
+ BS_SWImage * pImage = new BS_SWImage(FileName, Result);
+ if (!Result)
+ {
+ delete pImage;
+ return 0;
+ }
+
+ BS_BitmapResource * pResource = new BS_BitmapResource(FileName, pImage);
+ if (!pResource->IsValid())
+ {
+ delete pResource;
+ return 0;
+ }
+
+ return pResource;
+ }
+
+ // Sprite-Bild laden
+ if (DoesStringEndWith(FileName, PNG_EXTENSION) || DoesStringEndWith(FileName, B25S_EXTENSION))
+ {
+ bool Result;
+ BS_GLImage * pImage = new BS_GLImage(FileName, Result);
+ if (!Result)
+ {
+ delete pImage;
+ return 0;
+ }
+
+ BS_BitmapResource * pResource = new BS_BitmapResource(FileName, pImage);
+ if (!pResource->IsValid())
+ {
+ delete pResource;
+ return 0;
+ }
+
+ return pResource;
+ }
+
+
+ // Vectorgraphik laden
+ if (DoesStringEndWith(FileName, SWF_EXTENSION))
+ {
+ // Pointer auf Package-Manager holen
+ BS_PackageManager * pPackage = BS_Kernel::GetInstance()->GetPackage();
+ BS_ASSERT(pPackage);
+
+ // Datei laden
+ unsigned char* pFileData;
+ unsigned int FileSize;
+ if (!(pFileData = static_cast<unsigned char*>(pPackage->GetFile(FileName, &FileSize))))
+ {
+ BS_LOG_ERRORLN("File \"%s\" could not be loaded.", FileName.c_str());
+ return 0;
+ }
+
+ bool Result;
+ BS_VectorImage * pImage = new BS_VectorImage(pFileData, FileSize, Result);
+ if (!Result)
+ {
+ delete pImage;
+ delete [] pFileData;
+ return 0;
+ }
+
+ BS_BitmapResource * pResource = new BS_BitmapResource(FileName, pImage);
+ if (!pResource->IsValid())
+ {
+ delete pResource;
+ delete [] pFileData;
+ return 0;
+ }
+
+ delete [] pFileData;
+ return pResource;
+ }
+
+ // Animation laden
+ if (DoesStringEndWith(FileName, ANI_EXTENSION))
+ {
+ BS_AnimationResource * pResource = new BS_AnimationResource(FileName);
+ if (pResource->IsValid())
+ return pResource;
+ else
+ {
+ delete pResource;
+ return 0;
+ }
+ }
+
+ // Font laden
+ if (DoesStringEndWith(FileName, FNT_EXTENSION))
+ {
+ BS_FontResource * pResource = new BS_FontResource(BS_Kernel::GetInstance(), FileName);
+ if (pResource->IsValid())
+ return pResource;
+ else
+ {
+ delete pResource;
+ return 0;
+ }
+ }
+
+ BS_LOG_ERRORLN("Service cannot load \"%s\".", FileName.c_str());
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::CanLoadResource(const std::string& FileName)
+{
+ return DoesStringEndWith(FileName, PNG_EXTENSION) ||
+ DoesStringEndWith(FileName, ANI_EXTENSION) ||
+ DoesStringEndWith(FileName, FNT_EXTENSION) ||
+ DoesStringEndWith(FileName, SWF_EXTENSION) ||
+ DoesStringEndWith(FileName, B25S_EXTENSION);
+}
+
+
+// -----------------------------------------------------------------------------
+// DEBUGGING
+// -----------------------------------------------------------------------------
+
+void BS_OpenGLGfx::DrawDebugLine(const BS_Vertex & Start, const BS_Vertex & End, unsigned int Color)
+{
+ m_DebugLines.push_back(DebugLine(Start, End, Color));
+}
+
+// -----------------------------------------------------------------------------
+// PERSISTENZ
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool result = true;
+
+ result &= BS_GraphicEngine::Persist(Writer);
+ result &= m_RenderObjectManagerPtr->Persist(Writer);
+
+ return result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_OpenGLGfx::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool result = true;
+
+ result &= BS_GraphicEngine::Unpersist(Reader);
+ result &= m_RenderObjectManagerPtr->Unpersist(Reader);
+
+ return result && Reader.IsGood();
+}
diff --git a/engines/sword25/gfx/opengl/openglgfx.h b/engines/sword25/gfx/opengl/openglgfx.h
new file mode 100755
index 0000000000..ec305bee8f
--- /dev/null
+++ b/engines/sword25/gfx/opengl/openglgfx.h
@@ -0,0 +1,114 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_OPENGLGFX_H
+#define BS_OPENGLGFX_H
+
+// -----------------------------------------------------------------------------
+// INCLUDES
+// -----------------------------------------------------------------------------
+
+#include "kernel/memlog_off.h"
+#include <memory>
+#include <vector>
+#include "kernel/memlog_on.h"
+
+#include "kernel/common.h"
+#include "../graphicengine.h"
+#include "../renderobjectptr.h"
+#include "util/glsprites/glsprites.h"
+
+// -----------------------------------------------------------------------------
+// FORWARD DECLARATIONS
+// -----------------------------------------------------------------------------
+
+class BS_Kernel;
+class BS_Service;
+class BS_Resource;
+class BS_Panel;
+class BS_Image;
+class BS_RenderObjectManager;
+
+
+// -----------------------------------------------------------------------------
+// CLASS DECLARATION
+// -----------------------------------------------------------------------------
+
+class BS_OpenGLGfx : public BS_GraphicEngine
+{
+public:
+ BS_OpenGLGfx(BS_Kernel* pKernel);
+ virtual ~BS_OpenGLGfx();
+
+ // Interface
+ // ---------
+ virtual bool Init(int Width, int Height, int BitDepth, int BackbufferCount, bool Windowed);
+ virtual bool StartFrame(bool UpdateAll);
+ virtual bool EndFrame();
+
+ virtual BS_RenderObjectPtr<BS_Panel> GetMainPanel();
+
+ virtual void SetVsync(bool Vsync);
+ virtual bool GetVsync() const;
+
+ virtual bool Fill(const BS_Rect* FillRectPtr = 0, unsigned int Color = BS_RGB(0, 0, 0));
+ virtual bool GetScreenshot(unsigned int & Width, unsigned int & Height, std::vector<unsigned int> & Data);
+
+ // Resource-Managing Methoden
+ // --------------------------
+ virtual BS_Resource* LoadResource(const std::string& FileName);
+ virtual bool CanLoadResource(const std::string& FileName);
+
+ // Debugging Methoden
+ // ------------------
+ virtual void DrawDebugLine(const BS_Vertex & Start, const BS_Vertex & End, unsigned int Color);
+ static const char * GetGLSResultString(GLS_Result Result);
+
+ // Persistenz Methoden
+ // -------------------
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+private:
+ bool m_GLspritesInitialized;
+
+ BS_RenderObjectPtr<BS_Panel> m_MainPanelPtr;
+
+ std::auto_ptr<BS_RenderObjectManager> m_RenderObjectManagerPtr;
+
+ struct DebugLine
+ {
+ DebugLine(const BS_Vertex & _Start, const BS_Vertex & _End, unsigned int _Color) :
+ Start(_Start),
+ End(_End),
+ Color(_Color) {};
+
+ BS_Vertex Start;
+ BS_Vertex End;
+ unsigned int Color;
+ };
+
+ std::vector<DebugLine> m_DebugLines;
+
+ static bool ReadFramebufferContents(unsigned int Width, unsigned int Height, std::vector<unsigned int> & Data);
+ static void ReverseRGBAComponentOrder(std::vector<unsigned int> & Data);
+ static void FlipImagedataVertical(unsigned int Width, unsigned int Height, std::vector<unsigned int> & Data);
+};
+
+#endif
diff --git a/engines/sword25/gfx/opengl/swimage.cpp b/engines/sword25/gfx/opengl/swimage.cpp
new file mode 100755
index 0000000000..7bc36b5f69
--- /dev/null
+++ b/engines/sword25/gfx/opengl/swimage.cpp
@@ -0,0 +1,125 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// INCLUDES
+// -----------------------------------------------------------------------------
+
+#include "package/packagemanager.h"
+#include "gfx/image/imageloader.h"
+
+#include "swimage.h"
+
+#define BS_LOG_PREFIX "SWIMAGE"
+
+
+// -----------------------------------------------------------------------------
+// CONSTRUCTION / DESTRUCTION
+// -----------------------------------------------------------------------------
+
+BS_SWImage::BS_SWImage(const std::string & Filename, bool & Result) :
+ _ImageDataPtr(0),
+ m_Width(0),
+ m_Height(0)
+{
+ Result = false;
+
+ BS_PackageManager * pPackage = static_cast<BS_PackageManager*>(BS_Kernel::GetInstance()->GetService("package"));
+ BS_ASSERT(pPackage);
+
+ // Datei laden
+ char* pFileData;
+ unsigned int FileSize;
+ if (!(pFileData = (char*) pPackage->GetFile(Filename, &FileSize)))
+ {
+ BS_LOG_ERRORLN("File \"%s\" could not be loaded.", Filename.c_str());
+ return;
+ }
+
+ // Bildeigenschaften bestimmen
+ BS_GraphicEngine::COLOR_FORMATS ColorFormat;
+ int Pitch;
+ if (!BS_ImageLoader::ExtractImageProperties(pFileData, FileSize, ColorFormat, m_Width, m_Height))
+ {
+ BS_LOG_ERRORLN("Could not read image properties.");
+ return;
+ }
+
+ // Das Bild dekomprimieren
+ char * pUncompressedData;
+ if (!BS_ImageLoader::LoadImage(pFileData, FileSize, BS_GraphicEngine::CF_ABGR32, pUncompressedData, m_Width, m_Height, Pitch))
+ {
+ BS_LOG_ERRORLN("Could not decode image.");
+ return;
+ }
+
+ // Dateidaten freigeben
+ delete[] pFileData;
+
+ _ImageDataPtr = (unsigned int *) pUncompressedData;
+
+ Result = true;
+ return;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_SWImage::~BS_SWImage()
+{
+ delete [] _ImageDataPtr;
+}
+
+
+// -----------------------------------------------------------------------------
+
+bool BS_SWImage::Blit(int PosX, int PosY,
+ int Flipping,
+ BS_Rect* pPartRect,
+ unsigned int Color,
+ int Width, int Height)
+{
+ BS_LOG_ERRORLN("Blit() is not supported.");
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_SWImage::Fill(const BS_Rect* pFillRect, unsigned int Color)
+{
+ BS_LOG_ERRORLN("Fill() is not supported.");
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_SWImage::SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride)
+{
+ BS_LOG_ERRORLN("SetContent() is not supported.");
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_SWImage::GetPixel(int X, int Y)
+{
+ BS_ASSERT(X >= 0 && X < m_Width);
+ BS_ASSERT(Y >= 0 && Y < m_Height);
+
+ return _ImageDataPtr[m_Width * Y + X];
+}
diff --git a/engines/sword25/gfx/opengl/swimage.h b/engines/sword25/gfx/opengl/swimage.h
new file mode 100755
index 0000000000..1f48c238b3
--- /dev/null
+++ b/engines/sword25/gfx/opengl/swimage.h
@@ -0,0 +1,69 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_SWIMAGE_H
+#define BS_SWIMAGE_H
+
+// -----------------------------------------------------------------------------
+// INCLUDES
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "gfx/image/image.h"
+#include "gfx/graphicengine.h"
+
+
+// -----------------------------------------------------------------------------
+// CLASS DEFINITION
+// -----------------------------------------------------------------------------
+
+class BS_SWImage : public BS_Image
+{
+public:
+ BS_SWImage(const std::string & Filename, bool & Result);
+ virtual ~BS_SWImage();
+
+ virtual int GetWidth() const { return m_Width; }
+ virtual int GetHeight() const { return m_Height; }
+ virtual BS_GraphicEngine::COLOR_FORMATS GetColorFormat() const { return BS_GraphicEngine::CF_ARGB32; }
+
+ virtual bool Blit(int PosX = 0, int PosY = 0,
+ int Flipping = BS_Image::FLIP_NONE,
+ BS_Rect* pPartRect = NULL,
+ unsigned int Color = BS_ARGB(255, 255, 255, 255),
+ int Width = -1, int Height = -1);
+ virtual bool Fill(const BS_Rect* FillRectPtr, unsigned int Color);
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride);
+ virtual unsigned int GetPixel(int X, int Y);
+
+ virtual bool IsBlitSource() const { return false; }
+ virtual bool IsBlitTarget() const { return false; }
+ virtual bool IsScalingAllowed() const { return false; }
+ virtual bool IsFillingAllowed() const { return false; }
+ virtual bool IsAlphaAllowed() const { return false; }
+ virtual bool IsColorModulationAllowed() const { return false; }
+ virtual bool IsSetContentAllowed() const { return false; }
+private:
+ unsigned int * _ImageDataPtr;
+
+ int m_Width;
+ int m_Height;
+};
+
+#endif
diff --git a/engines/sword25/gfx/panel.cpp b/engines/sword25/gfx/panel.cpp
new file mode 100755
index 0000000000..715f306305
--- /dev/null
+++ b/engines/sword25/gfx/panel.cpp
@@ -0,0 +1,123 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "panel.h"
+
+#include "kernel/inputpersistenceblock.h"
+#include "kernel/outputpersistenceblock.h"
+#include "graphicengine.h"
+#include "image/image.h"
+
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "PANEL"
+
+// -----------------------------------------------------------------------------
+// Construction/Destruction
+// -----------------------------------------------------------------------------
+
+BS_Panel::BS_Panel(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, int Width, int Height, unsigned int Color) :
+ BS_RenderObject(ParentPtr, BS_RenderObject::TYPE_PANEL),
+ m_Color(Color)
+{
+ m_InitSuccess = false;
+
+ m_Width = Width;
+ m_Height = Height;
+
+ if (m_Width < 0)
+ {
+ BS_LOG_ERRORLN("Tried to initialise a panel with an invalid width (%d).", m_Width);
+ return;
+ }
+
+ if (m_Height < 0)
+ {
+ BS_LOG_ERRORLN("Tried to initialise a panel with an invalid height (%d).", m_Height);
+ return;
+ }
+
+ m_InitSuccess = true;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Panel::BS_Panel(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle) :
+ BS_RenderObject(ParentPtr, BS_RenderObject::TYPE_PANEL, Handle)
+{
+ m_InitSuccess = Unpersist(Reader);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Panel::~BS_Panel()
+{
+}
+
+// -----------------------------------------------------------------------------
+// Rendern
+// -----------------------------------------------------------------------------
+
+bool BS_Panel::DoRender()
+{
+ // Falls der Alphawert 0 ist, ist das Panel komplett durchsichtig und es muss nichts gezeichnet werden.
+ if (m_Color >> 24 == 0) return true;
+
+ BS_GraphicEngine * GfxPtr = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
+ BS_ASSERT(GfxPtr);
+
+ return GfxPtr->Fill(&m_BBox, m_Color);
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_Panel::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Persist(Writer);
+ Writer.Write(m_Color);
+
+ Result &= BS_RenderObject::PersistChildren(Writer);
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Panel::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Unpersist(Reader);
+
+ unsigned int Color;
+ Reader.Read(Color);
+ SetColor(Color);
+
+ Result &= BS_RenderObject::UnpersistChildren(Reader);
+
+ return Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/panel.h b/engines/sword25/gfx/panel.h
new file mode 100755
index 0000000000..b1ecd7ce69
--- /dev/null
+++ b/engines/sword25/gfx/panel.h
@@ -0,0 +1,58 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_PANEL_H
+#define BS_PANEL_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "renderobject.h"
+
+// -----------------------------------------------------------------------------
+// Class Definition
+// -----------------------------------------------------------------------------
+
+class BS_Panel : public BS_RenderObject
+{
+friend BS_RenderObject;
+
+private:
+ BS_Panel(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, int Width, int Height, unsigned int Color);
+ BS_Panel(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle);
+
+public:
+ virtual ~BS_Panel();
+
+ unsigned int GetColor() const { return m_Color; }
+ void SetColor(unsigned int Color) { m_Color = Color; ForceRefresh(); }
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+protected:
+ virtual bool DoRender();
+
+private:
+ unsigned int m_Color;
+};
+
+#endif
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;
+}
diff --git a/engines/sword25/gfx/renderobject.h b/engines/sword25/gfx/renderobject.h
new file mode 100755
index 0000000000..c0fd6f3afc
--- /dev/null
+++ b/engines/sword25/gfx/renderobject.h
@@ -0,0 +1,477 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ BS_RenderObject
+ ---------------
+ Dieses ist die Klasse die sämtliche sichtbaren Objekte beschreibt. Alle anderen sichtbaren Objekte müssen von ihr abgeleitet werden.
+ Diese Klasse erledigt Aufgaben wie: minimales Neuzeichnen, Renderreihenfolge, Objekthierachie.
+ Alle BS_RenderObject Instanzen werden von einem BS_RenderObjectManager in einem Baum verwaltet.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_RENDEROBJECT_H
+#define _BS_RENDEROBJECT_H
+
+// Includes
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+#include "kernel/common.h"
+#include "kernel/persistable.h"
+#include "math/rect.h"
+#include "renderobjectptr.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_Kernel;
+class BS_RenderObjectManager;
+class BS_Bitmap;
+class BS_Animation;
+class BS_AnimationTemplate;
+class BS_Panel;
+class BS_Text;
+
+// Klassendefinition
+/**
+ @brief Dieses ist die Klasse die sämtliche sichtbaren Objekte beschreibt.
+
+ Alle anderen sichtbaren Objekte müssen von ihr abgeleitet werden.
+ Diese Klasse erledigt Aufgaben wie: minimales Neuzeichnen, Renderreihenfolge, Objekthierachie.
+ Alle BS_RenderObject Instanzen werden von einem BS_RenderObjektManager in einem Baum verwaltet.
+ */
+class BS_RenderObject
+{
+public:
+ // Konstanten
+ // ----------
+ enum TYPES
+ {
+ /// Das Wurzelobjekt. Siehe BS_RenderObjectManager
+ TYPE_ROOT,
+ /// Ein Image. Siehe BS_Bitmap.
+ TYPE_STATICBITMAP,
+ TYPE_DYNAMICBITMAP,
+ /// Eine Animation. Siehe BS_Animation.
+ TYPE_ANIMATION,
+ /// Eine farbige Fläche. Siehe BS_Panel.
+ TYPE_PANEL,
+ /// Ein Text. Siehe BS_Text.
+ TYPE_TEXT,
+ /// Ein unbekannter Objekttyp. Diesen Typ sollte kein Renderobjekt annehmen.
+ TYPE_UNKNOWN,
+ };
+
+ // Add-Methoden
+ // ------------
+
+ /**
+ @brief Erzeugt ein Bitmap als Kinderobjekt des Renderobjektes.
+ @param FileName der Dateiname der Quellbilddatei
+ @return Gibt einen BS_RenderObjectPtr auf das erzeugte Objekt zurück.<br>
+ Falls ein Fehler aufgetreten ist wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Bitmap> AddBitmap(const std::string& FileName);
+ /**
+ @brief Erzeugt ein veränderbares Bitmap als Kinderobjekt des Renderobjektes.
+ @param Width die Breite des Bitmaps
+ @param Height die Höhe des Bitmaps
+ @return Gibt einen BS_RenderObjectPtr auf das erzeugte Objekt zurück.<br>
+ Falls ein Fehler aufgetreten ist wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Bitmap> AddDynamicBitmap(unsigned int Width, unsigned int Height);
+ /**
+ @brief Erzeugt eine Animation auf Basis einer Animationsdatei als Kinderobjekt des Renderobjektes.
+ @param FileName der Dateiname der Quelldatei
+ @return Gibt einen BS_RenderObjectPtr auf das erzeugte Objekt zurück.<br>
+ Falls ein Fehler aufgetreten ist wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Animation> AddAnimation(const std::string& FileName);
+ /**
+ @brief Erzeugt eine Animation auf Basis eines Animationstemplate als Kinderobjekt des Renderobjektes.
+ @param pAnimationTemplate ein Pointer auf das Animationstemplate
+ @return Gibt einen BS_RenderObjectPtr auf das erzeugte Objekt zurück.<br>
+ Falls ein Fehler aufgetreten ist wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ @remark Das Renderobjekt übernimmt die Verwaltung des Animationstemplate.
+ */
+ BS_RenderObjectPtr<BS_Animation> AddAnimation(const BS_AnimationTemplate & AnimationTemplate);
+ /**
+ @brief Erzeugt ein neues Farbpanel als Kinderobjekt des Renderobjektes.
+ @param Width die Breite des Panels
+ @param Height die Höhe des Panels
+ @param Color die Farbe des Panels.<br>
+ Der Standardwert ist Schwarz (BS_RGB(0, 0, 0)).
+ @return Gibt einen BS_RenderObjectPtr auf das erzeugte Objekt zurück.<br>
+ Falls ein Fehler aufgetreten ist wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+
+ BS_RenderObjectPtr<BS_Panel> AddPanel(int Width, int Height, unsigned int Color = 0xff000000);
+ /**
+ @brief Erzeugt ein Textobjekt als Kinderobjekt des Renderobjektes.
+ @param Font der Dateiname des zu verwendenen Fonts
+ @param Text der anzuzeigende Text.<br>
+ Der Standardwert ist "".
+ @return Gibt einen BS_RenderObjectPtr auf das erzeugte Objekt zurück.<br>
+ Falls ein Fehler aufgetreten ist wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Text> AddText(const std::string & Font, const std::string & Text = "");
+
+ // Cast-Methoden
+ // -------------
+ /**
+ @brief Castet das Objekt zu einem BS_Bitmap-Objekt wenn zulässig.
+ @return Gibt einen BS_RenderObjectPtr auf das Objekt zurück.<br>
+ Falls der Cast nicht zulässig ist, wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Bitmap> ToBitmap()
+ {
+ if (m_Type == TYPE_STATICBITMAP || m_Type == TYPE_DYNAMICBITMAP) return BS_RenderObjectPtr<BS_Bitmap>(this); else return BS_RenderObjectPtr<BS_Bitmap>();
+ }
+ /**
+ @brief Castet das Objekt zu einem BS_Animation-Objekt wenn zulässig.
+ @return Gibt einen BS_RenderObjectPtr auf das Objekt zurück.<br>
+ Falls der Cast nicht zulässig ist, wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Animation> ToAnimation()
+ {
+ if (m_Type == TYPE_ANIMATION) return BS_RenderObjectPtr<BS_Animation>(this); else return BS_RenderObjectPtr<BS_Animation>();
+ }
+ /**
+ @brief Castet das Objekt zu einem BS_Panel-Objekt wenn zulässig.
+ @return Gibt einen BS_RenderObjectPtr auf das Objekt zurück.<br>
+ Falls der Cast nicht zulässig ist, wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Panel> ToPanel()
+ {
+ if (m_Type == TYPE_PANEL) return BS_RenderObjectPtr<BS_Panel>(this); else return BS_RenderObjectPtr<BS_Panel>();
+ }
+ /**
+ @brief Castet das Object zu einem BS_Text-Objekt wenn zulässig.
+ @return Gibt einen BS_RenderObjectPtr auf das Objekt zurück.<br>
+ Falls der Cast nicht zulässig ist, wird ein ungültiger BS_RenderObjectPtr zurückgegeben.
+ */
+ BS_RenderObjectPtr<BS_Text> ToText()
+ {
+ if (m_Type == TYPE_TEXT) return BS_RenderObjectPtr<BS_Text>(this); else return BS_RenderObjectPtr<BS_Text>();
+ }
+
+ // Konstruktor / Desktruktor
+ // -------------------------
+ /**
+ @brief Erzeugt ein neues BS_RenderObject.
+ @param pKernel ein Pointer auf den Kernel
+ @param pParent ein Pointer auf das Elternobjekt des neuen Objektes im Objektbaum.<br>
+ Der Pointer darf nicht NULL sein.
+ @param Type der Objekttyp<br>
+ Der Typ BS_RenderObject::TYPE_ROOT ist nicht zulässig. Wurzelknoten müssen mit dem alternativen Konstruktor erzeugt
+ werden.
+ @param Handle das Handle, welches dem Objekt zugewiesen werden soll.<br>
+ Dieser Parameter erzwingt ein bestimmtes Handle für das neue Objekt, oder wählt automatisch ein Handle, wenn der Parameter 0 ist.
+ Ist das gewünschte Handle bereits vergeben, gibt GetInitSuccess() false zurück.<br>
+ Der Standardwert ist 0.
+ @remark Nach dem Aufruf des Konstruktors kann über die Methode GetInitSuccess() abgefragt werden, ob die Konstruktion erfolgreich war.<br>
+ Es ist nicht notwendig alle BS_RenderObject Instanzen einzeln zu löschen. Dieses geschiet automatisch beim Löschen eines
+ Vorfahren oder beim Löschen des zuständigen BS_RenderObjectManager.
+ */
+ BS_RenderObject(BS_RenderObjectPtr<BS_RenderObject> pParent, TYPES Type, unsigned int Handle = 0);
+ virtual ~BS_RenderObject();
+
+ // Interface
+ // ---------
+ /**
+ @brief Rendert des Objekt und alle seine Unterobjekte.
+ @return Gibt false zurück, falls beim Rendern ein Fehler aufgetreten ist.
+ @remark Vor jedem Aufruf dieser Methode muss ein Aufruf von UpdateObjectState() erfolgt sein.
+ Dieses kann entweder direkt geschehen oder durch den Aufruf von UpdateObjectState() an einem Vorfahren-Objekt.<br>
+ Diese Methode darf nur von BS_RenderObjectManager aufgerufen werden.
+ */
+ bool Render();
+ /**
+ @brief Bereitet das Objekt und alle seine Unterobjekte auf einen Rendervorgang vor.
+ Hierbei werden alle Dirty-Rectangles berechnet und die Renderreihenfolge aktualisiert.
+ @return Gibt false zurück, falls ein Fehler aufgetreten ist.
+ @remark Diese Methode darf nur von BS_RenderObjectManager aufgerufen werden.
+ */
+ bool UpdateObjectState();
+ /**
+ @brief Löscht alle Kinderobjekte.
+ */
+ void DeleteAllChildren();
+
+ // Accessor-Methoden
+ // -----------------
+ /**
+ @brief Setzt die Position des Objektes.
+ @param X die neue X-Koordinate des Objektes relativ zum Elternobjekt.
+ @param Y die neue Y-Koordinate des Objektes relativ zum Elternobjekt.
+ */
+ virtual void SetPos(int X, int Y);
+ /**
+ @brief Setzt die Position des Objektes auf der X-Achse.
+ @param X die neue X-Koordinate des Objektes relativ zum Elternobjekt.
+ */
+ virtual void SetX(int X);
+ /**
+ @brief Setzt die Position des Objektes auf der Y-Achse.
+ @param Y die neue Y-Koordinate des Objektes relativ zum Elternobjekt.
+ */
+ virtual void SetY(int Y);
+ /**
+ @brief Setzt den Z-Wert des Objektes.
+ @param Z der neue Z-Wert des Objektes relativ zum Elternobjekt<br>
+ Negative Z-Werte sind nicht zulässig.
+ @remark Der Z-Wert legt die Renderreihenfolge der Objekte fest. Objekte mit niedrigem Z-Wert werden vor Objekten mit höherem
+ Z-Wert gezeichnet. Je höher der Z-Wert desto weiter "vorne" liegt ein Objekt also.<br>
+ Wie alle andere Attribute ist auch dieses relativ zum Elternobjekt, ein Kinderobjekt kann also nie unter seinem
+ Elternobjekt liegen, auch wenn es einen Z-Wert von 0 hat.
+ */
+ virtual void SetZ(int Z);
+ /**
+ @brief Setzt die Sichtbarkeit eine Objektes.
+ @param Visible der neue Sichtbarkeits-Zustand des Objektes<br>
+ true entspricht sichtbar, false entspricht unsichtbar.
+ */
+ virtual void SetVisible(bool Visible);
+ /**
+ @brief Gibt die Position des Objektes auf der X-Achse relativ zum Elternobjekt zurück.
+ */
+ virtual int GetX() const { return m_X; }
+ /**
+ @brief Gibt die Position des Objektes auf der Y-Achse relativ zum Elternobjekt zurück.
+ */
+ virtual int GetY() const { return m_Y; }
+ /**
+ @brief Gibt die absolute Position des Objektes auf der X-Achse zurück.
+ */
+ virtual int GetAbsoluteX() const { return m_AbsoluteX; }
+ /**
+ @brief Gibt die absolute Position des Objektes auf der Y-Achse zurück.
+ */
+ virtual int GetAbsoluteY() const { return m_AbsoluteY; }
+ /**
+ @brief Gibt den Z-Wert des Objektes relativ zum Elternobjekt zurück.
+ @remark Der Z-Wert legt die Renderreihenfolge der Objekte fest. Objekte mit niedrigem Z-Wert werden vor Objekten mit höherem
+ Z-Wert gezeichnet. Je höher der Z-Wert desto weiter "vorne" liegt ein Objekt also.<br>
+ Wie alle andere Attribute ist auch dieses relativ zum Elternobjekt, ein Kinderobjekt kann also nie unter seinem
+ Elternobjekt liegen, auch wenn es einen Z-Wert von 0 hat.
+ */
+ int GetZ() const { return m_Z; }
+ /**
+ @brief Gibt die Breite des Objektes zurück.
+ */
+ int GetWidth() const { return m_Width; }
+ /**
+ @brief Gibt die Höhe des Objektes zurück.
+ */
+ int GetHeight() const { return m_Height; }
+ /**
+ @brief Gibt den Sichtbarkeitszustand des Objektes zurück.
+ @return Gibt den Sichtbarkeitszustand des Objektes zurück.<br>
+ true entspricht sichtbar, false entspricht unsichtbar.
+ */
+ bool IsVisible() const { return m_Visible; }
+ /**
+ @brief Gibt den Typ des Objektes zurück.
+ */
+ TYPES GetType() const { return m_Type; }
+ /**
+ @brief Gibt zurück, ob das Objekt erfolgreich initialisiert wurde.
+ @remark Hässlicher Workaround um das Problem, dass Konstruktoren keine Rückgabewerte haben.
+ */
+ bool GetInitSuccess() const { return m_InitSuccess; }
+ /**
+ @brief Gibt die Bounding-Box des Objektes zurück.
+ @remark Diese Angabe erfolgt ausnahmsweise in Bildschirmkoordianten und nicht relativ zum Elternobjekt.
+ */
+ const BS_Rect& GetBBox() const { return m_BBox; }
+ /**
+ @brief Stellt sicher, dass das Objekt im nächsten Frame neu gezeichnet wird.
+ */
+ void ForceRefresh() { m_RefreshForced = true; };
+ /**
+ @brief Gibt das Handle des Objekte zurück.
+ */
+ unsigned int GetHandle() const { return m_Handle; }
+
+ // Persistenz-Methoden
+ // -------------------
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+ // TODO: Evtl. protected
+ bool PersistChildren(BS_OutputPersistenceBlock & Writer);
+ bool UnpersistChildren(BS_InputPersistenceBlock & Reader);
+ // TODO: Evtl. private
+ BS_RenderObjectPtr<BS_RenderObject> RecreatePersistedRenderObject(BS_InputPersistenceBlock & Reader);
+
+protected:
+ // Typen
+ // -----
+ typedef std::vector<BS_RenderObjectPtr<BS_RenderObject> > RENDEROBJECT_LIST;
+ typedef std::vector<BS_RenderObjectPtr<BS_RenderObject> >::iterator RENDEROBJECT_ITER;
+
+ int m_X; ///< Die X-Position des Objektes relativ zum Eltern-Objekt
+ int m_Y; ///< Die Y-Position des Objektes relativ zum Eltern-Objekt
+ int m_AbsoluteX; ///< Die absolute X-Position des Objektes
+ int m_AbsoluteY; ///< Die absolute Y-Position des Objektes
+ int m_Z; ///< Der Z-Wert des Objektes relativ zum Eltern-Objekt
+ int m_Width; ///< Die Breite des Objektes
+ int m_Height; ///< Die Höhe des Objektes
+ bool m_Visible; ///< Ist true, wenn das Objekt sichtbar ist
+ bool m_ChildChanged; ///< Ist true, wenn sich ein Kinderobjekt verändert hat
+ TYPES m_Type; ///< Der Objekttyp
+ bool m_InitSuccess; ///< Ist true, wenn Objekt erfolgreich intialisiert werden konnte
+ BS_Rect m_BBox; ///< Die Bounding-Box des Objektes in Bildschirmkoordinaten
+
+ // Kopien der Variablen, die für die Errechnung des Dirty-Rects und zur Bestimmung der Objektveränderung notwendig sind
+ BS_Rect m_OldBBox;
+ int m_OldX;
+ int m_OldY;
+ int m_OldZ;
+ bool m_OldVisible;
+
+ /// Ein Pointer auf den BS_RenderObjektManager, der das Objekt verwaltet.
+ BS_RenderObjectManager* m_ManagerPtr;
+
+ // Render-Methode
+ // --------------
+ /**
+ @brief Einschubmethode, die den tatsächlichen Redervorgang durchführt.
+
+ Diese Methode wird von Render() aufgerufen um das Objekt darzustellen.
+ Diese Methode sollte von allen Klassen implementiert werden, die von BS_RederObject erben, um das Zeichnen umzusetzen.
+
+ @return Gibt false zurück, falls das Rendern fehlgeschlagen ist.
+ @remark
+ */
+ virtual bool DoRender() = 0; // { return true; };
+
+ // RenderObject-Baum Variablen
+ // ---------------------------
+ // Der Baum legt die hierachische Ordnung der BS_RenderObjects fest.
+ // Alle Eigenschaften wie X, Y, Z und Visible eines BS_RenderObjects sind relativ zu denen seines Vaters.
+ // Außerdem sind die Objekte von links nach rechts in ihrer Renderreihenfolge sortiert.
+ // Das primäre Sortierkriterium ist hierbei der Z-Wert und das sekundäre der Y-Wert (von oben nach unten).
+ // Beispiel:
+ // Screen
+ // / | \
+ // / | \
+ // / | \
+ // / | \
+ // Background Interface Maus
+ // / \ / | \
+ // / \ / | \
+ // George Tür Icn1 Icn2 Icn3
+ //
+ // Wenn jetzt das Interface mit SetVisible() ausgeblendet würde, verschwinden auch die Icons, die sich im Interface
+ // befinden.
+ // Wenn der Hintergrund bewegt wird (Scrolling), bewegen sich auch die darauf befindlichen Gegenstände und Personen.
+
+ /// Ein Pointer auf das Elternobjekt.
+ BS_RenderObjectPtr<BS_RenderObject> m_ParentPtr;
+ /// Die Liste der Kinderobjekte nach der Renderreihenfolge geordnet
+ RENDEROBJECT_LIST m_Children;
+
+ /**
+ @brief Gibt einen Pointer auf den BS_RenderObjektManager zurück, der das Objekt verwaltet.
+ */
+ BS_RenderObjectManager* GetManager() const { return m_ManagerPtr; }
+ /**
+ @brief Fügt dem Objekt ein neues Kinderobjekt hinzu.
+ @param pObject ein Pointer auf das einzufügende Objekt
+ @return Gibt false zurück, falls das Objekt nicht eingefügt werden konnte.
+ */
+ bool AddObject(BS_RenderObjectPtr<BS_RenderObject> pObject);
+
+private:
+ /// Ist true, wenn das Objekt in nächsten Frame neu gezeichnet werden soll
+ bool m_RefreshForced;
+
+ unsigned int m_Handle;
+
+ /**
+ @brief Entfernt ein Objekt aus der Kinderliste.
+ @param pObject ein Pointer auf das zu entfernende Objekt
+ @return Gibt false zurück, falls das zu entfernende Objekt nicht in der Liste gefunden werden konnte.
+ */
+ bool DetatchChildren(BS_RenderObjectPtr<BS_RenderObject> pObject);
+ /**
+ @brief Berechnet die Bounding-Box und registriert das Dirty-Rect beim BS_RenderObjectManager.
+ */
+ void UpdateBoxes();
+ /**
+ @brief Berechnet die Bounding-Box des Objektes.
+ @return Gibt die Bounding-Box des Objektes in Bildschirmkoordinaten zurück.
+ */
+ BS_Rect CalcBoundingBox() const;
+ /**
+ @brief Berechnet das Dirty-Rectangle des Objektes.
+ @return Gibt das Dirty-Rectangle des Objektes in Bildschirmkoordinaten zurück.
+ */
+ BS_Rect CalcDirtyRect() const;
+ /**
+ @brief Berechnet die absolute Position des Objektes.
+ */
+ void CalcAbsolutePos(int& X, int& Y) const;
+ /**
+ @brief Berechnet die absolute Position des Objektes auf der X-Achse.
+ */
+ int CalcAbsoluteX() const;
+ /**
+ @brief Berechnet die absolute Position des Objektes.
+ */
+ int CalcAbsoluteY() const;
+ /**
+ @brief Sortiert alle Kinderobjekte nach ihrem Renderang.
+ */
+ void SortRenderObjects();
+ /**
+ @brief Validiert den Zustand eines Objektes nachdem die durch die Veränderung verursachten Folgen abgearbeitet wurden.
+ */
+ void ValidateObject();
+ /**
+ @brief Berechnet die absolute Position des Objektes und aller seiner Kinderobjekte neu.
+
+ Diese Methode muss aufgerufen werden, wann immer sich die Position des Objektes verändert. Damit die Kinderobjekte immer die
+ richtige absolute Position haben.
+ */
+ void UpdateAbsolutePos();
+ /**
+ @brief Teilt dem Objekt mit, dass sich eines seiner Kinderobjekte dahingehend verändert hat, die eine erneute Bestimmung der
+ Rendereihenfolge verlangt.
+ */
+ void SignalChildChange() { m_ChildChanged = true; }
+ /**
+ @brief Berechnet des Schnittrechteck der Bounding-Box des Objektes mit einem anderen Objekt.
+ @param pObjekt ein Pointer auf das Objekt mit dem geschnitten werden soll
+ @param Result das Ergebnisrechteck
+ @return Gibt false zurück, falls sich die Objekte gar nicht schneiden.
+ */
+ bool GetObjectIntersection(BS_RenderObjectPtr<BS_RenderObject> pObject, BS_Rect& Result);
+ /**
+ @brief Vergleichsoperator der auf Objektpointern basiert statt auf Objekten.
+ @remark Diese Methode wird fürs Sortieren der Kinderliste nach der Rendereihenfolge benutzt.
+ */
+ static bool Greater(const BS_RenderObjectPtr<BS_RenderObject> lhs, const BS_RenderObjectPtr<BS_RenderObject> rhs);
+};
+
+#endif
diff --git a/engines/sword25/gfx/renderobjectmanager.cpp b/engines/sword25/gfx/renderobjectmanager.cpp
new file mode 100755
index 0000000000..af9e97afb6
--- /dev/null
+++ b/engines/sword25/gfx/renderobjectmanager.cpp
@@ -0,0 +1,163 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "renderobjectmanager.h"
+
+#include "kernel/kernel.h"
+#include "kernel/inputpersistenceblock.h"
+#include "kernel/outputpersistenceblock.h"
+#include "gfx/graphicengine.h"
+#include "gfx/animationtemplateregistry.h"
+#include "math/rect.h"
+#include "renderobject.h"
+#include "timedrenderobject.h"
+#include "rootrenderobject.h"
+
+#define BS_LOG_PREFIX "RENDEROBJECTMANAGER"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Desktruktion
+// -----------------------------------------------------------------------------
+
+BS_RenderObjectManager::BS_RenderObjectManager(int Width, int Height, int FramebufferCount) :
+ m_FrameStarted(false)
+{
+ // Wurzel des BS_RenderObject-Baumes erzeugen.
+ m_RootPtr = new BS_RootRenderObject(this, Width, Height);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_RenderObjectManager::~BS_RenderObjectManager()
+{
+ // Die Wurzel des Baumes löschen, damit werden alle BS_RenderObjects mitgelöscht.
+ m_RootPtr.Erase();
+}
+
+// -----------------------------------------------------------------------------
+// Interface
+// -----------------------------------------------------------------------------
+
+void BS_RenderObjectManager::StartFrame()
+{
+ m_FrameStarted = true;
+
+ // Verstrichene Zeit bestimmen
+ int TimeElapsed = BS_Kernel::GetInstance()->GetGfx()->GetLastFrameDurationMicro();
+
+ // Alle BS_TimedRenderObject Objekte über den Framestart und die verstrichene Zeit in Kenntnis setzen
+ RenderObjectList::iterator Iter = m_TimedRenderObjects.begin();
+ for (; Iter != m_TimedRenderObjects.end(); ++Iter)
+ (*Iter)->FrameNotification(TimeElapsed);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_RenderObjectManager::Render()
+{
+ // Den Objekt-Status des Wurzelobjektes aktualisieren. Dadurch werden rekursiv alle Baumelemente aktualisiert.
+ // Beim aktualisieren des Objekt-Status werden auch die Update-Rects gefunden, so dass feststeht, was neu gezeichnet
+ // werden muss.
+ if (!m_RootPtr.IsValid() || !m_RootPtr->UpdateObjectState()) return false;
+
+ m_FrameStarted = false;
+
+ // Die Render-Methode der Wurzel aufrufen. Dadurch wird das rekursive Rendern der Baumelemente angestoßen.
+ return m_RootPtr->Render();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_RenderObjectManager::AttatchTimedRenderObject(BS_RenderObjectPtr<BS_TimedRenderObject> RenderObjectPtr)
+{
+ m_TimedRenderObjects.push_back(RenderObjectPtr);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_RenderObjectManager::DetatchTimedRenderObject(BS_RenderObjectPtr<BS_TimedRenderObject> RenderObjectPtr)
+{
+ RenderObjectList::iterator Iter = find(m_TimedRenderObjects.begin(), m_TimedRenderObjects.end(), RenderObjectPtr);
+ if (Iter != m_TimedRenderObjects.end()) m_TimedRenderObjects.erase(Iter);
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_RenderObjectManager::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ // Alle Kinder des Wurzelknotens speichern. Dadurch werden alle BS_RenderObjects gespeichert rekursiv gespeichert.
+ Result &= m_RootPtr->PersistChildren(Writer);
+
+ Writer.Write(m_FrameStarted);
+
+ // Referenzen auf die TimedRenderObjects persistieren.
+ Writer.Write(m_TimedRenderObjects.size());
+ RenderObjectList::const_iterator Iter = m_TimedRenderObjects.begin();
+ while (Iter != m_TimedRenderObjects.end())
+ {
+ Writer.Write((*Iter)->GetHandle());
+ ++Iter;
+ }
+
+ // Alle BS_AnimationTemplates persistieren.
+ Result &= BS_AnimationTemplateRegistry::GetInstance().Persist(Writer);
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_RenderObjectManager::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ // Alle Kinder des Wurzelknotens löschen. Damit werden alle BS_RenderObjects gelöscht.
+ m_RootPtr->DeleteAllChildren();
+
+ // Alle BS_RenderObjects wieder hestellen.
+ if (!m_RootPtr->UnpersistChildren(Reader)) return false;
+
+ Reader.Read(m_FrameStarted);
+
+ // Momentan gespeicherte Referenzen auf TimedRenderObjects löschen.
+ m_TimedRenderObjects.resize(0);
+
+ // Referenzen auf die TimedRenderObjects wieder herstellen.
+ unsigned int TimedObjectCount;
+ Reader.Read(TimedObjectCount);
+ for (unsigned int i = 0; i < TimedObjectCount; ++i)
+ {
+ unsigned int Handle;
+ Reader.Read(Handle);
+ m_TimedRenderObjects.push_back(Handle);
+ }
+
+ // Alle BS_AnimationTemplates wieder herstellen.
+ Result &= BS_AnimationTemplateRegistry::GetInstance().Unpersist(Reader);
+
+ return Result;
+}
diff --git a/engines/sword25/gfx/renderobjectmanager.h b/engines/sword25/gfx/renderobjectmanager.h
new file mode 100755
index 0000000000..6a46cfa9e9
--- /dev/null
+++ b/engines/sword25/gfx/renderobjectmanager.h
@@ -0,0 +1,115 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ BS_RenderObjectManager
+ ----------------------
+ Diese Klasse ist für die Verwaltung von BS_RenderObjects zuständig.
+
+ Sie sorgt z.B. dafür, dass die BS_RenderObjects in der richtigen Reihenfolge gerendert werden.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_RENDEROBJECTMANAGER_H
+#define _BS_RENDEROBJECTMANAGER_H
+
+// Includes
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+#include "kernel/common.h"
+#include "renderobjectptr.h"
+#include "kernel/persistable.h"
+
+// Klassendefinition
+class BS_Kernel;
+class BS_Rect;
+class BS_RenderObject;
+class BS_TimedRenderObject;
+
+/**
+ @brief Diese Klasse ist für die Verwaltung von BS_RenderObjects zuständig.
+
+ Sie sorgt dafür, dass die BS_RenderObjects in der richtigen Reihenfolge gerendert werden und ermöglicht den Zugriff auf die
+ BS_RenderObjects über einen String.
+*/
+class BS_RenderObjectManager : public BS_Persistable
+{
+public:
+ /**
+ @brief Erzeugt ein neues BS_RenderObjectManager-Objekt.
+ @param Width die horizontale Bildschirmauflösung in Pixeln
+ @param Height die vertikale Bildschirmauflösung in Pixeln
+ @param Die Anzahl an Framebuffern, die eingesetzt wird (Backbuffer + Primary).
+ */
+ BS_RenderObjectManager(int Width, int Height, int FramebufferCount);
+ virtual ~BS_RenderObjectManager();
+
+ // Interface
+ // ---------
+ /**
+ @brief Initialisiert den Manager für einen neuen Frame.
+ @remark Alle Veränderungen an Objekten müssen nach einem Aufruf dieser Methode geschehen, damit sichergestellt ist, dass diese
+ visuell umgesetzt werden.<br>
+ Mit dem Aufruf dieser Methode werden die Rückgabewerte von GetUpdateRects() und GetUpdateRectCount() auf ihre Startwerte
+ zurückgesetzt. Wenn man also mit diesen Werten arbeiten möchten, muss man dies nach einem Aufruf von Render() und vor
+ einem Aufruf von StartFrame() tun.
+ */
+ void StartFrame();
+ /**
+ @brief Rendert alle Objekte die sich während des letzten Aufrufes von Render() verändert haben.
+ @return Gibt false zurück, falls das Rendern fehlgeschlagen ist.
+ */
+ bool Render();
+ /**
+ @brief Gibt einen Pointer auf die Wurzel des Objektbaumes zurück.
+ */
+ BS_RenderObjectPtr<BS_RenderObject> GetTreeRoot() { return m_RootPtr; }
+ /**
+ @brief Fügt ein BS_TimedRenderObject in die Liste der zeitabhängigen Render-Objekte.
+
+ Alle Objekte die sich in dieser Liste befinden werden vor jedem Frame über die seit dem letzten Frame
+ vergangene Zeit informiert, so dass sich ihren Zustand zeitabhängig verändern können.
+
+ @param RenderObject das einzufügende BS_TimedRenderObject
+ */
+ void AttatchTimedRenderObject(BS_RenderObjectPtr<BS_TimedRenderObject> pRenderObject);
+ /**
+ @brief Entfernt ein BS_TimedRenderObject aus der Liste für zeitabhängige Render-Objekte.
+ */
+ void DetatchTimedRenderObject(BS_RenderObjectPtr<BS_TimedRenderObject> pRenderObject);
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+private:
+ bool m_FrameStarted;
+ typedef std::vector<BS_RenderObjectPtr<BS_TimedRenderObject> > RenderObjectList;
+ RenderObjectList m_TimedRenderObjects;
+
+ // RenderObject-Tree Variablen
+ // ---------------------------
+ // Der Baum legt die hierachische Ordnung der BS_RenderObjects fest.
+ // Zu weiteren Informationen siehe: "renderobject.h"
+ BS_RenderObjectPtr<BS_RenderObject> m_RootPtr; // Die Wurzel der Baumes
+};
+
+#endif
diff --git a/engines/sword25/gfx/renderobjectptr.h b/engines/sword25/gfx/renderobjectptr.h
new file mode 100755
index 0000000000..bc2d00caac
--- /dev/null
+++ b/engines/sword25/gfx/renderobjectptr.h
@@ -0,0 +1,80 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_RENDER_OBJECT_PTR_H
+#define BS_RENDER_OBJECT_PTR_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "renderobjectregistry.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_RenderObject;
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+template<class T>
+class BS_RenderObjectPtr
+{
+public:
+ BS_RenderObjectPtr() : m_Handle(0)
+ {}
+
+ BS_RenderObjectPtr(unsigned int Handle) : m_Handle(Handle)
+ {}
+
+ BS_RenderObjectPtr(BS_RenderObject * RenderObjectPtr)
+ {
+ m_Handle = RenderObjectPtr->GetHandle();
+ }
+
+ T * operator->() const
+ {
+ return static_cast<T *>(BS_RenderObjectRegistry::GetInstance().ResolveHandle(m_Handle));
+ }
+
+ bool operator==(const BS_RenderObjectPtr<T> & other)
+ {
+ return m_Handle == other.m_Handle;
+ }
+
+ bool IsValid() const
+ {
+ return BS_RenderObjectRegistry::GetInstance().ResolveHandle(m_Handle) != 0;
+ }
+
+ void Erase()
+ {
+ delete static_cast<T *>(BS_RenderObjectRegistry::GetInstance().ResolveHandle(m_Handle));
+ m_Handle = 0;
+ }
+
+private:
+ unsigned int m_Handle;
+};
+
+#endif
diff --git a/engines/sword25/gfx/renderobjectregistry.cpp b/engines/sword25/gfx/renderobjectregistry.cpp
new file mode 100755
index 0000000000..bf96436eee
--- /dev/null
+++ b/engines/sword25/gfx/renderobjectregistry.cpp
@@ -0,0 +1,50 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "RENDEROBJECTREGISTRY"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "renderobjectregistry.h"
+
+// -----------------------------------------------------------------------------
+// Implementation
+// -----------------------------------------------------------------------------
+
+std::auto_ptr<BS_RenderObjectRegistry> BS_RenderObjectRegistry::m_InstancePtr;
+
+// -----------------------------------------------------------------------------
+
+void BS_RenderObjectRegistry::LogErrorLn(const char * Message) const
+{
+ BS_LOG_ERRORLN(Message);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_RenderObjectRegistry::LogWarningLn(const char * Message) const
+{
+ BS_LOG_WARNINGLN(Message);
+}
diff --git a/engines/sword25/gfx/renderobjectregistry.h b/engines/sword25/gfx/renderobjectregistry.h
new file mode 100755
index 0000000000..96df59ebe1
--- /dev/null
+++ b/engines/sword25/gfx/renderobjectregistry.h
@@ -0,0 +1,60 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_RENDEROBJECTREGISTRY_H
+#define BS_RENDEROBJECTREGISTRY_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/objectregistry.h"
+
+#include "kernel/memlog_off.h"
+#include <memory>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Forward Deklarationen
+// -----------------------------------------------------------------------------
+
+class BS_RenderObject;
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_RenderObjectRegistry : public BS_ObjectRegistry<BS_RenderObject>
+{
+public:
+ static BS_RenderObjectRegistry & GetInstance()
+ {
+ if (!m_InstancePtr.get()) m_InstancePtr.reset(new BS_RenderObjectRegistry);
+ return *m_InstancePtr.get();
+ }
+
+private:
+ virtual void LogErrorLn(const char * Message) const;
+ virtual void LogWarningLn(const char * Message) const;
+
+ static std::auto_ptr<BS_RenderObjectRegistry> m_InstancePtr;
+};
+
+#endif
diff --git a/engines/sword25/gfx/rootrenderobject.h b/engines/sword25/gfx/rootrenderobject.h
new file mode 100755
index 0000000000..8d92cb7a70
--- /dev/null
+++ b/engines/sword25/gfx/rootrenderobject.h
@@ -0,0 +1,53 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_ROOTRENDEROBJECT_H
+#define BS_ROOTRENDEROBJECT_H
+
+// Includes
+#include "kernel/common.h"
+#include "renderobject.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_Kernel;
+
+// Klassendefinition
+class BS_RenderObjectManager;
+
+class BS_RootRenderObject : public BS_RenderObject
+{
+friend BS_RenderObjectManager;
+
+private:
+ BS_RootRenderObject(BS_RenderObjectManager * ManagerPtr, int Width, int Height) :
+ BS_RenderObject(BS_RenderObjectPtr<BS_RenderObject>(), TYPE_ROOT)
+ {
+ m_ManagerPtr = ManagerPtr;
+ m_Width = Width;
+ m_Height = Height;
+ }
+
+protected:
+ virtual bool DoRender() { return true; }
+};
+
+#endif
diff --git a/engines/sword25/gfx/screenshot.cpp b/engines/sword25/gfx/screenshot.cpp
new file mode 100755
index 0000000000..82ba4a9374
--- /dev/null
+++ b/engines/sword25/gfx/screenshot.cpp
@@ -0,0 +1,202 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "SCREENSHOT"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "screenshot.h"
+#include "util/libpng/png.h"
+
+using namespace std;
+
+// -----------------------------------------------------------------------------
+
+struct RGB_PIXEL
+{
+ RGB_PIXEL(unsigned char _Red, unsigned char _Green, unsigned char _Blue) :
+ Red(_Red),
+ Green(_Green),
+ Blue(_Blue)
+ {};
+
+ unsigned char Red;
+ unsigned char Green;
+ unsigned char Blue;
+};
+
+bool BS_Screenshot::SaveToFile(unsigned int Width, unsigned int Height, const vector<unsigned int> & Data, const string & Filename)
+{
+ BS_ASSERT(Data.size() == Width * Height);
+
+ // Buffer für Bildschirminhalt in RGB reservieren
+ vector<RGB_PIXEL> PixelBuffer;
+ PixelBuffer.reserve(Width * Height);
+
+ // Framebufferdaten pixelweise von RGBA nach RGB konvertieren
+ vector<unsigned int>::const_iterator it = Data.begin();
+ for (unsigned int y = 0; y < Height; y++)
+ {
+ for (unsigned int x = 0; x < Width; x++)
+ {
+ unsigned int SrcPixel = *it++;
+ PixelBuffer.push_back(RGB_PIXEL((SrcPixel >> 16) & 0xff, (SrcPixel >> 8) & 0xff, SrcPixel & 0xff));
+ }
+ }
+ BS_ASSERT(it == Data.end());
+ BS_ASSERT(Data.size() == PixelBuffer.size());
+
+ // Variablen für die PNG-Erstellung
+ FILE * OutFile = 0;
+ png_structp png_ptr = 0;
+ png_infop info_ptr = 0;
+
+ try
+ {
+ OutFile = fopen(Filename.c_str(), "wb");
+ if (!OutFile)
+ {
+ BS_LOG_ERRORLN("Could not create screenshot-file \"%s\".", Filename.c_str());
+ throw(0);
+ }
+
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ BS_LOG_ERRORLN("Could not create PNG write-struct.");
+ throw(0);
+ }
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ BS_LOG_ERRORLN("Could not create PNG info-struct.");
+ throw(0);
+ }
+
+ // Der Kompressionsbuffer muss groß genug sein um das gesamte Bild zu beinhalten.
+ // Dieses stellt sicher, dass nur ein IDAT Chunk erstellt wird.
+ // Als Buffergröße wird 110% der Rohdatengröße verwandt, um sicher zu gehen.
+ png_set_compression_buffer_size(png_ptr, (Width * Height * 3 * 110) / 100);
+
+ // PNG-Info Struktur initialisieren
+ png_set_IHDR(png_ptr, info_ptr,
+ Width, // Breite
+ Height, // Höhe
+ 8, // Bittiefe pro Kanal
+ PNG_COLOR_TYPE_RGB, // Farbformat
+ PNG_INTERLACE_NONE, // Interlacing-Typ
+ PNG_COMPRESSION_TYPE_DEFAULT, // Kompressions-Typ
+ PNG_FILTER_TYPE_DEFAULT); // Filter-Typ
+
+ // Rowpointer erstellen
+ vector<png_bytep> RowPointers;
+ RowPointers.reserve(Height);
+ for (unsigned int i = 0; i < Height; i++)
+ {
+ RowPointers.push_back((png_bytep)(&PixelBuffer[Width * i]));
+ }
+ png_set_rows(png_ptr, info_ptr, &RowPointers[0]);
+
+ png_init_io(png_ptr, OutFile);
+
+ // Bild schreiben
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(OutFile);
+ }
+
+ catch (int)
+ {
+ // Wenn die Datei bereits erstellt wurde, Datei schließen und löschen.
+ if (OutFile)
+ {
+ fclose(OutFile);
+ remove(Filename.c_str());
+ }
+
+ if (info_ptr) png_destroy_write_struct(0, &info_ptr);
+ if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp) 0);
+
+ BS_LOG_ERRORLN("Could not create screenshot (\"%s\").", Filename.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Screenshot::SaveThumbnailToFile(unsigned int Width, unsigned int Height, const vector<unsigned int> & Data, const string & Filename)
+{
+ //
+ // Diese Methode nimmt ein Screenshot mit den Maßen von 800x600 und erzeugt einen Screenshot mit den Maßen von 200x125.
+ // Dabei werden je 50 Pixel oben und unten abgeschnitten (die Interface-Leisten im Spiel). Das verbleibende Bild von 800x500 wird auf
+ // ein 16tel seiner Größe reduziert, indem es in 4x4 Pixelblöcke ausgeteilt wird und der Durchschnitt jedes Blockes einen Pixel des Zielbildes generiert.
+ // Abschließend wird das Ergebnis als PNG-Datei unter dem übergebenen Dateinamen gespeichert.
+ //
+
+ // Die Ausgangsgröße muss 800x600 sein.
+ if (Width != 800 || Height != 600)
+ {
+ BS_LOG_ERRORLN("The sreenshot dimensions have to be 800x600 in order to be saved as a thumbnail.");
+ return false;
+ }
+
+ // Buffer für die Zieldaten erstellen (RGBA Bild mit den Maßen 200x125).
+ vector<unsigned int> ThumbnailData(200 * 125);
+
+ // Über das Zielbild iterieren und einen Pixel zur Zeit berechnen.
+ unsigned int x, y;
+ x = y = 0;
+ for(vector<unsigned int>::iterator Iter = ThumbnailData.begin(); Iter != ThumbnailData.end(); ++Iter)
+ {
+ // Durchschnitt über 4x4 Pixelblock im Quellbild bilden.
+ unsigned int Alpha, Red, Green, Blue;
+ Alpha = Red = Green = Blue = 0;
+ for (unsigned int j = 0; j < 4; ++j)
+ {
+ for (unsigned int i = 0; i < 4; ++i)
+ {
+ unsigned int Pixel = Data[((y * 4) + j + 50) * 800 + ((x * 4) + i)];
+ Alpha += (Pixel >> 24);
+ Red += (Pixel >> 16) & 0xff;
+ Green += (Pixel >> 8) & 0xff;
+ Blue += Pixel & 0xff;
+ }
+ }
+
+ // Zielpixel schreiben.
+ *Iter = ((Alpha / 16) << 24) | ((Red / 16) << 16) | ((Green / 16) << 8) | (Blue / 16);
+
+ // Mitzählen an welcher Stelle im Zielbild wir uns befinden.
+ ++x;
+ if (x == 200)
+ {
+ x = 0;
+ ++y;
+ }
+ }
+
+ // Bild als PNG Speichern.
+ return SaveToFile(200, 125, ThumbnailData, Filename);
+}
diff --git a/engines/sword25/gfx/screenshot.h b/engines/sword25/gfx/screenshot.h
new file mode 100755
index 0000000000..453579cb53
--- /dev/null
+++ b/engines/sword25/gfx/screenshot.h
@@ -0,0 +1,44 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_SCREENSHOT_H
+#define BS_SCREENSHOT_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/memlog_off.h"
+#include <string>
+#include <vector>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Class declaration
+// -----------------------------------------------------------------------------
+
+class BS_Screenshot
+{
+public:
+ static bool SaveToFile(unsigned int Width, unsigned int Height, const std::vector<unsigned int> & Data, const std::string & Filename);
+ static bool SaveThumbnailToFile(unsigned int Width, unsigned int Height, const std::vector<unsigned int> & Data, const std::string & Filename);
+};
+
+#endif
diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp
new file mode 100755
index 0000000000..34d89107f1
--- /dev/null
+++ b/engines/sword25/gfx/staticbitmap.cpp
@@ -0,0 +1,218 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "staticbitmap.h"
+#include "bitmapresource.h"
+#include "package/packagemanager.h"
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/inputpersistenceblock.h"
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "STATICBITMAP"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_StaticBitmap::BS_StaticBitmap(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, const std::string& Filename) :
+ BS_Bitmap(ParentPtr, TYPE_STATICBITMAP)
+{
+ // Das BS_Bitmap konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
+ if (!m_InitSuccess) return;
+
+ m_InitSuccess = InitBitmapResource(Filename);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_StaticBitmap::BS_StaticBitmap(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle) :
+ BS_Bitmap(ParentPtr, TYPE_STATICBITMAP, Handle)
+{
+ m_InitSuccess = Unpersist(Reader);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::InitBitmapResource(const std::string & Filename)
+{
+ // Bild-Resource laden
+ BS_Resource* ResourcePtr = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(Filename);
+ if (!ResourcePtr)
+ {
+ BS_LOG_ERRORLN("Could not request resource \"%s\".", Filename.c_str());
+ return false;
+ }
+ if (ResourcePtr->GetType() != BS_Resource::TYPE_BITMAP)
+ {
+ BS_LOG_ERRORLN("Requested resource \"%s\" is not a bitmap.", Filename.c_str());
+ return false;
+ }
+
+ BS_BitmapResource * BitmapPtr = static_cast<BS_BitmapResource*>(ResourcePtr);
+
+ // Den eindeutigen Dateinamen zum späteren Referenzieren speichern
+ m_ResourceFilename = BitmapPtr->GetFileName();
+
+ // RenderObject Eigenschaften aktualisieren
+ m_OriginalWidth = m_Width = BitmapPtr->GetWidth();
+ m_OriginalHeight = m_Height = BitmapPtr->GetHeight();
+
+ // Bild-Resource freigeben
+ BitmapPtr->Release();
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_StaticBitmap::~BS_StaticBitmap()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::DoRender()
+{
+ // Bitmap holen
+ BS_Resource* ResourcePtr = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(m_ResourceFilename);
+ BS_ASSERT(ResourcePtr);
+ BS_ASSERT(ResourcePtr->GetType() == BS_Resource::TYPE_BITMAP);
+ BS_BitmapResource * BitmapResourcePtr = static_cast<BS_BitmapResource*>(ResourcePtr);
+
+ // Framebufferobjekt holen
+ BS_GraphicEngine * GfxPtr = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
+ BS_ASSERT(GfxPtr);
+
+ // Bitmap zeichnen
+ bool Result;
+ if (m_ScaleFactorX == 1.0f && m_ScaleFactorY == 1.0f)
+ {
+ Result = BitmapResourcePtr->Blit(m_AbsoluteX, m_AbsoluteY,
+ (m_FlipV ? BS_BitmapResource::FLIP_V : 0) |
+ (m_FlipH ? BS_BitmapResource::FLIP_H : 0),
+ 0, m_ModulationColor, -1, -1);
+ }
+ else
+ {
+ Result = BitmapResourcePtr->Blit(m_AbsoluteX, m_AbsoluteY,
+ (m_FlipV ? BS_BitmapResource::FLIP_V : 0) |
+ (m_FlipH ? BS_BitmapResource::FLIP_H : 0),
+ 0, m_ModulationColor, m_Width, m_Height);
+ }
+
+ // Resource freigeben
+ BitmapResourcePtr->Release();
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_StaticBitmap::GetPixel(int X, int Y) const
+{
+ BS_ASSERT(X >= 0 && X < m_Width);
+ BS_ASSERT(Y >= 0 && Y < m_Height);
+
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(m_ResourceFilename);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ BS_BitmapResource* pBitmapResource = static_cast<BS_BitmapResource*>(pResource);
+ unsigned int Result = pBitmapResource->GetPixel(X, Y);
+ pResource->Release();
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride)
+{
+ BS_LOG_ERRORLN("SetContent() ist not supported with this object.");
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+// Auskunftsmethoden
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::IsAlphaAllowed() const
+{
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(m_ResourceFilename);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ bool Result = static_cast<BS_BitmapResource*>(pResource)->IsAlphaAllowed();
+ pResource->Release();
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::IsColorModulationAllowed() const
+{
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(m_ResourceFilename);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ bool Result = static_cast<BS_BitmapResource*>(pResource)->IsColorModulationAllowed();
+ pResource->Release();
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::IsScalingAllowed() const
+{
+ BS_Resource* pResource = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(m_ResourceFilename);
+ BS_ASSERT(pResource->GetType() == BS_Resource::TYPE_BITMAP);
+ bool Result = static_cast<BS_BitmapResource*>(pResource)->IsScalingAllowed();
+ pResource->Release();
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_StaticBitmap::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ Result &= BS_Bitmap::Persist(Writer);
+ Writer.Write(m_ResourceFilename);
+
+ Result &= BS_RenderObject::PersistChildren(Writer);
+
+ return Result;
+}
+
+bool BS_StaticBitmap::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ Result &= BS_Bitmap::Unpersist(Reader);
+ std::string ResourceFilename;
+ Reader.Read(ResourceFilename);
+ Result &= InitBitmapResource(ResourceFilename);
+
+ Result &= BS_RenderObject::UnpersistChildren(Reader);
+
+ return Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/staticbitmap.h b/engines/sword25/gfx/staticbitmap.h
new file mode 100755
index 0000000000..bdf99e8ce0
--- /dev/null
+++ b/engines/sword25/gfx/staticbitmap.h
@@ -0,0 +1,69 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_STATIC_BITMAP_H
+#define BS_STATIC_BITMAP_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "bitmap.h"
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_StaticBitmap : public BS_Bitmap
+{
+friend BS_RenderObject;
+
+private:
+ /**
+ @remark Filename muss absoluter Pfad sein
+ */
+ BS_StaticBitmap(BS_RenderObjectPtr<BS_RenderObject> ParentPtr, const std::string& Filename);
+ BS_StaticBitmap(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle);
+
+public:
+ virtual ~BS_StaticBitmap();
+
+ virtual unsigned int GetPixel(int X, int Y) const;
+
+ virtual bool SetContent(const std::vector<unsigned char> & Pixeldata, unsigned int Offset, unsigned int Stride);
+
+ virtual bool IsScalingAllowed() const;
+ virtual bool IsAlphaAllowed() const;
+ virtual bool IsColorModulationAllowed() const;
+ virtual bool IsSetContentAllowed() const { return false; }
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+protected:
+ virtual bool DoRender();
+
+private:
+ std::string m_ResourceFilename;
+
+ bool InitBitmapResource(const std::string & Filename);
+};
+
+#endif
diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp
new file mode 100755
index 0000000000..c51d728cc4
--- /dev/null
+++ b/engines/sword25/gfx/text.cpp
@@ -0,0 +1,404 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// TODO:
+// Entweder Fontfile absolut abspeichern, oder Verzeichniswechseln verbieten
+// Eine relative Fontfile-Angabe könnte verwandt werden nachdem das Verzeichnis bereits gewechselt wurde und die Datei würde nicht mehr gefunden
+
+#define BS_LOG_PREFIX "TEXT"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/kernel.h"
+#include "kernel/outputpersistenceblock.h"
+#include "kernel/inputpersistenceblock.h"
+#include "fontresource.h"
+#include "bitmapresource.h"
+
+#include "text.h"
+
+
+// -----------------------------------------------------------------------------
+// Konstanten
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const unsigned int AUTO_WRAP_THRESHOLD_DEFAULT = 300;
+}
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_Text::BS_Text(BS_RenderObjectPtr<BS_RenderObject> ParentPtr) :
+ BS_RenderObject(ParentPtr, BS_RenderObject::TYPE_TEXT),
+ m_ModulationColor(0xffffffff),
+ m_AutoWrap(false),
+ m_AutoWrapThreshold(AUTO_WRAP_THRESHOLD_DEFAULT)
+{
+
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Text::BS_Text(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle) :
+ BS_RenderObject(ParentPtr, TYPE_TEXT, Handle)
+{
+ m_InitSuccess = Unpersist(Reader);
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Text::SetFont(const std::string & Font)
+{
+ // Font precachen.
+ if (GetResourceManager()->PrecacheResource(Font))
+ {
+ m_Font = Font;
+ UpdateFormat();
+ ForceRefresh();
+ return true;
+ }
+ else
+ {
+ BS_LOG_ERRORLN("Could not precache font \"%s\". Font probably does not exist.", Font.c_str());
+ return false;
+ }
+
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::SetText(const std::string & Text)
+{
+ m_Text = Text;
+ UpdateFormat();
+ ForceRefresh();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::SetColor(unsigned int ModulationColor)
+{
+ unsigned int NewModulationColor = (ModulationColor & 0x00ffffff) | (m_ModulationColor & 0xff000000);
+ if (NewModulationColor != m_ModulationColor)
+ {
+ m_ModulationColor = NewModulationColor;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::SetAlpha(int Alpha)
+{
+ BS_ASSERT(Alpha >= 0 && Alpha < 256);
+ unsigned int NewModulationColor = (m_ModulationColor & 0x00ffffff) | Alpha << 24;
+ if (NewModulationColor != m_ModulationColor)
+ {
+ m_ModulationColor = NewModulationColor;
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::SetAutoWrap(bool AutoWrap)
+{
+ if (AutoWrap != m_AutoWrap)
+ {
+ m_AutoWrap = AutoWrap;
+ UpdateFormat();
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::SetAutoWrapThreshold(unsigned int AutoWrapThreshold)
+{
+ if (AutoWrapThreshold != m_AutoWrapThreshold)
+ {
+ m_AutoWrapThreshold = AutoWrapThreshold;
+ UpdateFormat();
+ ForceRefresh();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_Text::DoRender()
+{
+ // Font-Resource locken.
+ BS_FontResource * FontPtr = LockFontResource();
+ if (!FontPtr) return false;
+
+ // Charactermap-Resource locken.
+ BS_ResourceManager * RMPtr = GetResourceManager();
+ BS_BitmapResource * CharMapPtr;
+ {
+ BS_Resource * pResource = RMPtr->RequestResource(FontPtr->GetCharactermapFileName());
+ if (!pResource)
+ {
+ BS_LOG_ERRORLN("Could not request resource \"%s\".", FontPtr->GetCharactermapFileName().c_str());
+ return false;
+ }
+ if (pResource->GetType() != BS_Resource::TYPE_BITMAP)
+ {
+ BS_LOG_ERRORLN("Requested resource \"%s\" is not a bitmap.", FontPtr->GetCharactermapFileName().c_str());
+ return false;
+ }
+
+ CharMapPtr = static_cast<BS_BitmapResource*>(pResource);
+ }
+
+ // Framebufferobjekt holen.
+ BS_GraphicEngine * GfxPtr = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
+ BS_ASSERT(GfxPtr);
+
+ bool Result = true;
+ std::vector<LINE>::iterator Iter = m_Lines.begin();
+ for (; Iter != m_Lines.end(); ++Iter)
+ {
+ // Feststellen, ob überhaupt Buchstaben der aktuellen Zeile vom Update betroffen sind.
+ BS_Rect CheckRect = (*Iter).BBox;
+ CheckRect.Move(m_AbsoluteX, m_AbsoluteY);
+
+ // Jeden Buchstaben einzeln Rendern.
+ int CurX = m_AbsoluteX + (*Iter).BBox.left;
+ int CurY = m_AbsoluteY + (*Iter).BBox.top;
+ for (unsigned int i = 0; i < (*Iter).Text.size(); ++i)
+ {
+ BS_Rect CurRect = FontPtr->GetCharacterRect((unsigned char)(*Iter).Text.at(i));
+
+ BS_Rect RenderRect(CurX, CurY, CurX + CurRect.GetWidth(), CurY + CurRect.GetHeight());
+ int RenderX = CurX + (RenderRect.left - RenderRect.left);
+ int RenderY = CurY + (RenderRect.top - RenderRect.top);
+ RenderRect.Move(CurRect.left - CurX, CurRect.top - CurY);
+ Result = CharMapPtr->Blit(RenderX, RenderY, BS_Image::FLIP_NONE, &RenderRect, m_ModulationColor);
+ if (!Result) break;
+
+ CurX += CurRect.GetWidth() + FontPtr->GetGapWidth();
+ }
+ }
+
+ // Charactermap-Resource freigeben.
+ CharMapPtr->Release();
+
+ // Font-Resource freigeben.
+ FontPtr->Release();
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_ResourceManager * BS_Text::GetResourceManager()
+{
+ // Pointer auf den Resource-Manager holen.
+ return BS_Kernel::GetInstance()->GetResourceManager();
+}
+
+// -----------------------------------------------------------------------------
+
+BS_FontResource * BS_Text::LockFontResource()
+{
+ BS_ResourceManager * RMPtr = GetResourceManager();
+
+ // Font-Resource locken.
+ BS_FontResource * FontPtr;
+ {
+ BS_Resource * ResourcePtr = RMPtr->RequestResource(m_Font);
+ if (!ResourcePtr)
+ {
+ BS_LOG_ERRORLN("Could not request resource \"%s\".", m_Font.c_str());
+ return NULL;
+ }
+ if (ResourcePtr->GetType() != BS_Resource::TYPE_FONT)
+ {
+ BS_LOG_ERRORLN("Requested resource \"%s\" is not a font.", m_Font.c_str());
+ return NULL;
+ }
+
+ FontPtr = static_cast<BS_FontResource*>(ResourcePtr);
+ }
+
+ return FontPtr;
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::UpdateFormat()
+{
+ BS_FontResource * FontPtr = LockFontResource();
+ BS_ASSERT(FontPtr);
+
+ UpdateMetrics(*FontPtr);
+
+ m_Lines.resize(1);
+ if (m_AutoWrap && (unsigned int) m_Width >= m_AutoWrapThreshold && m_Text.size() >= 2)
+ {
+ m_Width = 0;
+ unsigned int CurLineWidth = 0;
+ unsigned int CurLineHeight = 0;
+ unsigned int CurLine = 0;
+ unsigned int TempLineWidth = 0;
+ unsigned int LastSpace = 0; // we need at least 1 space character to start a new line...
+ m_Lines[0].Text = "";
+ for (unsigned int i = 0; i < m_Text.size(); ++i)
+ {
+ unsigned int j;
+ TempLineWidth = 0;
+ LastSpace = 0;
+ for (j = i; j < m_Text.size(); ++j)
+ {
+ if ((unsigned char)m_Text[j] == ' ') LastSpace = j;
+
+ const BS_Rect & CurCharRect = FontPtr->GetCharacterRect((unsigned char)m_Text[j]);
+ TempLineWidth += CurCharRect.GetWidth();
+ TempLineWidth += FontPtr->GetGapWidth();
+
+ if ((TempLineWidth >= m_AutoWrapThreshold) && (LastSpace > 0))
+ break;
+ }
+
+ if (j == m_Text.size()) LastSpace = m_Text.size(); // everything in 1 line.
+
+ CurLineWidth = 0;
+ CurLineHeight = 0;
+ for (j = i; j < LastSpace; ++j)
+ {
+ m_Lines[CurLine].Text += m_Text[j];
+
+ const BS_Rect & CurCharRect = FontPtr->GetCharacterRect((unsigned char)m_Text[j]);
+ CurLineWidth += CurCharRect.GetWidth();
+ CurLineWidth += FontPtr->GetGapWidth();
+ if ((unsigned int) CurCharRect.GetHeight() > CurLineHeight) CurLineHeight = CurCharRect.GetHeight();
+ }
+
+ m_Lines[CurLine].BBox.right = CurLineWidth;
+ m_Lines[CurLine].BBox.bottom = CurLineHeight;
+ if ((unsigned int) m_Width < CurLineWidth) m_Width = CurLineWidth;
+
+ if(LastSpace < m_Text.size())
+ {
+ ++CurLine;
+ BS_ASSERT(CurLine == m_Lines.size());
+ m_Lines.resize(CurLine + 1);
+ m_Lines[CurLine].Text = "";
+ }
+
+ i = LastSpace;
+ }
+
+ // Bounding-Box der einzelnen Zeilen relativ zur ersten festlegen (vor allem zentrieren).
+ m_Height = 0;
+ std::vector<LINE>::iterator Iter = m_Lines.begin();
+ for (; Iter != m_Lines.end(); ++Iter)
+ {
+ BS_Rect & BBox = (*Iter).BBox;
+ BBox.left = (m_Width - BBox.right) / 2;
+ BBox.right = BBox.left + BBox.right;
+ BBox.top = (Iter - m_Lines.begin()) * FontPtr->GetLineHeight();
+ BBox.bottom = BBox.top + BBox.bottom;
+ m_Height += BBox.GetHeight();
+ }
+ }
+ else
+ {
+ // Keine automatische Formatierung, also wird der gesamte Text in nur eine Zeile kopiert.
+ m_Lines[0].Text = m_Text;
+ m_Lines[0].BBox = BS_Rect(0, 0, m_Width, m_Height);
+ }
+
+ FontPtr->Release();
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Text::UpdateMetrics(BS_FontResource & FontResource)
+{
+ m_Width = 0;
+ m_Height = 0;
+
+ for (unsigned int i = 0; i < m_Text.size(); ++i)
+ {
+ const BS_Rect & CurRect = FontResource.GetCharacterRect((unsigned char)m_Text.at(i));
+ m_Width += CurRect.GetWidth();
+ if (i != m_Text.size() - 1) m_Width += FontResource.GetGapWidth();
+ if (m_Height < CurRect.GetHeight()) m_Height = CurRect.GetHeight();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_Text::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Persist(Writer);
+
+ Writer.Write(m_ModulationColor);
+ Writer.Write(m_Font);
+ Writer.Write(m_Text);
+ Writer.Write(m_AutoWrap);
+ Writer.Write(m_AutoWrapThreshold);
+
+ Result &= BS_RenderObject::PersistChildren(Writer);
+
+ return Result;
+}
+
+bool BS_Text::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ bool Result = true;
+
+ Result &= BS_RenderObject::Unpersist(Reader);
+
+ // Farbe und Alpha einlesen.
+ Reader.Read(m_ModulationColor);
+
+ // Beim Laden der anderen Member werden die Set-Methoden benutzt statt der tatsächlichen Member.
+ // So wird das Layout automatisch aktualisiert und auch alle anderen notwendigen Methoden ausgeführt.
+
+ std::string Font;
+ Reader.Read(Font);
+ SetFont(Font);
+
+ std::string Text;
+ Reader.Read(Text);
+ SetText(Text);
+
+ bool AutoWrap;
+ Reader.Read(AutoWrap);
+ SetAutoWrap(AutoWrap);
+
+ unsigned int AutoWrapThreshold;
+ Reader.Read(AutoWrapThreshold);
+ SetAutoWrapThreshold(AutoWrapThreshold);
+
+ Result &= BS_RenderObject::UnpersistChildren(Reader);
+
+ return Reader.IsGood() && Result;
+}
diff --git a/engines/sword25/gfx/text.h b/engines/sword25/gfx/text.h
new file mode 100755
index 0000000000..5b0fefe7d7
--- /dev/null
+++ b/engines/sword25/gfx/text.h
@@ -0,0 +1,156 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_TEXT_H
+#define BS_TEXT_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "math/rect.h"
+#include "renderobject.h"
+
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_Kernel;
+class BS_FontResource;
+class BS_ResourceManager;
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_Text : public BS_RenderObject
+{
+friend BS_RenderObject;
+
+public:
+ /**
+ @brief Setzt den Font mit dem der Text dargestellt werden soll.
+ @param Font der Dateiname der Fontdatei.
+ @return Gibt false zurück, wenn der Font nicht gefunden wurde.
+ */
+ bool SetFont(const std::string & Font);
+
+ /**
+ @brief Setzt den darzustellenden Text.
+ @param Text der darzustellende Text
+ */
+ void SetText(const std::string & Text);
+
+ /**
+ @brief Setzt den Alphawert des Textes.
+ @param Alpha der neue Alphawert des Textes (0 = keine Deckung, 255 = volle Deckung).
+ */
+ void SetAlpha(int Alpha);
+
+ /**
+ @brief Legt fest, ob der Text automatisch umgebrochen werden soll.
+
+ Wenn dieses Attribut auf true gesetzt ist, wird der Text umgebrochen, sofern er länger als GetAutoWrapThreshold() ist.
+
+ @param AutoWrap gibt an, ob der automatische Umbruch aktiviert oder deaktiviert werden soll.
+ @remark Dieses Attribut wird mit dem Wert false initialisiert.
+ */
+ void SetAutoWrap(bool AutoWrap);
+
+ /**
+ @brief Legt die Längengrenze des Textes in Pixeln fest, ab der ein automatischer Zeilenumbruch vorgenommen wird.
+ @remark Dieses Attribut wird mit dem Wert 300 initialisiert.
+ @remark Eine automatische Formatierung wird nur vorgenommen, wenn diese durch einen Aufruf von SetAutoWrap() aktiviert wurde.
+ */
+ void SetAutoWrapThreshold(unsigned int AutoWrapThreshold);
+
+ /**
+ @brief Gibt den dargestellten Text zurück.
+ */
+ const std::string & GetText() { return m_Text; }
+
+ /**
+ @brief Gibt den Namen das momentan benutzten Fonts zurück.
+ */
+ const std::string & GetFont() { return m_Font; }
+
+ /**
+ @brief Setzt die Farbe des Textes.
+ @param Color eine 24-Bit RGB Farbe, die die Farbe des Textes festlegt.
+ */
+ void SetColor(unsigned int ModulationColor);
+
+ /**
+ @brief Gibt den Alphawert des Textes zurück.
+ @return Der Alphawert des Textes (0 = keine Deckung, 255 = volle Deckung).
+ */
+ int GetAlpha() const { return m_ModulationColor >> 24; }
+
+ /**
+ @brief Gibt die Farbe des Textes zurück.
+ @return Eine 24-Bit RGB Farbe, die die Farbe des Textes angibt.
+ */
+ int GetColor() const { return m_ModulationColor & 0x00ffffff; }
+
+ /**
+ @brief Gibt zurück, ob die automatische Formatierung aktiviert ist.
+ */
+ bool IsAutoWrapActive() const { return m_AutoWrap; }
+
+ /**
+ @brief Gibt die Längengrenze des Textes in Pixeln zurück, ab der eine automatische Formatierung vorgenommen wird.
+ */
+ unsigned int GetAutoWrapThreshold() const { return m_AutoWrapThreshold; }
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer);
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+protected:
+ virtual bool DoRender();
+
+private:
+ BS_Text(BS_RenderObjectPtr<BS_RenderObject> ParentPtr);
+ BS_Text(BS_InputPersistenceBlock & Reader, BS_RenderObjectPtr<BS_RenderObject> ParentPtr, unsigned int Handle);
+
+ unsigned int m_ModulationColor;
+ std::string m_Font;
+ std::string m_Text;
+ bool m_AutoWrap;
+ unsigned int m_AutoWrapThreshold;
+
+ struct LINE
+ {
+ BS_Rect BBox;
+ std::string Text;
+ };
+
+ std::vector<LINE> m_Lines;
+
+ void UpdateFormat();
+ void UpdateMetrics(BS_FontResource & FontResource);
+ BS_ResourceManager * GetResourceManager();
+ BS_FontResource * LockFontResource();
+};
+
+#endif
diff --git a/engines/sword25/gfx/timedrenderobject.cpp b/engines/sword25/gfx/timedrenderobject.cpp
new file mode 100755
index 0000000000..aecf1038e6
--- /dev/null
+++ b/engines/sword25/gfx/timedrenderobject.cpp
@@ -0,0 +1,39 @@
+// -----------------------------------------------------------------------------
+// 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 "timedrenderobject.h"
+
+#include "renderobjectmanager.h"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_TimedRenderObject::BS_TimedRenderObject(BS_RenderObjectPtr<BS_RenderObject> pParent, TYPES Type, unsigned int Handle) :
+ BS_RenderObject(pParent, Type, Handle)
+{
+ BS_ASSERT(GetManager());
+ GetManager()->AttatchTimedRenderObject(this);
+}
+
+BS_TimedRenderObject::~BS_TimedRenderObject()
+{
+ BS_ASSERT(GetManager());
+ GetManager()->DetatchTimedRenderObject(this);
+} \ No newline at end of file
diff --git a/engines/sword25/gfx/timedrenderobject.h b/engines/sword25/gfx/timedrenderobject.h
new file mode 100755
index 0000000000..61a9709a94
--- /dev/null
+++ b/engines/sword25/gfx/timedrenderobject.h
@@ -0,0 +1,57 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// System Includes
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Engine Includes
+// -----------------------------------------------------------------------------
+
+#include "../kernel/common.h"
+#include "renderobject.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Class Definition
+// -----------------------------------------------------------------------------
+
+/**
+ @brief
+*/
+
+class BS_TimedRenderObject : public BS_RenderObject
+{
+public:
+ BS_TimedRenderObject(BS_RenderObjectPtr<BS_RenderObject> pParent, TYPES Type, unsigned int Handle = 0);
+ BS_TimedRenderObject::~BS_TimedRenderObject();
+
+ /**
+ @brief Teilt dem Objekt mit, dass ein neuer Frame begonnen wird.
+
+ Diese Methode wird jeden Frame an jedem BS_TimedRenderObject aufgerufen um diesen zu ermöglichen
+ ihren Zustand Zeitabhängig zu verändern (z.B. Animationen).<br>
+ @param int TimeElapsed gibt an wie viel Zeit (in Microsekunden) seit dem letzten Frame vergangen ist.
+ */
+ virtual void FrameNotification(int TimeElapsed) = 0;
+}; \ No newline at end of file