Initial commit
This commit is contained in:
680
engines/sword25/gfx/animation.cpp
Normal file
680
engines/sword25/gfx/animation.cpp
Normal file
@@ -0,0 +1,680 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/animation.h"
|
||||
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/resmanager.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
#include "sword25/gfx/animationtemplate.h"
|
||||
#include "sword25/gfx/animationtemplateregistry.h"
|
||||
#include "sword25/gfx/animationresource.h"
|
||||
#include "sword25/gfx/bitmapresource.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
Animation::Animation(RenderObjectPtr<RenderObject> parentPtr, const Common::String &fileName) :
|
||||
TimedRenderObject(parentPtr, RenderObject::TYPE_ANIMATION) {
|
||||
// Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
|
||||
if (!_initSuccess)
|
||||
return;
|
||||
|
||||
initMembers();
|
||||
|
||||
// Vom negativen Fall ausgehen.
|
||||
_initSuccess = false;
|
||||
|
||||
initializeAnimationResource(fileName);
|
||||
|
||||
// Erfolg signalisieren.
|
||||
_initSuccess = true;
|
||||
}
|
||||
|
||||
Animation::Animation(RenderObjectPtr<RenderObject> parentPtr, const AnimationTemplate &templ) :
|
||||
TimedRenderObject(parentPtr, RenderObject::TYPE_ANIMATION) {
|
||||
// Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
|
||||
if (!_initSuccess)
|
||||
return;
|
||||
|
||||
initMembers();
|
||||
|
||||
// Vom negativen Fall ausgehen.
|
||||
_initSuccess = false;
|
||||
|
||||
_animationTemplateHandle = AnimationTemplate::create(templ);
|
||||
|
||||
// Erfolg signalisieren.
|
||||
_initSuccess = true;
|
||||
}
|
||||
|
||||
Animation::Animation(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
|
||||
TimedRenderObject(parentPtr, RenderObject::TYPE_ANIMATION, handle) {
|
||||
// Das BS_RenderObject konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
|
||||
if (!_initSuccess)
|
||||
return;
|
||||
|
||||
initMembers();
|
||||
|
||||
// Objekt vom Stream laden.
|
||||
_initSuccess = unpersist(reader);
|
||||
}
|
||||
|
||||
void Animation::initializeAnimationResource(const Common::String &fileName) {
|
||||
// Die Resource wird für die gesamte Lebensdauer des Animations-Objektes gelockt.
|
||||
Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(fileName);
|
||||
if (resourcePtr && resourcePtr->getType() == Resource::TYPE_ANIMATION)
|
||||
_animationResourcePtr = static_cast<AnimationResource *>(resourcePtr);
|
||||
else {
|
||||
error("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 Animation::initMembers() {
|
||||
_currentFrame = 0;
|
||||
_currentFrameTime = 0;
|
||||
_direction = FORWARD;
|
||||
_running = false;
|
||||
_finished = false;
|
||||
_relX = 0;
|
||||
_relY = 0;
|
||||
_scaleFactorX = 1.0f;
|
||||
_scaleFactorY = 1.0f;
|
||||
_modulationColor = BS_ARGBMASK;
|
||||
_animationResourcePtr = 0;
|
||||
_animationTemplateHandle = 0;
|
||||
_framesLocked = false;
|
||||
|
||||
_loopPointCallback = 0;
|
||||
_actionCallback = 0;
|
||||
_deleteCallback = 0;
|
||||
}
|
||||
|
||||
Animation::~Animation() {
|
||||
if (getAnimationDescription()) {
|
||||
stop();
|
||||
getAnimationDescription()->unlock();
|
||||
}
|
||||
|
||||
// Invoke the "delete" callback
|
||||
if (_deleteCallback)
|
||||
(_deleteCallback)(getHandle());
|
||||
|
||||
}
|
||||
|
||||
void Animation::play() {
|
||||
// If the animation was completed, then play it again from the start.
|
||||
if (_finished)
|
||||
stop();
|
||||
|
||||
_running = true;
|
||||
lockAllFrames();
|
||||
}
|
||||
|
||||
void Animation::pause() {
|
||||
_running = false;
|
||||
unlockAllFrames();
|
||||
}
|
||||
|
||||
void Animation::stop() {
|
||||
_currentFrame = 0;
|
||||
_currentFrameTime = 0;
|
||||
_direction = FORWARD;
|
||||
pause();
|
||||
}
|
||||
|
||||
void Animation::setFrame(uint nr) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
|
||||
if (nr >= animationDescriptionPtr->getFrameCount()) {
|
||||
error("Tried to set animation to illegal frame (%d). Value must be between 0 and %d.",
|
||||
nr, animationDescriptionPtr->getFrameCount());
|
||||
return;
|
||||
}
|
||||
|
||||
_currentFrame = nr;
|
||||
_currentFrameTime = 0;
|
||||
computeCurrentCharacteristics();
|
||||
forceRefresh();
|
||||
}
|
||||
|
||||
bool Animation::doRender(RectangleList *updateRects) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
assert(_currentFrame < animationDescriptionPtr->getFrameCount());
|
||||
|
||||
// Bitmap des aktuellen Frames holen
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(_currentFrame).fileName);
|
||||
assert(pResource);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
BitmapResource *pBitmapResource = static_cast<BitmapResource *>(pResource);
|
||||
|
||||
// Framebufferobjekt holen
|
||||
GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
|
||||
assert(pGfx);
|
||||
|
||||
// Bitmap zeichnen
|
||||
bool result;
|
||||
if (isScalingAllowed() && (_width != pBitmapResource->getWidth() || _height != pBitmapResource->getHeight())) {
|
||||
result = pBitmapResource->blit(_absoluteX, _absoluteY,
|
||||
(animationDescriptionPtr->getFrame(_currentFrame).flipV ? Graphics::FLIP_V : 0) |
|
||||
(animationDescriptionPtr->getFrame(_currentFrame).flipH ? Graphics::FLIP_H : 0),
|
||||
0, _modulationColor, _width, _height,
|
||||
updateRects);
|
||||
} else {
|
||||
result = pBitmapResource->blit(_absoluteX, _absoluteY,
|
||||
(animationDescriptionPtr->getFrame(_currentFrame).flipV ? Graphics::FLIP_V : 0) |
|
||||
(animationDescriptionPtr->getFrame(_currentFrame).flipH ? Graphics::FLIP_H : 0),
|
||||
0, _modulationColor, -1, -1,
|
||||
updateRects);
|
||||
}
|
||||
|
||||
// Resource freigeben
|
||||
pBitmapResource->release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Animation::frameNotification(int timeElapsed) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
assert(timeElapsed >= 0);
|
||||
|
||||
// Nur wenn die Animation läuft wird sie auch weiterbewegt
|
||||
if (_running) {
|
||||
// Gesamte vergangene Zeit bestimmen (inkl. Restzeit des aktuellen Frames)
|
||||
_currentFrameTime += timeElapsed;
|
||||
|
||||
// Anzahl an zu überpringenden Frames bestimmen
|
||||
int skipFrames = animationDescriptionPtr->getMillisPerFrame() == 0 ? 0 : _currentFrameTime / animationDescriptionPtr->getMillisPerFrame();
|
||||
|
||||
// Neue Frame-Restzeit bestimmen
|
||||
_currentFrameTime -= animationDescriptionPtr->getMillisPerFrame() * skipFrames;
|
||||
|
||||
// Neuen Frame bestimmen (je nach aktuellener Abspielrichtung wird addiert oder subtrahiert)
|
||||
int tmpCurFrame = _currentFrame;
|
||||
switch (_direction) {
|
||||
case FORWARD:
|
||||
tmpCurFrame += skipFrames;
|
||||
break;
|
||||
|
||||
case BACKWARD:
|
||||
tmpCurFrame -= skipFrames;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// Deal with overflows
|
||||
if (tmpCurFrame < 0) {
|
||||
// Loop-Point callback
|
||||
if (_loopPointCallback && !(_loopPointCallback)(getHandle()))
|
||||
_loopPointCallback = 0;
|
||||
|
||||
// An underflow may only occur if the animation type is JOJO.
|
||||
assert(animationDescriptionPtr->getAnimationType() == AT_JOJO);
|
||||
tmpCurFrame = - tmpCurFrame;
|
||||
_direction = FORWARD;
|
||||
} else if (static_cast<uint>(tmpCurFrame) >= animationDescriptionPtr->getFrameCount()) {
|
||||
// Loop-Point callback
|
||||
if (_loopPointCallback && !(_loopPointCallback)(getHandle()))
|
||||
_loopPointCallback = 0;
|
||||
|
||||
switch (animationDescriptionPtr->getAnimationType()) {
|
||||
case AT_ONESHOT:
|
||||
tmpCurFrame = animationDescriptionPtr->getFrameCount() - 1;
|
||||
_finished = true;
|
||||
pause();
|
||||
break;
|
||||
|
||||
case AT_LOOP:
|
||||
tmpCurFrame = tmpCurFrame % animationDescriptionPtr->getFrameCount();
|
||||
break;
|
||||
|
||||
case AT_JOJO:
|
||||
tmpCurFrame = animationDescriptionPtr->getFrameCount() - (tmpCurFrame % animationDescriptionPtr->getFrameCount()) - 1;
|
||||
_direction = BACKWARD;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)_currentFrame != tmpCurFrame) {
|
||||
forceRefresh();
|
||||
|
||||
if (animationDescriptionPtr->getFrame(_currentFrame).action != "") {
|
||||
// action callback
|
||||
if (_actionCallback && !(_actionCallback)(getHandle()))
|
||||
_actionCallback = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_currentFrame = static_cast<uint>(tmpCurFrame);
|
||||
}
|
||||
|
||||
// Größe und Position der Animation anhand des aktuellen Frames bestimmen
|
||||
computeCurrentCharacteristics();
|
||||
|
||||
assert(_currentFrame < animationDescriptionPtr->getFrameCount());
|
||||
assert(_currentFrameTime >= 0);
|
||||
}
|
||||
|
||||
void Animation::computeCurrentCharacteristics() {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
|
||||
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
|
||||
assert(pResource);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
|
||||
|
||||
// Größe des Bitmaps auf die Animation übertragen
|
||||
_width = static_cast<int>(pBitmap->getWidth() * _scaleFactorX);
|
||||
_height = static_cast<int>(pBitmap->getHeight() * _scaleFactorY);
|
||||
|
||||
// Position anhand des Hotspots berechnen und setzen
|
||||
int posX = _relX + computeXModifier();
|
||||
int posY = _relY + computeYModifier();
|
||||
|
||||
RenderObject::setPos(posX, posY);
|
||||
|
||||
pBitmap->release();
|
||||
}
|
||||
|
||||
bool Animation::lockAllFrames() {
|
||||
if (!_framesLocked) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
for (uint i = 0; i < animationDescriptionPtr->getFrameCount(); ++i) {
|
||||
if (!Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(i).fileName)) {
|
||||
error("Could not lock all animation frames.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_framesLocked = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Animation::unlockAllFrames() {
|
||||
if (_framesLocked) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
for (uint i = 0; i < animationDescriptionPtr->getFrameCount(); ++i) {
|
||||
Resource *pResource;
|
||||
if (!(pResource = Kernel::getInstance()->getResourceManager()->requestResource(animationDescriptionPtr->getFrame(i).fileName))) {
|
||||
error("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();
|
||||
}
|
||||
|
||||
_framesLocked = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Animation::ANIMATION_TYPES Animation::getAnimationType() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->getAnimationType();
|
||||
}
|
||||
|
||||
int Animation::getFPS() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->getFPS();
|
||||
}
|
||||
|
||||
int Animation::getFrameCount() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->getFrameCount();
|
||||
}
|
||||
|
||||
bool Animation::isScalingAllowed() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->isScalingAllowed();
|
||||
}
|
||||
|
||||
bool Animation::isAlphaAllowed() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->isAlphaAllowed();
|
||||
}
|
||||
|
||||
bool Animation::isColorModulationAllowed() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->isColorModulationAllowed();
|
||||
}
|
||||
|
||||
void Animation::setPos(int relX, int relY) {
|
||||
_relX = relX;
|
||||
_relY = relY;
|
||||
|
||||
computeCurrentCharacteristics();
|
||||
}
|
||||
|
||||
void Animation::setX(int relX) {
|
||||
_relX = relX;
|
||||
|
||||
computeCurrentCharacteristics();
|
||||
}
|
||||
|
||||
void Animation::setY(int relY) {
|
||||
_relY = relY;
|
||||
|
||||
computeCurrentCharacteristics();
|
||||
}
|
||||
|
||||
void Animation::setAlpha(int alpha) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
if (!animationDescriptionPtr->isAlphaAllowed()) {
|
||||
warning("Tried to set alpha value on an animation that does not support alpha. Call was ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint newModulationColor = (_modulationColor & BS_RGBMASK) | alpha << BS_ASHIFT;
|
||||
if (newModulationColor != _modulationColor) {
|
||||
_modulationColor = newModulationColor;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::setModulationColor(uint modulationColor) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
if (!animationDescriptionPtr->isColorModulationAllowed()) {
|
||||
warning("Tried to set modulation color on an animation that does not support color modulation. Call was ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
uint newModulationColor = (modulationColor & BS_RGBMASK) | (_modulationColor & BS_AMASK);
|
||||
if (newModulationColor != _modulationColor) {
|
||||
_modulationColor = newModulationColor;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::setScaleFactor(float scaleFactor) {
|
||||
setScaleFactorX(scaleFactor);
|
||||
setScaleFactorY(scaleFactor);
|
||||
}
|
||||
|
||||
void Animation::setScaleFactorX(float scaleFactorX) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
if (!animationDescriptionPtr->isScalingAllowed()) {
|
||||
warning("Tried to set x scale factor on an animation that does not support scaling. Call was ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaleFactorX != _scaleFactorX) {
|
||||
_scaleFactorX = scaleFactorX;
|
||||
if (_scaleFactorX <= 0.0f)
|
||||
_scaleFactorX = 0.001f;
|
||||
forceRefresh();
|
||||
computeCurrentCharacteristics();
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::setScaleFactorY(float scaleFactorY) {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
if (!animationDescriptionPtr->isScalingAllowed()) {
|
||||
warning("Tried to set y scale factor on an animation that does not support scaling. Call was ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaleFactorY != _scaleFactorY) {
|
||||
_scaleFactorY = scaleFactorY;
|
||||
if (_scaleFactorY <= 0.0f)
|
||||
_scaleFactorY = 0.001f;
|
||||
forceRefresh();
|
||||
computeCurrentCharacteristics();
|
||||
}
|
||||
}
|
||||
|
||||
const Common::String &Animation::getCurrentAction() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
return animationDescriptionPtr->getFrame(_currentFrame).action;
|
||||
}
|
||||
|
||||
int Animation::getX() const {
|
||||
return _relX;
|
||||
}
|
||||
|
||||
int Animation::getY() const {
|
||||
return _relY;
|
||||
}
|
||||
|
||||
int Animation::getAbsoluteX() const {
|
||||
return _absoluteX + (_relX - _x);
|
||||
}
|
||||
|
||||
int Animation::getAbsoluteY() const {
|
||||
return _absoluteY + (_relY - _y);
|
||||
}
|
||||
|
||||
int Animation::computeXModifier() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
|
||||
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
|
||||
assert(pResource);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
|
||||
|
||||
int result = curFrame.flipV ? - static_cast<int>((pBitmap->getWidth() - 1 - curFrame.hotspotX) * _scaleFactorX) :
|
||||
- static_cast<int>(curFrame.hotspotX * _scaleFactorX);
|
||||
|
||||
pBitmap->release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Animation::computeYModifier() const {
|
||||
AnimationDescription *animationDescriptionPtr = getAnimationDescription();
|
||||
assert(animationDescriptionPtr);
|
||||
const AnimationResource::Frame &curFrame = animationDescriptionPtr->getFrame(_currentFrame);
|
||||
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(curFrame.fileName);
|
||||
assert(pResource);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
BitmapResource *pBitmap = static_cast<BitmapResource *>(pResource);
|
||||
|
||||
int result = curFrame.flipH ? - static_cast<int>((pBitmap->getHeight() - 1 - curFrame.hotspotY) * _scaleFactorY) :
|
||||
- static_cast<int>(curFrame.hotspotY * _scaleFactorY);
|
||||
|
||||
pBitmap->release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Animation::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::persist(writer);
|
||||
|
||||
writer.write(_relX);
|
||||
writer.write(_relY);
|
||||
writer.write(_scaleFactorX);
|
||||
writer.write(_scaleFactorY);
|
||||
writer.write(_modulationColor);
|
||||
writer.write(_currentFrame);
|
||||
writer.write(_currentFrameTime);
|
||||
writer.write(_running);
|
||||
writer.write(_finished);
|
||||
writer.write(static_cast<uint32>(_direction));
|
||||
|
||||
// Je nach Animationstyp entweder das Template oder die Ressource speichern.
|
||||
if (_animationResourcePtr) {
|
||||
uint32 marker = 0;
|
||||
writer.write(marker);
|
||||
writer.writeString(_animationResourcePtr->getFileName());
|
||||
} else if (_animationTemplateHandle) {
|
||||
uint32 marker = 1;
|
||||
writer.write(marker);
|
||||
writer.write(_animationTemplateHandle);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
//writer.write(_AnimationDescriptionPtr);
|
||||
|
||||
writer.write(_framesLocked);
|
||||
|
||||
// The following is only there to for compatibility with older saves
|
||||
// resp. the original engine.
|
||||
writer.write((uint32)1);
|
||||
writer.writeString("LuaLoopPointCB");
|
||||
writer.write(getHandle());
|
||||
writer.write((uint32)1);
|
||||
writer.writeString("LuaActionCB");
|
||||
writer.write(getHandle());
|
||||
writer.write((uint32)1);
|
||||
writer.writeString("LuaDeleteCB");
|
||||
writer.write(getHandle());
|
||||
|
||||
result &= RenderObject::persistChildren(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool Animation::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::unpersist(reader);
|
||||
|
||||
reader.read(_relX);
|
||||
reader.read(_relY);
|
||||
reader.read(_scaleFactorX);
|
||||
reader.read(_scaleFactorY);
|
||||
reader.read(_modulationColor);
|
||||
reader.read(_currentFrame);
|
||||
reader.read(_currentFrameTime);
|
||||
reader.read(_running);
|
||||
reader.read(_finished);
|
||||
uint32 direction;
|
||||
reader.read(direction);
|
||||
_direction = static_cast<Direction>(direction);
|
||||
|
||||
// Animationstyp einlesen.
|
||||
uint32 marker;
|
||||
reader.read(marker);
|
||||
if (marker == 0) {
|
||||
Common::String resourceFilename;
|
||||
reader.readString(resourceFilename);
|
||||
initializeAnimationResource(resourceFilename);
|
||||
} else if (marker == 1) {
|
||||
reader.read(_animationTemplateHandle);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
reader.read(_framesLocked);
|
||||
if (_framesLocked)
|
||||
lockAllFrames();
|
||||
|
||||
|
||||
// The following is only there to for compatibility with older saves
|
||||
// resp. the original engine.
|
||||
uint32 callbackCount;
|
||||
Common::String callbackFunctionName;
|
||||
uint32 callbackData;
|
||||
|
||||
// loop point callback
|
||||
reader.read(callbackCount);
|
||||
assert(callbackCount == 1);
|
||||
reader.readString(callbackFunctionName);
|
||||
assert(callbackFunctionName == "LuaLoopPointCB");
|
||||
reader.read(callbackData);
|
||||
assert(callbackData == getHandle());
|
||||
|
||||
// loop point callback
|
||||
reader.read(callbackCount);
|
||||
assert(callbackCount == 1);
|
||||
reader.readString(callbackFunctionName);
|
||||
assert(callbackFunctionName == "LuaActionCB");
|
||||
reader.read(callbackData);
|
||||
assert(callbackData == getHandle());
|
||||
|
||||
// loop point callback
|
||||
reader.read(callbackCount);
|
||||
assert(callbackCount == 1);
|
||||
reader.readString(callbackFunctionName);
|
||||
assert(callbackFunctionName == "LuaDeleteCB");
|
||||
reader.read(callbackData);
|
||||
assert(callbackData == getHandle());
|
||||
|
||||
// Set the callbacks
|
||||
setCallbacks();
|
||||
|
||||
result &= RenderObject::unpersistChildren(reader);
|
||||
|
||||
return reader.isGood() && result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
AnimationDescription *Animation::getAnimationDescription() const {
|
||||
if (_animationResourcePtr)
|
||||
return _animationResourcePtr;
|
||||
else
|
||||
return AnimationTemplateRegistry::instance().resolveHandle(_animationTemplateHandle);
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
219
engines/sword25/gfx/animation.h
Normal file
219
engines/sword25/gfx/animation.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_ANIMATION_H
|
||||
#define SWORD25_ANIMATION_H
|
||||
|
||||
// Includes
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/timedrenderobject.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
// Forward declarations
|
||||
class Kernel;
|
||||
class AnimationResource;
|
||||
class AnimationTemplate;
|
||||
class AnimationDescription;
|
||||
class InputPersistenceBlock;
|
||||
|
||||
class Animation : public TimedRenderObject {
|
||||
friend class RenderObject;
|
||||
|
||||
private:
|
||||
Animation(RenderObjectPtr<RenderObject> parentPtr, const Common::String &fileName);
|
||||
Animation(RenderObjectPtr<RenderObject> parentPtr, const AnimationTemplate &template_);
|
||||
Animation(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle);
|
||||
|
||||
public:
|
||||
enum ANIMATION_TYPES {
|
||||
AT_ONESHOT,
|
||||
AT_LOOP,
|
||||
AT_JOJO
|
||||
};
|
||||
|
||||
~Animation() override;
|
||||
|
||||
void play();
|
||||
void pause();
|
||||
void stop();
|
||||
void setFrame(uint nr);
|
||||
|
||||
void setPos(int x, int y) override;
|
||||
void setX(int x) override;
|
||||
void setY(int y) override;
|
||||
|
||||
int getX() const override;
|
||||
int getY() const override;
|
||||
int getAbsoluteX() const override;
|
||||
int getAbsoluteY() const override;
|
||||
|
||||
/**
|
||||
@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(uint 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 _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 _scaleFactorY;
|
||||
}
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
void frameNotification(int timeElapsed) override;
|
||||
|
||||
ANIMATION_TYPES getAnimationType() const;
|
||||
int getFPS() const;
|
||||
int getFrameCount() const;
|
||||
bool isScalingAllowed() const;
|
||||
bool isAlphaAllowed() const;
|
||||
bool isColorModulationAllowed() const;
|
||||
uint getCurrentFrame() const {
|
||||
return _currentFrame;
|
||||
}
|
||||
const Common::String &getCurrentAction() const;
|
||||
bool isRunning() const {
|
||||
return _running;
|
||||
}
|
||||
|
||||
typedef bool (*ANIMATION_CALLBACK)(uint);
|
||||
|
||||
void setCallbacks();
|
||||
|
||||
protected:
|
||||
bool doRender(RectangleList *updateRects) override;
|
||||
|
||||
private:
|
||||
enum Direction {
|
||||
FORWARD,
|
||||
BACKWARD
|
||||
};
|
||||
|
||||
int32 _relX;
|
||||
int32 _relY;
|
||||
float _scaleFactorX;
|
||||
float _scaleFactorY;
|
||||
uint32 _modulationColor;
|
||||
uint32 _currentFrame;
|
||||
int32 _currentFrameTime;
|
||||
bool _running;
|
||||
bool _finished;
|
||||
Direction _direction;
|
||||
AnimationResource *_animationResourcePtr;
|
||||
uint32 _animationTemplateHandle;
|
||||
bool _framesLocked;
|
||||
|
||||
ANIMATION_CALLBACK _loopPointCallback;
|
||||
ANIMATION_CALLBACK _actionCallback;
|
||||
ANIMATION_CALLBACK _deleteCallback;
|
||||
|
||||
/**
|
||||
@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();
|
||||
AnimationDescription *getAnimationDescription() const;
|
||||
|
||||
/**
|
||||
* Initializes a new animation resource from an XML file.
|
||||
*/
|
||||
void initializeAnimationResource(const Common::String &fileName);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
61
engines/sword25/gfx/animationdescription.cpp
Normal file
61
engines/sword25/gfx/animationdescription.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/gfx/animationdescription.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
bool AnimationDescription::persist(OutputPersistenceBlock &writer) {
|
||||
writer.write(static_cast<uint32>(_animationType));
|
||||
writer.write(_FPS);
|
||||
writer.write(_millisPerFrame);
|
||||
writer.write(_scalingAllowed);
|
||||
writer.write(_alphaAllowed);
|
||||
writer.write(_colorModulationAllowed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationDescription::unpersist(InputPersistenceBlock &reader) {
|
||||
uint32 animationType;
|
||||
reader.read(animationType);
|
||||
_animationType = static_cast<Animation::ANIMATION_TYPES>(animationType);
|
||||
reader.read(_FPS);
|
||||
reader.read(_millisPerFrame);
|
||||
reader.read(_scalingAllowed);
|
||||
reader.read(_alphaAllowed);
|
||||
reader.read(_colorModulationAllowed);
|
||||
|
||||
return reader.isGood();
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
99
engines/sword25/gfx/animationdescription.h
Normal file
99
engines/sword25/gfx/animationdescription.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_ANIMATIONDESCRIPTION_H
|
||||
#define SWORD25_ANIMATIONDESCRIPTION_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
#include "sword25/gfx/animation.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class AnimationDescription : public Persistable {
|
||||
protected:
|
||||
AnimationDescription() :
|
||||
_animationType(Animation::AT_LOOP),
|
||||
_FPS(10),
|
||||
_millisPerFrame(0),
|
||||
_scalingAllowed(true),
|
||||
_alphaAllowed(true),
|
||||
_colorModulationAllowed(true)
|
||||
{}
|
||||
|
||||
public:
|
||||
struct Frame {
|
||||
// Die Hotspot-Angabe bezieht sich auf das ungeflippte Bild!!
|
||||
int32 hotspotX;
|
||||
int32 hotspotY;
|
||||
bool flipV;
|
||||
bool flipH;
|
||||
Common::String fileName;
|
||||
Common::String action;
|
||||
};
|
||||
|
||||
virtual const Frame &getFrame(uint index) const = 0;
|
||||
virtual uint getFrameCount() const = 0;
|
||||
virtual void unlock() = 0;
|
||||
|
||||
Animation::ANIMATION_TYPES getAnimationType() const {
|
||||
return _animationType;
|
||||
}
|
||||
int getFPS() const {
|
||||
return _FPS;
|
||||
}
|
||||
int getMillisPerFrame() const {
|
||||
return _millisPerFrame;
|
||||
}
|
||||
bool isScalingAllowed() const {
|
||||
return _scalingAllowed;
|
||||
}
|
||||
bool isAlphaAllowed() const {
|
||||
return _alphaAllowed;
|
||||
}
|
||||
bool isColorModulationAllowed() const {
|
||||
return _colorModulationAllowed;
|
||||
}
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
protected:
|
||||
Animation::ANIMATION_TYPES _animationType;
|
||||
int32 _FPS;
|
||||
int32 _millisPerFrame;
|
||||
bool _scalingAllowed;
|
||||
bool _alphaAllowed;
|
||||
bool _colorModulationAllowed;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
252
engines/sword25/gfx/animationresource.cpp
Normal file
252
engines/sword25/gfx/animationresource.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/animationresource.h"
|
||||
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/resmanager.h" // for PRECACHE_RESOURCES
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/gfx/bitmapresource.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
enum {
|
||||
DEFAULT_FPS = 10,
|
||||
MIN_FPS = 1,
|
||||
MAX_FPS = 200
|
||||
};
|
||||
|
||||
AnimationResource::AnimationResource(const Common::String &filename) :
|
||||
Resource(filename, Resource::TYPE_ANIMATION),
|
||||
Common::XMLParser(),
|
||||
_valid(false) {
|
||||
// Get a pointer to the package manager
|
||||
_pPackage = Kernel::getInstance()->getPackage();
|
||||
assert(_pPackage);
|
||||
|
||||
// Switch to the folder the specified Xml fiile is in
|
||||
Common::String oldDirectory = _pPackage->getCurrentDirectory();
|
||||
if (getFileName().contains('/')) {
|
||||
Common::String dir = Common::String(getFileName().c_str(), strrchr(getFileName().c_str(), '/'));
|
||||
_pPackage->changeDirectory(dir);
|
||||
}
|
||||
|
||||
// Load the contents of the file
|
||||
uint fileSize;
|
||||
char *xmlData = _pPackage->getXmlFile(getFileName(), &fileSize);
|
||||
if (!xmlData) {
|
||||
error("Could not read \"%s\".", getFileName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the contents
|
||||
if (!loadBuffer((const byte *)xmlData, fileSize))
|
||||
return;
|
||||
|
||||
_valid = parse();
|
||||
close();
|
||||
free(xmlData);
|
||||
|
||||
// Switch back to the previous folder
|
||||
_pPackage->changeDirectory(oldDirectory);
|
||||
|
||||
// Give an error message if there weren't any frames specified
|
||||
if (_frames.empty()) {
|
||||
error("\"%s\" does not have any frames.", getFileName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Pre-cache all the frames
|
||||
if (!precacheAllFrames()) {
|
||||
error("Could not precache all frames of \"%s\".", getFileName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Post processing to compute animation features
|
||||
if (!computeFeatures()) {
|
||||
error("Could not determine the features of \"%s\".", getFileName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
bool AnimationResource::parseBooleanKey(Common::String s, bool &result) {
|
||||
s.toLowercase();
|
||||
if (!strcmp(s.c_str(), "true"))
|
||||
result = true;
|
||||
else if (!strcmp(s.c_str(), "false"))
|
||||
result = false;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationResource::parserCallback_animation(ParserNode *node) {
|
||||
if (!parseIntegerKey(node->values["fps"], 1, &_FPS) || (_FPS < MIN_FPS) || (_FPS > MAX_FPS)) {
|
||||
return parserError(Common::String::format("Illegal or missing fps attribute in <animation> tag in \"%s\". Assuming default (\"%d\").",
|
||||
getFileName().c_str(), DEFAULT_FPS));
|
||||
}
|
||||
|
||||
// Loop type value
|
||||
const char *loopTypeString = node->values["type"].c_str();
|
||||
|
||||
if (strcmp(loopTypeString, "oneshot") == 0) {
|
||||
_animationType = Animation::AT_ONESHOT;
|
||||
} else if (strcmp(loopTypeString, "loop") == 0) {
|
||||
_animationType = Animation::AT_LOOP;
|
||||
} else if (strcmp(loopTypeString, "jojo") == 0) {
|
||||
_animationType = Animation::AT_JOJO;
|
||||
} else {
|
||||
warning("Illegal type value (\"%s\") in <animation> tag in \"%s\". Assuming default (\"loop\").",
|
||||
loopTypeString, getFileName().c_str());
|
||||
_animationType = Animation::AT_LOOP;
|
||||
}
|
||||
|
||||
// Calculate the milliseconds required per frame
|
||||
// FIXME: Double check variable naming. Based on the constant, it may be microseconds
|
||||
_millisPerFrame = 1000000 / _FPS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationResource::parserCallback_frame(ParserNode *node) {
|
||||
Frame frame;
|
||||
|
||||
const char *fileString = node->values["file"].c_str();
|
||||
if (!fileString) {
|
||||
error("<frame> tag without file attribute occurred in \"%s\".", getFileName().c_str());
|
||||
return false;
|
||||
}
|
||||
frame.fileName = _pPackage->getAbsolutePath(fileString);
|
||||
if (frame.fileName.empty()) {
|
||||
error("Could not create absolute path for file specified in <frame> tag in \"%s\": \"%s\".",
|
||||
getFileName().c_str(), fileString);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *actionString = node->values["action"].c_str();
|
||||
if (actionString)
|
||||
frame.action = actionString;
|
||||
|
||||
const char *hotspotxString = node->values["hotspotx"].c_str();
|
||||
const char *hotspotyString = node->values["hotspoty"].c_str();
|
||||
if ((!hotspotxString && hotspotyString) ||
|
||||
(hotspotxString && !hotspotyString))
|
||||
warning("%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 && !parseIntegerKey(hotspotxString, 1, &frame.hotspotX))
|
||||
warning("Illegal hotspotx value (\"%s\") in frame tag in \"%s\". Assuming default (\"%d\").",
|
||||
hotspotxString, getFileName().c_str(), frame.hotspotX);
|
||||
|
||||
frame.hotspotY = 0;
|
||||
if (hotspotyString && !parseIntegerKey(hotspotyString, 1, &frame.hotspotY))
|
||||
warning("Illegal hotspoty value (\"%s\") in frame tag in \"%s\". Assuming default (\"%d\").",
|
||||
hotspotyString, getFileName().c_str(), frame.hotspotY);
|
||||
|
||||
Common::String flipVString = node->values["flipv"];
|
||||
if (!flipVString.empty()) {
|
||||
if (!parseBooleanKey(flipVString, frame.flipV)) {
|
||||
warning("Illegal flipv value (\"%s\") in <frame> tag in \"%s\". Assuming default (\"false\").",
|
||||
flipVString.c_str(), getFileName().c_str());
|
||||
frame.flipV = false;
|
||||
}
|
||||
} else
|
||||
frame.flipV = false;
|
||||
|
||||
Common::String flipHString = node->values["fliph"];
|
||||
if (!flipHString.empty()) {
|
||||
if (!parseBooleanKey(flipHString, frame.flipH)) {
|
||||
warning("Illegal fliph value (\"%s\") in <frame> tag in \"%s\". Assuming default (\"false\").",
|
||||
flipHString.c_str(), getFileName().c_str());
|
||||
frame.flipH = false;
|
||||
}
|
||||
} else
|
||||
frame.flipH = false;
|
||||
|
||||
_frames.push_back(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
AnimationResource::~AnimationResource() {
|
||||
}
|
||||
|
||||
bool AnimationResource::precacheAllFrames() const {
|
||||
Common::Array<Frame>::const_iterator iter = _frames.begin();
|
||||
for (; iter != _frames.end(); ++iter) {
|
||||
#ifdef PRECACHE_RESOURCES
|
||||
if (!Kernel::getInstance()->getResourceManager()->precacheResource((*iter).fileName)) {
|
||||
error("Could not precache \"%s\".", (*iter).fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName);
|
||||
pResource->release(); //unlock precached resource
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationResource::computeFeatures() {
|
||||
assert(_frames.size());
|
||||
|
||||
// Alle Features werden als vorhanden angenommen
|
||||
_scalingAllowed = true;
|
||||
_alphaAllowed = true;
|
||||
_colorModulationAllowed = true;
|
||||
|
||||
// Alle Frame durchgehen und alle Features deaktivieren, die auch nur von einem Frame nicht unterstützt werden.
|
||||
Common::Array<Frame>::const_iterator iter = _frames.begin();
|
||||
for (; iter != _frames.end(); ++iter) {
|
||||
BitmapResource *pBitmap;
|
||||
if (!(pBitmap = static_cast<BitmapResource *>(Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName)))) {
|
||||
error("Could not request \"%s\".", (*iter).fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pBitmap->isScalingAllowed())
|
||||
_scalingAllowed = false;
|
||||
if (!pBitmap->isAlphaAllowed())
|
||||
_alphaAllowed = false;
|
||||
if (!pBitmap->isColorModulationAllowed())
|
||||
_colorModulationAllowed = false;
|
||||
|
||||
pBitmap->release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
118
engines/sword25/gfx/animationresource.h
Normal file
118
engines/sword25/gfx/animationresource.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_ANIMATIONRESOURCE_H
|
||||
#define SWORD25_ANIMATIONRESOURCE_H
|
||||
|
||||
#include "common/formats/xmlparser.h"
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/resource.h"
|
||||
#include "sword25/gfx/animationdescription.h"
|
||||
#include "sword25/gfx/animation.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Kernel;
|
||||
class PackageManager;
|
||||
|
||||
class AnimationResource : public Resource, public AnimationDescription, public Common::XMLParser {
|
||||
public:
|
||||
AnimationResource(const Common::String &filename);
|
||||
~AnimationResource() override;
|
||||
|
||||
const Frame &getFrame(uint index) const override {
|
||||
return _frames[index];
|
||||
}
|
||||
uint getFrameCount() const override {
|
||||
return _frames.size();
|
||||
}
|
||||
void unlock() override {
|
||||
release();
|
||||
}
|
||||
|
||||
Animation::ANIMATION_TYPES getAnimationType() const {
|
||||
return _animationType;
|
||||
}
|
||||
int getFPS() const {
|
||||
return _FPS;
|
||||
}
|
||||
int getMillisPerFrame() const {
|
||||
return _millisPerFrame;
|
||||
}
|
||||
bool isScalingAllowed() const {
|
||||
return _scalingAllowed;
|
||||
}
|
||||
bool isAlphaAllowed() const {
|
||||
return _alphaAllowed;
|
||||
}
|
||||
bool isColorModulationAllowed() const {
|
||||
return _colorModulationAllowed;
|
||||
}
|
||||
bool isValid() const {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _valid;
|
||||
|
||||
Common::Array<Frame> _frames;
|
||||
|
||||
PackageManager *_pPackage;
|
||||
|
||||
|
||||
bool computeFeatures();
|
||||
bool precacheAllFrames() const;
|
||||
|
||||
// Parser
|
||||
CUSTOM_XML_PARSER(AnimationResource) {
|
||||
XML_KEY(animation)
|
||||
XML_PROP(fps, true)
|
||||
XML_PROP(type, true)
|
||||
|
||||
XML_KEY(frame)
|
||||
XML_PROP(file, true)
|
||||
XML_PROP(hotspotx, true)
|
||||
XML_PROP(hotspoty, true)
|
||||
XML_PROP(fliph, false)
|
||||
XML_PROP(flipv, false)
|
||||
KEY_END()
|
||||
KEY_END()
|
||||
} PARSER_END()
|
||||
|
||||
bool parseBooleanKey(Common::String s, bool &result);
|
||||
|
||||
// Parser callback methods
|
||||
bool parserCallback_animation(ParserNode *node);
|
||||
bool parserCallback_frame(ParserNode *node);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
237
engines/sword25/gfx/animationtemplate.cpp
Normal file
237
engines/sword25/gfx/animationtemplate.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/resource.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
|
||||
#include "sword25/gfx/animationresource.h"
|
||||
#include "sword25/gfx/animationtemplate.h"
|
||||
#include "sword25/gfx/animationtemplateregistry.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
uint AnimationTemplate::create(const Common::String &sourceAnimation) {
|
||||
AnimationTemplate *animationTemplatePtr = new AnimationTemplate(sourceAnimation);
|
||||
|
||||
if (animationTemplatePtr->isValid()) {
|
||||
return AnimationTemplateRegistry::instance().resolvePtr(animationTemplatePtr);
|
||||
} else {
|
||||
delete animationTemplatePtr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint AnimationTemplate::create(const AnimationTemplate &other) {
|
||||
AnimationTemplate *animationTemplatePtr = new AnimationTemplate(other);
|
||||
|
||||
if (animationTemplatePtr->isValid()) {
|
||||
return AnimationTemplateRegistry::instance().resolvePtr(animationTemplatePtr);
|
||||
} else {
|
||||
delete animationTemplatePtr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint AnimationTemplate::create(InputPersistenceBlock &reader, uint handle) {
|
||||
AnimationTemplate *animationTemplatePtr = new AnimationTemplate(reader, handle);
|
||||
|
||||
if (animationTemplatePtr->isValid()) {
|
||||
return AnimationTemplateRegistry::instance().resolvePtr(animationTemplatePtr);
|
||||
} else {
|
||||
delete animationTemplatePtr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
AnimationTemplate::AnimationTemplate(const Common::String &sourceAnimation) {
|
||||
// Objekt registrieren.
|
||||
AnimationTemplateRegistry::instance().registerObject(this);
|
||||
|
||||
_valid = false;
|
||||
|
||||
// Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt
|
||||
_sourceAnimationPtr = requestSourceAnimation(sourceAnimation);
|
||||
|
||||
// Erfolg signalisieren
|
||||
_valid = (_sourceAnimationPtr != 0);
|
||||
}
|
||||
|
||||
AnimationTemplate::AnimationTemplate(const AnimationTemplate &other) : AnimationDescription() {
|
||||
// Objekt registrieren.
|
||||
AnimationTemplateRegistry::instance().registerObject(this);
|
||||
|
||||
_valid = false;
|
||||
|
||||
// Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt.
|
||||
if (!other._sourceAnimationPtr)
|
||||
return;
|
||||
_sourceAnimationPtr = requestSourceAnimation(other._sourceAnimationPtr->getFileName());
|
||||
|
||||
// Alle Member kopieren.
|
||||
_animationType = other._animationType;
|
||||
_FPS = other._FPS;
|
||||
_millisPerFrame = other._millisPerFrame;
|
||||
_scalingAllowed = other._scalingAllowed;
|
||||
_alphaAllowed = other._alphaAllowed;
|
||||
_colorModulationAllowed = other._colorModulationAllowed;
|
||||
_frames = other._frames;
|
||||
_sourceAnimationPtr = other._sourceAnimationPtr;
|
||||
_valid = other._valid;
|
||||
|
||||
_valid &= (_sourceAnimationPtr != 0);
|
||||
}
|
||||
|
||||
AnimationTemplate::AnimationTemplate(InputPersistenceBlock &reader, uint handle) {
|
||||
// Objekt registrieren.
|
||||
AnimationTemplateRegistry::instance().registerObject(this, handle);
|
||||
|
||||
// Objekt laden.
|
||||
_valid = unpersist(reader);
|
||||
}
|
||||
|
||||
AnimationResource *AnimationTemplate::requestSourceAnimation(const Common::String &sourceAnimation) const {
|
||||
ResourceManager *RMPtr = Kernel::getInstance()->getResourceManager();
|
||||
Resource *resourcePtr;
|
||||
if (NULL == (resourcePtr = RMPtr->requestResource(sourceAnimation)) || resourcePtr->getType() != Resource::TYPE_ANIMATION) {
|
||||
error("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<AnimationResource *>(resourcePtr);
|
||||
}
|
||||
|
||||
AnimationTemplate::~AnimationTemplate() {
|
||||
// Animations-Resource freigeben
|
||||
if (_sourceAnimationPtr) {
|
||||
_sourceAnimationPtr->release();
|
||||
}
|
||||
|
||||
// Objekt deregistrieren
|
||||
AnimationTemplateRegistry::instance().deregisterObject(this);
|
||||
}
|
||||
|
||||
void AnimationTemplate::addFrame(int index) {
|
||||
if (validateSourceIndex(index)) {
|
||||
_frames.push_back(_sourceAnimationPtr->getFrame(index));
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTemplate::setFrame(int destIndex, int srcIndex) {
|
||||
if (validateDestIndex(destIndex) && validateSourceIndex(srcIndex)) {
|
||||
_frames[destIndex] = _sourceAnimationPtr->getFrame(srcIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimationTemplate::validateSourceIndex(uint index) const {
|
||||
if (index > _sourceAnimationPtr->getFrameCount()) {
|
||||
warning("Tried to insert a frame (\"%d\") that does not exist in the source animation (\"%s\"). Ignoring call.",
|
||||
index, _sourceAnimationPtr->getFileName().c_str());
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationTemplate::validateDestIndex(uint index) const {
|
||||
if (index > _frames.size()) {
|
||||
warning("Tried to change a nonexistent frame (\"%d\") in a template animation. Ignoring call.",
|
||||
index);
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationTemplate::setFPS(int FPS) {
|
||||
_FPS = FPS;
|
||||
_millisPerFrame = 1000000 / _FPS;
|
||||
}
|
||||
|
||||
bool AnimationTemplate::persist(OutputPersistenceBlock &writer) {
|
||||
bool Result = true;
|
||||
|
||||
// Parent persistieren.
|
||||
Result &= AnimationDescription::persist(writer);
|
||||
|
||||
// Frameanzahl schreiben.
|
||||
writer.write((uint32)_frames.size());
|
||||
|
||||
// Frames einzeln persistieren.
|
||||
Common::Array<const Frame>::const_iterator Iter = _frames.begin();
|
||||
while (Iter != _frames.end()) {
|
||||
writer.write(Iter->hotspotX);
|
||||
writer.write(Iter->hotspotY);
|
||||
writer.write(Iter->flipV);
|
||||
writer.write(Iter->flipH);
|
||||
writer.writeString(Iter->fileName);
|
||||
writer.writeString(Iter->action);
|
||||
++Iter;
|
||||
}
|
||||
|
||||
// Restliche Member persistieren.
|
||||
writer.writeString(_sourceAnimationPtr->getFileName());
|
||||
writer.write(_valid);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool AnimationTemplate::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
// Parent wieder herstellen.
|
||||
result &= AnimationDescription::unpersist(reader);
|
||||
|
||||
// Frameanzahl lesen.
|
||||
uint32 frameCount;
|
||||
reader.read(frameCount);
|
||||
|
||||
// Frames einzeln wieder herstellen.
|
||||
for (uint i = 0; i < frameCount; ++i) {
|
||||
Frame frame;
|
||||
reader.read(frame.hotspotX);
|
||||
reader.read(frame.hotspotY);
|
||||
reader.read(frame.flipV);
|
||||
reader.read(frame.flipH);
|
||||
reader.readString(frame.fileName);
|
||||
reader.readString(frame.action);
|
||||
|
||||
_frames.push_back(frame);
|
||||
}
|
||||
|
||||
// Die Animations-Resource wird für die gesamte Lebensdauer des Objektes gelockt
|
||||
Common::String sourceAnimation;
|
||||
reader.readString(sourceAnimation);
|
||||
_sourceAnimationPtr = requestSourceAnimation(sourceAnimation);
|
||||
|
||||
reader.read(_valid);
|
||||
|
||||
return _sourceAnimationPtr && reader.isGood() && result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
121
engines/sword25/gfx/animationtemplate.h
Normal file
121
engines/sword25/gfx/animationtemplate.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_ANIMATION_TEMPLATE_H
|
||||
#define SWORD25_ANIMATION_TEMPLATE_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
#include "sword25/gfx/animationdescription.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class AnimationResource;
|
||||
|
||||
class AnimationTemplate : public AnimationDescription {
|
||||
public:
|
||||
static uint create(const Common::String &sourceAnimation);
|
||||
static uint create(const AnimationTemplate &other);
|
||||
static uint create(InputPersistenceBlock &reader, uint handle);
|
||||
AnimationTemplate *resolveHandle(uint handle) const;
|
||||
|
||||
private:
|
||||
AnimationTemplate(const Common::String &sourceAnimation);
|
||||
AnimationTemplate(const AnimationTemplate &other);
|
||||
AnimationTemplate(InputPersistenceBlock &reader, uint handle);
|
||||
|
||||
public:
|
||||
~AnimationTemplate() override;
|
||||
|
||||
const Frame &getFrame(uint index) const override {
|
||||
assert(index < _frames.size());
|
||||
return _frames[index];
|
||||
}
|
||||
uint getFrameCount() const override {
|
||||
return _frames.size();
|
||||
}
|
||||
void unlock() override {
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return _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(Animation::ANIMATION_TYPES type) {
|
||||
_animationType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Setzt die Abspielgeschwindigkeit.
|
||||
@param FPS die Abspielgeschwindigkeit in Frames pro Sekunde.
|
||||
*/
|
||||
void setFPS(int FPS);
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
private:
|
||||
Common::Array<Frame> _frames;
|
||||
AnimationResource *_sourceAnimationPtr;
|
||||
bool _valid;
|
||||
|
||||
AnimationResource *requestSourceAnimation(const Common::String &sourceAnimation) const;
|
||||
bool validateSourceIndex(uint index) const;
|
||||
bool validateDestIndex(uint index) const;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
95
engines/sword25/gfx/animationtemplateregistry.cpp
Normal file
95
engines/sword25/gfx/animationtemplateregistry.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/gfx/animationtemplateregistry.h"
|
||||
#include "sword25/gfx/animationtemplate.h"
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(Sword25::AnimationTemplateRegistry);
|
||||
}
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
bool AnimationTemplateRegistry::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
// Das nächste zu vergebene Handle schreiben.
|
||||
writer.write(_nextHandle);
|
||||
|
||||
// Anzahl an BS_AnimationTemplates schreiben.
|
||||
writer.write((uint32)_handle2PtrMap.size());
|
||||
|
||||
// Alle BS_AnimationTemplates persistieren.
|
||||
HANDLE2PTR_MAP::const_iterator iter = _handle2PtrMap.begin();
|
||||
while (iter != _handle2PtrMap.end()) {
|
||||
// Handle persistieren.
|
||||
writer.write(iter->_key);
|
||||
|
||||
// Objekt persistieren.
|
||||
result &= iter->_value->persist(writer);
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool AnimationTemplateRegistry::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
// Das nächste zu vergebene Handle wieder herstellen.
|
||||
reader.read(_nextHandle);
|
||||
|
||||
// Alle vorhandenen BS_AnimationTemplates zerstören.
|
||||
while (!_handle2PtrMap.empty())
|
||||
delete _handle2PtrMap.begin()->_value;
|
||||
|
||||
// Anzahl an BS_AnimationTemplates einlesen.
|
||||
uint32 animationTemplateCount;
|
||||
reader.read(animationTemplateCount);
|
||||
|
||||
// Alle gespeicherten BS_AnimationTemplates wieder herstellen.
|
||||
for (uint i = 0; i < animationTemplateCount; ++i) {
|
||||
// Handle lesen.
|
||||
uint32 handle;
|
||||
reader.read(handle);
|
||||
|
||||
// BS_AnimationTemplate wieder herstellen.
|
||||
result &= (AnimationTemplate::create(reader, handle) != 0);
|
||||
}
|
||||
|
||||
return reader.isGood() && result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
56
engines/sword25/gfx/animationtemplateregistry.h
Normal file
56
engines/sword25/gfx/animationtemplateregistry.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_ANIMATIONTEMPLATEREGISTRY_H
|
||||
#define SWORD25_ANIMATIONTEMPLATEREGISTRY_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
#include "sword25/kernel/objectregistry.h"
|
||||
|
||||
#include "common/singleton.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class AnimationTemplate;
|
||||
|
||||
class AnimationTemplateRegistry :
|
||||
public ObjectRegistry<AnimationTemplate>,
|
||||
public Persistable,
|
||||
public Common::Singleton<AnimationTemplateRegistry> {
|
||||
public:
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
177
engines/sword25/gfx/bitmap.cpp
Normal file
177
engines/sword25/gfx/bitmap.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/bitmap.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
Bitmap::Bitmap(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle) :
|
||||
RenderObject(parentPtr, type, handle),
|
||||
_modulationColor(BS_ARGBMASK),
|
||||
_scaleFactorX(1.0f),
|
||||
_scaleFactorY(1.0f),
|
||||
_flipH(false),
|
||||
_flipV(false) {
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap() {
|
||||
}
|
||||
|
||||
void Bitmap::setAlpha(int alpha) {
|
||||
if (!isAlphaAllowed()) {
|
||||
warning("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;
|
||||
warning("Tried to set an invalid alpha value (%d) on a bitmap. Value was changed to %d.", oldAlpha, alpha);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint newModulationColor = (_modulationColor & BS_RGBMASK) | alpha << BS_ASHIFT;
|
||||
if (newModulationColor != _modulationColor) {
|
||||
_modulationColor = newModulationColor;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::setModulationColor(uint modulationColor) {
|
||||
if (!isColorModulationAllowed()) {
|
||||
warning("Tried to set modulation color of a bitmap that does not support color modulation. Call was ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint newModulationColor = (modulationColor & BS_RGBMASK) | (_modulationColor & BS_AMASK);
|
||||
if (newModulationColor != _modulationColor) {
|
||||
_modulationColor = newModulationColor;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::setScaleFactor(float scaleFactor) {
|
||||
setScaleFactorX(scaleFactor);
|
||||
setScaleFactorY(scaleFactor);
|
||||
}
|
||||
|
||||
void Bitmap::setScaleFactorX(float scaleFactorX) {
|
||||
if (!isScalingAllowed()) {
|
||||
warning("Tried to set scale factor of a bitmap that does not support scaling. Call was ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaleFactorX < 0) {
|
||||
warning("Tried to set scale factor of a bitmap to a negative value. Call was ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaleFactorX != _scaleFactorX) {
|
||||
_scaleFactorX = scaleFactorX;
|
||||
_width = static_cast<int>(_originalWidth * _scaleFactorX);
|
||||
if (_scaleFactorX <= 0.0f)
|
||||
_scaleFactorX = 0.001f;
|
||||
if (_width <= 0)
|
||||
_width = 1;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::setScaleFactorY(float scaleFactorY) {
|
||||
if (!isScalingAllowed()) {
|
||||
warning("Tried to set scale factor of a bitmap that does not support scaling. Call was ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaleFactorY < 0) {
|
||||
warning("Tried to set scale factor of a bitmap to a negative value. Call was ignored.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scaleFactorY != _scaleFactorY) {
|
||||
_scaleFactorY = scaleFactorY;
|
||||
_height = static_cast<int>(_originalHeight * scaleFactorY);
|
||||
if (_scaleFactorY <= 0.0f)
|
||||
_scaleFactorY = 0.001f;
|
||||
if (_height <= 0)
|
||||
_height = 1;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::setFlipH(bool flipH) {
|
||||
_flipH = flipH;
|
||||
forceRefresh();
|
||||
}
|
||||
|
||||
void Bitmap::setFlipV(bool flipV) {
|
||||
_flipV = flipV;
|
||||
forceRefresh();
|
||||
}
|
||||
|
||||
bool Bitmap::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::persist(writer);
|
||||
writer.write(_flipH);
|
||||
writer.write(_flipV);
|
||||
writer.write(_scaleFactorX);
|
||||
writer.write(_scaleFactorY);
|
||||
writer.write(_modulationColor);
|
||||
writer.write(_originalWidth);
|
||||
writer.write(_originalHeight);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bitmap::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::unpersist(reader);
|
||||
reader.read(_flipH);
|
||||
reader.read(_flipV);
|
||||
reader.read(_scaleFactorX);
|
||||
reader.read(_scaleFactorY);
|
||||
reader.read(_modulationColor);
|
||||
reader.read(_originalWidth);
|
||||
reader.read(_originalHeight);
|
||||
|
||||
forceRefresh();
|
||||
|
||||
return reader.isGood() && result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
186
engines/sword25/gfx/bitmap.h
Normal file
186
engines/sword25/gfx/bitmap.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_BITMAP_H
|
||||
#define SWORD25_BITMAP_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Bitmap : public RenderObject {
|
||||
protected:
|
||||
Bitmap(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle = 0);
|
||||
|
||||
public:
|
||||
|
||||
~Bitmap() override;
|
||||
|
||||
/**
|
||||
@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(uint 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 _modulationColor >> BS_ASHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
@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 _modulationColor & BS_RGBMASK;
|
||||
}
|
||||
|
||||
/**
|
||||
@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 _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 _scaleFactorY;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt zurück, ob das Bild an der X-Achse gespiegelt angezeigt wird.
|
||||
*/
|
||||
bool isFlipH() {
|
||||
return _flipH;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt zurück, ob das Bild an der Y-Achse gespiegelt angezeigt wird.
|
||||
*/
|
||||
bool isFlipV() {
|
||||
return _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 uint 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 byte *pixeldata, uint size, uint offset = 0, uint stride = 0) = 0;
|
||||
|
||||
virtual bool isScalingAllowed() const = 0;
|
||||
virtual bool isAlphaAllowed() const = 0;
|
||||
virtual bool isColorModulationAllowed() const = 0;
|
||||
virtual bool isSetContentAllowed() const = 0;
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
protected:
|
||||
bool _flipH;
|
||||
bool _flipV;
|
||||
float _scaleFactorX;
|
||||
float _scaleFactorY;
|
||||
uint32 _modulationColor;
|
||||
int32 _originalWidth;
|
||||
int32 _originalHeight;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
200
engines/sword25/gfx/bitmapresource.h
Normal file
200
engines/sword25/gfx/bitmapresource.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_BITMAP_RESOURCE_H
|
||||
#define SWORD25_BITMAP_RESOURCE_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/resource.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class BitmapResource : public Resource {
|
||||
public:
|
||||
BitmapResource(const Common::String &filename, Image *pImage) :
|
||||
_pImage(pImage), Resource(filename, Resource::TYPE_BITMAP) {}
|
||||
~BitmapResource() override { delete _pImage; }
|
||||
|
||||
/**
|
||||
@brief Gibt zurück, ob das Objekt einen gültigen Zustand hat.
|
||||
*/
|
||||
bool isValid() const {
|
||||
return (_pImage != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt die Breite des Bitmaps zurück.
|
||||
*/
|
||||
int getWidth() const {
|
||||
assert(_pImage);
|
||||
return _pImage->getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt die Höhe des Bitmaps zurück.
|
||||
*/
|
||||
int getHeight() const {
|
||||
assert(_pImage);
|
||||
return _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 Common::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 = Graphics::FLIP_NONE,
|
||||
Common::Rect *pSrcPartRect = NULL,
|
||||
uint color = BS_ARGB(255, 255, 255, 255),
|
||||
int width = -1, int height = -1,
|
||||
RectangleList *updateRects = 0) {
|
||||
assert(_pImage);
|
||||
return _pImage->blit(posX, posY, flipping, pSrcPartRect, color, width, height, updateRects);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Füllt einen Rechteckigen Bereich des Bildes mit einer Farbe.
|
||||
@param pFillRect Pointer auf ein Common::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 Common::Rect *pFillRect = 0, uint color = BS_RGB(0, 0, 0)) {
|
||||
assert(_pImage);
|
||||
return _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.
|
||||
*/
|
||||
uint getPixel(int x, int y) const {
|
||||
return _pImage->getPixel(x, y);
|
||||
}
|
||||
|
||||
//@{
|
||||
/** @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() {
|
||||
assert(_pImage);
|
||||
return _pImage->isBlitTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt true zurück, falls das BS_Image bei einem Aufruf von Blit() skaliert dargestellt werden kann.
|
||||
*/
|
||||
bool isScalingAllowed() {
|
||||
assert(_pImage);
|
||||
return _pImage->isScalingAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt true zurück, wenn das BS_Image mit einem Aufruf von Fill() gefüllt werden kann.
|
||||
*/
|
||||
bool isFillingAllowed() {
|
||||
assert(_pImage);
|
||||
return _pImage->isFillingAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt true zurück, wenn das BS_Image bei einem Aufruf von Blit() mit einem Alphawert dargestellt werden kann.
|
||||
*/
|
||||
bool isAlphaAllowed() {
|
||||
assert(_pImage);
|
||||
return _pImage->isAlphaAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt true zurück, wenn das BS_Image bei einem Aufruf von Blit() mit Farbmodulation dargestellt werden kann.
|
||||
*/
|
||||
bool isColorModulationAllowed() {
|
||||
assert(_pImage);
|
||||
return _pImage->isColorModulationAllowed();
|
||||
}
|
||||
|
||||
bool isSolid() {
|
||||
assert(_pImage);
|
||||
return _pImage->isSolid();
|
||||
}
|
||||
|
||||
private:
|
||||
Image *_pImage;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
179
engines/sword25/gfx/dynamicbitmap.cpp
Normal file
179
engines/sword25/gfx/dynamicbitmap.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/dynamicbitmap.h"
|
||||
#include "sword25/gfx/bitmapresource.h"
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
DynamicBitmap::DynamicBitmap(RenderObjectPtr<RenderObject> parentPtr, uint width, uint height) :
|
||||
Bitmap(parentPtr, TYPE_DYNAMICBITMAP) {
|
||||
// The BS_BITMAP could not be created, so stop.
|
||||
if (!_initSuccess)
|
||||
return;
|
||||
|
||||
_initSuccess = createRenderedImage(width, height);
|
||||
}
|
||||
|
||||
DynamicBitmap::DynamicBitmap(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
|
||||
Bitmap(parentPtr, TYPE_DYNAMICBITMAP, handle) {
|
||||
_initSuccess = unpersist(reader);
|
||||
}
|
||||
|
||||
bool DynamicBitmap::createRenderedImage(uint width, uint height) {
|
||||
bool result = false;
|
||||
_image.reset(new RenderedImage(width, height, result));
|
||||
|
||||
_originalWidth = _width = width;
|
||||
_originalHeight = _height = height;
|
||||
|
||||
_image->setAlphaType(Graphics::ALPHA_OPAQUE);
|
||||
_isSolid = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicBitmap::~DynamicBitmap() {
|
||||
}
|
||||
|
||||
uint DynamicBitmap::getPixel(int x, int y) const {
|
||||
assert(x >= 0 && x < _width);
|
||||
assert(y >= 0 && y < _height);
|
||||
|
||||
return _image->getPixel(x, y);
|
||||
}
|
||||
|
||||
bool DynamicBitmap::doRender(RectangleList *updateRects) {
|
||||
// Get the frame buffer object
|
||||
GraphicEngine *pGfx = Kernel::getInstance()->getGfx();
|
||||
assert(pGfx);
|
||||
|
||||
// Draw the bitmap
|
||||
bool result;
|
||||
if (_scaleFactorX == 1.0f && _scaleFactorY == 1.0f) {
|
||||
#if 1
|
||||
// This is what the game does originally, which can be
|
||||
// a bit slow when drawing videos, but it's not the main
|
||||
// bottleneck.
|
||||
result = _image->blit(_absoluteX, _absoluteY,
|
||||
(_flipV ? Graphics::FLIP_V : 0) |
|
||||
(_flipH ? Graphics::FLIP_H : 0),
|
||||
0, _modulationColor, -1, -1,
|
||||
updateRects);
|
||||
#else
|
||||
// WIP: A bit faster code
|
||||
|
||||
// We don't need to check for transparency when drawing
|
||||
// videos, thus just copy the buffer contents directly.
|
||||
// This messes up the fire animation in the menu, for
|
||||
// some odd reason. It also makes the video colors a
|
||||
// bit lighter, resulting in a visible black border
|
||||
// around the typed letters in the intro (which are
|
||||
// drawn over a black border)
|
||||
_image->copyDirectly(_absoluteX, _absoluteY);
|
||||
#endif
|
||||
return true;
|
||||
} else {
|
||||
result = _image->blit(_absoluteX, _absoluteY,
|
||||
(_flipV ? Graphics::FLIP_V : 0) |
|
||||
(_flipH ? Graphics::FLIP_H : 0),
|
||||
0, _modulationColor, _width, _height,
|
||||
updateRects);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DynamicBitmap::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
|
||||
++_version; // Update version to display the new video image
|
||||
return _image->setContent(pixeldata, size, offset, stride);
|
||||
}
|
||||
|
||||
bool DynamicBitmap::isScalingAllowed() const {
|
||||
return _image->isScalingAllowed();
|
||||
}
|
||||
|
||||
bool DynamicBitmap::isAlphaAllowed() const {
|
||||
return _image->isAlphaAllowed();
|
||||
}
|
||||
|
||||
bool DynamicBitmap::isColorModulationAllowed() const {
|
||||
return _image->isColorModulationAllowed();
|
||||
}
|
||||
|
||||
bool DynamicBitmap::isSetContentAllowed() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicBitmap::persist(OutputPersistenceBlock &writer) {
|
||||
#if 0
|
||||
bool result = true;
|
||||
|
||||
result &= Bitmap::persist(writer);
|
||||
|
||||
// Image data is not saved. This is not important, since BS_DynamicBitmap is only used by the video player.
|
||||
// A video cannot be saved while it's being played. Only the state of a BS_DynamicBitmap can be persisted.
|
||||
warning("Persisting a BS_DynamicBitmap. Bitmap content is not persisted.");
|
||||
|
||||
result &= RenderObject::persistChildren(writer);
|
||||
|
||||
return result;
|
||||
#endif
|
||||
|
||||
error("Request to persist a dynamic bitmap (video) - probably a bug");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicBitmap::unpersist(InputPersistenceBlock &reader) {
|
||||
#if 0
|
||||
bool result = true;
|
||||
|
||||
result &= Bitmap::unpersist(reader);
|
||||
result &= createRenderedImage(_width, _height);
|
||||
|
||||
warning("Unpersisting a BS_DynamicBitmap. Bitmap contents are missing.");
|
||||
|
||||
// Initialize a transparent image.
|
||||
byte *transparentImageData = (byte *)calloc(_width * _height * 4, 1);
|
||||
_image->setContent(transparentImageData, _width * _height);
|
||||
free(transparentImageData);
|
||||
|
||||
result &= RenderObject::unpersistChildren(reader);
|
||||
|
||||
return reader.isGood() && result;
|
||||
#endif
|
||||
|
||||
error("Request to unpersist a dynamic bitmap (video) - probably a corrupted saved game or a bug");
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
74
engines/sword25/gfx/dynamicbitmap.h
Normal file
74
engines/sword25/gfx/dynamicbitmap.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_DYNAMIC_BITMAP_H
|
||||
#define SWORD25_DYNAMIC_BITMAP_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/bitmap.h"
|
||||
#include "sword25/gfx/image/renderedimage.h"
|
||||
|
||||
#include "common/ptr.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class DynamicBitmap : public Bitmap {
|
||||
friend class RenderObject;
|
||||
|
||||
public:
|
||||
~DynamicBitmap() override;
|
||||
|
||||
uint getPixel(int x, int y) const override;
|
||||
|
||||
bool setContent(const byte *pixeldata, uint size, uint offset, uint stride) override;
|
||||
|
||||
bool isScalingAllowed() const override;
|
||||
bool isAlphaAllowed() const override;
|
||||
bool isColorModulationAllowed() const override;
|
||||
bool isSetContentAllowed() const override;
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
protected:
|
||||
bool doRender(RectangleList *updateRects) override;
|
||||
|
||||
private:
|
||||
DynamicBitmap(RenderObjectPtr<RenderObject> parentPtr, uint width, uint height);
|
||||
DynamicBitmap(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle);
|
||||
|
||||
bool createRenderedImage(uint width, uint height);
|
||||
|
||||
Common::ScopedPtr<RenderedImage> _image;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
138
engines/sword25/gfx/fontresource.cpp
Normal file
138
engines/sword25/gfx/fontresource.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/resmanager.h" // for PRECACHE_RESOURCES
|
||||
#include "sword25/package/packagemanager.h"
|
||||
|
||||
#include "sword25/gfx/fontresource.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
enum {
|
||||
DEFAULT_LINEHEIGHT = 20,
|
||||
DEFAULT_GAPWIDTH = 1
|
||||
};
|
||||
|
||||
FontResource::FontResource(Kernel *pKernel, const Common::String &fileName) :
|
||||
_pKernel(pKernel),
|
||||
_valid(false),
|
||||
Resource(fileName, Resource::TYPE_FONT),
|
||||
Common::XMLParser() {
|
||||
|
||||
// Get a pointer to the package manager
|
||||
assert(_pKernel);
|
||||
PackageManager *pPackage = _pKernel->getPackage();
|
||||
assert(pPackage);
|
||||
|
||||
// Load the contents of the file
|
||||
uint fileSize;
|
||||
char *xmlData = pPackage->getXmlFile(getFileName(), &fileSize);
|
||||
if (!xmlData) {
|
||||
error("Could not read \"%s\".", getFileName().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the contents
|
||||
if (!loadBuffer((const byte *)xmlData, fileSize))
|
||||
return;
|
||||
|
||||
_valid = parse();
|
||||
close();
|
||||
free(xmlData);
|
||||
}
|
||||
|
||||
bool FontResource::parserCallback_font(ParserNode *node) {
|
||||
// Get the attributes of the font
|
||||
Common::String bitmapFilename = node->values["bitmap"];
|
||||
|
||||
if (!parseIntegerKey(node->values["lineheight"], 1, &_lineHeight)) {
|
||||
warning("Illegal or missing lineheight attribute in <font> tag in \"%s\". Assuming default (\"%d\").",
|
||||
getFileName().c_str(), DEFAULT_LINEHEIGHT);
|
||||
_lineHeight = DEFAULT_LINEHEIGHT;
|
||||
}
|
||||
|
||||
if (!parseIntegerKey(node->values["gap"], 1, &_gapWidth)) {
|
||||
warning("Illegal or missing gap attribute in <font> tag in \"%s\". Assuming default (\"%d\").",
|
||||
getFileName().c_str(), DEFAULT_GAPWIDTH);
|
||||
_gapWidth = DEFAULT_GAPWIDTH;
|
||||
}
|
||||
|
||||
// Get a reference to the package manager
|
||||
assert(_pKernel);
|
||||
PackageManager *pPackage = _pKernel->getPackage();
|
||||
assert(pPackage);
|
||||
|
||||
// Get the full path and filename for the bitmap resource
|
||||
_bitmapFileName = pPackage->getAbsolutePath(bitmapFilename);
|
||||
if (_bitmapFileName == "") {
|
||||
error("Image file \"%s\" was specified in <font> tag of \"%s\" but could not be found.",
|
||||
_bitmapFileName.c_str(), getFileName().c_str());
|
||||
}
|
||||
|
||||
#ifdef PRECACHE_RESOURCES
|
||||
// Pre-cache the resource
|
||||
if (!_pKernel->getResourceManager()->precacheResource(_bitmapFileName)) {
|
||||
error("Could not precache \"%s\".", _bitmapFileName.c_str());
|
||||
}
|
||||
#else
|
||||
Resource *pResource = _pKernel->getResourceManager()->requestResource(_bitmapFileName);
|
||||
pResource->release(); //unlock precached resource
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontResource::parserCallback_character(ParserNode *node) {
|
||||
// Get the attributes of the character
|
||||
int charCode, top, left, right, bottom;
|
||||
|
||||
if (!parseIntegerKey(node->values["code"], 1, &charCode) || (charCode < 0) || (charCode >= 256)) {
|
||||
return parserError("Illegal or missing code attribute in <character> tag in '" + getFileName() + "'.");
|
||||
}
|
||||
|
||||
if (!parseIntegerKey(node->values["top"], 1, &top) || (top < 0)) {
|
||||
return parserError("Illegal or missing top attribute in <character> tag in '" + getFileName() + "'.");
|
||||
}
|
||||
if (!parseIntegerKey(node->values["left"], 1, &left) || (left < 0)) {
|
||||
return parserError("Illegal or missing left attribute in <character> tag in '" + getFileName() + "'.");
|
||||
}
|
||||
if (!parseIntegerKey(node->values["right"], 1, &right) || (right < 0)) {
|
||||
return parserError("Illegal or missing right attribute in <character> tag in '" + getFileName() + "'.");
|
||||
}
|
||||
if (!parseIntegerKey(node->values["bottom"], 1, &bottom) || (bottom < 0)) {
|
||||
return parserError("Illegal or missing bottom attribute in <character> tag in '" + getFileName() + "'.");
|
||||
}
|
||||
|
||||
_characterRects[charCode] = Common::Rect(left, top, right, bottom);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
130
engines/sword25/gfx/fontresource.h
Normal file
130
engines/sword25/gfx/fontresource.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_FONTRESOURCE_H
|
||||
#define SWORD25_FONTRESOURCE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/formats/xmlparser.h"
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/resource.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Kernel;
|
||||
|
||||
class FontResource : public Resource, Common::XMLParser {
|
||||
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.
|
||||
*/
|
||||
FontResource(Kernel *pKernel, const Common::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 Common::Rect &getCharacterRect(int character) const {
|
||||
assert(character >= 0 && character < 256);
|
||||
return _characterRects[character];
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt den Dateinamen der Charactermap zurück.
|
||||
*/
|
||||
const Common::String &getCharactermapFileName() const {
|
||||
return _bitmapFileName;
|
||||
}
|
||||
|
||||
private:
|
||||
Kernel *_pKernel;
|
||||
bool _valid;
|
||||
Common::String _bitmapFileName;
|
||||
int _lineHeight;
|
||||
int _gapWidth;
|
||||
Common::Rect _characterRects[256];
|
||||
|
||||
// Parser
|
||||
CUSTOM_XML_PARSER(FontResource) {
|
||||
XML_KEY(font)
|
||||
XML_PROP(bitmap, true)
|
||||
XML_PROP(lineheight, false)
|
||||
XML_PROP(gap, false)
|
||||
|
||||
XML_KEY(character)
|
||||
XML_PROP(code, true)
|
||||
XML_PROP(left, true)
|
||||
XML_PROP(top, true)
|
||||
XML_PROP(right, true)
|
||||
XML_PROP(bottom, true)
|
||||
KEY_END()
|
||||
KEY_END()
|
||||
} PARSER_END()
|
||||
|
||||
// Parser callback methods
|
||||
bool parserCallback_font(ParserNode *node);
|
||||
bool parserCallback_character(ParserNode *node);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
498
engines/sword25/gfx/graphicengine.cpp
Normal file
498
engines/sword25/gfx/graphicengine.cpp
Normal file
@@ -0,0 +1,498 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "sword25/sword25.h" // for kDebugScript
|
||||
#include "sword25/gfx/bitmapresource.h"
|
||||
#include "sword25/gfx/animationresource.h"
|
||||
#include "sword25/gfx/fontresource.h"
|
||||
#include "sword25/gfx/panel.h"
|
||||
#include "sword25/gfx/renderobjectmanager.h"
|
||||
#include "sword25/gfx/screenshot.h"
|
||||
#include "sword25/gfx/image/renderedimage.h"
|
||||
#include "sword25/gfx/image/swimage.h"
|
||||
#include "sword25/gfx/image/vectorimage.h"
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
|
||||
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
|
||||
#include "sword25/fmv/movieplayer.h"
|
||||
|
||||
#include "common/lua/lua.h"
|
||||
#include "common/lua/lauxlib.h"
|
||||
#include "common/config-manager.h"
|
||||
|
||||
enum {
|
||||
BIT_DEPTH = 32,
|
||||
BACKBUFFER_COUNT = 1
|
||||
};
|
||||
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
static const uint FRAMETIME_SAMPLE_COUNT = 5; // Frame duration is averaged over FRAMETIME_SAMPLE_COUNT frames
|
||||
|
||||
GraphicEngine::GraphicEngine(Kernel *pKernel) :
|
||||
_width(0),
|
||||
_height(0),
|
||||
_bitDepth(0),
|
||||
_lastTimeStamp((uint) -1), // force reset of _UpdateLastFrameDuration() on first call
|
||||
_lastFrameDuration(0),
|
||||
_timerActive(true),
|
||||
_frameTimeSampleSlot(0),
|
||||
_thumbnail(NULL),
|
||||
ResourceService(pKernel) {
|
||||
_frameTimeSamples.resize(FRAMETIME_SAMPLE_COUNT);
|
||||
|
||||
if (!registerScriptBindings())
|
||||
error("Script bindings could not be registered.");
|
||||
else
|
||||
debugC(kDebugScript, "Script bindings registered.");
|
||||
}
|
||||
|
||||
GraphicEngine::~GraphicEngine() {
|
||||
unregisterScriptBindings();
|
||||
_backSurface.free();
|
||||
delete _thumbnail;
|
||||
}
|
||||
|
||||
bool GraphicEngine::init(int width, int height, int bitDepth, int backbufferCount) {
|
||||
// Warn when an unsupported bit depth has been selected.
|
||||
if (bitDepth != BIT_DEPTH) {
|
||||
warning("Can't use a bit depth of %d (not supported). Falling back to %d.", bitDepth, BIT_DEPTH);
|
||||
_bitDepth = BIT_DEPTH;
|
||||
}
|
||||
|
||||
// Warn when wrong BackBuffer is specified.
|
||||
if (backbufferCount != BACKBUFFER_COUNT) {
|
||||
warning("Can't use %d backbuffers (not supported). Falling back to %d.", backbufferCount, BACKBUFFER_COUNT);
|
||||
backbufferCount = BACKBUFFER_COUNT;
|
||||
}
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
_bitDepth = bitDepth;
|
||||
_screenRect.left = 0;
|
||||
_screenRect.top = 0;
|
||||
_screenRect.right = _width;
|
||||
_screenRect.bottom = _height;
|
||||
_isRTL = Common::parseLanguage(ConfMan.get("language")) == Common::HE_ISR;
|
||||
|
||||
const Graphics::PixelFormat format = g_system->getScreenFormat();
|
||||
|
||||
_backSurface.create(width, height, format);
|
||||
|
||||
// By default Vsync is on.
|
||||
setVsync(true);
|
||||
|
||||
// Layer-Manager initialization
|
||||
_renderObjectManagerPtr.reset(new RenderObjectManager(width, height, backbufferCount + 1));
|
||||
|
||||
// Create the main panel
|
||||
_mainPanelPtr = _renderObjectManagerPtr->getTreeRoot()->addPanel(width, height, BS_ARGB(0, 0, 0, 0));
|
||||
if (!_mainPanelPtr.isValid())
|
||||
return false;
|
||||
_mainPanelPtr->setVisible(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GraphicEngine::startFrame(bool updateAll) {
|
||||
// Calculate how much time has elapsed since the last frame.
|
||||
updateLastFrameDuration();
|
||||
|
||||
// Prepare the Layer Manager for the next frame
|
||||
_renderObjectManagerPtr->startFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GraphicEngine::endFrame() {
|
||||
#ifndef THEORA_INDIRECT_RENDERING
|
||||
if (Kernel::getInstance()->getFMV()->isMovieLoaded())
|
||||
return true;
|
||||
#endif
|
||||
|
||||
_renderObjectManagerPtr->render();
|
||||
|
||||
g_system->updateScreen();
|
||||
|
||||
// Debug-Lines zeichnen
|
||||
if (!_debugLines.empty()) {
|
||||
#if 0
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glBegin(GL_LINES);
|
||||
|
||||
Common::Array<DebugLine>::const_iterator iter = m_DebugLines.begin();
|
||||
for (; iter != m_DebugLines.end(); ++iter) {
|
||||
const uint &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);
|
||||
#endif
|
||||
|
||||
warning("STUB: Drawing debug lines");
|
||||
|
||||
_debugLines.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderObjectPtr<Panel> GraphicEngine::getMainPanel() {
|
||||
return _mainPanelPtr;
|
||||
}
|
||||
|
||||
void GraphicEngine::setVsync(bool vsync) {
|
||||
// ScummVM has no concept of VSync
|
||||
}
|
||||
|
||||
bool GraphicEngine::getVsync() const {
|
||||
warning("STUB: getVsync()");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) {
|
||||
Common::Rect rect(_width - 1, _height - 1);
|
||||
|
||||
int ca = (color >> BS_ASHIFT) & 0xff;
|
||||
|
||||
if (ca == 0)
|
||||
return true;
|
||||
|
||||
int cr = (color >> BS_RSHIFT) & 0xff;
|
||||
int cg = (color >> BS_GSHIFT) & 0xff;
|
||||
int cb = (color >> BS_BSHIFT) & 0xff;
|
||||
|
||||
if (fillRectPtr) {
|
||||
rect = *fillRectPtr;
|
||||
}
|
||||
|
||||
if (rect.width() > 0 && rect.height() > 0) {
|
||||
if (ca == 0xff) {
|
||||
_backSurface.fillRect(rect, _backSurface.format.ARGBToColor(ca, cr, cg, cb));
|
||||
} else {
|
||||
byte *outo = (byte *)_backSurface.getBasePtr(rect.left, rect.top);
|
||||
byte *out;
|
||||
|
||||
for (int i = rect.top; i < rect.bottom; i++) {
|
||||
out = outo;
|
||||
for (int j = rect.left; j < rect.right; j++) {
|
||||
#if defined(SCUMM_LITTLE_ENDIAN)
|
||||
*out = 255;
|
||||
out++;
|
||||
*out += (byte)(((cb - *out) * ca) >> 8);
|
||||
out++;
|
||||
*out += (byte)(((cg - *out) * ca) >> 8);
|
||||
out++;
|
||||
*out += (byte)(((cr - *out) * ca) >> 8);
|
||||
out++;
|
||||
#else
|
||||
*out += (byte)(((cr - *out) * ca) >> 8);
|
||||
out++;
|
||||
*out += (byte)(((cg - *out) * ca) >> 8);
|
||||
out++;
|
||||
*out += (byte)(((cb - *out) * ca) >> 8);
|
||||
out++;
|
||||
*out = 255;
|
||||
out++;
|
||||
#endif
|
||||
}
|
||||
|
||||
outo += _backSurface.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RESOURCE MANAGING
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Resource *GraphicEngine::loadResource(const Common::String &filename) {
|
||||
assert(canLoadResource(filename));
|
||||
|
||||
// Load image for "software buffer". These are images used to dynamically
|
||||
// add shadows to actors (e.g. when George walks under the shadow of a
|
||||
// a building)
|
||||
if (filename.hasSuffix("_s.png")) {
|
||||
bool result = false;
|
||||
SWImage *pImage = new SWImage(filename, result);
|
||||
if (!result) {
|
||||
delete pImage;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BitmapResource *pResource = new BitmapResource(filename, pImage);
|
||||
if (!pResource->isValid()) {
|
||||
delete pResource;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pResource;
|
||||
}
|
||||
|
||||
// Load sprite image. Savegame thumbnails are also loaded here.
|
||||
if (filename.hasSuffix(".png") || filename.hasSuffix(".b25s") ||
|
||||
filename.hasPrefix("/saves")) {
|
||||
bool result = false;
|
||||
RenderedImage *pImage = new RenderedImage(filename, result);
|
||||
if (!result) {
|
||||
delete pImage;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BitmapResource *pResource = new BitmapResource(filename, pImage);
|
||||
if (!pResource->isValid()) {
|
||||
delete pResource;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pResource;
|
||||
}
|
||||
|
||||
|
||||
// Load vector graphics
|
||||
if (filename.hasSuffix(".swf")) {
|
||||
debug(2, "VectorImage: %s", filename.c_str());
|
||||
|
||||
// Pointer auf Package-Manager holen
|
||||
PackageManager *pPackage = Kernel::getInstance()->getPackage();
|
||||
assert(pPackage);
|
||||
|
||||
// Loading data
|
||||
byte *pFileData;
|
||||
uint fileSize;
|
||||
pFileData = pPackage->getFile(filename, &fileSize);
|
||||
if (!pFileData) {
|
||||
error("File \"%s\" could not be loaded.", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
VectorImage *pImage = new VectorImage(pFileData, fileSize, result, filename);
|
||||
if (!result) {
|
||||
delete pImage;
|
||||
delete[] pFileData;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BitmapResource *pResource = new BitmapResource(filename, pImage);
|
||||
if (!pResource->isValid()) {
|
||||
delete pResource;
|
||||
delete[] pFileData;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete[] pFileData;
|
||||
return pResource;
|
||||
}
|
||||
|
||||
// Load animation
|
||||
if (filename.hasSuffix("_ani.xml")) {
|
||||
AnimationResource *pResource = new AnimationResource(filename);
|
||||
if (pResource->isValid())
|
||||
return pResource;
|
||||
else {
|
||||
delete pResource;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Load font
|
||||
if (filename.hasSuffix("_fnt.xml")) {
|
||||
FontResource *pResource = new FontResource(Kernel::getInstance(), filename);
|
||||
if (pResource->isValid())
|
||||
return pResource;
|
||||
else {
|
||||
delete pResource;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error("Service cannot load \"%s\".", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool GraphicEngine::canLoadResource(const Common::String &filename) {
|
||||
return filename.hasSuffix(".png") ||
|
||||
filename.hasSuffix("_ani.xml") ||
|
||||
filename.hasSuffix("_fnt.xml") ||
|
||||
filename.hasSuffix(".swf") ||
|
||||
filename.hasSuffix(".b25s") ||
|
||||
filename.hasPrefix("/saves");
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DEBUGGING
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void GraphicEngine::drawDebugLine(const Vertex &start, const Vertex &end, uint color) {
|
||||
_debugLines.push_back(DebugLine(start, end, color));
|
||||
}
|
||||
|
||||
void GraphicEngine::updateLastFrameDuration() {
|
||||
// Record current time
|
||||
const uint currentTime = Kernel::getInstance()->getMilliTicks();
|
||||
|
||||
// Compute the elapsed time since the last frame and prevent too big ( > 250 msecs) time jumps.
|
||||
// These can occur when loading save states, during debugging or due to hardware inaccuracies.
|
||||
_frameTimeSamples[_frameTimeSampleSlot] = static_cast<uint>(currentTime - _lastTimeStamp);
|
||||
if (_frameTimeSamples[_frameTimeSampleSlot] > 250000)
|
||||
_frameTimeSamples[_frameTimeSampleSlot] = 250000;
|
||||
_frameTimeSampleSlot = (_frameTimeSampleSlot + 1) % FRAMETIME_SAMPLE_COUNT;
|
||||
|
||||
// Compute the average frame duration over multiple frames to eliminate outliers.
|
||||
Common::Array<uint>::const_iterator it = _frameTimeSamples.begin();
|
||||
uint sum = *it;
|
||||
for (it++; it != _frameTimeSamples.end(); it++)
|
||||
sum += *it;
|
||||
_lastFrameDuration = sum * 1000 / FRAMETIME_SAMPLE_COUNT;
|
||||
|
||||
// Update m_LastTimeStamp with the current frame's timestamp
|
||||
_lastTimeStamp = currentTime;
|
||||
}
|
||||
|
||||
bool GraphicEngine::saveThumbnailScreenshot(const Common::String &filename) {
|
||||
// Note: In ScummVM, rather than saving the thumbnail to a file, we store it in memory
|
||||
// until needed when creating savegame files
|
||||
delete _thumbnail;
|
||||
|
||||
_thumbnail = Screenshot::createThumbnail(_backSurface.surfacePtr());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GraphicEngine::ARGBColorToLuaColor(lua_State *L, uint color) {
|
||||
lua_Number components[4] = {
|
||||
(lua_Number)((color >> BS_RSHIFT) & 0xff), // Red
|
||||
(lua_Number)((color >> BS_GSHIFT) & 0xff), // Green
|
||||
(lua_Number)((color >> BS_BSHIFT) & 0xff), // Blue
|
||||
(lua_Number)( color >> BS_ASHIFT), // Alpha
|
||||
};
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
for (uint i = 1; i <= 4; i++) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushnumber(L, components[i - 1]);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
|
||||
uint GraphicEngine::luaColorToARGBColor(lua_State *L, int stackIndex) {
|
||||
#ifdef DEBUG
|
||||
int __startStackDepth = lua_gettop(L);
|
||||
#endif
|
||||
|
||||
// Make sure that we really look at a table
|
||||
luaL_checktype(L, stackIndex, LUA_TTABLE);
|
||||
// getting table size
|
||||
uint n = luaL_getn(L, stackIndex);
|
||||
// only RGB or RGBA colors are supported
|
||||
if (n != 3 && n != 4)
|
||||
luaL_argcheck(L, 0, stackIndex, "at least 3 of the 4 color components have to be specified");
|
||||
|
||||
// Red color component reading
|
||||
lua_rawgeti(L, stackIndex, 1);
|
||||
uint red = static_cast<uint>(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);
|
||||
|
||||
// Green color component reading
|
||||
lua_rawgeti(L, stackIndex, 2);
|
||||
uint green = static_cast<uint>(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);
|
||||
|
||||
// Blue color component reading
|
||||
lua_rawgeti(L, stackIndex, 3);
|
||||
uint blue = static_cast<uint>(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 color component reading
|
||||
uint alpha = 0xff;
|
||||
if (n == 4) {
|
||||
lua_rawgeti(L, stackIndex, 4);
|
||||
alpha = static_cast<uint>(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
|
||||
assert(__startStackDepth == lua_gettop(L));
|
||||
#endif
|
||||
|
||||
return BS_ARGB(alpha, red, green, blue);
|
||||
}
|
||||
|
||||
bool GraphicEngine::persist(OutputPersistenceBlock &writer) {
|
||||
writer.write(_timerActive);
|
||||
|
||||
bool result = _renderObjectManagerPtr->persist(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GraphicEngine::unpersist(InputPersistenceBlock &reader) {
|
||||
reader.read(_timerActive);
|
||||
_renderObjectManagerPtr->unpersist(reader);
|
||||
|
||||
return reader.isGood();
|
||||
}
|
||||
|
||||
bool GraphicEngine::isRTL() {
|
||||
return _isRTL;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
309
engines/sword25/gfx/graphicengine.h
Normal file
309
engines/sword25/gfx/graphicengine.h
Normal file
@@ -0,0 +1,309 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* GraphicEngine
|
||||
* ----------------
|
||||
* This the graphics engine interface.
|
||||
*
|
||||
* Autor: Malte Thiesen
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_GRAPHICENGINE_H
|
||||
#define SWORD25_GRAPHICENGINE_H
|
||||
|
||||
// Includes
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/str.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/resservice.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
#include "sword25/gfx/renderobjectptr.h"
|
||||
#include "sword25/math/vertex.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Kernel;
|
||||
class Image;
|
||||
class Panel;
|
||||
class Screenshot;
|
||||
class RenderObjectManager;
|
||||
|
||||
#define BS_ASHIFT 24
|
||||
#define BS_RSHIFT 16
|
||||
#define BS_GSHIFT 8
|
||||
#define BS_BSHIFT 0
|
||||
|
||||
#define BS_AMASK 0xFF000000
|
||||
#define BS_RMASK 0x00FF0000
|
||||
#define BS_GMASK 0x0000FF00
|
||||
#define BS_BMASK 0x000000FF
|
||||
|
||||
#define BS_RGBMASK (BS_RMASK | BS_GMASK | BS_BMASK)
|
||||
#define BS_ARGBMASK (BS_AMASK | BS_RMASK | BS_GMASK | BS_BMASK)
|
||||
|
||||
#define BS_RGB(R,G,B) (BS_AMASK | ((R) << BS_RSHIFT) | ((G) << BS_GSHIFT) | ((B) << BS_BSHIFT))
|
||||
#define BS_ARGB(A,R,G,B) (((A) << BS_ASHIFT) | ((R) << BS_RSHIFT) | ((G) << BS_GSHIFT) | ((B) << BS_BSHIFT))
|
||||
|
||||
/**
|
||||
* This is the graphics engine. Unlike the original code, this is not
|
||||
* an interface that needs to be subclassed, but rather already contains
|
||||
* all required functionality.
|
||||
*/
|
||||
class GraphicEngine : public ResourceService, public Persistable {
|
||||
public:
|
||||
// Constructor
|
||||
// -----------
|
||||
GraphicEngine(Kernel *pKernel);
|
||||
~GraphicEngine() override;
|
||||
|
||||
// Interface
|
||||
// ---------
|
||||
|
||||
/**
|
||||
* Initializes the graphics engine and sets the screen mode. Returns
|
||||
* true if initialisation failed.
|
||||
* @note This method should be called immediately after the
|
||||
* initialisation of all services.
|
||||
*
|
||||
* @param Height The height of the output buffer in pixels. The default value is 600
|
||||
* @param BitDepth The bit depth of the desired output buffer in bits. The default value is 16
|
||||
* @param BackbufferCount The number of back buffers to be created. The default value is 2
|
||||
*/
|
||||
bool init(int width = 800, int height = 600, int bitDepth = 16, int backbufferCount = 2);
|
||||
|
||||
/**
|
||||
* Begins rendering a new frame.
|
||||
* Notes: This method must be called at the beginning of the main loop, before any rendering methods are used.
|
||||
* Notes: Implementations of this method must call _UpdateLastFrameDuration()
|
||||
* @param UpdateAll Specifies whether the renderer should redraw everything on the next frame.
|
||||
* This feature can be useful if the renderer with Dirty Rectangles works, but sometimes the client may
|
||||
*/
|
||||
bool startFrame(bool updateAll = false);
|
||||
|
||||
/**
|
||||
* Ends the rendering of a frame and draws it on the screen.
|
||||
*
|
||||
* This method must be at the end of the main loop. After this call, no further Render method may be called.
|
||||
* This should only be called once for a given previous call to #StartFrame.
|
||||
*/
|
||||
bool endFrame();
|
||||
|
||||
// Debug methods
|
||||
|
||||
/**
|
||||
* Draws a line in the frame buffer
|
||||
*
|
||||
* This method must be called between calls to StartFrame() and EndFrame(), and is intended only for debugging
|
||||
* purposes. The line will only appear for a single frame. If the line is to be shown permanently, it must be
|
||||
* called for every frame.
|
||||
* @param Start The starting point of the line
|
||||
* @param End The ending point of the line
|
||||
* @param Color The color of the line. The default is BS_RGB (255,255,255) (White)
|
||||
*/
|
||||
void drawDebugLine(const Vertex &start, const Vertex &end, uint color = BS_RGB(255, 255, 255));
|
||||
|
||||
/**
|
||||
* Creates a thumbnail with the dimensions of 200x125. This will not include the top and bottom of the screen..
|
||||
* the interface boards the image as a 16th of it's original size.
|
||||
* Notes: This method should only be called after a call to EndFrame(), and before the next call to StartFrame().
|
||||
* The frame buffer must have a resolution of 800x600.
|
||||
* @param Filename The filename for the screenshot
|
||||
*/
|
||||
bool saveThumbnailScreenshot(const Common::String &filename);
|
||||
|
||||
RenderObjectPtr<Panel> getMainPanel();
|
||||
|
||||
/**
|
||||
* Specifies the time (in microseconds) since the last frame has passed
|
||||
*/
|
||||
int getLastFrameDurationMicro() const {
|
||||
if (!_timerActive)
|
||||
return 0;
|
||||
return _lastFrameDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the time (in microseconds) the previous frame took
|
||||
*/
|
||||
float getLastFrameDuration() const {
|
||||
if (!_timerActive)
|
||||
return 0;
|
||||
return static_cast<float>(_lastFrameDuration) / 1000000.0f;
|
||||
}
|
||||
|
||||
void stopMainTimer() {
|
||||
_timerActive = false;
|
||||
}
|
||||
|
||||
void resumeMainTimer() {
|
||||
_timerActive = true;
|
||||
}
|
||||
|
||||
float getSecondaryFrameDuration() const {
|
||||
return static_cast<float>(_lastFrameDuration) / 1000000.0f;
|
||||
}
|
||||
|
||||
// Accessor methods
|
||||
|
||||
/**
|
||||
* Returns the width of the output buffer in pixels
|
||||
*/
|
||||
int getDisplayWidth() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the height of the output buffer in pixels
|
||||
*/
|
||||
int getDisplayHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounding box of the output buffer: (0, 0, Width, Height)
|
||||
*/
|
||||
Common::Rect &getDisplayRect() {
|
||||
return _screenRect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit depth of the output buffer
|
||||
*/
|
||||
int getBitDepth() {
|
||||
return _bitDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the frame buffer change is to be synchronised with Vsync. This is turned on by default.
|
||||
* Notes: In windowed mode, this setting has no effect.
|
||||
* @param Vsync Indicates whether the frame buffer changes are to be synchronised with Vsync.
|
||||
*/
|
||||
void setVsync(bool vsync);
|
||||
|
||||
/**
|
||||
* Returns true if V-Sync is on.
|
||||
* Notes: In windowed mode, this setting has no effect.
|
||||
*/
|
||||
bool getVsync() const;
|
||||
|
||||
/**
|
||||
* Returns true if the engine is running in Windowed mode.
|
||||
*/
|
||||
bool isWindowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills a rectangular area of the frame buffer with a color.
|
||||
* Notes: It is possible to create transparent rectangles by passing a color with an Alpha value of 255.
|
||||
* @param FillRectPtr Pointer to a Common::Rect, which specifies the section of the frame buffer to be filled.
|
||||
* If the rectangle falls partly off-screen, then it is automatically trimmed.
|
||||
* If a NULL value is passed, then the entire image is to be filled.
|
||||
* @param Color The 32-bit color with which the area is to be filled. The default is BS_RGB(0, 0, 0) (black)
|
||||
* @note FIf the rectangle is not completely inside the screen, it is automatically clipped.
|
||||
*/
|
||||
bool fill(const Common::Rect *fillRectPtr = 0, uint color = BS_RGB(0, 0, 0));
|
||||
|
||||
Graphics::ManagedSurface _backSurface;
|
||||
Graphics::ManagedSurface *getSurface() { return &_backSurface; }
|
||||
|
||||
Common::SeekableReadStream *_thumbnail;
|
||||
Common::SeekableReadStream *getThumbnail() { return _thumbnail; }
|
||||
|
||||
// Access methods
|
||||
|
||||
// Resource-Managing Methods
|
||||
// --------------------------
|
||||
Resource *loadResource(const Common::String &fileName) override;
|
||||
bool canLoadResource(const Common::String &fileName) override;
|
||||
|
||||
// Persistence Methods
|
||||
// -------------------
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
bool isRTL();
|
||||
static void ARGBColorToLuaColor(lua_State *L, uint color);
|
||||
static uint luaColorToARGBColor(lua_State *L, int stackIndex);
|
||||
|
||||
protected:
|
||||
|
||||
// Display Variables
|
||||
// -----------------
|
||||
int _width;
|
||||
int _height;
|
||||
Common::Rect _screenRect;
|
||||
int _bitDepth;
|
||||
|
||||
/**
|
||||
* Calculates the time since the last frame beginning has passed.
|
||||
*/
|
||||
void updateLastFrameDuration();
|
||||
|
||||
private:
|
||||
bool registerScriptBindings();
|
||||
void unregisterScriptBindings();
|
||||
|
||||
// LastFrameDuration Variables
|
||||
// ---------------------------
|
||||
uint _lastTimeStamp;
|
||||
uint _lastFrameDuration;
|
||||
bool _timerActive;
|
||||
Common::Array<uint> _frameTimeSamples;
|
||||
uint _frameTimeSampleSlot;
|
||||
|
||||
private:
|
||||
RenderObjectPtr<Panel> _mainPanelPtr;
|
||||
|
||||
Common::ScopedPtr<RenderObjectManager> _renderObjectManagerPtr;
|
||||
|
||||
bool _isRTL;
|
||||
|
||||
struct DebugLine {
|
||||
DebugLine(const Vertex &start, const Vertex &end, uint color) :
|
||||
_start(start),
|
||||
_end(end),
|
||||
_color(color) {}
|
||||
DebugLine() {}
|
||||
|
||||
Vertex _start;
|
||||
Vertex _end;
|
||||
uint _color;
|
||||
};
|
||||
|
||||
Common::Array<DebugLine> _debugLines;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
1273
engines/sword25/gfx/graphicengine_script.cpp
Normal file
1273
engines/sword25/gfx/graphicengine_script.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2649
engines/sword25/gfx/image/art.cpp
Normal file
2649
engines/sword25/gfx/image/art.cpp
Normal file
File diff suppressed because it is too large
Load Diff
215
engines/sword25/gfx/image/art.h
Normal file
215
engines/sword25/gfx/image/art.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Libart_LGPL - library of basic graphic primitives
|
||||
*
|
||||
* Copyright (c) 1998 Raph Levien
|
||||
*
|
||||
* Licensed under GNU LGPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/* Simple macros to set up storage allocation and basic types for libart
|
||||
functions. */
|
||||
|
||||
#ifndef __ART_H__
|
||||
#define __ART_H__
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
/* These aren't, strictly speaking, configuration macros, but they're
|
||||
damn handy to have around, and may be worth playing with for
|
||||
debugging. */
|
||||
#define art_new(type, n) ((type *)malloc ((n) * sizeof(type)))
|
||||
|
||||
#define art_renew(p, type, n) ((type *)realloc (p, (n) * sizeof(type)))
|
||||
|
||||
/* This one must be used carefully - in particular, p and max should
|
||||
be variables. They can also be pstruct->el lvalues. */
|
||||
#define art_expand(p, type, max) \
|
||||
do { \
|
||||
if (max) {\
|
||||
type *tmp = art_renew(p, type, max <<= 1); \
|
||||
if (!tmp) error("Cannot reallocate memory for art data"); \
|
||||
p = tmp; \
|
||||
} else { \
|
||||
max = 1; \
|
||||
p = art_new(type, 1); \
|
||||
if (!p) error("Cannot allocate memory for art data"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct ArtDRect {
|
||||
/*< public >*/
|
||||
double x0, y0, x1, y1;
|
||||
};
|
||||
|
||||
struct ArtPoint {
|
||||
/*< public >*/
|
||||
double x, y;
|
||||
};
|
||||
|
||||
/* Basic data structures and constructors for sorted vector paths */
|
||||
|
||||
struct ArtSVPSeg {
|
||||
int n_points;
|
||||
int dir; /* == 0 for "up", 1 for "down" */
|
||||
ArtDRect bbox;
|
||||
ArtPoint *points;
|
||||
};
|
||||
|
||||
struct ArtSVP {
|
||||
int n_segs;
|
||||
ArtSVPSeg segs[1];
|
||||
};
|
||||
|
||||
void art_svp_free(ArtSVP *svp);
|
||||
|
||||
/* Basic data structures and constructors for bezier paths */
|
||||
|
||||
enum ArtPathcode {
|
||||
ART_MOVETO,
|
||||
ART_MOVETO_OPEN,
|
||||
ART_CURVETO,
|
||||
ART_LINETO,
|
||||
ART_END
|
||||
};
|
||||
|
||||
struct ArtBpath {
|
||||
/*< public >*/
|
||||
ArtPathcode code;
|
||||
double x1;
|
||||
double y1;
|
||||
double x2;
|
||||
double y2;
|
||||
double x3;
|
||||
double y3;
|
||||
};
|
||||
|
||||
/* Basic data structures and constructors for simple vector paths */
|
||||
|
||||
/* CURVETO is not allowed! */
|
||||
struct ArtVpath {
|
||||
ArtPathcode code;
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
/* Some of the functions need to go into their own modules */
|
||||
|
||||
void art_vpath_add_point(ArtVpath **p_vpath, int *pn_points, int *pn_points_max,
|
||||
ArtPathcode code, double x, double y);
|
||||
|
||||
ArtVpath *art_bez_path_to_vec(const ArtBpath *bez, double flatness);
|
||||
|
||||
/* The funky new SVP intersector. */
|
||||
|
||||
#ifndef ART_WIND_RULE_DEFINED
|
||||
#define ART_WIND_RULE_DEFINED
|
||||
enum ArtWindRule {
|
||||
ART_WIND_RULE_NONZERO,
|
||||
ART_WIND_RULE_INTERSECT,
|
||||
ART_WIND_RULE_ODDEVEN,
|
||||
ART_WIND_RULE_POSITIVE
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ArtSvpWriter {
|
||||
int (*add_segment)(ArtSvpWriter *self, int wind_left, int delta_wind,
|
||||
double x, double y);
|
||||
void (*add_point)(ArtSvpWriter *self, int seg_id, double x, double y);
|
||||
void (*close_segment)(ArtSvpWriter *self, int seg_id);
|
||||
};
|
||||
|
||||
ArtSvpWriter *art_svp_writer_rewind_new(ArtWindRule rule);
|
||||
|
||||
ArtSVP *art_svp_writer_rewind_reap(ArtSvpWriter *self);
|
||||
|
||||
int art_svp_seg_compare(const void *s1, const void *s2);
|
||||
|
||||
void art_svp_intersector(const ArtSVP *in, ArtSvpWriter *out);
|
||||
|
||||
|
||||
/* Sort vector paths into sorted vector paths. */
|
||||
|
||||
ArtSVP *art_svp_from_vpath(ArtVpath *vpath);
|
||||
|
||||
/* Sort vector paths into sorted vector paths. */
|
||||
|
||||
enum ArtPathStrokeJoinType {
|
||||
ART_PATH_STROKE_JOIN_MITER,
|
||||
ART_PATH_STROKE_JOIN_ROUND,
|
||||
ART_PATH_STROKE_JOIN_BEVEL
|
||||
};
|
||||
|
||||
enum ArtPathStrokeCapType {
|
||||
ART_PATH_STROKE_CAP_BUTT,
|
||||
ART_PATH_STROKE_CAP_ROUND,
|
||||
ART_PATH_STROKE_CAP_SQUARE
|
||||
};
|
||||
|
||||
ArtSVP *art_svp_vpath_stroke(ArtVpath *vpath,
|
||||
ArtPathStrokeJoinType join,
|
||||
ArtPathStrokeCapType cap,
|
||||
double line_width,
|
||||
double miter_limit,
|
||||
double flatness);
|
||||
|
||||
/* This version may have winding numbers exceeding 1. */
|
||||
ArtVpath *art_svp_vpath_stroke_raw(ArtVpath *vpath,
|
||||
ArtPathStrokeJoinType join,
|
||||
ArtPathStrokeCapType cap,
|
||||
double line_width,
|
||||
double miter_limit,
|
||||
double flatness);
|
||||
|
||||
|
||||
/* The spiffy antialiased renderer for sorted vector paths. */
|
||||
|
||||
struct ArtSVPRenderAAStep {
|
||||
int x;
|
||||
int delta; /* stored with 16 fractional bits */
|
||||
};
|
||||
|
||||
struct ArtSVPRenderAAIter;
|
||||
|
||||
ArtSVPRenderAAIter *art_svp_render_aa_iter(const ArtSVP *svp,
|
||||
int x0, int y0, int x1, int y1);
|
||||
|
||||
void art_svp_render_aa_iter_step(ArtSVPRenderAAIter *iter, int *p_start,
|
||||
ArtSVPRenderAAStep **p_steps, int *p_n_steps);
|
||||
|
||||
void art_svp_render_aa_iter_done(ArtSVPRenderAAIter *iter);
|
||||
|
||||
void art_svp_render_aa(const ArtSVP *svp,
|
||||
int x0, int y0, int x1, int y1,
|
||||
void (*callback)(void *callback_data,
|
||||
int y,
|
||||
int start,
|
||||
ArtSVPRenderAAStep *steps, int n_steps),
|
||||
void *callback_data);
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif /* __ART_H__ */
|
||||
193
engines/sword25/gfx/image/image.h
Normal file
193
engines/sword25/gfx/image/image.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
BS_Image
|
||||
--------
|
||||
|
||||
Autor: Malte Thiesen
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_IMAGE_H
|
||||
#define SWORD25_IMAGE_H
|
||||
|
||||
// Includes
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "common/rect.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class RectangleList;
|
||||
|
||||
class Image {
|
||||
public:
|
||||
virtual ~Image() {}
|
||||
|
||||
//@{
|
||||
/** @name Accessor methods */
|
||||
|
||||
/**
|
||||
@brief Returns the width of the image in pixels
|
||||
*/
|
||||
virtual int getWidth() const = 0;
|
||||
|
||||
/**
|
||||
@brief Returns the height of the image in pixels
|
||||
*/
|
||||
virtual int getHeight() const = 0;
|
||||
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/** @name Render methodes */
|
||||
|
||||
/**
|
||||
@brief renders the image in the framebuffer
|
||||
@param pDest a pointer to the target image. In most cases this is the framebuffer.
|
||||
@param PosX the position on the X-axis in the target image in pixels where the image is supposed to be rendered.<br>
|
||||
The default value is 0.
|
||||
@param PosY the position on the Y-axis in the target image in pixels where the image is supposed to be rendered.<br>
|
||||
The default value is 0.
|
||||
@param Flipping how the image should be flipped.<br>
|
||||
The default value is Graphics::FLIP_NONE (no flipping)
|
||||
@param pSrcPartRect Pointer on Common::Rect which specifies the section to be rendered. If the whole image has to be rendered the Pointer is NULL.<br>
|
||||
This referes to the unflipped and unscaled image.<br>
|
||||
The default value is NULL.
|
||||
@param Color an ARGB color value, which determines the parameters for the color modulation und alpha blending.<br>
|
||||
The alpha component of the color determines the alpha blending parameter (0 = no covering, 255 = full covering).<br>
|
||||
The color components determines the color for color modulation.<br>
|
||||
The default value is BS_ARGB(255, 255, 255, 255) (full covering, no color modulation).
|
||||
The macros BS_RGB and BS_ARGB can be used for the creation of the color value.
|
||||
@param Width the output width of the screen section.
|
||||
The images will be scaled if the output width of the screen section differs from the image section.<br>
|
||||
The value -1 determines that the image should not be scaled.<br>
|
||||
The default value is -1.
|
||||
@param Width the output height of the screen section.
|
||||
The images will be scaled if the output width of the screen section differs from the image section.<br>
|
||||
The value -1 determines that the image should not be scaled.<br>
|
||||
The default value is -1.
|
||||
@return returns false if the rendering failed.
|
||||
@remark Not all blitting operations of all BS_Image classes are supported.<br>
|
||||
More information can be find in the class description of BS_Image and the following methodes:
|
||||
- IsBlitTarget()
|
||||
- IsScalingAllowed()
|
||||
- IsFillingAllowed()
|
||||
- IsAlphaAllowed()
|
||||
- IsColorModulationAllowed()
|
||||
- IsSetContentAllowed()
|
||||
*/
|
||||
virtual bool blit(int posX = 0, int posY = 0,
|
||||
int flipping = Graphics::FLIP_NONE,
|
||||
Common::Rect *pPartRect = NULL,
|
||||
uint color = BS_ARGB(255, 255, 255, 255),
|
||||
int width = -1, int height = -1,
|
||||
RectangleList *updateRects = 0) = 0;
|
||||
|
||||
/**
|
||||
@brief fills a rectangular section of the image with a color.
|
||||
@param pFillRect Pointer on Common::Rect which specifies the section of the image which is supposed to be filled. If the whole image has to be filled this value is NULL.<br>
|
||||
The default value is NULL.
|
||||
@param Color the 32 Bit color value for filling the image section.
|
||||
@remark It is possible to create transparent rectangulars by using a color with alpha value not equal to 255.
|
||||
@remark Independent from the color format of the image, it must be given a 32 bit color value. The macros BS_RGB and BS_ARGB can be used for the creation of the color value.
|
||||
@remark If the rectangular is not completely inside the screen area, it will be automatically trimmed.
|
||||
*/
|
||||
virtual bool fill(const Common::Rect *pFillRect = 0, uint color = BS_RGB(0, 0, 0)) = 0;
|
||||
|
||||
/**
|
||||
@brief Fills the content of the image with pixel data.
|
||||
@param Pixeldata a vector which cotains the pixel data. They must be present in the color format of the image and there must be enough data available for filling the whole image.
|
||||
@param Offset the offset in Byte in Pixeldata-Vector on which the first pixel to write is located.<br>
|
||||
The default value is 0.
|
||||
@param Stride the distance in Byte between the end of line and the beginning of a new line in Pixeldata-Vector.<br>
|
||||
The default value is 0.
|
||||
@return returns false, if the call failed.
|
||||
@remark A call of this methode is only allowd if IsSetContentAllowed() returns true.
|
||||
*/
|
||||
virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride) = 0;
|
||||
|
||||
/**
|
||||
@brief Reads out a pixel of the image.
|
||||
@param X the X-coordinate of the pixel.
|
||||
@param Y the y-coordinate of the pixel.
|
||||
@return Returns the 32-bit color value of the pixel at the given position.
|
||||
@remark This methode should not be used in no way to read out bigger parts of the image because the method is very slow. The method is rather intended for reading out single pixels of the image..
|
||||
*/
|
||||
virtual uint getPixel(int x, int y) = 0;
|
||||
|
||||
//@{
|
||||
/** @name Information methodes */
|
||||
|
||||
/**
|
||||
@brief Checks, if it is allowed to call BS_Image Blit().
|
||||
@return Returns false, if a Blit() call is not allowed at this object.
|
||||
*/
|
||||
virtual bool isBlitSource() const = 0;
|
||||
|
||||
/**
|
||||
@brief Checks, if the BS_Image can be a target image for a Blit call.
|
||||
@return Returns false, if a Blit() call with this object as a target is not allowed.
|
||||
*/
|
||||
virtual bool isBlitTarget() const = 0;
|
||||
|
||||
/**
|
||||
@brief Returns true, if the BS_Image is allowed to be scaled by a Blit() call.
|
||||
*/
|
||||
virtual bool isScalingAllowed() const = 0;
|
||||
|
||||
/**
|
||||
@brief Returns true, if the BS_Image is allowed to be filled by a Fill() call.
|
||||
*/
|
||||
virtual bool isFillingAllowed() const = 0;
|
||||
|
||||
/**
|
||||
@brief Returns true, if the BS_Image is allowed to be displayed with an alpha value.
|
||||
*/
|
||||
virtual bool isAlphaAllowed() const = 0;
|
||||
|
||||
/**
|
||||
@brief Return true, if the BS_Image is allowed to be displayed with color modulation by a Blit() call
|
||||
*/
|
||||
virtual bool isColorModulationAllowed() const = 0;
|
||||
|
||||
/**
|
||||
@brief Returns true, if the content of the BS_Image is allowed to be replaced by call of SetContent().
|
||||
*/
|
||||
virtual bool isSetContentAllowed() const = 0;
|
||||
|
||||
virtual bool isSolid() const { return false; }
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
82
engines/sword25/gfx/image/imgloader.cpp
Normal file
82
engines/sword25/gfx/image/imgloader.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
#include "sword25/gfx/image/imgloader.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "image/png.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, Graphics::Surface *dest) {
|
||||
assert(dest);
|
||||
Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO);
|
||||
|
||||
::Image::PNGDecoder png;
|
||||
if (!png.loadStream(*fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done
|
||||
error("Error while reading PNG image");
|
||||
|
||||
const Graphics::Surface *sourceSurface = png.getSurface();
|
||||
Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette().data(), png.getPalette().size());
|
||||
|
||||
dest->copyFrom(*pngSurface);
|
||||
|
||||
pngSurface->free();
|
||||
delete pngSurface;
|
||||
delete fileStr;
|
||||
|
||||
// Signal success
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImgLoader::decodeThumbnailImage(const byte *pFileData, uint fileSize, Graphics::Surface *dest) {
|
||||
assert(dest);
|
||||
const byte *src = pFileData + 4; // skip header
|
||||
uint width = READ_LE_UINT16(src); src += 2;
|
||||
uint height = READ_LE_UINT16(src); src += 2;
|
||||
src++; // version, ignored for now
|
||||
|
||||
dest->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
|
||||
uint32 *dst = (uint32 *)dest->getBasePtr(0, 0); // treat as uint32, for pixelformat output
|
||||
byte r, g, b;
|
||||
|
||||
for (uint32 i = 0; i < width * height; i++) {
|
||||
r = *src++;
|
||||
g = *src++;
|
||||
b = *src++;
|
||||
*dst++ = dest->format.RGBToColor(r, g, b);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
74
engines/sword25/gfx/image/imgloader.h
Normal file
74
engines/sword25/gfx/image/imgloader.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_IMGLOADER_H
|
||||
#define SWORD25_IMGLOADER_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
/**
|
||||
* Class for loading PNG files, and PNG data embedded into savegames.
|
||||
*
|
||||
* Originally written by Malte Thiesen.
|
||||
*/
|
||||
class ImgLoader {
|
||||
protected:
|
||||
ImgLoader() {} // Protected constructor to prevent instances
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Decode an image.
|
||||
* @param[in] fileDatePtr pointer to the image data
|
||||
* @param[in] fileSize size of the image data in bytes
|
||||
* @param[out] dest if successful, surface will contain the image
|
||||
* data (storage is allocated via create).
|
||||
* @return false in case of an error
|
||||
*
|
||||
* @remark This function does not free the image buffer passed to it,
|
||||
* it is the callers responsibility to do so.
|
||||
*/
|
||||
static bool decodePNGImage(const byte *pFileData, uint fileSize,
|
||||
Graphics::Surface *dest);
|
||||
|
||||
static bool decodeThumbnailImage(const byte *pFileData, uint fileSize,
|
||||
Graphics::Surface *dest);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
266
engines/sword25/gfx/image/renderedimage.cpp
Normal file
266
engines/sword25/gfx/image/renderedimage.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// INCLUDES
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/gfx/image/imgloader.h"
|
||||
#include "sword25/gfx/image/renderedimage.h"
|
||||
|
||||
#include "sword25/gfx/renderobjectmanager.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CONSTRUCTION / DESTRUCTION
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Load a NULL-terminated string from the given stream.
|
||||
*/
|
||||
static Common::String loadString(Common::SeekableReadStream &in, uint maxSize = 999) {
|
||||
Common::String result;
|
||||
|
||||
while (!in.eos() && (result.size() < maxSize)) {
|
||||
char ch = (char)in.readByte();
|
||||
if (ch == '\0')
|
||||
break;
|
||||
|
||||
result += ch;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSize, bool &isPNG) {
|
||||
byte *pFileData;
|
||||
Common::SaveFileManager *sfm = g_system->getSavefileManager();
|
||||
Common::InSaveFile *file = sfm->openForLoading(lastPathComponent(filename, '/'));
|
||||
if (!file)
|
||||
error("Save file \"%s\" could not be loaded.", filename.c_str());
|
||||
|
||||
// Seek to the actual PNG image
|
||||
loadString(*file); // Marker (BS25SAVEGAME)
|
||||
Common::String storedVersionID = loadString(*file); // Version
|
||||
if (storedVersionID != "SCUMMVM1")
|
||||
loadString(*file);
|
||||
|
||||
loadString(*file); // Description
|
||||
uint32 compressedGamedataSize = atoi(loadString(*file).c_str());
|
||||
loadString(*file); // Uncompressed game data size
|
||||
file->skip(compressedGamedataSize); // Skip the game data and move to the thumbnail itself
|
||||
uint32 thumbnailStart = file->pos();
|
||||
|
||||
fileSize = file->size() - thumbnailStart;
|
||||
|
||||
// Check if the thumbnail is in our own format, or a PNG file.
|
||||
uint32 header = file->readUint32BE();
|
||||
isPNG = (header != MKTAG('S','C','R','N'));
|
||||
file->seek(-4, SEEK_CUR);
|
||||
|
||||
pFileData = new byte[fileSize];
|
||||
file->read(pFileData, fileSize);
|
||||
delete file;
|
||||
|
||||
return pFileData;
|
||||
}
|
||||
|
||||
RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
|
||||
_alphaType(Graphics::ALPHA_FULL) {
|
||||
result = false;
|
||||
|
||||
PackageManager *pPackage = Kernel::getInstance()->getPackage();
|
||||
assert(pPackage);
|
||||
|
||||
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
|
||||
|
||||
// Load file
|
||||
byte *pFileData;
|
||||
uint fileSize;
|
||||
|
||||
bool isPNG = true;
|
||||
|
||||
if (filename.hasPrefix("/saves")) {
|
||||
pFileData = readSavegameThumbnail(filename, fileSize, isPNG);
|
||||
} else {
|
||||
pFileData = pPackage->getFile(filename, &fileSize);
|
||||
}
|
||||
|
||||
if (!pFileData) {
|
||||
error("File \"%s\" could not be loaded.", filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Uncompress the image
|
||||
if (isPNG)
|
||||
result = ImgLoader::decodePNGImage(pFileData, fileSize, _surface.surfacePtr());
|
||||
else
|
||||
result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, _surface.surfacePtr());
|
||||
|
||||
if (!result) {
|
||||
error("Could not decode image.");
|
||||
delete[] pFileData;
|
||||
return;
|
||||
}
|
||||
|
||||
// Cleanup FileData
|
||||
delete[] pFileData;
|
||||
|
||||
_doCleanup = true;
|
||||
_alphaType = _surface.detectAlpha();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
RenderedImage::RenderedImage(uint width, uint height, bool &result) :
|
||||
_alphaType(Graphics::ALPHA_FULL) {
|
||||
|
||||
_surface.create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
|
||||
|
||||
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
|
||||
|
||||
_doCleanup = true;
|
||||
|
||||
result = true;
|
||||
return;
|
||||
}
|
||||
|
||||
RenderedImage::RenderedImage() : _alphaType(Graphics::ALPHA_FULL) {
|
||||
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
|
||||
|
||||
_surface.format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
|
||||
|
||||
_doCleanup = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
RenderedImage::~RenderedImage() {
|
||||
if (_doCleanup) {
|
||||
_surface.free();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool RenderedImage::fill(const Common::Rect *pFillRect, uint color) {
|
||||
error("Fill() is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool RenderedImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
|
||||
// Check if PixelData contains enough pixel to create an image with image size equals width * height
|
||||
if (size < static_cast<uint>(_surface.w * _surface.h * 4)) {
|
||||
error("PixelData vector is too small to define a 32 bit %dx%d image.", _surface.w, _surface.h);
|
||||
return false;
|
||||
}
|
||||
|
||||
const byte *in = &pixeldata[offset];
|
||||
byte *out = (byte *)_surface.getPixels();
|
||||
|
||||
for (int i = 0; i < _surface.h; i++) {
|
||||
memcpy(out, in, _surface.w * 4);
|
||||
out += _surface.w * 4;
|
||||
in += stride;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderedImage::replaceContent(byte *pixeldata, int width, int height) {
|
||||
_surface.w = width;
|
||||
_surface.h = height;
|
||||
_surface.pitch = width * 4;
|
||||
_surface.setPixels(pixeldata);
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
uint RenderedImage::getPixel(int x, int y) {
|
||||
error("GetPixel() is not supported. Returning black.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, RectangleList *updateRects) {
|
||||
int newFlipping = (((flipping & 1) ? Graphics::FLIP_V : 0) | ((flipping & 2) ? Graphics::FLIP_H : 0));
|
||||
|
||||
int ca = (color >> BS_ASHIFT) & 0xff;
|
||||
int cr = (color >> BS_RSHIFT) & 0xff;
|
||||
int cg = (color >> BS_GSHIFT) & 0xff;
|
||||
int cb = (color >> BS_BSHIFT) & 0xff;
|
||||
|
||||
Common::Rect srcRect = pPartRect ? *pPartRect : Common::Rect(_surface.w, _surface.h);
|
||||
if (width == -1) width = srcRect.width();
|
||||
if (height == -1) height = srcRect.height();
|
||||
|
||||
_backSurface->blendBlitFrom(_surface, srcRect, Common::Rect(posX, posY, posX + width, posY + height),
|
||||
newFlipping, _surface.format.ARGBToColor(ca, cr, cg, cb), Graphics::BLEND_NORMAL, _alphaType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderedImage::copyDirectly(int posX, int posY) {
|
||||
byte *data = (byte *)_surface.getPixels();
|
||||
int w = _surface.w;
|
||||
int h = _surface.h;
|
||||
|
||||
// Handle off-screen clipping
|
||||
if (posY < 0) {
|
||||
h = MAX(0, (int)_surface.h - -posY);
|
||||
data = (byte *)_surface.getPixels() + _surface.w * -posY;
|
||||
posY = 0;
|
||||
}
|
||||
|
||||
if (posX < 0) {
|
||||
w = MAX(0, (int)_surface.h - -posX);
|
||||
data = (byte *)_surface.getPixels() + (-posX * 4);
|
||||
posX = 0;
|
||||
}
|
||||
|
||||
w = CLIP((int)w, 0, (int)MAX((int)_backSurface->w - posX, 0));
|
||||
h = CLIP((int)h, 0, (int)MAX((int)_backSurface->h - posY, 0));
|
||||
|
||||
g_system->copyRectToScreen(data, _backSurface->pitch, posX, posY, w, h);
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
120
engines/sword25/gfx/image/renderedimage.h
Normal file
120
engines/sword25/gfx/image/renderedimage.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_RENDERED_IMAGE_H
|
||||
#define SWORD25_RENDERED_IMAGE_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// INCLUDES
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class RenderedImage : public Image {
|
||||
private:
|
||||
RenderedImage(const RenderedImage &) : Image(), _doCleanup(false) {}
|
||||
RenderedImage &operator=(const RenderedImage &) { return *this; }
|
||||
public:
|
||||
RenderedImage(const Common::String &filename, bool &result);
|
||||
|
||||
/**
|
||||
@brief Creates an empty BS_RenderedImage
|
||||
|
||||
@param Width The width of the image to be created.
|
||||
@param Height The height of the image to be created
|
||||
@param Result Informs the caller, whether the constructor is executed successfully. If it contains false
|
||||
after the call, do not call methods on the object and destroy the object immediately.
|
||||
*/
|
||||
RenderedImage(uint width, uint height, bool &result);
|
||||
RenderedImage();
|
||||
|
||||
~RenderedImage() override;
|
||||
|
||||
int getWidth() const override {
|
||||
return _surface.w;
|
||||
}
|
||||
int getHeight() const override {
|
||||
return _surface.h;
|
||||
}
|
||||
|
||||
void copyDirectly(int posX, int posY);
|
||||
|
||||
bool blit(int posX = 0, int posY = 0,
|
||||
int flipping = Graphics::FLIP_NONE,
|
||||
Common::Rect *pPartRect = NULL,
|
||||
uint color = BS_ARGB(255, 255, 255, 255),
|
||||
int width = -1, int height = -1,
|
||||
RectangleList *updateRects = 0) override;
|
||||
bool fill(const Common::Rect *pFillRect, uint color) override;
|
||||
bool setContent(const byte *pixeldata, uint size, uint offset = 0, uint stride = 0) override;
|
||||
void replaceContent(byte *pixeldata, int width, int height);
|
||||
uint getPixel(int x, int y) override;
|
||||
|
||||
bool isBlitSource() const override {
|
||||
return true;
|
||||
}
|
||||
bool isBlitTarget() const override {
|
||||
return false;
|
||||
}
|
||||
bool isScalingAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
bool isFillingAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool isAlphaAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
bool isColorModulationAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
bool isSetContentAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void setAlphaType(Graphics::AlphaType alphaType) { _alphaType = alphaType; }
|
||||
bool isSolid() const override { return _alphaType == Graphics::ALPHA_OPAQUE; }
|
||||
|
||||
private:
|
||||
Graphics::ManagedSurface _surface;
|
||||
Graphics::AlphaType _alphaType;
|
||||
bool _doCleanup;
|
||||
|
||||
Graphics::ManagedSurface *_backSurface;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
100
engines/sword25/gfx/image/swimage.cpp
Normal file
100
engines/sword25/gfx/image/swimage.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/gfx/image/imgloader.h"
|
||||
#include "sword25/gfx/image/swimage.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
SWImage::SWImage(const Common::String &filename, bool &result) : _image() {
|
||||
result = false;
|
||||
|
||||
PackageManager *pPackage = Kernel::getInstance()->getPackage();
|
||||
assert(pPackage);
|
||||
|
||||
// Load file
|
||||
byte *pFileData;
|
||||
uint fileSize;
|
||||
pFileData = pPackage->getFile(filename, &fileSize);
|
||||
if (!pFileData) {
|
||||
error("File \"%s\" could not be loaded.", filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Uncompress the image
|
||||
if (!ImgLoader::decodePNGImage(pFileData, fileSize, &_image)) {
|
||||
error("Could not decode image.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Cleanup FileData
|
||||
delete[] pFileData;
|
||||
|
||||
result = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SWImage::~SWImage() {
|
||||
_image.free();
|
||||
}
|
||||
|
||||
|
||||
bool SWImage::blit(int posX, int posY,
|
||||
int flipping,
|
||||
Common::Rect *pPartRect,
|
||||
uint color,
|
||||
int width, int height,
|
||||
RectangleList *updateRects) {
|
||||
error("Blit() is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SWImage::fill(const Common::Rect *pFillRect, uint color) {
|
||||
error("Fill() is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SWImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
|
||||
error("SetContent() is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint SWImage::getPixel(int x, int y) {
|
||||
assert(x >= 0 && x < _image.w);
|
||||
assert(y >= 0 && y < _image.h);
|
||||
|
||||
byte a, r, g, b;
|
||||
_image.format.colorToARGB(_image.getPixel(x, y), a, r, g, b);
|
||||
|
||||
return BS_ARGB(a, r, g, b);
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
90
engines/sword25/gfx/image/swimage.h
Normal file
90
engines/sword25/gfx/image/swimage.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_SWIMAGE_H
|
||||
#define SWORD25_SWIMAGE_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class SWImage : public Image {
|
||||
public:
|
||||
SWImage(const Common::String &filename, bool &result);
|
||||
~SWImage() override;
|
||||
|
||||
int getWidth() const override {
|
||||
return _image.w;
|
||||
}
|
||||
int getHeight() const override {
|
||||
return _image.h;
|
||||
}
|
||||
|
||||
bool blit(int posX = 0, int posY = 0,
|
||||
int flipping = Graphics::FLIP_NONE,
|
||||
Common::Rect *pPartRect = NULL,
|
||||
uint color = BS_ARGB(255, 255, 255, 255),
|
||||
int width = -1, int height = -1,
|
||||
RectangleList *updateRects = 0) override;
|
||||
bool fill(const Common::Rect *fillRectPtr, uint color) override;
|
||||
bool setContent(const byte *pixeldata, uint size, uint offset, uint stride) override;
|
||||
uint getPixel(int x, int y) override;
|
||||
|
||||
bool isBlitSource() const override {
|
||||
return false;
|
||||
}
|
||||
bool isBlitTarget() const override {
|
||||
return false;
|
||||
}
|
||||
bool isScalingAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool isFillingAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool isAlphaAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool isColorModulationAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool isSetContentAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
Graphics::Surface _image;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
643
engines/sword25/gfx/image/vectorimage.cpp
Normal file
643
engines/sword25/gfx/image/vectorimage.cpp
Normal file
@@ -0,0 +1,643 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "sword25/gfx/image/art.h"
|
||||
#include "sword25/gfx/image/vectorimage.h"
|
||||
#include "sword25/gfx/image/renderedimage.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
#define BEZSMOOTHNESS 0.5
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SWF datatype
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Bitstream helper class
|
||||
// -----------------------------------------------------------------------------
|
||||
// The parsing of SWF files requires both bitwise readout and on Byte boundaries
|
||||
// oriented reading.
|
||||
// This class is specially equipped for this.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class VectorImage::SWFBitStream {
|
||||
public:
|
||||
SWFBitStream(const byte *pData, uint dataSize) :
|
||||
m_Pos(pData), m_End(pData + dataSize), m_WordMask(0)
|
||||
{}
|
||||
|
||||
inline uint32 getBits(uint bitCount) {
|
||||
if (bitCount == 0 || bitCount > 32) {
|
||||
error("SWFBitStream::GetBits() must read at least 1 and at most 32 bits at a time");
|
||||
}
|
||||
|
||||
uint32 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 int32 getSignedBits(uint bitCount) {
|
||||
// readout bits
|
||||
uint32 temp = getBits(bitCount);
|
||||
|
||||
// If the sign-bit is set, fill the rest of the return value with 1-bit (sign extension)
|
||||
if (temp & 1 << (bitCount - 1))
|
||||
return (0xffffffff << bitCount) | temp;
|
||||
else
|
||||
return temp;
|
||||
}
|
||||
|
||||
inline uint32 getUInt32() {
|
||||
uint32 byte1 = getByte();
|
||||
uint32 byte2 = getByte();
|
||||
uint32 byte3 = getByte();
|
||||
uint32 byte4 = getByte();
|
||||
|
||||
return byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24);
|
||||
}
|
||||
|
||||
inline uint16 getUInt16() {
|
||||
uint32 byte1 = getByte();
|
||||
uint32 byte2 = getByte();
|
||||
|
||||
return byte1 | (byte2 << 8);
|
||||
}
|
||||
|
||||
inline byte getByte() {
|
||||
flushByte();
|
||||
byte value = m_Word;
|
||||
m_WordMask = 0;
|
||||
flushByte();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
inline void flushByte() {
|
||||
if (m_WordMask != 128) {
|
||||
if (m_Pos >= m_End) {
|
||||
error("Attempted to read past end of file");
|
||||
} else {
|
||||
m_Word = *m_Pos++;
|
||||
m_WordMask = 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void skipBytes(uint skipLength) {
|
||||
flushByte();
|
||||
if (m_Pos + skipLength >= m_End) {
|
||||
error("Attempted to read past end of file");
|
||||
} else {
|
||||
m_Pos += skipLength;
|
||||
m_Word = *(m_Pos - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const byte *m_Pos;
|
||||
const byte *m_End;
|
||||
|
||||
byte m_Word;
|
||||
uint m_WordMask;
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants and utility functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const uint32 MAX_ACCEPTED_FLASH_VERSION = 3; // The maximum flash file version that is accepted by the loader
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Converts SWF rectangle data in a bit stream in Common::Rect objects
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Common::Rect flashRectToBSRect(VectorImage::SWFBitStream &bs) {
|
||||
bs.flushByte();
|
||||
|
||||
// Determines how many bits of the single components are encoded
|
||||
uint32 bitsPerValue = bs.getBits(5);
|
||||
|
||||
// Readout the single components
|
||||
int32 xMin = bs.getSignedBits(bitsPerValue);
|
||||
int32 xMax = bs.getSignedBits(bitsPerValue);
|
||||
int32 yMin = bs.getSignedBits(bitsPerValue);
|
||||
int32 yMax = bs.getSignedBits(bitsPerValue);
|
||||
|
||||
return Common::Rect(xMin, yMin, xMax + 1, yMax + 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Calculate the bounding box of a BS_VectorImageElement
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement) {
|
||||
double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
|
||||
|
||||
for (int j = vectorImageElement.getPathCount() - 1; j >= 0; j--) {
|
||||
ArtBpath *bez = vectorImageElement.getPathInfo(j).getVec();
|
||||
ArtVpath *vec = art_bez_path_to_vec(bez, 0.5);
|
||||
|
||||
if (vec[0].code == ART_END) {
|
||||
free(vec);
|
||||
continue;
|
||||
} else {
|
||||
x0 = x1 = vec[0].x;
|
||||
y0 = y1 = vec[0].y;
|
||||
for (int i = 1; vec[i].code != ART_END; i++) {
|
||||
if (vec[i].x < x0) x0 = vec[i].x;
|
||||
if (vec[i].x > x1) x1 = vec[i].x;
|
||||
if (vec[i].y < y0) y0 = vec[i].y;
|
||||
if (vec[i].y > y1) y1 = vec[i].y;
|
||||
}
|
||||
}
|
||||
free(vec);
|
||||
}
|
||||
|
||||
return Common::Rect(static_cast<int>(x0), static_cast<int>(y0), static_cast<int>(x1) + 1, static_cast<int>(y1) + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Construction
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, const Common::String &fname) : _pixelData(0), _fname(fname) {
|
||||
success = false;
|
||||
_bgColor = 0;
|
||||
|
||||
// Create bitstream object
|
||||
// In the following the file data will be readout of the bitstream object.
|
||||
SWFBitStream bs(pFileData, fileSize);
|
||||
|
||||
// Check SWF signature
|
||||
uint32 signature[3];
|
||||
signature[0] = bs.getByte();
|
||||
signature[1] = bs.getByte();
|
||||
signature[2] = bs.getByte();
|
||||
if (signature[0] != 'F' ||
|
||||
signature[1] != 'W' ||
|
||||
signature[2] != 'S') {
|
||||
error("File is not a valid SWF-file");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the version
|
||||
uint32 version = bs.getByte();
|
||||
if (version > MAX_ACCEPTED_FLASH_VERSION) {
|
||||
error("File is of version %d. Highest accepted version is %d.", version, MAX_ACCEPTED_FLASH_VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
// Readout filesize and compare with the actual size
|
||||
uint32 storedFileSize = bs.getUInt32();
|
||||
if (storedFileSize != fileSize) {
|
||||
error("File is not a valid SWF-file");
|
||||
return;
|
||||
}
|
||||
|
||||
// readout SWF size
|
||||
flashRectToBSRect(bs);
|
||||
|
||||
// Get frame rate and frame count
|
||||
/* uint32 frameRate = */
|
||||
bs.getUInt16();
|
||||
/* uint32 frameCount = */
|
||||
bs.getUInt16();
|
||||
|
||||
// Parse tags
|
||||
// Because we are only interested in the first DifneShape-Tag...
|
||||
bool keepParsing = true;
|
||||
while (keepParsing) {
|
||||
// Tags always begin on byte boundaries
|
||||
bs.flushByte();
|
||||
|
||||
// Readout tag type and length
|
||||
uint16 tagTypeAndLength = bs.getUInt16();
|
||||
uint32 tagType = tagTypeAndLength >> 6;
|
||||
uint32 tagLength = tagTypeAndLength & 0x3f;
|
||||
if (tagLength == 0x3f)
|
||||
tagLength = bs.getUInt32();
|
||||
|
||||
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;
|
||||
case 9:
|
||||
// SetBackgroundColor
|
||||
{
|
||||
byte r, g, b;
|
||||
r = bs.getByte();
|
||||
g = bs.getByte();
|
||||
b = bs.getByte();
|
||||
_bgColor = BS_RGB(r, g, b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warning("Ignoring tag: %d, %d bytes", tagType, tagLength);
|
||||
// Ignore unknown tags
|
||||
bs.skipBytes(tagLength);
|
||||
}
|
||||
}
|
||||
|
||||
// The execution must not arrive at this point: Either a shape is found, then the function will be leaved before, or it is found none, then
|
||||
// an exception occurs as soon as it is read beyond of the end of file.
|
||||
assert(false);
|
||||
}
|
||||
|
||||
VectorImage::~VectorImage() {
|
||||
for (int j = _elements.size() - 1; j >= 0; j--)
|
||||
for (int i = _elements[j].getPathCount() - 1; i >= 0; i--)
|
||||
if (_elements[j].getPathInfo(i).getVec())
|
||||
free(_elements[j].getPathInfo(i).getVec());
|
||||
|
||||
free(_pixelData);
|
||||
}
|
||||
|
||||
|
||||
ArtBpath *ensureBezStorage(ArtBpath *bez, int nodes, int *allocated) {
|
||||
if (*allocated <= nodes) {
|
||||
(*allocated) += 20;
|
||||
|
||||
return art_renew(bez, ArtBpath, *allocated);
|
||||
}
|
||||
|
||||
return bez;
|
||||
}
|
||||
|
||||
ArtBpath *VectorImage::storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, int fillStyle1, int *bezNodes, int *bezAllocated) {
|
||||
(*bezNodes)++;
|
||||
|
||||
bez = ensureBezStorage(bez, *bezNodes, bezAllocated);
|
||||
bez[*bezNodes].code = ART_END;
|
||||
|
||||
ArtBpath *bez1 = art_new(ArtBpath, *bezNodes + 1);
|
||||
if (!bez1)
|
||||
error("[VectorImage::storeBez] Cannot allocate memory");
|
||||
|
||||
for (int i = 0; i <= *bezNodes; i++)
|
||||
bez1[i] = bez[i];
|
||||
|
||||
_elements.back()._pathInfos.push_back(VectorPathInfo(bez1, *bezNodes, lineStyle, fillStyle0, fillStyle1));
|
||||
|
||||
return bez;
|
||||
}
|
||||
|
||||
bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
|
||||
/*uint32 shapeID = */bs.getUInt16();
|
||||
|
||||
// readout bounding box
|
||||
_boundingBox = flashRectToBSRect(bs);
|
||||
|
||||
// create first image element
|
||||
_elements.resize(1);
|
||||
|
||||
// read styles
|
||||
uint numFillBits;
|
||||
uint numLineBits;
|
||||
if (!parseStyles(shapeType, bs, numFillBits, numLineBits))
|
||||
return false;
|
||||
|
||||
uint lineStyle = 0;
|
||||
uint fillStyle0 = 0;
|
||||
uint fillStyle1 = 0;
|
||||
|
||||
// parse shaperecord
|
||||
// ------------------
|
||||
|
||||
double curX = 0;
|
||||
double curY = 0;
|
||||
int bezNodes = 0;
|
||||
int bezAllocated = 10;
|
||||
ArtBpath *bez = art_new(ArtBpath, bezAllocated);
|
||||
|
||||
bool endOfShapeDiscovered = false;
|
||||
while (!endOfShapeDiscovered) {
|
||||
uint32 typeFlag = bs.getBits(1);
|
||||
|
||||
// Non-Edge Record
|
||||
if (typeFlag == 0) {
|
||||
// Determines which parameters are set
|
||||
uint32 stateNewStyles = bs.getBits(1);
|
||||
uint32 stateLineStyle = bs.getBits(1);
|
||||
uint32 stateFillStyle1 = bs.getBits(1);
|
||||
uint32 stateFillStyle0 = bs.getBits(1);
|
||||
uint32 stateMoveTo = bs.getBits(1);
|
||||
|
||||
uint prevLineStyle = lineStyle;
|
||||
uint prevFillStyle0 = fillStyle0;
|
||||
uint prevFillStyle1 = fillStyle1;
|
||||
|
||||
// End of the shape definition is reached?
|
||||
if (!stateNewStyles && !stateLineStyle && !stateFillStyle0 && !stateFillStyle1 && !stateMoveTo) {
|
||||
endOfShapeDiscovered = true;
|
||||
// Decode parameters
|
||||
} else {
|
||||
if (stateMoveTo) {
|
||||
uint32 moveToBits = bs.getBits(5);
|
||||
curX = bs.getSignedBits(moveToBits);
|
||||
curY = 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;
|
||||
}
|
||||
|
||||
// Create a new path, unless there were only defined new styles
|
||||
if (stateLineStyle || stateFillStyle0 || stateFillStyle1 || stateMoveTo) {
|
||||
// Store previous curve if any
|
||||
if (bezNodes) {
|
||||
bez = storeBez(bez, prevLineStyle, prevFillStyle0, prevFillStyle1, &bezNodes, &bezAllocated);
|
||||
}
|
||||
|
||||
// Start new curve
|
||||
bez = ensureBezStorage(bez, 1, &bezAllocated);
|
||||
bez[0].code = ART_MOVETO_OPEN;
|
||||
bez[0].x3 = curX;
|
||||
bez[0].y3 = curY;
|
||||
bezNodes = 0;
|
||||
}
|
||||
|
||||
if (stateNewStyles) {
|
||||
// The old style definitions will be discarded and overwritten with the new at this point in Flash.
|
||||
// A new element will be started with a new element.
|
||||
_elements.resize(_elements.size() + 1);
|
||||
if (!parseStyles(shapeType, bs, numFillBits, numLineBits))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Edge record
|
||||
uint32 edgeFlag = bs.getBits(1);
|
||||
uint32 numBits = bs.getBits(4) + 2;
|
||||
|
||||
// Curved edge
|
||||
if (edgeFlag == 0) {
|
||||
double controlDeltaX = bs.getSignedBits(numBits);
|
||||
double controlDeltaY = bs.getSignedBits(numBits);
|
||||
double anchorDeltaX = bs.getSignedBits(numBits);
|
||||
double anchorDeltaY = bs.getSignedBits(numBits);
|
||||
|
||||
double controlX = curX + controlDeltaX;
|
||||
double controlY = curY + controlDeltaY;
|
||||
double newX = controlX + anchorDeltaX;
|
||||
double newY = controlY + anchorDeltaY;
|
||||
|
||||
#define WEIGHT (2.0/3.0)
|
||||
|
||||
bezNodes++;
|
||||
bez = ensureBezStorage(bez, bezNodes, &bezAllocated);
|
||||
bez[bezNodes].code = ART_CURVETO;
|
||||
bez[bezNodes].x1 = WEIGHT * controlX + (1 - WEIGHT) * curX;
|
||||
bez[bezNodes].y1 = WEIGHT * controlY + (1 - WEIGHT) * curY;
|
||||
bez[bezNodes].x2 = WEIGHT * controlX + (1 - WEIGHT) * newX;
|
||||
bez[bezNodes].y2 = WEIGHT * controlY + (1 - WEIGHT) * newY;
|
||||
bez[bezNodes].x3 = newX;
|
||||
bez[bezNodes].y3 = newY;
|
||||
|
||||
curX = newX;
|
||||
curY = newY;
|
||||
} else {
|
||||
// Staight edge
|
||||
int32 deltaX = 0;
|
||||
int32 deltaY = 0;
|
||||
|
||||
uint32 generalLineFlag = bs.getBits(1);
|
||||
if (generalLineFlag) {
|
||||
deltaX = bs.getSignedBits(numBits);
|
||||
deltaY = bs.getSignedBits(numBits);
|
||||
} else {
|
||||
uint32 vertLineFlag = bs.getBits(1);
|
||||
if (vertLineFlag)
|
||||
deltaY = bs.getSignedBits(numBits);
|
||||
else
|
||||
deltaX = bs.getSignedBits(numBits);
|
||||
}
|
||||
|
||||
curX += deltaX;
|
||||
curY += deltaY;
|
||||
|
||||
bezNodes++;
|
||||
bez = ensureBezStorage(bez, bezNodes, &bezAllocated);
|
||||
bez[bezNodes].code = ART_LINETO;
|
||||
bez[bezNodes].x3 = curX;
|
||||
bez[bezNodes].y3 = curY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store last curve
|
||||
if (bezNodes)
|
||||
bez = storeBez(bez, lineStyle, fillStyle0, fillStyle1, &bezNodes, &bezAllocated);
|
||||
|
||||
free(bez);
|
||||
|
||||
// Calculate the bounding boxes of each element
|
||||
Common::Array<VectorImageElement>::iterator it = _elements.begin();
|
||||
for (; it != _elements.end(); ++it)
|
||||
it->_boundingBox = CalculateBoundingBox(*it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool VectorImage::parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBits, uint &numLineBits) {
|
||||
bs.flushByte();
|
||||
|
||||
// Parse fill styles
|
||||
// -----------------
|
||||
|
||||
// Determine number of fill styles
|
||||
uint fillStyleCount = bs.getByte();
|
||||
if (fillStyleCount == 0xff)
|
||||
fillStyleCount = bs.getUInt16();
|
||||
|
||||
// Readout all fill styles. If a fill style with Typ != 0 is found, the parsing is aborted.
|
||||
// Only "solid fill" (Typ 0) is supported.
|
||||
_elements.back()._fillStyles.reserve(fillStyleCount);
|
||||
for (uint i = 0; i < fillStyleCount; ++i) {
|
||||
byte type = bs.getByte();
|
||||
uint32 color;
|
||||
byte r = bs.getByte();
|
||||
byte g = bs.getByte();
|
||||
byte b = bs.getByte();
|
||||
byte a = 0xff;
|
||||
|
||||
if (shapeType == 3)
|
||||
a = bs.getByte();
|
||||
|
||||
color = BS_ARGB(a, r, g, b);
|
||||
|
||||
if (type != 0)
|
||||
return false;
|
||||
|
||||
_elements.back()._fillStyles.push_back(color);
|
||||
}
|
||||
|
||||
// Line styles parsen
|
||||
// -----------------
|
||||
|
||||
// Determine number of line styles
|
||||
uint lineStyleCount = bs.getByte();
|
||||
if (lineStyleCount == 0xff)
|
||||
lineStyleCount = bs.getUInt16();
|
||||
|
||||
// Readout all line styles
|
||||
_elements.back()._lineStyles.reserve(lineStyleCount);
|
||||
for (uint i = 0; i < lineStyleCount; ++i) {
|
||||
double width = bs.getUInt16();
|
||||
uint32 color;
|
||||
byte r = bs.getByte();
|
||||
byte g = bs.getByte();
|
||||
byte b = bs.getByte();
|
||||
byte a = 0xff;
|
||||
|
||||
if (shapeType == 3)
|
||||
a = bs.getByte();
|
||||
|
||||
color = BS_ARGB(a, r, g, b);
|
||||
|
||||
_elements.back()._lineStyles.push_back(VectorImageElement::LineStyleType(width, color));
|
||||
}
|
||||
|
||||
// Readout the bit width for the following style indices
|
||||
numFillBits = bs.getBits(4);
|
||||
numLineBits = bs.getBits(4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool VectorImage::fill(const Common::Rect *pFillRect, uint color) {
|
||||
error("Fill() is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
uint VectorImage::getPixel(int x, int y) {
|
||||
error("GetPixel() is not supported. Returning black.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool VectorImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
|
||||
error("SetContent() is not supported.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool VectorImage::blit(int posX, int posY,
|
||||
int flipping,
|
||||
Common::Rect *pPartRect,
|
||||
uint color,
|
||||
int width, int height,
|
||||
RectangleList *updateRects) {
|
||||
static VectorImage *oldThis = 0;
|
||||
static int oldWidth = -2;
|
||||
static int oldHeight = -2;
|
||||
|
||||
// If width or height to 0, nothing needs to be shown.
|
||||
if (width == 0 || height == 0)
|
||||
return true;
|
||||
|
||||
// Determine if the old image in the cache can not be reused and must be recalculated
|
||||
if (!(oldThis == this && oldWidth == width && oldHeight == height)) {
|
||||
render(width, height);
|
||||
|
||||
oldThis = this;
|
||||
oldHeight = height;
|
||||
oldWidth = width;
|
||||
}
|
||||
|
||||
RenderedImage *rend = new RenderedImage();
|
||||
|
||||
rend->replaceContent(_pixelData, width, height);
|
||||
rend->blit(posX, posY, flipping, pPartRect, color, width, height, updateRects);
|
||||
|
||||
delete rend;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
232
engines/sword25/gfx/image/vectorimage.h
Normal file
232
engines/sword25/gfx/image/vectorimage.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_VECTORIMAGE_H
|
||||
#define SWORD25_VECTORIMAGE_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "art.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class 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 VectorPathInfo {
|
||||
public:
|
||||
VectorPathInfo(ArtBpath *vec, int len, uint lineStyle, uint fillStyle0, uint fillStyle1) :
|
||||
_vec(vec), _lineStyle(lineStyle), _fillStyle0(fillStyle0), _fillStyle1(fillStyle1), _len(len) {}
|
||||
|
||||
VectorPathInfo() {
|
||||
_lineStyle = _fillStyle0 = _fillStyle1 = _len = 0;
|
||||
_vec = 0;
|
||||
}
|
||||
|
||||
ArtBpath *getVec() const {
|
||||
return _vec;
|
||||
}
|
||||
int getVecLen() const {
|
||||
return _len;
|
||||
}
|
||||
uint getLineStyle() const {
|
||||
return _lineStyle;
|
||||
}
|
||||
uint getFillStyle0() const {
|
||||
return _fillStyle0;
|
||||
}
|
||||
uint getFillStyle1() const {
|
||||
return _fillStyle1;
|
||||
}
|
||||
|
||||
private:
|
||||
ArtBpath *_vec;
|
||||
uint _lineStyle;
|
||||
uint _fillStyle0;
|
||||
uint _fillStyle1;
|
||||
uint _len;
|
||||
};
|
||||
|
||||
/**
|
||||
@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 VectorImageElement {
|
||||
friend class VectorImage;
|
||||
public:
|
||||
uint getPathCount() const {
|
||||
return _pathInfos.size();
|
||||
}
|
||||
const VectorPathInfo &getPathInfo(uint pathNr) const {
|
||||
assert(pathNr < getPathCount());
|
||||
return _pathInfos[pathNr];
|
||||
}
|
||||
|
||||
double getLineStyleWidth(uint lineStyle) const {
|
||||
assert(lineStyle < _lineStyles.size());
|
||||
return _lineStyles[lineStyle].width;
|
||||
}
|
||||
|
||||
uint getLineStyleCount() const {
|
||||
return _lineStyles.size();
|
||||
}
|
||||
|
||||
uint32 getLineStyleColor(uint lineStyle) const {
|
||||
assert(lineStyle < _lineStyles.size());
|
||||
return _lineStyles[lineStyle].color;
|
||||
}
|
||||
|
||||
uint getFillStyleCount() const {
|
||||
return _fillStyles.size();
|
||||
}
|
||||
|
||||
uint32 getFillStyleColor(uint fillStyle) const {
|
||||
assert(fillStyle < _fillStyles.size());
|
||||
return _fillStyles[fillStyle];
|
||||
}
|
||||
|
||||
const Common::Rect &getBoundingBox() const {
|
||||
return _boundingBox;
|
||||
}
|
||||
|
||||
private:
|
||||
struct LineStyleType {
|
||||
LineStyleType(double width_, uint32 color_) : width(width_), color(color_) {}
|
||||
LineStyleType() {
|
||||
width = 0;
|
||||
color = 0;
|
||||
}
|
||||
double width;
|
||||
uint32 color;
|
||||
};
|
||||
|
||||
Common::Array<VectorPathInfo> _pathInfos;
|
||||
Common::Array<LineStyleType> _lineStyles;
|
||||
Common::Array<uint32> _fillStyles;
|
||||
Common::Rect _boundingBox;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@brief Eine Vektorgraphik
|
||||
|
||||
Objekte dieser Klasse enthalten die Informationen eines SWF-Shapes.
|
||||
*/
|
||||
|
||||
class VectorImage : public Image {
|
||||
public:
|
||||
VectorImage(const byte *pFileData, uint fileSize, bool &success, const Common::String &fname);
|
||||
~VectorImage() override;
|
||||
|
||||
uint getElementCount() const {
|
||||
return _elements.size();
|
||||
}
|
||||
const VectorImageElement &getElement(uint elementNr) const {
|
||||
assert(elementNr < _elements.size());
|
||||
return _elements[elementNr];
|
||||
}
|
||||
const Common::Rect &getBoundingBox() const {
|
||||
return _boundingBox;
|
||||
}
|
||||
|
||||
//
|
||||
// Die abstrakten Methoden von BS_Image
|
||||
//
|
||||
int getWidth() const override {
|
||||
return _boundingBox.width();
|
||||
}
|
||||
int getHeight() const override {
|
||||
return _boundingBox.height();
|
||||
}
|
||||
bool fill(const Common::Rect *pFillRect = 0, uint color = BS_RGB(0, 0, 0)) override;
|
||||
|
||||
void render(int width, int height);
|
||||
|
||||
uint getPixel(int x, int y) override;
|
||||
bool isBlitSource() const override {
|
||||
return true;
|
||||
}
|
||||
bool isBlitTarget() const override {
|
||||
return false;
|
||||
}
|
||||
bool isScalingAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
bool isFillingAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool isAlphaAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
bool isColorModulationAllowed() const override {
|
||||
return true;
|
||||
}
|
||||
bool isSetContentAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
bool setContent(const byte *pixeldata, uint size, uint offset, uint stride) override;
|
||||
bool blit(int posX = 0, int posY = 0,
|
||||
int flipping = Graphics::FLIP_NONE,
|
||||
Common::Rect *pPartRect = NULL,
|
||||
uint color = BS_ARGB(255, 255, 255, 255),
|
||||
int width = -1, int height = -1,
|
||||
RectangleList *updateRects = 0) override;
|
||||
|
||||
class SWFBitStream;
|
||||
|
||||
private:
|
||||
bool parseDefineShape(uint shapeType, SWFBitStream &bs);
|
||||
bool parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBits, uint &numLineBits);
|
||||
|
||||
ArtBpath *storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, int fillStyle1, int *bezNodes, int *bezAllocated);
|
||||
Common::Array<VectorImageElement> _elements;
|
||||
Common::Rect _boundingBox;
|
||||
|
||||
byte *_pixelData;
|
||||
|
||||
Common::String _fname;
|
||||
uint _bgColor;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
470
engines/sword25/gfx/image/vectorimagerenderer.cpp
Normal file
470
engines/sword25/gfx/image/vectorimagerenderer.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code contains portions of Libart_LGPL - library of basic graphic primitives
|
||||
*
|
||||
* Copyright (c) 1998 Raph Levien
|
||||
*
|
||||
* Licensed under GNU LGPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code contains portions of Swfdec
|
||||
*
|
||||
* Copyright (c) 2004-2006 David Schleef <ds@schleef.org>
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/image/art.h"
|
||||
#include "sword25/gfx/image/vectorimage.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
void art_rgb_fill_run1(byte *buf, byte r, byte g, byte b, int n) {
|
||||
int i;
|
||||
|
||||
if (r == g && g == b && r == 255) {
|
||||
memset(buf, g, n + n + n + n);
|
||||
} else {
|
||||
uint32 *alt = (uint32 *)buf;
|
||||
uint32 color = MS_RGB(r, g, b);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
*alt++ = color;
|
||||
}
|
||||
}
|
||||
|
||||
void art_rgb_run_alpha1(byte *buf, byte r, byte g, byte b, int alpha, int n) {
|
||||
int i;
|
||||
int v;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
#if defined(SCUMM_LITTLE_ENDIAN)
|
||||
v = *buf;
|
||||
*buf++ = MIN(v + alpha, 0xff);
|
||||
v = *buf;
|
||||
*buf++ = v + (((b - v) * alpha + 0x80) >> 8);
|
||||
v = *buf;
|
||||
*buf++ = v + (((g - v) * alpha + 0x80) >> 8);
|
||||
v = *buf;
|
||||
*buf++ = v + (((r - v) * alpha + 0x80) >> 8);
|
||||
#else
|
||||
v = *buf;
|
||||
*buf++ = v + (((r - v) * alpha + 0x80) >> 8);
|
||||
v = *buf;
|
||||
*buf++ = v + (((g - v) * alpha + 0x80) >> 8);
|
||||
v = *buf;
|
||||
*buf++ = v + (((b - v) * alpha + 0x80) >> 8);
|
||||
v = *buf;
|
||||
*buf++ = MIN(v + alpha, 0xff);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _ArtRgbSVPAlphaData ArtRgbSVPAlphaData;
|
||||
|
||||
struct _ArtRgbSVPAlphaData {
|
||||
int alphatab[256];
|
||||
byte r, g, b, alpha;
|
||||
byte *buf;
|
||||
int rowstride;
|
||||
int x0, x1;
|
||||
};
|
||||
|
||||
static void art_rgb_svp_alpha_callback1(void *callback_data, int y,
|
||||
int start, ArtSVPRenderAAStep *steps, int n_steps) {
|
||||
ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data;
|
||||
byte *linebuf;
|
||||
int run_x0, run_x1;
|
||||
uint32 running_sum = start;
|
||||
int x0, x1;
|
||||
int k;
|
||||
byte r, g, b;
|
||||
int *alphatab;
|
||||
int alpha;
|
||||
|
||||
linebuf = data->buf;
|
||||
x0 = data->x0;
|
||||
x1 = data->x1;
|
||||
|
||||
r = data->r;
|
||||
g = data->g;
|
||||
b = data->b;
|
||||
alphatab = data->alphatab;
|
||||
|
||||
if (n_steps > 0) {
|
||||
run_x1 = steps[0].x;
|
||||
if (run_x1 > x0) {
|
||||
alpha = (running_sum >> 16) & 0xff;
|
||||
if (alpha)
|
||||
art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], run_x1 - x0);
|
||||
}
|
||||
|
||||
for (k = 0; k < n_steps - 1; k++) {
|
||||
running_sum += steps[k].delta;
|
||||
run_x0 = run_x1;
|
||||
run_x1 = steps[k + 1].x;
|
||||
if (run_x1 > run_x0) {
|
||||
alpha = (running_sum >> 16) & 0xff;
|
||||
if (alpha)
|
||||
art_rgb_run_alpha1(linebuf + (run_x0 - x0) * 4, r, g, b, alphatab[alpha], run_x1 - run_x0);
|
||||
}
|
||||
}
|
||||
running_sum += steps[k].delta;
|
||||
if (x1 > run_x1) {
|
||||
alpha = (running_sum >> 16) & 0xff;
|
||||
if (alpha)
|
||||
art_rgb_run_alpha1(linebuf + (run_x1 - x0) * 4, r, g, b, alphatab[alpha], x1 - run_x1);
|
||||
}
|
||||
} else {
|
||||
alpha = (running_sum >> 16) & 0xff;
|
||||
if (alpha)
|
||||
art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], x1 - x0);
|
||||
}
|
||||
|
||||
data->buf += data->rowstride;
|
||||
}
|
||||
|
||||
static void art_rgb_svp_alpha_opaque_callback1(void *callback_data, int y,
|
||||
int start,
|
||||
ArtSVPRenderAAStep *steps, int n_steps) {
|
||||
ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data;
|
||||
byte *linebuf;
|
||||
int run_x0, run_x1;
|
||||
uint32 running_sum = start;
|
||||
int x0, x1;
|
||||
int k;
|
||||
byte r, g, b;
|
||||
int *alphatab;
|
||||
int alpha;
|
||||
|
||||
linebuf = data->buf;
|
||||
x0 = data->x0;
|
||||
x1 = data->x1;
|
||||
|
||||
r = data->r;
|
||||
g = data->g;
|
||||
b = data->b;
|
||||
alphatab = data->alphatab;
|
||||
|
||||
if (n_steps > 0) {
|
||||
run_x1 = steps[0].x;
|
||||
if (run_x1 > x0) {
|
||||
alpha = running_sum >> 16;
|
||||
if (alpha) {
|
||||
if (alpha >= 255)
|
||||
art_rgb_fill_run1(linebuf, r, g, b, run_x1 - x0);
|
||||
else
|
||||
art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], run_x1 - x0);
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < n_steps - 1; k++) {
|
||||
running_sum += steps[k].delta;
|
||||
run_x0 = run_x1;
|
||||
run_x1 = steps[k + 1].x;
|
||||
if (run_x1 > run_x0) {
|
||||
alpha = running_sum >> 16;
|
||||
if (alpha) {
|
||||
if (alpha >= 255)
|
||||
art_rgb_fill_run1(linebuf + (run_x0 - x0) * 4, r, g, b, run_x1 - run_x0);
|
||||
else
|
||||
art_rgb_run_alpha1(linebuf + (run_x0 - x0) * 4, r, g, b, alphatab[alpha], run_x1 - run_x0);
|
||||
}
|
||||
}
|
||||
}
|
||||
running_sum += steps[k].delta;
|
||||
if (x1 > run_x1) {
|
||||
alpha = running_sum >> 16;
|
||||
if (alpha) {
|
||||
if (alpha >= 255)
|
||||
art_rgb_fill_run1(linebuf + (run_x1 - x0) * 4, r, g, b, x1 - run_x1);
|
||||
else
|
||||
art_rgb_run_alpha1(linebuf + (run_x1 - x0) * 4, r, g, b, alphatab[alpha], x1 - run_x1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alpha = running_sum >> 16;
|
||||
if (alpha) {
|
||||
if (alpha >= 255)
|
||||
art_rgb_fill_run1(linebuf, r, g, b, x1 - x0);
|
||||
else
|
||||
art_rgb_run_alpha1(linebuf, r, g, b, alphatab[alpha], x1 - x0);
|
||||
}
|
||||
}
|
||||
|
||||
data->buf += data->rowstride;
|
||||
}
|
||||
|
||||
void art_rgb_svp_alpha1(const ArtSVP *svp,
|
||||
int x0, int y0, int x1, int y1,
|
||||
uint32 color,
|
||||
byte *buf, int rowstride) {
|
||||
ArtRgbSVPAlphaData data;
|
||||
int i;
|
||||
int a, da;
|
||||
|
||||
data.r = (color >> 16) & 0xFF;
|
||||
data.g = (color >> 8) & 0xFF;
|
||||
data.b = (color >> 0) & 0xFF;
|
||||
data.alpha = (color >> 24) & 0xFF;
|
||||
|
||||
a = 0x8000;
|
||||
da = (data.alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
data.alphatab[i] = a >> 16;
|
||||
a += da;
|
||||
}
|
||||
|
||||
data.buf = buf;
|
||||
data.rowstride = rowstride;
|
||||
data.x0 = x0;
|
||||
data.x1 = x1;
|
||||
if (data.alpha == 255)
|
||||
art_svp_render_aa(svp, x0, y0, x1, y1, art_rgb_svp_alpha_opaque_callback1, &data);
|
||||
else
|
||||
art_svp_render_aa(svp, x0, y0, x1, y1, art_rgb_svp_alpha_callback1, &data);
|
||||
}
|
||||
|
||||
static int art_vpath_len(ArtVpath *a) {
|
||||
int i = 0;
|
||||
while (a[i].code != ART_END)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
ArtVpath *art_vpath_cat(ArtVpath *a, ArtVpath *b) {
|
||||
ArtVpath *dest;
|
||||
ArtVpath *p;
|
||||
int len_a, len_b;
|
||||
|
||||
len_a = art_vpath_len(a);
|
||||
len_b = art_vpath_len(b);
|
||||
dest = art_new(ArtVpath, len_a + len_b + 1);
|
||||
if (!dest)
|
||||
error("[art_vpath_cat] Cannot allocate memory");
|
||||
|
||||
p = dest;
|
||||
|
||||
for (int i = 0; i < len_a; i++)
|
||||
*p++ = *a++;
|
||||
for (int i = 0; i <= len_b; i++)
|
||||
*p++ = *b++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void art_svp_make_convex(ArtSVP *svp) {
|
||||
int i;
|
||||
|
||||
if (svp->n_segs > 0 && svp->segs[0].dir == 0) {
|
||||
for (i = 0; i < svp->n_segs; i++) {
|
||||
svp->segs[i].dir = !svp->segs[i].dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArtVpath *art_vpath_reverse(ArtVpath *a) {
|
||||
ArtVpath *dest;
|
||||
ArtVpath it;
|
||||
int len;
|
||||
int state = 0;
|
||||
int i;
|
||||
|
||||
len = art_vpath_len(a);
|
||||
dest = art_new(ArtVpath, len + 1);
|
||||
if (!dest)
|
||||
error("[art_vpath_reverse] Cannot allocate memory");
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
it = a[len - i - 1];
|
||||
if (state) {
|
||||
it.code = ART_LINETO;
|
||||
} else {
|
||||
it.code = ART_MOVETO_OPEN;
|
||||
state = 1;
|
||||
}
|
||||
if (a[len - i - 1].code == ART_MOVETO ||
|
||||
a[len - i - 1].code == ART_MOVETO_OPEN) {
|
||||
state = 0;
|
||||
}
|
||||
dest[i] = it;
|
||||
}
|
||||
dest[len] = a[len];
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
ArtVpath *art_vpath_reverse_free(ArtVpath *a) {
|
||||
ArtVpath *dest;
|
||||
|
||||
dest = art_vpath_reverse(a);
|
||||
free(a);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void drawBez(ArtBpath *bez1, ArtBpath *bez2, byte *buffer, int width, int height, int deltaX, int deltaY, double scaleX, double scaleY, double penWidth, unsigned int color) {
|
||||
ArtVpath *vec = NULL;
|
||||
ArtVpath *vec1 = NULL;
|
||||
ArtVpath *vec2 = NULL;
|
||||
ArtSVP *svp = NULL;
|
||||
|
||||
#if 0
|
||||
const char *codes[] = {"ART_MOVETO", "ART_MOVETO_OPEN", "ART_CURVETO", "ART_LINETO", "ART_END"};
|
||||
for (int i = 0;; i++) {
|
||||
debugN(" bez[%d].code = %s;\n", i, codes[bez[i].code]);
|
||||
if (bez[i].code == ART_END)
|
||||
break;
|
||||
if (bez[i].code == ART_CURVETO) {
|
||||
debugN(" bez[%d].x1 = %f; bez[%d].y1 = %f;\n", i, bez[i].x1, i, bez[i].y1);
|
||||
debugN(" bez[%d].x2 = %f; bez[%d].y2 = %f;\n", i, bez[i].x2, i, bez[i].y2);
|
||||
}
|
||||
debugN(" bez[%d].x3 = %f; bez[%d].y3 = %f;\n", i, bez[i].x3, i, bez[i].y3);
|
||||
}
|
||||
|
||||
debugN(" drawBez(bez, buffer, 1.0, 1.0, %f, 0x%08x);\n", penWidth, color);
|
||||
#endif
|
||||
|
||||
// HACK: Some frames have green bounding boxes drawn.
|
||||
// Perhaps they were used by original game artist Umriss
|
||||
// We skip them just like the original
|
||||
if (bez2 == 0 && color == BS_RGB(0x00, 0xff, 0x00)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec1 = art_bez_path_to_vec(bez1, 0.5);
|
||||
if (bez2 != 0) {
|
||||
vec2 = art_bez_path_to_vec(bez2, 0.5);
|
||||
vec2 = art_vpath_reverse_free(vec2);
|
||||
vec = art_vpath_cat(vec1, vec2);
|
||||
|
||||
free(vec1);
|
||||
free(vec2);
|
||||
} else {
|
||||
vec = vec1;
|
||||
}
|
||||
|
||||
int size = art_vpath_len(vec);
|
||||
ArtVpath *vect = art_new(ArtVpath, size + 1);
|
||||
if (!vect)
|
||||
error("[drawBez] Cannot allocate memory");
|
||||
|
||||
int k;
|
||||
for (k = 0; k < size; k++) {
|
||||
vect[k].code = vec[k].code;
|
||||
vect[k].x = (vec[k].x - deltaX) * scaleX;
|
||||
vect[k].y = (vec[k].y - deltaY) * scaleY;
|
||||
}
|
||||
vect[k].code = ART_END;
|
||||
|
||||
if (bez2 == 0) { // Line drawing
|
||||
svp = art_svp_vpath_stroke(vect, ART_PATH_STROKE_JOIN_ROUND, ART_PATH_STROKE_CAP_ROUND, penWidth, 1.0, 0.5);
|
||||
} else {
|
||||
svp = art_svp_from_vpath(vect);
|
||||
art_svp_make_convex(svp);
|
||||
}
|
||||
|
||||
art_rgb_svp_alpha1(svp, 0, 0, width, height, color, buffer, width * 4);
|
||||
|
||||
free(vect);
|
||||
art_svp_free(svp);
|
||||
free(vec);
|
||||
}
|
||||
|
||||
void VectorImage::render(int width, int height) {
|
||||
double scaleX = (width == - 1) ? 1 : static_cast<double>(width) / static_cast<double>(getWidth());
|
||||
double scaleY = (height == - 1) ? 1 : static_cast<double>(height) / static_cast<double>(getHeight());
|
||||
|
||||
debug(3, "VectorImage::render(%d, %d) %s", width, height, _fname.c_str());
|
||||
|
||||
if (_pixelData)
|
||||
free(_pixelData);
|
||||
|
||||
_pixelData = (byte *)malloc(width * height * 4);
|
||||
memset(_pixelData, 0, width * height * 4);
|
||||
|
||||
for (uint e = 0; e < _elements.size(); e++) {
|
||||
|
||||
//// Draw shapes
|
||||
for (uint s = 0; s < _elements[e].getFillStyleCount(); s++) {
|
||||
int fill0len = 0;
|
||||
int fill1len = 0;
|
||||
|
||||
// Count vector sizes in order to minimize memory
|
||||
// fragmentation
|
||||
for (uint p = 0; p < _elements[e].getPathCount(); p++) {
|
||||
if (_elements[e].getPathInfo(p).getFillStyle0() == s + 1)
|
||||
fill0len += _elements[e].getPathInfo(p).getVecLen();
|
||||
|
||||
if (_elements[e].getPathInfo(p).getFillStyle1() == s + 1)
|
||||
fill1len += _elements[e].getPathInfo(p).getVecLen();
|
||||
}
|
||||
|
||||
// Now lump together vectors
|
||||
ArtBpath *fill1 = art_new(ArtBpath, fill1len + 1);
|
||||
ArtBpath *fill0 = art_new(ArtBpath, fill0len + 1);
|
||||
ArtBpath *fill1pos = fill1;
|
||||
ArtBpath *fill0pos = fill0;
|
||||
|
||||
for (uint p = 0; p < _elements[e].getPathCount(); p++) {
|
||||
if (_elements[e].getPathInfo(p).getFillStyle0() == s + 1) {
|
||||
for (int i = 0; i < _elements[e].getPathInfo(p).getVecLen(); i++)
|
||||
*fill0pos++ = _elements[e].getPathInfo(p).getVec()[i];
|
||||
}
|
||||
|
||||
if (_elements[e].getPathInfo(p).getFillStyle1() == s + 1) {
|
||||
for (int i = 0; i < _elements[e].getPathInfo(p).getVecLen(); i++)
|
||||
*fill1pos++ = _elements[e].getPathInfo(p).getVec()[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Close vectors
|
||||
(*fill0pos).code = ART_END;
|
||||
(*fill1pos).code = ART_END;
|
||||
|
||||
drawBez(fill1, fill0, _pixelData, width, height, _boundingBox.left, _boundingBox.top, scaleX, scaleY, -1, _elements[e].getFillStyleColor(s));
|
||||
|
||||
free(fill0);
|
||||
free(fill1);
|
||||
}
|
||||
|
||||
//// Draw strokes
|
||||
for (uint s = 0; s < _elements[e].getLineStyleCount(); s++) {
|
||||
double penWidth = _elements[e].getLineStyleWidth(s);
|
||||
penWidth *= sqrt(fabs(scaleX * scaleY));
|
||||
|
||||
for (uint p = 0; p < _elements[e].getPathCount(); p++) {
|
||||
if (_elements[e].getPathInfo(p).getLineStyle() == s + 1) {
|
||||
drawBez(_elements[e].getPathInfo(p).getVec(), 0, _pixelData, width, height, _boundingBox.left, _boundingBox.top, scaleX, scaleY, penWidth, _elements[e].getLineStyleColor(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Sword25
|
||||
159
engines/sword25/gfx/microtiles.cpp
Normal file
159
engines/sword25/gfx/microtiles.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/microtiles.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
MicroTileArray::MicroTileArray(int16 width, int16 height) {
|
||||
_tilesW = (width / TileSize) + ((width % TileSize) > 0 ? 1 : 0);
|
||||
_tilesH = (height / TileSize) + ((height % TileSize) > 0 ? 1 : 0);
|
||||
_tiles = new BoundingBox[_tilesW * _tilesH];
|
||||
clear();
|
||||
}
|
||||
|
||||
MicroTileArray::~MicroTileArray() {
|
||||
delete[] _tiles;
|
||||
}
|
||||
|
||||
void MicroTileArray::addRect(Common::Rect r) {
|
||||
|
||||
int ux0, uy0, ux1, uy1;
|
||||
int tx0, ty0, tx1, ty1;
|
||||
int ix0, iy0, ix1, iy1;
|
||||
|
||||
r.clip(Common::Rect(0, 0, 799, 599));
|
||||
|
||||
ux0 = r.left / TileSize;
|
||||
uy0 = r.top / TileSize;
|
||||
ux1 = r.right / TileSize;
|
||||
uy1 = r.bottom / TileSize;
|
||||
|
||||
tx0 = r.left % TileSize;
|
||||
ty0 = r.top % TileSize;
|
||||
tx1 = r.right % TileSize;
|
||||
ty1 = r.bottom % TileSize;
|
||||
|
||||
for (int yc = uy0; yc <= uy1; yc++) {
|
||||
for (int xc = ux0; xc <= ux1; xc++) {
|
||||
ix0 = (xc == ux0) ? tx0 : 0;
|
||||
ix1 = (xc == ux1) ? tx1 : TileSize - 1;
|
||||
iy0 = (yc == uy0) ? ty0 : 0;
|
||||
iy1 = (yc == uy1) ? ty1 : TileSize - 1;
|
||||
updateBoundingBox(_tiles[xc + yc * _tilesW], ix0, iy0, ix1, iy1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MicroTileArray::clear() {
|
||||
memset(_tiles, 0, _tilesW * _tilesH * sizeof(BoundingBox));
|
||||
}
|
||||
|
||||
byte MicroTileArray::TileX0(const BoundingBox &boundingBox) {
|
||||
return (boundingBox >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
byte MicroTileArray::TileY0(const BoundingBox &boundingBox) {
|
||||
return (boundingBox >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
byte MicroTileArray::TileX1(const BoundingBox &boundingBox) {
|
||||
return (boundingBox >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
byte MicroTileArray::TileY1(const BoundingBox &boundingBox) {
|
||||
return boundingBox & 0xFF;
|
||||
}
|
||||
|
||||
bool MicroTileArray::isBoundingBoxEmpty(const BoundingBox &boundingBox) {
|
||||
return boundingBox == EmptyBoundingBox;
|
||||
}
|
||||
|
||||
bool MicroTileArray::isBoundingBoxFull(const BoundingBox &boundingBox) {
|
||||
return boundingBox == FullBoundingBox;
|
||||
}
|
||||
|
||||
void MicroTileArray::setBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1) {
|
||||
boundingBox = (x0 << 24) | (y0 << 16) | (x1 << 8) | y1;
|
||||
}
|
||||
|
||||
void MicroTileArray::updateBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1) {
|
||||
if (!isBoundingBoxEmpty(boundingBox)) {
|
||||
x0 = MIN(TileX0(boundingBox), x0);
|
||||
y0 = MIN(TileY0(boundingBox), y0);
|
||||
x1 = MAX(TileX1(boundingBox), x1);
|
||||
y1 = MAX(TileY1(boundingBox), y1);
|
||||
}
|
||||
setBoundingBox(boundingBox, x0, y0, x1, y1);
|
||||
}
|
||||
|
||||
RectangleList *MicroTileArray::getRectangles() {
|
||||
|
||||
RectangleList *rects = new RectangleList();
|
||||
|
||||
int x, y;
|
||||
int x0, y0, x1, y1;
|
||||
int i = 0;
|
||||
|
||||
for (y = 0; y < _tilesH; ++y) {
|
||||
for (x = 0; x < _tilesW; ++x) {
|
||||
|
||||
int finish = 0;
|
||||
BoundingBox boundingBox = _tiles[i];
|
||||
|
||||
if (isBoundingBoxEmpty(boundingBox)) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
x0 = (x * TileSize) + TileX0(boundingBox);
|
||||
y0 = (y * TileSize) + TileY0(boundingBox);
|
||||
y1 = (y * TileSize) + TileY1(boundingBox);
|
||||
|
||||
if (TileX1(boundingBox) == TileSize - 1 && x != _tilesW - 1) { // check if the tile continues
|
||||
while (!finish) {
|
||||
++x;
|
||||
++i;
|
||||
if (x == _tilesW || i >= _tilesW * _tilesH ||
|
||||
TileY0(_tiles[i]) != TileY0(boundingBox) ||
|
||||
TileY1(_tiles[i]) != TileY1(boundingBox) ||
|
||||
TileX0(_tiles[i]) != 0)
|
||||
{
|
||||
--x;
|
||||
--i;
|
||||
finish = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x1 = (x * TileSize) + TileX1(_tiles[i]);
|
||||
|
||||
rects->push_back(Common::Rect(x0, y0, x1 + 1, y1 + 1));
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return rects;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
63
engines/sword25/gfx/microtiles.h
Normal file
63
engines/sword25/gfx/microtiles.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_MICROTILES_H
|
||||
#define SWORD25_MICROTILES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/list.h"
|
||||
#include "common/util.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
typedef uint32 BoundingBox;
|
||||
|
||||
const BoundingBox FullBoundingBox = 0x00001F1F;
|
||||
const BoundingBox EmptyBoundingBox = 0x00000000;
|
||||
const int TileSize = 32;
|
||||
|
||||
class RectangleList : public Common::List<Common::Rect> {
|
||||
};
|
||||
|
||||
class MicroTileArray {
|
||||
public:
|
||||
MicroTileArray(int16 width, int16 height);
|
||||
~MicroTileArray();
|
||||
void addRect(Common::Rect r);
|
||||
void clear();
|
||||
RectangleList *getRectangles();
|
||||
protected:
|
||||
BoundingBox *_tiles;
|
||||
int16 _tilesW, _tilesH;
|
||||
byte TileX0(const BoundingBox &boundingBox);
|
||||
byte TileY0(const BoundingBox &boundingBox);
|
||||
byte TileX1(const BoundingBox &boundingBox);
|
||||
byte TileY1(const BoundingBox &boundingBox);
|
||||
bool isBoundingBoxEmpty(const BoundingBox &boundingBox);
|
||||
bool isBoundingBoxFull(const BoundingBox &boundingBox);
|
||||
void setBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1);
|
||||
void updateBoundingBox(BoundingBox &boundingBox, byte x0, byte y0, byte x1, byte y1);
|
||||
};
|
||||
|
||||
} // namespace Sword25
|
||||
|
||||
#endif // SWORD25_MICROTILES_H
|
||||
115
engines/sword25/gfx/panel.cpp
Normal file
115
engines/sword25/gfx/panel.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/panel.h"
|
||||
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
#include "sword25/gfx/image/image.h"
|
||||
|
||||
#include "sword25/gfx/renderobjectmanager.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
Panel::Panel(RenderObjectPtr<RenderObject> parentPtr, int width, int height, uint color) :
|
||||
RenderObject(parentPtr, RenderObject::TYPE_PANEL),
|
||||
_color(color) {
|
||||
_initSuccess = false;
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
if (_width < 0) {
|
||||
error("Tried to initialize a panel with an invalid width (%d).", _width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_height < 0) {
|
||||
error("Tried to initialize a panel with an invalid height (%d).", _height);
|
||||
return;
|
||||
}
|
||||
|
||||
_initSuccess = true;
|
||||
}
|
||||
|
||||
Panel::Panel(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
|
||||
RenderObject(parentPtr, RenderObject::TYPE_PANEL, handle), _color(0) {
|
||||
_initSuccess = unpersist(reader);
|
||||
}
|
||||
|
||||
Panel::~Panel() {
|
||||
}
|
||||
|
||||
bool Panel::doRender(RectangleList *updateRects) {
|
||||
// Falls der Alphawert 0 ist, ist das Panel komplett durchsichtig und es muss nichts gezeichnet werden.
|
||||
if (_color >> BS_ASHIFT == 0)
|
||||
return true;
|
||||
|
||||
GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
|
||||
assert(gfxPtr);
|
||||
|
||||
for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) {
|
||||
const Common::Rect &clipRect = *it;
|
||||
if (_bbox.intersects(clipRect)) {
|
||||
Common::Rect intersectionRect = _bbox.findIntersectingRect(clipRect);
|
||||
gfxPtr->fill(&intersectionRect, _color);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Panel::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::persist(writer);
|
||||
writer.write(_color);
|
||||
|
||||
result &= RenderObject::persistChildren(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Panel::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::unpersist(reader);
|
||||
|
||||
uint32 color;
|
||||
reader.read(color);
|
||||
setColor(color);
|
||||
|
||||
result &= RenderObject::unpersistChildren(reader);
|
||||
|
||||
return reader.isGood() && result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
71
engines/sword25/gfx/panel.h
Normal file
71
engines/sword25/gfx/panel.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_PANEL_H
|
||||
#define SWORD25_PANEL_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Panel : public RenderObject {
|
||||
friend class RenderObject;
|
||||
|
||||
private:
|
||||
Panel(RenderObjectPtr<RenderObject> parentPtr, int width, int height, uint color);
|
||||
Panel(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle);
|
||||
|
||||
public:
|
||||
~Panel() override;
|
||||
|
||||
uint getColor() const {
|
||||
return _color;
|
||||
}
|
||||
void setColor(uint color) {
|
||||
if (_color != color) {
|
||||
_color = color;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
protected:
|
||||
bool doRender(RectangleList *updateRects) override;
|
||||
|
||||
private:
|
||||
uint32 _color;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
542
engines/sword25/gfx/renderobject.cpp
Normal file
542
engines/sword25/gfx/renderobject.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
|
||||
#include "sword25/gfx/renderobjectregistry.h"
|
||||
#include "sword25/gfx/renderobjectmanager.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
|
||||
#include "sword25/gfx/bitmap.h"
|
||||
#include "sword25/gfx/staticbitmap.h"
|
||||
#include "sword25/gfx/dynamicbitmap.h"
|
||||
#include "sword25/gfx/animation.h"
|
||||
#include "sword25/gfx/panel.h"
|
||||
#include "sword25/gfx/text.h"
|
||||
#include "sword25/gfx/animationtemplate.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
int RenderObject::_nextGlobalVersion = 0;
|
||||
|
||||
RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type, uint handle) :
|
||||
_managerPtr(0),
|
||||
_parentPtr(parentPtr),
|
||||
_x(0),
|
||||
_y(0),
|
||||
_z(0),
|
||||
_oldX(-1),
|
||||
_oldY(-1),
|
||||
_oldZ(-1),
|
||||
_width(0),
|
||||
_height(0),
|
||||
_visible(true),
|
||||
_oldVisible(false),
|
||||
_childChanged(true),
|
||||
_type(type),
|
||||
_initSuccess(false),
|
||||
_refreshForced(true),
|
||||
_handle(0),
|
||||
_version(++_nextGlobalVersion),
|
||||
_isSolid(false) {
|
||||
|
||||
if (handle == 0)
|
||||
_handle = RenderObjectRegistry::instance().registerObject(this);
|
||||
else
|
||||
_handle = RenderObjectRegistry::instance().registerObject(this, handle);
|
||||
|
||||
if (_handle == 0)
|
||||
error("Failed to initialize RenderObject()");
|
||||
|
||||
updateAbsolutePos();
|
||||
|
||||
// Add this item to the children of the parent object, if not root (ParentPtr is invalid),
|
||||
// assign to the same RenderObjectManager.
|
||||
if (_parentPtr.isValid()) {
|
||||
_managerPtr = _parentPtr->getManager();
|
||||
_parentPtr->addObject(this->getHandle());
|
||||
} else {
|
||||
if (getType() != TYPE_ROOT) {
|
||||
error("Tried to create a non-root render object and has no parent. All non-root render objects have to have a parent.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
updateObjectState();
|
||||
|
||||
_initSuccess = true;
|
||||
}
|
||||
|
||||
RenderObject::~RenderObject() {
|
||||
// Remove object from its parent.
|
||||
if (_parentPtr.isValid())
|
||||
_parentPtr->detatchChildren(this->getHandle());
|
||||
|
||||
deleteAllChildren();
|
||||
|
||||
RenderObjectRegistry::instance().deregisterObject(this);
|
||||
}
|
||||
|
||||
void RenderObject::preRender(RenderObjectQueue *renderQueue) {
|
||||
validateObject();
|
||||
|
||||
if (!_visible)
|
||||
return;
|
||||
|
||||
// If necessary, update the children rendering order of the updated objects.
|
||||
if (_childChanged) {
|
||||
sortRenderObjects();
|
||||
_childChanged = false;
|
||||
}
|
||||
|
||||
renderQueue->add(this);
|
||||
|
||||
RENDEROBJECT_ITER it = _children.begin();
|
||||
for (; it != _children.end(); ++it)
|
||||
(*it)->preRender(renderQueue);
|
||||
|
||||
}
|
||||
|
||||
bool RenderObject::render(RectangleList *updateRects, const Common::Array<int> &updateRectsMinZ) {
|
||||
|
||||
// Falls das Objekt nicht sichtbar ist, muss gar nichts gezeichnet werden
|
||||
if (!_visible)
|
||||
return true;
|
||||
|
||||
// Objekt zeichnen.
|
||||
bool needRender = false;
|
||||
int index = 0;
|
||||
|
||||
// Only draw if the bounding box intersects any update rectangle and
|
||||
// the object is in front of the minimum Z value.
|
||||
for (RectangleList::iterator rectIt = updateRects->begin(); !needRender && rectIt != updateRects->end(); ++rectIt, ++index)
|
||||
needRender = (_bbox.contains(*rectIt) || _bbox.intersects(*rectIt)) && getAbsoluteZ() >= updateRectsMinZ[index];
|
||||
|
||||
if (needRender)
|
||||
doRender(updateRects);
|
||||
|
||||
// Draw all children
|
||||
RENDEROBJECT_ITER it = _children.begin();
|
||||
for (; it != _children.end(); ++it)
|
||||
if (!(*it)->render(updateRects, updateRectsMinZ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderObject::validateObject() {
|
||||
_oldBbox = _bbox;
|
||||
_oldVisible = _visible;
|
||||
_oldX = _x;
|
||||
_oldY = _y;
|
||||
_oldZ = _z;
|
||||
_refreshForced = false;
|
||||
}
|
||||
|
||||
bool RenderObject::updateObjectState() {
|
||||
// If the object has changed, the internal state must be recalculated and possibly
|
||||
// update Regions be registered for the next frame.
|
||||
if ((calcBoundingBox() != _oldBbox) ||
|
||||
(_visible != _oldVisible) ||
|
||||
(_x != _oldX) ||
|
||||
(_y != _oldY) ||
|
||||
(_z != _oldZ) ||
|
||||
_refreshForced) {
|
||||
if (_parentPtr.isValid())
|
||||
_parentPtr->signalChildChange();
|
||||
|
||||
// Die Bounding-Box neu berechnen und Update-Regions registrieren.
|
||||
updateBoxes();
|
||||
|
||||
++_version;
|
||||
|
||||
// Änderungen Validieren
|
||||
validateObject();
|
||||
}
|
||||
|
||||
// Dann muss der Objektstatus der Kinder aktualisiert werden.
|
||||
RENDEROBJECT_ITER it = _children.begin();
|
||||
for (; it != _children.end(); ++it)
|
||||
if (!(*it)->updateObjectState())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderObject::updateBoxes() {
|
||||
_bbox = calcBoundingBox();
|
||||
}
|
||||
|
||||
Common::Rect RenderObject::calcBoundingBox() const {
|
||||
Common::Rect bbox(0, 0, _width, _height);
|
||||
|
||||
// Die absolute Position der Bounding-Box berechnen.
|
||||
bbox.translate(_absoluteX, _absoluteY);
|
||||
|
||||
// Die Bounding-Box am Elternobjekt clippen.
|
||||
if (_parentPtr.isValid()) {
|
||||
bbox.clip(_parentPtr->getBbox());
|
||||
}
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
void RenderObject::calcAbsolutePos(int32 &x, int32 &y, int32 &z) const {
|
||||
x = calcAbsoluteX();
|
||||
y = calcAbsoluteY();
|
||||
z = calcAbsoluteZ();
|
||||
}
|
||||
|
||||
int32 RenderObject::calcAbsoluteX() const {
|
||||
if (_parentPtr.isValid())
|
||||
return _parentPtr->getAbsoluteX() + _x;
|
||||
else
|
||||
return _x;
|
||||
}
|
||||
|
||||
int32 RenderObject::calcAbsoluteY() const {
|
||||
if (_parentPtr.isValid())
|
||||
return _parentPtr->getAbsoluteY() + _y;
|
||||
else
|
||||
return _y;
|
||||
}
|
||||
|
||||
int32 RenderObject::calcAbsoluteZ() const {
|
||||
if (_parentPtr.isValid())
|
||||
return _parentPtr->getAbsoluteZ() + _z;
|
||||
else
|
||||
return _z;
|
||||
}
|
||||
|
||||
void RenderObject::deleteAllChildren() {
|
||||
while (!_children.empty()) {
|
||||
RenderObjectPtr<RenderObject> curPtr = _children.back();
|
||||
curPtr.erase();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderObject::addObject(RenderObjectPtr<RenderObject> pObject) {
|
||||
if (!pObject.isValid()) {
|
||||
error("Tried to add a null object to a renderobject.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert Object in the children list.
|
||||
_children.push_back(pObject);
|
||||
|
||||
// Make sure that before the next render the channel order is updated.
|
||||
if (_parentPtr.isValid())
|
||||
_parentPtr->signalChildChange();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderObject::detatchChildren(RenderObjectPtr<RenderObject> pObject) {
|
||||
// Kinderliste durchgehen und Objekt entfernen falls vorhanden
|
||||
RENDEROBJECT_ITER it = _children.begin();
|
||||
for (; it != _children.end(); ++it)
|
||||
if (*it == pObject) {
|
||||
_children.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
error("Tried to detach children from a render object that isn't its parent.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderObject::sortRenderObjects() {
|
||||
Common::sort(_children.begin(), _children.end(), greater);
|
||||
}
|
||||
|
||||
void RenderObject::updateAbsolutePos() {
|
||||
calcAbsolutePos(_absoluteX, _absoluteY, _absoluteZ);
|
||||
|
||||
RENDEROBJECT_ITER it = _children.begin();
|
||||
for (; it != _children.end(); ++it)
|
||||
(*it)->updateAbsolutePos();
|
||||
}
|
||||
|
||||
bool RenderObject::getObjectIntersection(RenderObjectPtr<RenderObject> pObject, Common::Rect &result) {
|
||||
result = pObject->getBbox();
|
||||
result.clip(_bbox);
|
||||
return result.isValidRect();
|
||||
}
|
||||
|
||||
void RenderObject::setPos(int x, int y) {
|
||||
_x = x;
|
||||
_y = y;
|
||||
updateAbsolutePos();
|
||||
}
|
||||
|
||||
void RenderObject::setX(int x) {
|
||||
_x = x;
|
||||
updateAbsolutePos();
|
||||
}
|
||||
|
||||
void RenderObject::setY(int y) {
|
||||
_y = y;
|
||||
updateAbsolutePos();
|
||||
}
|
||||
|
||||
void RenderObject::setZ(int z) {
|
||||
if (z < 0)
|
||||
error("Tried to set a negative Z value (%d).", z);
|
||||
else {
|
||||
_z = z;
|
||||
updateAbsolutePos();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderObject::setVisible(bool visible) {
|
||||
_visible = visible;
|
||||
}
|
||||
|
||||
RenderObjectPtr<Animation> RenderObject::addAnimation(const Common::String &filename) {
|
||||
RenderObjectPtr<Animation> aniPtr((new Animation(this->getHandle(), filename))->getHandle());
|
||||
if (aniPtr.isValid() && aniPtr->getInitSuccess())
|
||||
return aniPtr;
|
||||
else {
|
||||
if (aniPtr.isValid())
|
||||
aniPtr.erase();
|
||||
return RenderObjectPtr<Animation>();
|
||||
}
|
||||
}
|
||||
|
||||
RenderObjectPtr<Animation> RenderObject::addAnimation(const AnimationTemplate &animationTemplate) {
|
||||
Animation *aniPtr = new Animation(this->getHandle(), animationTemplate);
|
||||
if (aniPtr && aniPtr->getInitSuccess())
|
||||
return aniPtr->getHandle();
|
||||
else {
|
||||
delete aniPtr;
|
||||
return RenderObjectPtr<Animation>();
|
||||
}
|
||||
}
|
||||
|
||||
RenderObjectPtr<Bitmap> RenderObject::addBitmap(const Common::String &filename) {
|
||||
RenderObjectPtr<Bitmap> bitmapPtr((new StaticBitmap(this->getHandle(), filename))->getHandle());
|
||||
if (bitmapPtr.isValid() && bitmapPtr->getInitSuccess())
|
||||
return RenderObjectPtr<Bitmap>(bitmapPtr);
|
||||
else {
|
||||
if (bitmapPtr.isValid())
|
||||
bitmapPtr.erase();
|
||||
return RenderObjectPtr<Bitmap>();
|
||||
}
|
||||
}
|
||||
|
||||
RenderObjectPtr<Bitmap> RenderObject::addDynamicBitmap(uint width, uint height) {
|
||||
RenderObjectPtr<Bitmap> bitmapPtr((new DynamicBitmap(this->getHandle(), width, height))->getHandle());
|
||||
if (bitmapPtr.isValid() && bitmapPtr->getInitSuccess())
|
||||
return bitmapPtr;
|
||||
else {
|
||||
if (bitmapPtr.isValid())
|
||||
bitmapPtr.erase();
|
||||
return RenderObjectPtr<Bitmap>();
|
||||
}
|
||||
}
|
||||
|
||||
RenderObjectPtr<Panel> RenderObject::addPanel(int width, int height, uint color) {
|
||||
RenderObjectPtr<Panel> panelPtr((new Panel(this->getHandle(), width, height, color))->getHandle());
|
||||
if (panelPtr.isValid() && panelPtr->getInitSuccess())
|
||||
return panelPtr;
|
||||
else {
|
||||
if (panelPtr.isValid())
|
||||
panelPtr.erase();
|
||||
return RenderObjectPtr<Panel>();
|
||||
}
|
||||
}
|
||||
|
||||
RenderObjectPtr<Text> RenderObject::addText(const Common::String &font, const Common::String &text) {
|
||||
RenderObjectPtr<Text> textPtr((new Text(this->getHandle()))->getHandle());
|
||||
if (textPtr.isValid() && textPtr->getInitSuccess() && textPtr->setFont(font)) {
|
||||
textPtr->setText(text);
|
||||
return textPtr;
|
||||
} else {
|
||||
if (textPtr.isValid())
|
||||
textPtr.erase();
|
||||
return RenderObjectPtr<Text>();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderObject::persist(OutputPersistenceBlock &writer) {
|
||||
// Typ und Handle werden als erstes gespeichert, damit beim Laden ein Objekt vom richtigen Typ mit dem richtigen Handle erzeugt werden kann.
|
||||
writer.write(static_cast<uint32>(_type));
|
||||
writer.write(_handle);
|
||||
|
||||
// Restliche Objekteigenschaften speichern.
|
||||
writer.write(_x);
|
||||
writer.write(_y);
|
||||
writer.write(_absoluteX);
|
||||
writer.write(_absoluteY);
|
||||
writer.write(_z);
|
||||
writer.write(_width);
|
||||
writer.write(_height);
|
||||
writer.write(_visible);
|
||||
writer.write(_childChanged);
|
||||
writer.write(_initSuccess);
|
||||
writer.write((int32)_bbox.left);
|
||||
writer.write((int32)_bbox.top);
|
||||
writer.write((int32)_bbox.right);
|
||||
writer.write((int32)_bbox.bottom);
|
||||
writer.write((int32)_oldBbox.left);
|
||||
writer.write((int32)_oldBbox.top);
|
||||
writer.write((int32)_oldBbox.right);
|
||||
writer.write((int32)_oldBbox.bottom);
|
||||
writer.write(_oldX);
|
||||
writer.write(_oldY);
|
||||
writer.write(_oldZ);
|
||||
writer.write(_oldVisible);
|
||||
writer.write(_parentPtr.isValid() ? _parentPtr->getHandle() : 0);
|
||||
writer.write(_refreshForced);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderObject::unpersist(InputPersistenceBlock &reader) {
|
||||
// Typ und Handle wurden schon von RecreatePersistedRenderObject() ausgelesen. Jetzt werden die restlichen Objekteigenschaften ausgelesen.
|
||||
reader.read(_x);
|
||||
reader.read(_y);
|
||||
reader.read(_absoluteX);
|
||||
reader.read(_absoluteY);
|
||||
reader.read(_z);
|
||||
reader.read(_width);
|
||||
reader.read(_height);
|
||||
reader.read(_visible);
|
||||
reader.read(_childChanged);
|
||||
reader.read(_initSuccess);
|
||||
reader.read(_bbox.left);
|
||||
reader.read(_bbox.top);
|
||||
reader.read(_bbox.right);
|
||||
reader.read(_bbox.bottom);
|
||||
reader.read(_oldBbox.left);
|
||||
reader.read(_oldBbox.top);
|
||||
reader.read(_oldBbox.right);
|
||||
reader.read(_oldBbox.bottom);
|
||||
reader.read(_oldX);
|
||||
reader.read(_oldY);
|
||||
reader.read(_oldZ);
|
||||
reader.read(_oldVisible);
|
||||
uint32 parentHandle;
|
||||
reader.read(parentHandle);
|
||||
_parentPtr = RenderObjectPtr<RenderObject>(parentHandle);
|
||||
reader.read(_refreshForced);
|
||||
|
||||
updateAbsolutePos();
|
||||
updateObjectState();
|
||||
|
||||
return reader.isGood();
|
||||
}
|
||||
|
||||
bool RenderObject::persistChildren(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
// Kinderanzahl speichern.
|
||||
writer.write((uint32)_children.size());
|
||||
|
||||
// Rekursiv alle Kinder speichern.
|
||||
RENDEROBJECT_LIST::iterator it = _children.begin();
|
||||
while (it != _children.end()) {
|
||||
result &= (*it)->persist(writer);
|
||||
++it;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RenderObject::unpersistChildren(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
// Kinderanzahl einlesen.
|
||||
uint32 childrenCount;
|
||||
reader.read(childrenCount);
|
||||
if (!reader.isGood())
|
||||
return false;
|
||||
|
||||
// Alle Kinder rekursiv wieder herstellen.
|
||||
for (uint32 i = 0; i < childrenCount; ++i) {
|
||||
if (!recreatePersistedRenderObject(reader).isValid())
|
||||
return false;
|
||||
}
|
||||
|
||||
return result && reader.isGood();
|
||||
}
|
||||
|
||||
RenderObjectPtr<RenderObject> RenderObject::recreatePersistedRenderObject(InputPersistenceBlock &reader) {
|
||||
RenderObjectPtr<RenderObject> result;
|
||||
|
||||
// Typ und Handle auslesen.
|
||||
uint32 type;
|
||||
uint32 handle;
|
||||
reader.read(type);
|
||||
reader.read(handle);
|
||||
if (!reader.isGood())
|
||||
return result;
|
||||
|
||||
switch (type) {
|
||||
case TYPE_PANEL:
|
||||
result = (new Panel(reader, this->getHandle(), handle))->getHandle();
|
||||
break;
|
||||
|
||||
case TYPE_STATICBITMAP:
|
||||
result = (new StaticBitmap(reader, this->getHandle(), handle))->getHandle();
|
||||
break;
|
||||
|
||||
case TYPE_DYNAMICBITMAP:
|
||||
// Videos are not normally saved: this probably indicates a bug, thus die here.
|
||||
//result = (new DynamicBitmap(reader, this->getHandle(), handle))->getHandle();
|
||||
error("Request to recreate a video. This is either a corrupted saved game, or a bug");
|
||||
break;
|
||||
|
||||
case TYPE_TEXT:
|
||||
result = (new Text(reader, this->getHandle(), handle))->getHandle();
|
||||
break;
|
||||
|
||||
case TYPE_ANIMATION:
|
||||
result = (new Animation(reader, this->getHandle(), handle))->getHandle();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Cannot recreate render object of unknown type %d.", type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RenderObject::greater(const RenderObjectPtr<RenderObject> lhs, const RenderObjectPtr<RenderObject> rhs) {
|
||||
// Das Objekt mit dem kleinem Z-Wert müssen zuerst gerendert werden.
|
||||
if (lhs->_z != rhs->_z)
|
||||
return lhs->_z < rhs->_z;
|
||||
// Falls der Z-Wert gleich ist, wird das weiter oben gelegenen Objekte zuerst gezeichnet.
|
||||
return lhs->_y < rhs->_y;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
553
engines/sword25/gfx/renderobject.h
Normal file
553
engines/sword25/gfx/renderobject.h
Normal file
@@ -0,0 +1,553 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
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 SWORD25_RENDEROBJECT_H
|
||||
#define SWORD25_RENDEROBJECT_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
#include "common/rect.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
#include "sword25/gfx/renderobjectptr.h"
|
||||
|
||||
#include "common/list.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Kernel;
|
||||
class RenderObjectManager;
|
||||
class RenderObjectQueue;
|
||||
class RectangleList;
|
||||
class Bitmap;
|
||||
class Animation;
|
||||
class AnimationTemplate;
|
||||
class Panel;
|
||||
class 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 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.
|
||||
*/
|
||||
RenderObjectPtr<Bitmap> addBitmap(const Common::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.
|
||||
*/
|
||||
RenderObjectPtr<Bitmap> addDynamicBitmap(uint width, uint 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.
|
||||
*/
|
||||
RenderObjectPtr<Animation> addAnimation(const Common::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.
|
||||
*/
|
||||
RenderObjectPtr<Animation> addAnimation(const 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.
|
||||
*/
|
||||
|
||||
RenderObjectPtr<Panel> addPanel(int width, int height, uint color = BS_RGB(0, 0, 0));
|
||||
/**
|
||||
@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.
|
||||
*/
|
||||
RenderObjectPtr<Text> addText(const Common::String &font, const Common::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.
|
||||
*/
|
||||
RenderObjectPtr<Bitmap> toBitmap() {
|
||||
if (_type == TYPE_STATICBITMAP || _type == TYPE_DYNAMICBITMAP)
|
||||
return RenderObjectPtr<Bitmap>(this->getHandle());
|
||||
else
|
||||
return RenderObjectPtr<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.
|
||||
*/
|
||||
RenderObjectPtr<Animation> toAnimation() {
|
||||
if (_type == TYPE_ANIMATION)
|
||||
return RenderObjectPtr<Animation>(this->getHandle());
|
||||
else
|
||||
return RenderObjectPtr<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.
|
||||
*/
|
||||
RenderObjectPtr<Panel> toPanel() {
|
||||
if (_type == TYPE_PANEL)
|
||||
return RenderObjectPtr<Panel>(this->getHandle());
|
||||
else
|
||||
return RenderObjectPtr<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.
|
||||
*/
|
||||
RenderObjectPtr<Text> toText() {
|
||||
if (_type == TYPE_TEXT)
|
||||
return RenderObjectPtr<Text>(this->getHandle());
|
||||
else
|
||||
return RenderObjectPtr<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.
|
||||
*/
|
||||
RenderObject(RenderObjectPtr<RenderObject> pParent, TYPES type, uint handle = 0);
|
||||
virtual ~RenderObject();
|
||||
|
||||
// Interface
|
||||
// ---------
|
||||
|
||||
void preRender(RenderObjectQueue *renderQueue);
|
||||
|
||||
/**
|
||||
@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(RectangleList *updateRects, const Common::Array<int> &updateRectsMinZ);
|
||||
|
||||
/**
|
||||
@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 _x;
|
||||
}
|
||||
/**
|
||||
@brief Gibt die Position des Objektes auf der Y-Achse relativ zum Elternobjekt zurück.
|
||||
*/
|
||||
virtual int getY() const {
|
||||
return _y;
|
||||
}
|
||||
/**
|
||||
@brief Gibt die absolute Position des Objektes auf der X-Achse zurück.
|
||||
*/
|
||||
virtual int getAbsoluteX() const {
|
||||
return _absoluteX;
|
||||
}
|
||||
/**
|
||||
@brief Gibt die absolute Position des Objektes auf der Y-Achse zurück.
|
||||
*/
|
||||
virtual int getAbsoluteY() const {
|
||||
return _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 _z;
|
||||
}
|
||||
|
||||
int getAbsoluteZ() const {
|
||||
return _absoluteZ;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt die Breite des Objektes zurück.
|
||||
*/
|
||||
int getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
/**
|
||||
@brief Gibt die Höhe des Objektes zurück.
|
||||
*/
|
||||
int getHeight() const {
|
||||
return _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 _visible;
|
||||
}
|
||||
/**
|
||||
@brief Gibt den Typ des Objektes zurück.
|
||||
*/
|
||||
TYPES getType() const {
|
||||
return _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 _initSuccess;
|
||||
}
|
||||
/**
|
||||
@brief Gibt die Bounding-Box des Objektes zurück.
|
||||
@remark Diese Angabe erfolgt ausnahmsweise in Bildschirmkoordianten und nicht relativ zum Elternobjekt.
|
||||
*/
|
||||
const Common::Rect &getBbox() const {
|
||||
return _bbox;
|
||||
}
|
||||
/**
|
||||
@brief Stellt sicher, dass das Objekt im nächsten Frame neu gezeichnet wird.
|
||||
*/
|
||||
void forceRefresh() {
|
||||
_refreshForced = true;
|
||||
}
|
||||
/**
|
||||
@brief Gibt das Handle des Objekte zurück.
|
||||
*/
|
||||
uint32 getHandle() const {
|
||||
return _handle;
|
||||
}
|
||||
|
||||
// Get the RenderObjects current version
|
||||
int getVersion() const {
|
||||
return _version;
|
||||
}
|
||||
|
||||
bool isSolid() const {
|
||||
return _isSolid;
|
||||
}
|
||||
|
||||
// Persistenz-Methoden
|
||||
// -------------------
|
||||
virtual bool persist(OutputPersistenceBlock &writer);
|
||||
virtual bool unpersist(InputPersistenceBlock &reader);
|
||||
// TODO: Evtl. protected
|
||||
bool persistChildren(OutputPersistenceBlock &writer);
|
||||
bool unpersistChildren(InputPersistenceBlock &reader);
|
||||
// TODO: Evtl. private
|
||||
RenderObjectPtr<RenderObject> recreatePersistedRenderObject(InputPersistenceBlock &reader);
|
||||
|
||||
protected:
|
||||
// Typen
|
||||
// -----
|
||||
typedef Common::List<RenderObjectPtr<RenderObject> > RENDEROBJECT_LIST;
|
||||
typedef Common::List<RenderObjectPtr<RenderObject> >::iterator RENDEROBJECT_ITER;
|
||||
|
||||
int32 _x; ///< Die X-Position des Objektes relativ zum Eltern-Objekt
|
||||
int32 _y; ///< Die Y-Position des Objektes relativ zum Eltern-Objekt
|
||||
int32 _z; ///< Der Z-Wert des Objektes relativ zum Eltern-Objekt
|
||||
int32 _absoluteX; ///< Die absolute X-Position des Objektes
|
||||
int32 _absoluteY; ///< Die absolute Y-Position des Objektes
|
||||
int32 _absoluteZ;
|
||||
int32 _width; ///< Die Breite des Objektes
|
||||
int32 _height; ///< Die Höhe des Objektes
|
||||
bool _visible; ///< Ist true, wenn das Objekt sichtbar ist
|
||||
bool _childChanged; ///< Ist true, wenn sich ein Kinderobjekt verändert hat
|
||||
TYPES _type; ///< Der Objekttyp
|
||||
bool _initSuccess; ///< Ist true, wenn Objekt erfolgreich intialisiert werden konnte
|
||||
Common::Rect _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
|
||||
Common::Rect _oldBbox;
|
||||
int32 _oldX;
|
||||
int32 _oldY;
|
||||
int32 _oldZ;
|
||||
bool _oldVisible;
|
||||
|
||||
static int _nextGlobalVersion;
|
||||
|
||||
int32 _version;
|
||||
|
||||
// This should be set to true if the RenderObject is NOT alpha-blended to optimize drawing
|
||||
bool _isSolid;
|
||||
|
||||
/// Ein Pointer auf den BS_RenderObjektManager, der das Objekt verwaltet.
|
||||
RenderObjectManager *_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(RectangleList *updateRects) = 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.
|
||||
RenderObjectPtr<RenderObject> _parentPtr;
|
||||
/// Die Liste der Kinderobjekte nach der Renderreihenfolge geordnet
|
||||
RENDEROBJECT_LIST _children;
|
||||
|
||||
/**
|
||||
@brief Gibt einen Pointer auf den BS_RenderObjektManager zurück, der das Objekt verwaltet.
|
||||
*/
|
||||
RenderObjectManager *getManager() const {
|
||||
return _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(RenderObjectPtr<RenderObject> pObject);
|
||||
|
||||
private:
|
||||
/// Ist true, wenn das Objekt in nächsten Frame neu gezeichnet werden soll
|
||||
bool _refreshForced;
|
||||
|
||||
uint32 _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(RenderObjectPtr<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.
|
||||
*/
|
||||
Common::Rect calcBoundingBox() const;
|
||||
/**
|
||||
@brief Berechnet das Dirty-Rectangle des Objektes.
|
||||
@return Gibt das Dirty-Rectangle des Objektes in Bildschirmkoordinaten zurück.
|
||||
*/
|
||||
Common::Rect calcDirtyRect() const;
|
||||
/**
|
||||
@brief Berechnet die absolute Position des Objektes.
|
||||
*/
|
||||
void calcAbsolutePos(int32 &x, int32 &y, int32 &z) const;
|
||||
/**
|
||||
@brief Berechnet die absolute Position des Objektes auf der X-Achse.
|
||||
*/
|
||||
int32 calcAbsoluteX() const;
|
||||
/**
|
||||
@brief Berechnet die absolute Position des Objektes.
|
||||
*/
|
||||
int32 calcAbsoluteY() const;
|
||||
|
||||
int32 calcAbsoluteZ() 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() {
|
||||
_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(RenderObjectPtr<RenderObject> pObject, Common::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 RenderObjectPtr<RenderObject> lhs, const RenderObjectPtr<RenderObject> rhs);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
220
engines/sword25/gfx/renderobjectmanager.cpp
Normal file
220
engines/sword25/gfx/renderobjectmanager.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/renderobjectmanager.h"
|
||||
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/gfx/graphicengine.h"
|
||||
#include "sword25/gfx/animationtemplateregistry.h"
|
||||
#include "common/rect.h"
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
#include "sword25/gfx/timedrenderobject.h"
|
||||
#include "sword25/gfx/rootrenderobject.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
void RenderObjectQueue::add(RenderObject *renderObject) {
|
||||
push_back(RenderObjectQueueItem(renderObject, renderObject->getBbox(), renderObject->getVersion()));
|
||||
}
|
||||
|
||||
bool RenderObjectQueue::exists(const RenderObjectQueueItem &renderObjectQueueItem) {
|
||||
for (RenderObjectQueue::iterator it = begin(); it != end(); ++it)
|
||||
if ((*it)._renderObject == renderObjectQueueItem._renderObject &&
|
||||
(*it)._version == renderObjectQueueItem._version &&
|
||||
(*it)._bbox == renderObjectQueueItem._bbox)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderObjectManager::RenderObjectManager(int width, int height, int framebufferCount) :
|
||||
_frameStarted(false) {
|
||||
// Wurzel des BS_RenderObject-Baumes erzeugen.
|
||||
_rootPtr = (new RootRenderObject(this, width, height))->getHandle();
|
||||
_uta = new MicroTileArray(width, height);
|
||||
_currQueue = new RenderObjectQueue();
|
||||
_prevQueue = new RenderObjectQueue();
|
||||
}
|
||||
|
||||
RenderObjectManager::~RenderObjectManager() {
|
||||
// Die Wurzel des Baumes löschen, damit werden alle BS_RenderObjects mitgelöscht.
|
||||
_rootPtr.erase();
|
||||
delete _uta;
|
||||
delete _currQueue;
|
||||
delete _prevQueue;
|
||||
}
|
||||
|
||||
void RenderObjectManager::startFrame() {
|
||||
_frameStarted = true;
|
||||
|
||||
// Verstrichene Zeit bestimmen
|
||||
int timeElapsed = Kernel::getInstance()->getGfx()->getLastFrameDurationMicro();
|
||||
|
||||
// Alle BS_TimedRenderObject Objekte über den Framestart und die verstrichene Zeit in Kenntnis setzen
|
||||
RenderObjectList::iterator iter = _timedRenderObjects.begin();
|
||||
for (; iter != _timedRenderObjects.end(); ++iter)
|
||||
(*iter)->frameNotification(timeElapsed);
|
||||
}
|
||||
|
||||
bool 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 (!_rootPtr.isValid() || !_rootPtr->updateObjectState())
|
||||
return false;
|
||||
|
||||
_frameStarted = false;
|
||||
|
||||
// Die Render-Methode der Wurzel aufrufen. Dadurch wird das rekursive Rendern der Baumelemente angestoßen.
|
||||
|
||||
_currQueue->clear();
|
||||
_rootPtr->preRender(_currQueue);
|
||||
|
||||
_uta->clear();
|
||||
|
||||
// Add rectangles of objects which don't exist in this frame any more
|
||||
for (RenderObjectQueue::iterator it = _prevQueue->begin(); it != _prevQueue->end(); ++it) {
|
||||
if (!_currQueue->exists(*it))
|
||||
_uta->addRect((*it)._bbox);
|
||||
}
|
||||
|
||||
// Add rectangles of objects which are different from the previous frame
|
||||
for (RenderObjectQueue::iterator it = _currQueue->begin(); it != _currQueue->end(); ++it) {
|
||||
if (!_prevQueue->exists(*it))
|
||||
_uta->addRect((*it)._bbox);
|
||||
}
|
||||
|
||||
RectangleList *updateRects = _uta->getRectangles();
|
||||
Common::Array<int> updateRectsMinZ;
|
||||
|
||||
updateRectsMinZ.reserve(updateRects->size());
|
||||
|
||||
// Calculate the minimum drawing Z value of each update rectangle
|
||||
// Solid bitmaps with a Z order less than the value calculated here would be overdrawn again and
|
||||
// so don't need to be drawn in the first place which speeds things up a bit.
|
||||
for (RectangleList::iterator rectIt = updateRects->begin(); rectIt != updateRects->end(); ++rectIt) {
|
||||
int minZ = 0;
|
||||
for (RenderObjectQueue::iterator it = _currQueue->reverse_begin(); it != _currQueue->end(); --it) {
|
||||
if ((*it)._renderObject->isVisible() && (*it)._renderObject->isSolid() &&
|
||||
(*it)._renderObject->getBbox().contains(*rectIt)) {
|
||||
minZ = (*it)._renderObject->getAbsoluteZ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateRectsMinZ.push_back(minZ);
|
||||
}
|
||||
|
||||
if (_rootPtr->render(updateRects, updateRectsMinZ)) {
|
||||
// Copy updated rectangles to the video screen
|
||||
Graphics::ManagedSurface *backSurface = Kernel::getInstance()->getGfx()->getSurface();
|
||||
for (RectangleList::iterator rectIt = updateRects->begin(); rectIt != updateRects->end(); ++rectIt) {
|
||||
const int x = (*rectIt).left;
|
||||
const int y = (*rectIt).top;
|
||||
const int width = (*rectIt).width();
|
||||
const int height = (*rectIt).height();
|
||||
g_system->copyRectToScreen(backSurface->getBasePtr(x, y), backSurface->pitch, x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
delete updateRects;
|
||||
|
||||
SWAP(_currQueue, _prevQueue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderObjectManager::attatchTimedRenderObject(RenderObjectPtr<TimedRenderObject> renderObjectPtr) {
|
||||
_timedRenderObjects.push_back(renderObjectPtr);
|
||||
}
|
||||
|
||||
void RenderObjectManager::detatchTimedRenderObject(RenderObjectPtr<TimedRenderObject> renderObjectPtr) {
|
||||
for (uint i = 0; i < _timedRenderObjects.size(); i++)
|
||||
if (_timedRenderObjects[i] == renderObjectPtr) {
|
||||
_timedRenderObjects.remove_at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderObjectManager::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
// Alle Kinder des Wurzelknotens speichern. Dadurch werden alle BS_RenderObjects gespeichert rekursiv gespeichert.
|
||||
result &= _rootPtr->persistChildren(writer);
|
||||
|
||||
writer.write(_frameStarted);
|
||||
|
||||
// Referenzen auf die TimedRenderObjects persistieren.
|
||||
writer.write((uint32)_timedRenderObjects.size());
|
||||
RenderObjectList::const_iterator iter = _timedRenderObjects.begin();
|
||||
while (iter != _timedRenderObjects.end()) {
|
||||
writer.write((*iter)->getHandle());
|
||||
++iter;
|
||||
}
|
||||
|
||||
// Alle BS_AnimationTemplates persistieren.
|
||||
result &= AnimationTemplateRegistry::instance().persist(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RenderObjectManager::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
// Alle Kinder des Wurzelknotens löschen. Damit werden alle BS_RenderObjects gelöscht.
|
||||
_rootPtr->deleteAllChildren();
|
||||
|
||||
// Alle BS_RenderObjects wieder hestellen.
|
||||
if (!_rootPtr->unpersistChildren(reader))
|
||||
return false;
|
||||
|
||||
reader.read(_frameStarted);
|
||||
|
||||
// Momentan gespeicherte Referenzen auf TimedRenderObjects löschen.
|
||||
_timedRenderObjects.resize(0);
|
||||
|
||||
// Referenzen auf die TimedRenderObjects wieder herstellen.
|
||||
uint32 timedObjectCount;
|
||||
reader.read(timedObjectCount);
|
||||
for (uint32 i = 0; i < timedObjectCount; ++i) {
|
||||
uint32 handle;
|
||||
reader.read(handle);
|
||||
_timedRenderObjects.push_back(handle);
|
||||
}
|
||||
|
||||
// Alle BS_AnimationTemplates wieder herstellen.
|
||||
result &= AnimationTemplateRegistry::instance().unpersist(reader);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
145
engines/sword25/gfx/renderobjectmanager.h
Normal file
145
engines/sword25/gfx/renderobjectmanager.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
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 SWORD25_RENDEROBJECTMANAGER_H
|
||||
#define SWORD25_RENDEROBJECTMANAGER_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/renderobjectptr.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
|
||||
#include "sword25/gfx/microtiles.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Kernel;
|
||||
class RenderObject;
|
||||
class TimedRenderObject;
|
||||
class RenderObjectManager;
|
||||
|
||||
struct RenderObjectQueueItem {
|
||||
RenderObject *_renderObject;
|
||||
Common::Rect _bbox;
|
||||
int _version;
|
||||
RenderObjectQueueItem(RenderObject *renderObject, const Common::Rect &bbox, int version)
|
||||
: _renderObject(renderObject), _bbox(bbox), _version(version) {}
|
||||
};
|
||||
|
||||
class RenderObjectQueue : public Common::List<RenderObjectQueueItem> {
|
||||
public:
|
||||
void add(RenderObject *renderObject);
|
||||
bool exists(const RenderObjectQueueItem &renderObjectQueueItem);
|
||||
};
|
||||
|
||||
/**
|
||||
@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 RenderObjectManager : public 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).
|
||||
*/
|
||||
RenderObjectManager(int width, int height, int framebufferCount);
|
||||
~RenderObjectManager() override;
|
||||
|
||||
// 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.
|
||||
*/
|
||||
RenderObjectPtr<RenderObject> getTreeRoot() {
|
||||
return _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(RenderObjectPtr<TimedRenderObject> pRenderObject);
|
||||
/**
|
||||
@brief Entfernt ein BS_TimedRenderObject aus der Liste für zeitabhängige Render-Objekte.
|
||||
*/
|
||||
void detatchTimedRenderObject(RenderObjectPtr<TimedRenderObject> pRenderObject);
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
private:
|
||||
bool _frameStarted;
|
||||
typedef Common::Array<RenderObjectPtr<TimedRenderObject> > RenderObjectList;
|
||||
RenderObjectList _timedRenderObjects;
|
||||
|
||||
MicroTileArray *_uta;
|
||||
RenderObjectQueue *_currQueue, *_prevQueue;
|
||||
|
||||
// RenderObject-Tree Variablen
|
||||
// ---------------------------
|
||||
// Der Baum legt die hierachische Ordnung der BS_RenderObjects fest.
|
||||
// Zu weiteren Informationen siehe: "renderobject.h"
|
||||
RenderObjectPtr<RenderObject> _rootPtr; // Die Wurzel der Baumes
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
75
engines/sword25/gfx/renderobjectptr.h
Normal file
75
engines/sword25/gfx/renderobjectptr.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_RENDER_OBJECT_PTR_H
|
||||
#define SWORD25_RENDER_OBJECT_PTR_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/renderobjectregistry.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class RenderObject;
|
||||
|
||||
template<class T>
|
||||
class RenderObjectPtr {
|
||||
public:
|
||||
RenderObjectPtr() : _handle(0) {}
|
||||
|
||||
RenderObjectPtr(uint handle) : _handle(handle) {}
|
||||
|
||||
T *operator->() const {
|
||||
return static_cast<T *>(RenderObjectRegistry::instance().resolveHandle(_handle));
|
||||
}
|
||||
|
||||
bool operator==(const RenderObjectPtr<T> & other) {
|
||||
return _handle == other._handle;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return RenderObjectRegistry::instance().resolveHandle(_handle) != 0;
|
||||
}
|
||||
|
||||
void erase() {
|
||||
delete static_cast<T *>(RenderObjectRegistry::instance().resolveHandle(_handle));
|
||||
_handle = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint _handle;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
50
engines/sword25/gfx/renderobjectregistry.h
Normal file
50
engines/sword25/gfx/renderobjectregistry.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_RENDEROBJECTREGISTRY_H
|
||||
#define SWORD25_RENDEROBJECTREGISTRY_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/objectregistry.h"
|
||||
|
||||
#include "common/singleton.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class RenderObject;
|
||||
|
||||
class RenderObjectRegistry :
|
||||
public ObjectRegistry<RenderObject>,
|
||||
public Common::Singleton<RenderObjectRegistry> {
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
68
engines/sword25/gfx/rootrenderobject.h
Normal file
68
engines/sword25/gfx/rootrenderobject.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_ROOTRENDEROBJECT_H
|
||||
#define SWORD25_ROOTRENDEROBJECT_H
|
||||
|
||||
// Includes
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Forward Declarations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Kernel;
|
||||
|
||||
// Klassendefinition
|
||||
class RenderObjectManager;
|
||||
|
||||
class RootRenderObject : public RenderObject {
|
||||
friend class RenderObjectManager;
|
||||
|
||||
private:
|
||||
RootRenderObject(RenderObjectManager *managerPtr, int width, int height) :
|
||||
RenderObject(RenderObjectPtr<RenderObject>(), TYPE_ROOT) {
|
||||
_managerPtr = managerPtr;
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool doRender(RectangleList *updateRects) override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
125
engines/sword25/gfx/screenshot.cpp
Normal file
125
engines/sword25/gfx/screenshot.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "sword25/gfx/screenshot.h"
|
||||
#include "sword25/kernel/filesystemutil.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
#define THUMBNAIL_VERSION 1
|
||||
|
||||
bool Screenshot::saveToFile(Graphics::Surface *data, Common::WriteStream *stream) {
|
||||
// Convert the RGBA data to RGB
|
||||
const uint32 *pSrc = (const uint32 *)data->getPixels();
|
||||
|
||||
// Write our own custom header
|
||||
stream->writeUint32BE(MKTAG('S','C','R','N')); // SCRN, short for "Screenshot"
|
||||
stream->writeUint16LE(data->w);
|
||||
stream->writeUint16LE(data->h);
|
||||
stream->writeByte(THUMBNAIL_VERSION);
|
||||
|
||||
for (int y = 0; y < data->h; y++) {
|
||||
for (int x = 0; x < data->w; x++) {
|
||||
// This is only called by createThumbnail below, which
|
||||
// provides a fake 'surface' with LE data in it.
|
||||
byte a, r, g, b;
|
||||
|
||||
data->format.colorToARGB(*pSrc++, a, r, g, b);
|
||||
stream->writeByte(r);
|
||||
stream->writeByte(g);
|
||||
stream->writeByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Common::SeekableReadStream *Screenshot::createThumbnail(Graphics::Surface *data) {
|
||||
// This method takes a screen image with a dimension of 800x600, and creates a screenshot with a dimension of 200x125.
|
||||
// First 50 pixels are cut off the top and bottom (the interface boards in the game). The remaining image of 800x500
|
||||
// will be on a 16th of its size, reduced by being handed out in 4x4 pixel blocks and the average of each block
|
||||
// generates a pixel of the target image. Finally, the result as a PNG file is stored as a file.
|
||||
|
||||
// The source image must be 800x600.
|
||||
if (data->w != 800 || data->h != 600 || data->format.bytesPerPixel != 4) {
|
||||
error("The sreenshot dimensions have to be 800x600 in order to be saved as a thumbnail.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Buffer for the output thumbnail
|
||||
Graphics::Surface thumbnail;
|
||||
thumbnail.create(200, 125, g_system->getScreenFormat());
|
||||
|
||||
// Uber das Zielbild iterieren und einen Pixel zur Zeit berechnen.
|
||||
uint x, y;
|
||||
x = y = 0;
|
||||
|
||||
for (uint32 *pDest = (uint32 *)thumbnail.getPixels(); pDest < thumbnail.getBasePtr(0, thumbnail.h); ) {
|
||||
// Get an average over a 4x4 pixel block in the source image
|
||||
int alpha, red, green, blue;
|
||||
alpha = red = green = blue = 0;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
const uint32 *srcP = (const uint32 *)data->getBasePtr(x * 4, y * 4 + j + 50);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
byte a, r, g, b;
|
||||
data->format.colorToARGB(*(srcP + i), a, r, g, b);
|
||||
alpha += a;
|
||||
red += r;
|
||||
green += g;
|
||||
blue += b;
|
||||
}
|
||||
}
|
||||
|
||||
*pDest++ = thumbnail.format.ARGBToColor(alpha / 16, red / 16, green / 16, blue / 16);
|
||||
|
||||
// Move to next block
|
||||
++x;
|
||||
if (x == (uint)thumbnail.w) {
|
||||
x = 0;
|
||||
++y;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a PNG representation of the thumbnail data
|
||||
Common::MemoryWriteStreamDynamic stream(DisposeAfterUse::NO);
|
||||
saveToFile(&thumbnail, &stream);
|
||||
thumbnail.free();
|
||||
|
||||
// Output a MemoryReadStream that encompasses the written data
|
||||
Common::SeekableReadStream *result = new Common::MemoryReadStream(stream.getData(), stream.size(),
|
||||
DisposeAfterUse::YES);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
47
engines/sword25/gfx/screenshot.h
Normal file
47
engines/sword25/gfx/screenshot.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_SCREENSHOT_H
|
||||
#define SWORD25_SCREENSHOT_H
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "sword25/kernel/common.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Screenshot {
|
||||
public:
|
||||
static bool saveToFile(Graphics::Surface *data, Common::WriteStream *stream);
|
||||
static Common::SeekableReadStream *createThumbnail(Graphics::Surface *data);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
186
engines/sword25/gfx/staticbitmap.cpp
Normal file
186
engines/sword25/gfx/staticbitmap.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/staticbitmap.h"
|
||||
#include "sword25/gfx/bitmapresource.h"
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
StaticBitmap::StaticBitmap(RenderObjectPtr<RenderObject> parentPtr, const Common::String &filename) :
|
||||
Bitmap(parentPtr, TYPE_STATICBITMAP) {
|
||||
// Das BS_Bitmap konnte nicht erzeugt werden, daher muss an dieser Stelle abgebrochen werden.
|
||||
if (!_initSuccess)
|
||||
return;
|
||||
|
||||
_initSuccess = initBitmapResource(filename);
|
||||
}
|
||||
|
||||
StaticBitmap::StaticBitmap(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
|
||||
Bitmap(parentPtr, TYPE_STATICBITMAP, handle) {
|
||||
_initSuccess = unpersist(reader);
|
||||
}
|
||||
|
||||
bool StaticBitmap::initBitmapResource(const Common::String &filename) {
|
||||
// Bild-Resource laden
|
||||
Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(filename);
|
||||
if (!resourcePtr) {
|
||||
warning("Could not request resource \"%s\".", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
if (resourcePtr->getType() != Resource::TYPE_BITMAP) {
|
||||
error("Requested resource \"%s\" is not a bitmap.", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
BitmapResource *bitmapPtr = static_cast<BitmapResource *>(resourcePtr);
|
||||
|
||||
// Den eindeutigen Dateinamen zum späteren Referenzieren speichern
|
||||
_resourceFilename = bitmapPtr->getFileName();
|
||||
|
||||
// RenderObject Eigenschaften aktualisieren
|
||||
_originalWidth = _width = bitmapPtr->getWidth();
|
||||
_originalHeight = _height = bitmapPtr->getHeight();
|
||||
|
||||
_isSolid = bitmapPtr->isSolid();
|
||||
|
||||
// Bild-Resource freigeben
|
||||
bitmapPtr->release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
StaticBitmap::~StaticBitmap() {
|
||||
}
|
||||
|
||||
bool StaticBitmap::doRender(RectangleList *updateRects) {
|
||||
// Bitmap holen
|
||||
Resource *resourcePtr = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
|
||||
assert(resourcePtr);
|
||||
assert(resourcePtr->getType() == Resource::TYPE_BITMAP);
|
||||
BitmapResource *bitmapResourcePtr = static_cast<BitmapResource *>(resourcePtr);
|
||||
|
||||
// Framebufferobjekt holen
|
||||
GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
|
||||
assert(gfxPtr);
|
||||
|
||||
// Bitmap zeichnen
|
||||
bool result;
|
||||
if (_scaleFactorX == 1.0f && _scaleFactorY == 1.0f) {
|
||||
result = bitmapResourcePtr->blit(_absoluteX, _absoluteY,
|
||||
(_flipV ? Graphics::FLIP_V : 0) |
|
||||
(_flipH ? Graphics::FLIP_H : 0),
|
||||
0, _modulationColor, -1, -1,
|
||||
updateRects);
|
||||
} else {
|
||||
result = bitmapResourcePtr->blit(_absoluteX, _absoluteY,
|
||||
(_flipV ? Graphics::FLIP_V : 0) |
|
||||
(_flipH ? Graphics::FLIP_H : 0),
|
||||
0, _modulationColor, _width, _height,
|
||||
updateRects);
|
||||
}
|
||||
|
||||
// Resource freigeben
|
||||
bitmapResourcePtr->release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint StaticBitmap::getPixel(int x, int y) const {
|
||||
assert(x >= 0 && x < _width);
|
||||
assert(y >= 0 && y < _height);
|
||||
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
BitmapResource *pBitmapResource = static_cast<BitmapResource *>(pResource);
|
||||
uint result = pBitmapResource->getPixel(x, y);
|
||||
pResource->release();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StaticBitmap::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
|
||||
error("SetContent() ist not supported with this object.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StaticBitmap::isAlphaAllowed() const {
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
bool result = static_cast<BitmapResource *>(pResource)->isAlphaAllowed();
|
||||
pResource->release();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StaticBitmap::isColorModulationAllowed() const {
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
bool result = static_cast<BitmapResource *>(pResource)->isColorModulationAllowed();
|
||||
pResource->release();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StaticBitmap::isScalingAllowed() const {
|
||||
Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource(_resourceFilename);
|
||||
assert(pResource->getType() == Resource::TYPE_BITMAP);
|
||||
bool result = static_cast<BitmapResource *>(pResource)->isScalingAllowed();
|
||||
pResource->release();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StaticBitmap::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
result &= Bitmap::persist(writer);
|
||||
writer.writeString(_resourceFilename);
|
||||
|
||||
result &= RenderObject::persistChildren(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StaticBitmap::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
result &= Bitmap::unpersist(reader);
|
||||
Common::String resourceFilename;
|
||||
reader.readString(resourceFilename);
|
||||
// We may not have saves, and we actually do not need to
|
||||
// restore them. So do not even try to load them.
|
||||
if (!resourceFilename.hasPrefix("/saves"))
|
||||
result &= initBitmapResource(resourceFilename);
|
||||
|
||||
result &= RenderObject::unpersistChildren(reader);
|
||||
|
||||
return reader.isGood() && result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
77
engines/sword25/gfx/staticbitmap.h
Normal file
77
engines/sword25/gfx/staticbitmap.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_STATIC_BITMAP_H
|
||||
#define SWORD25_STATIC_BITMAP_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/bitmap.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class StaticBitmap : public Bitmap {
|
||||
friend class RenderObject;
|
||||
|
||||
private:
|
||||
/**
|
||||
@remark Filename muss absoluter Pfad sein
|
||||
*/
|
||||
StaticBitmap(RenderObjectPtr<RenderObject> parentPtr, const Common::String &filename);
|
||||
StaticBitmap(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle);
|
||||
|
||||
public:
|
||||
~StaticBitmap() override;
|
||||
|
||||
uint getPixel(int x, int y) const override;
|
||||
|
||||
bool setContent(const byte *pixeldata, uint size, uint offset, uint stride) override;
|
||||
|
||||
bool isScalingAllowed() const override;
|
||||
bool isAlphaAllowed() const override;
|
||||
bool isColorModulationAllowed() const override;
|
||||
bool isSetContentAllowed() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
protected:
|
||||
bool doRender(RectangleList *updateRects) override;
|
||||
|
||||
private:
|
||||
Common::String _resourceFilename;
|
||||
|
||||
bool initBitmapResource(const Common::String &filename);
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
369
engines/sword25/gfx/text.cpp
Normal file
369
engines/sword25/gfx/text.cpp
Normal file
@@ -0,0 +1,369 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
#include "common/unicode-bidi.h"
|
||||
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/resmanager.h" // for PRECACHE_RESOURCES
|
||||
#include "sword25/gfx/fontresource.h"
|
||||
#include "sword25/gfx/bitmapresource.h"
|
||||
|
||||
#include "sword25/gfx/text.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
namespace {
|
||||
const uint32 AUTO_WRAP_THRESHOLD_DEFAULT = 300;
|
||||
}
|
||||
|
||||
Text::Text(RenderObjectPtr<RenderObject> parentPtr) :
|
||||
RenderObject(parentPtr, RenderObject::TYPE_TEXT),
|
||||
_modulationColor(BS_ARGBMASK),
|
||||
_autoWrap(false),
|
||||
_autoWrapThreshold(AUTO_WRAP_THRESHOLD_DEFAULT) {
|
||||
|
||||
}
|
||||
|
||||
Text::Text(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle) :
|
||||
RenderObject(parentPtr, TYPE_TEXT, handle),
|
||||
// Temporarily set fields prior to unpersisting actual values
|
||||
_modulationColor(BS_ARGBMASK),
|
||||
_autoWrap(false),
|
||||
_autoWrapThreshold(AUTO_WRAP_THRESHOLD_DEFAULT) {
|
||||
|
||||
// Unpersist the fields
|
||||
_initSuccess = unpersist(reader);
|
||||
}
|
||||
|
||||
bool Text::setFont(const Common::String &font) {
|
||||
// Load font
|
||||
|
||||
#ifdef PRECACHE_RESOURCES
|
||||
if (getResourceManager()->precacheResource(font)) {
|
||||
_font = font;
|
||||
updateFormat();
|
||||
forceRefresh();
|
||||
return true;
|
||||
} else {
|
||||
error("Could not precache font \"%s\". Font probably does not exist.", font.c_str());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
Resource *pResource = getResourceManager()->requestResource(font);
|
||||
pResource->release(); //unlock precached resource
|
||||
_font = font;
|
||||
updateFormat();
|
||||
forceRefresh();
|
||||
return true;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void Text::setText(const Common::String &text) {
|
||||
if (_text != text) {
|
||||
_text = text;
|
||||
updateFormat();
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Text::setColor(uint32 modulationColor) {
|
||||
uint32 newModulationColor = (modulationColor & BS_RGBMASK) | (_modulationColor & BS_AMASK);
|
||||
if (newModulationColor != _modulationColor) {
|
||||
_modulationColor = newModulationColor;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Text::setAlpha(int alpha) {
|
||||
assert(alpha >= 0 && alpha < 256);
|
||||
uint32 newModulationColor = (_modulationColor & BS_RGBMASK) | (alpha << BS_ASHIFT);
|
||||
if (newModulationColor != _modulationColor) {
|
||||
_modulationColor = newModulationColor;
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Text::setAutoWrap(bool autoWrap) {
|
||||
if (autoWrap != _autoWrap) {
|
||||
_autoWrap = autoWrap;
|
||||
updateFormat();
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Text::setAutoWrapThreshold(uint32 autoWrapThreshold) {
|
||||
if (autoWrapThreshold != _autoWrapThreshold) {
|
||||
_autoWrapThreshold = autoWrapThreshold;
|
||||
updateFormat();
|
||||
forceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
bool Text::doRender(RectangleList *updateRects) {
|
||||
// lock Font Resource
|
||||
FontResource *fontPtr = lockFontResource();
|
||||
if (!fontPtr)
|
||||
return false;
|
||||
|
||||
// lock Character map resource
|
||||
ResourceManager *rmPtr = getResourceManager();
|
||||
BitmapResource *charMapPtr;
|
||||
{
|
||||
Resource *pResource = rmPtr->requestResource(fontPtr->getCharactermapFileName());
|
||||
if (!pResource) {
|
||||
warning("Could not request resource \"%s\".", fontPtr->getCharactermapFileName().c_str());
|
||||
return false;
|
||||
}
|
||||
if (pResource->getType() != Resource::TYPE_BITMAP) {
|
||||
error("Requested resource \"%s\" is not a bitmap.", fontPtr->getCharactermapFileName().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
charMapPtr = static_cast<BitmapResource *>(pResource);
|
||||
}
|
||||
|
||||
// Getting frame buffer object
|
||||
GraphicEngine *gfxPtr = Kernel::getInstance()->getGfx();
|
||||
assert(gfxPtr);
|
||||
|
||||
bool result = true;
|
||||
Common::Array<Line>::iterator iter = _lines.begin();
|
||||
for (; iter != _lines.end(); ++iter) {
|
||||
// Determine whether any letters of the current line are affected by the update.
|
||||
Common::Rect checkRect = (*iter).bbox;
|
||||
checkRect.translate(_absoluteX, _absoluteY);
|
||||
|
||||
// Render each letter individually.
|
||||
int curX = _absoluteX + (*iter).bbox.left;
|
||||
int curY = _absoluteY + (*iter).bbox.top;
|
||||
for (uint i = 0; i < (*iter).text.size(); ++i) {
|
||||
Common::Rect curRect = fontPtr->getCharacterRect((byte)(*iter).text[i]);
|
||||
|
||||
Common::Rect renderRect(curX, curY, curX + curRect.width(), curY + curRect.height());
|
||||
renderRect.translate(curRect.left - curX, curRect.top - curY);
|
||||
result = charMapPtr->blit(curX, curY, Graphics::FLIP_NONE, &renderRect, _modulationColor, -1, -1, updateRects);
|
||||
if (!result)
|
||||
break;
|
||||
|
||||
curX += curRect.width() + fontPtr->getGapWidth();
|
||||
}
|
||||
}
|
||||
|
||||
// Free Character map resource
|
||||
charMapPtr->release();
|
||||
|
||||
// Free Font resource
|
||||
fontPtr->release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ResourceManager *Text::getResourceManager() {
|
||||
// Getting pointer to resource manager
|
||||
return Kernel::getInstance()->getResourceManager();
|
||||
}
|
||||
|
||||
FontResource *Text::lockFontResource() {
|
||||
ResourceManager *rmPtr = getResourceManager();
|
||||
|
||||
// Lock font resource
|
||||
FontResource *fontPtr;
|
||||
{
|
||||
Resource *resourcePtr = rmPtr->requestResource(_font);
|
||||
if (!resourcePtr) {
|
||||
warning("Could not request resource \"%s\".", _font.c_str());
|
||||
return NULL;
|
||||
}
|
||||
if (resourcePtr->getType() != Resource::TYPE_FONT) {
|
||||
error("Requested resource \"%s\" is not a font.", _font.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fontPtr = static_cast<FontResource *>(resourcePtr);
|
||||
}
|
||||
|
||||
return fontPtr;
|
||||
}
|
||||
|
||||
void Text::updateFormat() {
|
||||
FontResource *fontPtr = lockFontResource();
|
||||
assert(fontPtr);
|
||||
|
||||
bool isRTL = Kernel::getInstance()->getGfx()->isRTL();
|
||||
updateMetrics(*fontPtr);
|
||||
|
||||
_lines.resize(1);
|
||||
if (_autoWrap && (uint) _width >= _autoWrapThreshold && _text.size() >= 2) {
|
||||
_width = 0;
|
||||
uint curLineWidth = 0;
|
||||
uint curLineHeight = 0;
|
||||
uint curLine = 0;
|
||||
uint tempLineWidth = 0;
|
||||
uint lastSpace = 0; // we need at least 1 space character to start a new line...
|
||||
_lines[0].text = "";
|
||||
for (uint i = 0; i < _text.size(); ++i) {
|
||||
uint j;
|
||||
tempLineWidth = 0;
|
||||
lastSpace = 0;
|
||||
for (j = i; j < _text.size(); ++j) {
|
||||
if ((byte)_text[j] == ' ')
|
||||
lastSpace = j;
|
||||
|
||||
const Common::Rect &curCharRect = fontPtr->getCharacterRect((byte)_text[j]);
|
||||
tempLineWidth += curCharRect.width();
|
||||
tempLineWidth += fontPtr->getGapWidth();
|
||||
|
||||
if ((tempLineWidth >= _autoWrapThreshold) && (lastSpace > 0))
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == _text.size()) // everything in 1 line.
|
||||
lastSpace = _text.size();
|
||||
|
||||
curLineWidth = 0;
|
||||
curLineHeight = 0;
|
||||
for (j = i; j < lastSpace; ++j) {
|
||||
_lines[curLine].text += _text[j];
|
||||
|
||||
const Common::Rect &curCharRect = fontPtr->getCharacterRect((byte)_text[j]);
|
||||
curLineWidth += curCharRect.width();
|
||||
curLineWidth += fontPtr->getGapWidth();
|
||||
if ((uint)curCharRect.height() > curLineHeight)
|
||||
curLineHeight = curCharRect.height();
|
||||
}
|
||||
|
||||
if (isRTL) {
|
||||
_lines[curLine].text = Common::convertBiDiString(_lines[curLine].text, Common::kWindows1255);
|
||||
}
|
||||
|
||||
_lines[curLine].bbox.right = curLineWidth;
|
||||
_lines[curLine].bbox.bottom = curLineHeight;
|
||||
if ((uint)_width < curLineWidth)
|
||||
_width = curLineWidth;
|
||||
|
||||
if (lastSpace < _text.size()) {
|
||||
++curLine;
|
||||
assert(curLine == _lines.size());
|
||||
_lines.resize(curLine + 1);
|
||||
_lines[curLine].text = "";
|
||||
}
|
||||
|
||||
i = lastSpace;
|
||||
}
|
||||
|
||||
// Bounding box of each line relative to the first set (center aligned).
|
||||
_height = 0;
|
||||
Common::Array<Line>::iterator iter = _lines.begin();
|
||||
for (; iter != _lines.end(); ++iter) {
|
||||
Common::Rect &bbox = (*iter).bbox;
|
||||
bbox.left = (_width - bbox.right) / 2;
|
||||
bbox.right = bbox.left + bbox.right;
|
||||
bbox.top = (iter - _lines.begin()) * fontPtr->getLineHeight();
|
||||
bbox.bottom = bbox.top + bbox.bottom;
|
||||
_height += bbox.height();
|
||||
}
|
||||
} else {
|
||||
if (isRTL) {
|
||||
_lines[0].text = Common::convertBiDiString(_text, Common::kWindows1255);
|
||||
} else {
|
||||
// No auto format, so all the text is copied to a single line.
|
||||
_lines[0].text = _text;
|
||||
}
|
||||
_lines[0].bbox = Common::Rect(0, 0, _width, _height);
|
||||
}
|
||||
|
||||
fontPtr->release();
|
||||
}
|
||||
|
||||
void Text::updateMetrics(FontResource &fontResource) {
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
|
||||
for (uint i = 0; i < _text.size(); ++i) {
|
||||
const Common::Rect &curRect = fontResource.getCharacterRect((byte)_text[i]);
|
||||
_width += curRect.width();
|
||||
if (i != _text.size() - 1)
|
||||
_width += fontResource.getGapWidth();
|
||||
if (_height < curRect.height())
|
||||
_height = curRect.height();
|
||||
}
|
||||
}
|
||||
|
||||
bool Text::persist(OutputPersistenceBlock &writer) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::persist(writer);
|
||||
|
||||
writer.write(_modulationColor);
|
||||
writer.writeString(_font);
|
||||
writer.writeString(_text);
|
||||
writer.write(_autoWrap);
|
||||
writer.write(_autoWrapThreshold);
|
||||
|
||||
result &= RenderObject::persistChildren(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Text::unpersist(InputPersistenceBlock &reader) {
|
||||
bool result = true;
|
||||
|
||||
result &= RenderObject::unpersist(reader);
|
||||
|
||||
// Read color and alpha
|
||||
reader.read(_modulationColor);
|
||||
|
||||
// Run all methods on loading relevant members.
|
||||
// So, the layout is automatically updated and all necessary logic is executed.
|
||||
|
||||
Common::String font;
|
||||
reader.readString(font);
|
||||
setFont(font);
|
||||
|
||||
Common::String text;
|
||||
reader.readString(text);
|
||||
setText(text);
|
||||
|
||||
bool autoWrap;
|
||||
reader.read(autoWrap);
|
||||
setAutoWrap(autoWrap);
|
||||
|
||||
uint32 autoWrapThreshold;
|
||||
reader.read(autoWrapThreshold);
|
||||
setAutoWrapThreshold(autoWrapThreshold);
|
||||
|
||||
result &= RenderObject::unpersistChildren(reader);
|
||||
|
||||
return reader.isGood() && result;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
165
engines/sword25/gfx/text.h
Normal file
165
engines/sword25/gfx/text.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_TEXT_H
|
||||
#define SWORD25_TEXT_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "common/rect.h"
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class Kernel;
|
||||
class FontResource;
|
||||
class ResourceManager;
|
||||
|
||||
class Text : public RenderObject {
|
||||
friend class 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 Common::String &font);
|
||||
|
||||
/**
|
||||
@brief Setzt den darzustellenden Text.
|
||||
@param Text der darzustellende Text
|
||||
*/
|
||||
void setText(const Common::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(uint32 autoWrapThreshold);
|
||||
|
||||
/**
|
||||
@brief Gibt den dargestellten Text zurück.
|
||||
*/
|
||||
const Common::String &getText() {
|
||||
return _text;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt den Namen das momentan benutzten Fonts zurück.
|
||||
*/
|
||||
const Common::String &getFont() {
|
||||
return _font;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Setzt die Farbe des Textes.
|
||||
@param Color eine 24-Bit RGB Farbe, die die Farbe des Textes festlegt.
|
||||
*/
|
||||
void setColor(uint32 modulationColor);
|
||||
|
||||
/**
|
||||
@brief Gibt den Alphawert des Textes zurück.
|
||||
@return Der Alphawert des Textes (0 = keine Deckung, 255 = volle Deckung).
|
||||
*/
|
||||
int getAlpha() const {
|
||||
return _modulationColor >> BS_ASHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt die Farbe des Textes zurück.
|
||||
@return Eine 24-Bit RGB Farbe, die die Farbe des Textes angibt.
|
||||
*/
|
||||
int getColor() const {
|
||||
return _modulationColor & BS_RGBMASK;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt zurück, ob die automatische Formatierung aktiviert ist.
|
||||
*/
|
||||
bool isAutoWrapActive() const {
|
||||
return _autoWrap;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Gibt die Längengrenze des Textes in Pixeln zurück, ab der eine automatische Formatierung vorgenommen wird.
|
||||
*/
|
||||
uint32 getAutoWrapThreshold() const {
|
||||
return _autoWrapThreshold;
|
||||
}
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
protected:
|
||||
bool doRender(RectangleList *updateRects) override;
|
||||
|
||||
private:
|
||||
Text(RenderObjectPtr<RenderObject> parentPtr);
|
||||
Text(InputPersistenceBlock &reader, RenderObjectPtr<RenderObject> parentPtr, uint handle);
|
||||
|
||||
uint32 _modulationColor;
|
||||
Common::String _font;
|
||||
Common::String _text;
|
||||
bool _autoWrap;
|
||||
uint32 _autoWrapThreshold;
|
||||
|
||||
struct Line {
|
||||
Common::Rect bbox;
|
||||
Common::String text;
|
||||
};
|
||||
|
||||
Common::Array<Line> _lines;
|
||||
|
||||
void updateFormat();
|
||||
void updateMetrics(FontResource &fontResource);
|
||||
ResourceManager *getResourceManager();
|
||||
FontResource *lockFontResource();
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
48
engines/sword25/gfx/timedrenderobject.cpp
Normal file
48
engines/sword25/gfx/timedrenderobject.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/gfx/timedrenderobject.h"
|
||||
|
||||
#include "sword25/gfx/renderobjectmanager.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
TimedRenderObject::TimedRenderObject(RenderObjectPtr<RenderObject> pParent, TYPES type, uint handle) :
|
||||
RenderObject(pParent, type, handle) {
|
||||
assert(getManager());
|
||||
getManager()->attatchTimedRenderObject(this->getHandle());
|
||||
}
|
||||
|
||||
TimedRenderObject::~TimedRenderObject() {
|
||||
assert(getManager());
|
||||
getManager()->detatchTimedRenderObject(this->getHandle());
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
55
engines/sword25/gfx/timedrenderobject.h
Normal file
55
engines/sword25/gfx/timedrenderobject.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/gfx/renderobject.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
/**
|
||||
@brief
|
||||
*/
|
||||
|
||||
class TimedRenderObject : public RenderObject {
|
||||
public:
|
||||
TimedRenderObject(RenderObjectPtr<RenderObject> pParent, TYPES type, uint handle = 0);
|
||||
~TimedRenderObject() override;
|
||||
|
||||
/**
|
||||
@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;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
Reference in New Issue
Block a user