diff options
author | Eugene Sandulenko | 2010-07-29 19:53:02 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2010-10-12 21:38:20 +0000 |
commit | a683a420a9e43705c972b5e74d55e319729e1a81 (patch) | |
tree | bde6e4abd417bdfaec120aa951da9a19be36b654 /engines/sword25/gfx | |
parent | 7723d91c957d07205c51be32498d45cd0a78568f (diff) | |
download | scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.gz scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.bz2 scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.zip |
SWORD25: Importing original sources
svn-id: r53171
Diffstat (limited to 'engines/sword25/gfx')
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 |