Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseClass::BaseClass(BaseGame *gameOwner) {
_game = gameOwner;
_persistable = true;
}
//////////////////////////////////////////////////////////////////////////
BaseClass::BaseClass() {
_game = nullptr;
_persistable = true;
}
//////////////////////////////////////////////////////////////////////
BaseClass::~BaseClass() {
_editorProps.clear();
}
//////////////////////////////////////////////////////////////////////////
Common::String BaseClass::getEditorProp(const Common::String &propName, const Common::String &initVal) {
_editorPropsIter = _editorProps.find(propName);
if (_editorPropsIter != _editorProps.end()) {
return _editorPropsIter->_value.c_str();
} else {
return initVal;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseClass::setEditorProp(const Common::String &propName, const Common::String &propValue) {
if (propName.empty()) {
return STATUS_FAILED;
}
if (propValue.empty()) {
_editorProps.erase(propName);
} else {
_editorProps[propName] = propValue;
}
return STATUS_OK;
}
TOKEN_DEF_START
TOKEN_DEF(EDITOR_PROPERTY)
TOKEN_DEF(NAME)
TOKEN_DEF(VALUE)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////////
bool BaseClass::parseEditorProperty(char *buffer, bool complete) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(EDITOR_PROPERTY)
TOKEN_TABLE(NAME)
TOKEN_TABLE(VALUE)
TOKEN_TABLE_END
if (!_game->_editorMode) {
return STATUS_OK;
}
char *params;
int cmd;
BaseParser parser(_game);
if (complete) {
if (parser.getCommand(&buffer, commands, &params) != TOKEN_EDITOR_PROPERTY) {
_game->LOG(0, "'EDITOR_PROPERTY' keyword expected.");
return STATUS_FAILED;
}
buffer = params;
}
char *propName = nullptr;
char *propValue = nullptr;
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_NAME: {
SAFE_DELETE_ARRAY(propName);
size_t propNameSize = strlen(params) + 1;
propName = new char[propNameSize];
Common::strcpy_s(propName, propNameSize, params);
break;
}
case TOKEN_VALUE: {
SAFE_DELETE_ARRAY(propValue);
size_t propValueSize = strlen(params) + 1;
propValue = new char[propValueSize];
Common::strcpy_s(propValue, propValueSize, params);
break;
}
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
SAFE_DELETE_ARRAY(propName);
SAFE_DELETE_ARRAY(propValue);
_game->LOG(0, "Syntax error in EDITOR_PROPERTY definition");
return STATUS_FAILED;
}
if (cmd == PARSERR_GENERIC || propName == nullptr || propValue == nullptr) {
SAFE_DELETE_ARRAY(propName);
SAFE_DELETE_ARRAY(propValue);
_game->LOG(0, "Error loading EDITOR_PROPERTY definition");
return STATUS_FAILED;
}
setEditorProp(propName, propValue);
SAFE_DELETE_ARRAY(propName);
SAFE_DELETE_ARRAY(propValue);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseClass::saveAsText(BaseDynamicBuffer *buffer, int indent) {
_editorPropsIter = _editorProps.begin();
while (_editorPropsIter != _editorProps.end()) {
buffer->putTextIndent(indent, "EDITOR_PROPERTY\n");
buffer->putTextIndent(indent, "{\n");
buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _editorPropsIter->_key.c_str());
buffer->putTextIndent(indent + 2, "VALUE=\"%s\"\n", _editorPropsIter->_value.c_str());
buffer->putTextIndent(indent, "}\n\n");
_editorPropsIter++;
}
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,64 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_BASE_H
#define WINTERMUTE_BASE_BASE_H
#include "engines/wintermute/wintypes.h"
#include "engines/wintermute/dctypes.h"
#include "common/str.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
namespace Wintermute {
class BaseGame;
class BaseDynamicBuffer;
class BasePersistenceManager;
class BaseClass {
public:
bool _persistable;
bool setEditorProp(const Common::String &propName, const Common::String &propValue);
Common::String getEditorProp(const Common::String &propName, const Common::String &initVal = Common::String());
BaseClass(TDynamicConstructor, TDynamicConstructor) {}
bool parseEditorProperty(char *buffer, bool complete = true);
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent = 0);
BaseClass();
BaseGame *_game;
BaseClass(BaseGame *gameOwner);
virtual ~BaseClass();
virtual const char *getClassName() { return ""; }
virtual bool persist(BasePersistenceManager *persistMgr) { return true; }
Common::HashMap<Common::String, Common::String> _editorProps;
Common::HashMap<Common::String, Common::String>::iterator _editorPropsIter;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,221 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_access_mgr.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/utils/string_util.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/dcgf.h"
#include "common/text-to-speech.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseAccessMgr::BaseAccessMgr(BaseGame *inGame) : BaseClass(inGame) {
_voice = nullptr;
_ttsAvailable = false;
_activeObject = nullptr;
_prevActiveObject = nullptr;
BasePlatform::setRectEmpty(&_hintRect);
_hintAfterGUI = false;
_playingType = TTS_CAPTION;
_ctrlPressed = false;
}
//////////////////////////////////////////////////////////////////////////
BaseAccessMgr::~BaseAccessMgr() {
_activeObject = nullptr; // ref only
_ttsAvailable = false;
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::initialize() {
_ttsAvailable = false;
if (!_game->_accessTTSEnabled)
return true;
_voice = g_system->getTextToSpeechManager();
if (_voice) {
_ttsAvailable = true;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::initLoop() {
BasePlatform::setRectEmpty(&_hintRect);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::displayBeforeGUI() {
if (!_game->_accessKeyboardEnabled)
return true;
if (!_hintAfterGUI) {
return displayInternal();
} else {
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::displayAfterGUI() {
if (!_game->_accessKeyboardEnabled)
return true;
if (_hintAfterGUI) {
return displayInternal();
} else {
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::displayInternal() {
if (!_ctrlPressed) {
return true;
}
if (!BasePlatform::isRectEmpty(&_hintRect)) {
_game->_renderer->drawRect(_hintRect.left, _hintRect.top, _hintRect.right, _hintRect.bottom, 0xFFFF0000, 4);
// reposition mouse pointer
if (_game->_accessKeyboardCursorSkip && _activeObject != _prevActiveObject) {
_prevActiveObject = _activeObject;
Common::Point32 p;
p.x = _hintRect.left + (_hintRect.right - _hintRect.left) / 2;
p.y = _hintRect.top + (_hintRect.bottom - _hintRect.top) / 2;
p.x += _game->_renderer->_drawOffsetX;
p.y += _game->_renderer->_drawOffsetY;
p.x = MAX<int32>(0, p.x);
p.y = MAX<int32>(0, p.y);
p.x = MIN<int32>(_game->_renderer->_width - 1, p.x);
p.y = MIN<int32>(_game->_renderer->_height - 1, p.y);
//ClientToScreen(Game->m_Renderer->m_Window, &p);
BasePlatform::setCursorPos(p.x, p.y);
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::setHintRect(Common::Rect32 *hintRect, bool afterGUI) {
if (!hintRect) {
BasePlatform::setRectEmpty(&_hintRect);
} else {
_hintRect = *hintRect;
}
_hintAfterGUI = afterGUI;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::setActiveObject(BaseObject *activeObj) {
if (!_game->_accessKeyboardEnabled) {
return true;
}
_activeObject = activeObj;
if (!activeObj) {
_prevActiveObject = nullptr;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
BaseObject *BaseAccessMgr::getActiveObject() {
return _activeObject;
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::speak(const char *str, TTTSType type) {
if (!_ttsAvailable) {
return true;
}
if (type == TTS_CAPTION && !_game->_accessTTSCaptions) {
return true;
}
if (type == TTS_TALK && !_game->_accessTTSTalk) {
return true;
}
if (type == TTS_KEYPRESS && !_game->_accessTTSKeypress) {
return true;
}
if (!str || !str[0]) {
return true;
}
WideString textStr;
if (_game->_textEncoding == TEXT_UTF8) {
textStr = StringUtil::utf8ToWide(str);
} else {
textStr = StringUtil::ansiToWide(str, CHARSET_DEFAULT);
}
if (!textStr.empty()) {
_playingType = type;
return _voice->say(str);
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseAccessMgr::stop() {
if (!_ttsAvailable) {
return true;
}
_playingType = TTS_CAPTION;
return _voice->stop();
}
//////////////////////////////////////////////////////////////////////////
BaseObject *BaseAccessMgr::getNextObject() {
_activeObject = _game->getNextAccessObject(_activeObject);
return _activeObject;
}
//////////////////////////////////////////////////////////////////////////
BaseObject *BaseAccessMgr::getPrevObject() {
_activeObject = _game->getPrevAccessObject(_activeObject);
return _activeObject;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,73 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_BASE_ACCESS_MGR_H
#define WINTERMUTE_BASE_ACCESS_MGR_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/dctypes.h"
#include "common/rect.h"
#include "common/text-to-speech.h"
namespace Wintermute {
class BaseObject;
class BaseAccessMgr : public BaseClass {
public:
BaseAccessMgr(BaseGame *inGame);
virtual ~BaseAccessMgr();
bool _ttsAvailable;
bool initialize();
bool speak(const char *str, TTTSType type);
bool stop();
BaseObject *getNextObject();
BaseObject *getPrevObject();
bool initLoop();
bool displayBeforeGUI();
bool displayAfterGUI();
bool setHintRect(Common::Rect32 *hintRect = nullptr, bool afterGUI = false);
bool setActiveObject(BaseObject *activeObj = nullptr);
BaseObject *getActiveObject();
bool _ctrlPressed;
private:
TTTSType _playingType;
bool displayInternal();
Common::TextToSpeechManager *_voice;
BaseObject *_activeObject;
BaseObject *_prevActiveObject;
Common::Rect32 _hintRect;
bool _hintAfterGUI;
};
#endif
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseActiveRect::BaseActiveRect(BaseGame *inGame) : BaseClass(inGame) {
BasePlatform::setRectEmpty(&_rect);
_owner = nullptr;
_frame = nullptr;
#ifdef ENABLE_WME3D
_xmodel = nullptr;
#endif
_region = nullptr;
_zoomX = 100;
_zoomY = 100;
_offsetX = _offsetY = 0;
clipRect();
}
//////////////////////////////////////////////////////////////////////
BaseActiveRect::BaseActiveRect(BaseGame *inGame, BaseObject *owner, BaseSubFrame *frame, int x, int y, int width, int height, float zoomX, float zoomY, bool precise) : BaseClass(inGame) {
_owner = owner;
_frame = frame;
BasePlatform::setRect(&_rect, x, y, x + width, y + height);
_zoomX = zoomX;
_zoomY = zoomY;
_precise = precise;
#ifdef ENABLE_WME3D
_xmodel = nullptr;
#endif
_region = nullptr;
_offsetX = _offsetY = 0;
clipRect();
}
//////////////////////////////////////////////////////////////////////
#ifdef ENABLE_WME3D
BaseActiveRect::BaseActiveRect(BaseGame *inGame, BaseObject *owner, XModel *model, int x, int y, int width, int height, bool precise) : BaseClass(inGame) {
_owner = owner;
_xmodel = model;
BasePlatform::setRect(&_rect, x, y, x + width, y + height);
_zoomX = 100;
_zoomY = 100;
_precise = precise;
_frame = nullptr;
_region = nullptr;
_offsetX = _offsetY = 0;
clipRect();
}
#endif
//////////////////////////////////////////////////////////////////////
BaseActiveRect::BaseActiveRect(BaseGame *inGame, BaseObject *owner, BaseRegion *region, int offsetX, int offsetY) : BaseClass(inGame) {
_owner = owner;
_region = region;
BasePlatform::copyRect(&_rect, &region->_rect);
BasePlatform::offsetRect(&_rect, -offsetX, -offsetY);
_zoomX = 100;
_zoomY = 100;
_precise = true;
_frame = nullptr;
#ifdef ENABLE_WME3D
_xmodel = nullptr;
#endif
clipRect();
_offsetX = offsetX;
_offsetY = offsetY;
}
//////////////////////////////////////////////////////////////////////
BaseActiveRect::~BaseActiveRect() {
_owner = nullptr;
_frame = nullptr;
#ifdef ENABLE_WME3D
_xmodel = nullptr;
#endif
_region = nullptr;
}
//////////////////////////////////////////////////////////////////////////
void BaseActiveRect::clipRect() {
Common::Rect32 rc;
bool customViewport;
_game->getCurrentViewportRect(&rc, &customViewport);
BaseRenderer *rend = _game->_renderer;
if (!customViewport) {
rc.left -= rend->_drawOffsetX;
rc.right -= rend->_drawOffsetX;
rc.top -= rend->_drawOffsetY;
rc.bottom -= rend->_drawOffsetY;
}
if (rc.left > _rect.left) {
_offsetX = rc.left - _rect.left;
}
if (rc.top > _rect.top) {
_offsetY = rc.top - _rect.top;
}
BasePlatform::intersectRect(&_rect, &_rect, &rc);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,67 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_ACTIVE_RECT_H
#define WINTERMUTE_BASE_ACTIVE_RECT_H
#include "common/rect.h"
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BaseRegion;
class BaseSubFrame;
class BaseObject;
#ifdef ENABLE_WME3D
class XModel;
#endif
class BaseActiveRect : BaseClass {
public:
void clipRect();
bool _precise{};
float _zoomX;
float _zoomY;
BaseSubFrame *_frame;
#ifdef ENABLE_WME3D
XModel *_xmodel;
#endif
BaseObject *_owner;
BaseRegion *_region;
int32 _offsetX;
int32 _offsetY;
Common::Rect32 _rect;
BaseActiveRect(BaseGame *inGameOwner = nullptr);
BaseActiveRect(BaseGame *inGameOwner, BaseObject *owner, BaseSubFrame *frame, int x, int y, int width, int height, float zoomX = 100, float zoomY = 100, bool precise = true);
BaseActiveRect(BaseGame *inGame, BaseObject *owner, BaseRegion *region, int offsetX, int offsetY);
#ifdef ENABLE_WME3D
BaseActiveRect(BaseGame *inGame, BaseObject *owner, XModel *model, int x, int y, int width, int height, bool precise = true);
#endif
~BaseActiveRect() override;
};
} // End of namespace Wintermute
#endif

View 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/base_animation_transition_time.h"
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseAnimationTransitionTime::BaseAnimationTransitionTime(const char *from, const char *to, uint32 time) {
_animFrom = nullptr;
_animTo = nullptr;
BaseUtils::setString(&_animFrom, from);
BaseUtils::setString(&_animTo, to);
_time = time;
}
//////////////////////////////////////////////////////////////////////////
BaseAnimationTransitionTime::BaseAnimationTransitionTime() {
_animFrom = nullptr;
_animTo = nullptr;
_time = 0;
}
//////////////////////////////////////////////////////////////////////////
BaseAnimationTransitionTime::~BaseAnimationTransitionTime() {
SAFE_DELETE_ARRAY(_animFrom);
SAFE_DELETE_ARRAY(_animTo);
}
//////////////////////////////////////////////////////////////////////////
bool BaseAnimationTransitionTime::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferCharPtr(TMEMBER(_animFrom));
persistMgr->transferCharPtr(TMEMBER(_animTo));
persistMgr->transferUint32(TMEMBER(_time));
return true;
}
}

View File

@@ -0,0 +1,49 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_BASE_ANIMATION_TRANSITION_TIME_H
#define WINTERMUTE_BASE_ANIMATION_TRANSITION_TIME_H
#include "engines/wintermute/base/base_persistence_manager.h"
namespace Wintermute {
class BaseAnimationTransitionTime {
public:
BaseAnimationTransitionTime(const char *from, const char *to, uint32 Time);
BaseAnimationTransitionTime();
virtual ~BaseAnimationTransitionTime();
bool persist(BasePersistenceManager *persistMgr);
char *_animFrom;
char *_animTo;
uint32 _time;
};
}
#endif

View File

@@ -0,0 +1,204 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseDynamicBuffer::BaseDynamicBuffer(BaseGame *inGame, uint32 initSize, uint32 growBy) : BaseClass(inGame) {
_buffer = nullptr;
_size = 0;
_realSize = 0;
_offset = 0;
_initSize = initSize;
_growBy = growBy;
_initialized = false;
}
//////////////////////////////////////////////////////////////////////////
BaseDynamicBuffer::~BaseDynamicBuffer() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void BaseDynamicBuffer::cleanup() {
if (_buffer) {
free(_buffer);
}
_buffer = nullptr;
_size = 0;
_realSize = 0;
_offset = 0;
_initialized = false;
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseDynamicBuffer::getSize() {
return _size;
}
//////////////////////////////////////////////////////////////////////////
bool BaseDynamicBuffer::init(uint32 initSize) {
cleanup();
if (initSize == 0) {
initSize = _initSize;
}
_buffer = (byte *)malloc(initSize);
if (!_buffer) {
_game->LOG(0, "BaseDynamicBuffer::init - Error allocating %d bytes", initSize);
return STATUS_FAILED;
}
_realSize = initSize;
_initialized = true;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseDynamicBuffer::putBytes(const byte *buffer, uint32 size) {
if (!_initialized) {
init();
}
while (_offset + size > _realSize) {
_realSize += _growBy;
_buffer = (byte *)realloc(_buffer, _realSize);
if (!_buffer) {
_game->LOG(0, "BaseDynamicBuffer::putBytes - Error reallocating buffer to %d bytes", _realSize);
return STATUS_FAILED;
}
}
memcpy(_buffer + _offset, buffer, size);
_offset += size;
_size += size;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseDynamicBuffer::getBytes(byte *buffer, uint32 size) {
if (!_initialized) {
init();
}
if (_offset + size > _size) {
_game->LOG(0, "BaseDynamicBuffer::getBytes - Buffer underflow");
return STATUS_FAILED;
}
memcpy(buffer, _buffer + _offset, size);
_offset += size;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseDynamicBuffer::putDWORD(uint32 val) {
putBytes((byte *)&val, sizeof(uint32));
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseDynamicBuffer::getDWORD() {
uint32 ret = 0;
getBytes((byte *)&ret, sizeof(uint32));
return ret;
}
//////////////////////////////////////////////////////////////////////////
void BaseDynamicBuffer::putString(const char *val) {
if (!val) {
putString("(null)");
} else {
putDWORD(strlen(val) + 1);
putBytes((const byte *)val, strlen(val) + 1);
}
}
//////////////////////////////////////////////////////////////////////////
char *BaseDynamicBuffer::getString() {
uint32 len = getDWORD();
char *ret = (char *)(_buffer + _offset);
_offset += len;
if (!strcmp(ret, "(null)")) {
return nullptr;
} else {
return ret;
}
}
//////////////////////////////////////////////////////////////////////////
void BaseDynamicBuffer::putText(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
putTextForm(fmt, va);
va_end(va);
}
//////////////////////////////////////////////////////////////////////////
void BaseDynamicBuffer::putTextIndent(int indent, const char *fmt, ...) {
va_list va;
putText("%*s", indent, "");
va_start(va, fmt);
putTextForm(fmt, va);
va_end(va);
}
//////////////////////////////////////////////////////////////////////////
void BaseDynamicBuffer::putTextForm(const char *format, va_list argptr) {
char buff[32768];
Common::vsprintf_s(buff, format, argptr);
putBytes((byte *)buff, strlen(buff));
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,64 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_DYNAMIC_BUFFER_H
#define WINTERMUTE_BASE_DYNAMIC_BUFFER_H
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BaseDynamicBuffer : public BaseClass {
public:
bool _initialized;
void putText(const char *fmt, ...);
void putTextIndent(int indent, const char *fmt, ...);
uint32 getDWORD();
void putDWORD(uint32 val);
char *getString();
void putString(const char *val);
bool getBytes(byte *buffer, uint32 size);
bool putBytes(const byte *buffer, uint32 size);
uint32 getSize();
bool init(uint32 initSize = 0);
void cleanup();
uint32 _size;
byte *_buffer;
BaseDynamicBuffer(BaseGame *inGame, uint32 initSize = 1000, uint32 growBy = 1000);
virtual ~BaseDynamicBuffer();
private:
uint32 _realSize;
uint32 _growBy;
uint32 _initSize;
uint32 _offset;
void putTextForm(const char *format, va_list argptr);
};
} // End of namespace Wintermute
#endif

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/system/sys_class_registry.h"
#include "engines/wintermute/platform_osystem.h"
#include "common/system.h"
namespace Common {
DECLARE_SINGLETON(Wintermute::BaseEngine);
}
namespace Wintermute {
BaseEngine::BaseEngine() {
_fileManager = nullptr;
_gameRef = nullptr;
_classReg = nullptr;
_rnd = nullptr;
_gameId = "";
_language = Common::UNK_LANG;
_targetExecutable = LATEST_VERSION;
_flags = 0;
}
void BaseEngine::init() {
_fileManager = new BaseFileManager(_language);
// Don't forget to register your random source
_rnd = new Common::RandomSource("Wintermute");
_classReg = new SystemClassRegistry();
_classReg->registerClasses();
}
BaseEngine::~BaseEngine() {
delete _fileManager;
delete _rnd;
delete _classReg;
}
void BaseEngine::createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang, WMETargetExecutable targetExecutable, uint32 flags) {
instance()._targetName = targetName;
instance()._gameId = gameId;
instance()._language = lang;
instance()._targetExecutable = targetExecutable;
instance()._flags = flags;
instance().init();
}
void BaseEngine::LOG(bool res, const char *fmt, ...) {
uint32 secs = BasePlatform::getTime() / 1000;
uint32 hours = secs / 3600;
secs = secs % 3600;
uint32 mins = secs / 60;
secs = secs % 60;
char buff[512];
va_list va;
va_start(va, fmt);
Common::vsprintf_s(buff, fmt, va);
va_end(va);
if (instance()._gameRef) {
instance()._gameRef->LOG(res, "%s", buff);
} else {
debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
}
}
uint32 BaseEngine::randInt(int from, int to) {
return _rnd->getRandomNumberRng(from, to);
}
BaseSoundMgr *BaseEngine::getSoundMgr() {
if (instance()._gameRef) {
return _gameRef->_soundMgr;
} else {
return nullptr;
}
}
BaseRenderer *BaseEngine::getRenderer() {
if (instance()._gameRef) {
return instance()._gameRef->_renderer;
} else {
return nullptr;
}
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_ENGINE_H
#define WINTERMUTE_BASE_ENGINE_H
#include "common/str.h"
#include "common/singleton.h"
#include "common/random.h"
#include "common/language.h"
#include "engines/wintermute/detection.h"
namespace Wintermute {
class BaseFileManager;
class BaseRegistry;
class BaseGame;
class BaseSoundMgr;
class BaseRenderer;
class SystemClassRegistry;
class Timer;
class BaseEngine : public Common::Singleton<Wintermute::BaseEngine> {
void init();
BaseFileManager *_fileManager;
Common::String _gameId;
Common::String _targetName;
BaseGame *_gameRef;
// We need random numbers
Common::RandomSource *_rnd;
SystemClassRegistry *_classReg;
Common::Language _language;
WMETargetExecutable _targetExecutable;
uint32 _flags;
public:
BaseEngine();
~BaseEngine() override;
static void createInstance(const Common::String &targetName, const Common::String &gameId, Common::Language lang, WMETargetExecutable targetExecutable, uint32 flags);
void setGameRef(BaseGame *game) { _gameRef = game; }
Common::RandomSource *getRandomSource() { return _rnd; }
uint32 randInt(int from, int to);
SystemClassRegistry *getClassRegistry() { return _classReg; }
BaseGame *getGameRef() { return _gameRef; }
BaseFileManager *getFileManager() { return _fileManager; }
BaseSoundMgr *getSoundMgr();
static BaseRenderer *getRenderer();
static const Timer *getTimer();
static const Timer *getLiveTimer();
static void LOG(bool res, const char *fmt, ...);
Common::String getGameTargetName() const { return _targetName; }
Common::String getGameId() const { return _gameId; }
Common::Language getLanguage() const { return _language; }
uint32 getFlags() const { return _flags; }
WMETargetExecutable getTargetExecutable() const {
return _targetExecutable;
}
static bool isFoxTailCheck(WMETargetExecutable t, WMETargetExecutable v1=FOXTAIL_OLDEST_VERSION, WMETargetExecutable v2=FOXTAIL_LATEST_VERSION) {
return t >= v1 && t <= v2;
}
bool isFoxTail(WMETargetExecutable v1=FOXTAIL_OLDEST_VERSION, WMETargetExecutable v2=FOXTAIL_LATEST_VERSION) const {
return isFoxTailCheck(_targetExecutable, v1, v2);
}
void addFlags(uint32 flags) { _flags |= flags; }
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,196 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_fader.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/platform_osystem.h"
#include "common/util.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(BaseFader, false)
//////////////////////////////////////////////////////////////////////////
BaseFader::BaseFader(BaseGame *inGame) : BaseObject(inGame) {
_active = false;
_red = _green = _blue = 0;
_currentAlpha = 0x00;
_sourceAlpha = 0;
_targetAlpha = 0;
_duration = 1000;
_startTime = 0;
_system = false;
}
//////////////////////////////////////////////////////////////////////////
BaseFader::~BaseFader() {
}
//////////////////////////////////////////////////////////////////////////
bool BaseFader::update() {
if (!_active) {
return STATUS_OK;
}
int alphaDelta = _targetAlpha - _sourceAlpha;
uint32 time;
if (_system) {
time = BasePlatform::getTime() - _startTime;
} else {
time = _game->_timer - _startTime;
}
if (time >= _duration) {
_currentAlpha = _targetAlpha;
} else {
_currentAlpha = (byte)(_sourceAlpha + (float)time / (float)_duration * alphaDelta);
}
_currentAlpha = MIN((byte)255, MAX(_currentAlpha, (byte)0));
_ready = time >= _duration;
if (_ready && _currentAlpha == 0x00) {
_active = false;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFader::display() {
if (!_active) {
return STATUS_OK;
}
if (_currentAlpha > 0x00) {
return _game->_renderer->fadeToColor(_red, _green, _blue, _currentAlpha);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFader::deactivate() {
_active = false;
_ready = true;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFader::fadeIn(uint32 sourceColor, uint32 duration, bool system) {
_ready = false;
_active = true;
_red = RGBCOLGetR(sourceColor);
_green = RGBCOLGetG(sourceColor);
_blue = RGBCOLGetB(sourceColor);
_sourceAlpha = RGBCOLGetA(sourceColor);
_targetAlpha = 0;
_duration = duration;
_system = system;
if (_system) {
_startTime = BasePlatform::getTime();
} else {
_startTime = _game->_timer;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFader::fadeOut(uint32 targetColor, uint32 duration, bool system) {
_ready = false;
_active = true;
_red = RGBCOLGetR(targetColor);
_green = RGBCOLGetG(targetColor);
_blue = RGBCOLGetB(targetColor);
//_sourceAlpha = 0;
_sourceAlpha = _currentAlpha;
_targetAlpha = RGBCOLGetA(targetColor);
_duration = duration;
_system = system;
if (_system) {
_startTime = BasePlatform::getTime();
} else {
_startTime = _game->_timer;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseFader::getCurrentColor() {
return BYTETORGBA(_red, _green, _blue, _currentAlpha);
}
//////////////////////////////////////////////////////////////////////////
bool BaseFader::persist(BasePersistenceManager *persistMgr) {
BaseObject::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_active));
persistMgr->transferByte(TMEMBER(_blue));
persistMgr->transferByte(TMEMBER(_currentAlpha));
persistMgr->transferUint32(TMEMBER(_duration));
persistMgr->transferByte(TMEMBER(_green));
persistMgr->transferByte(TMEMBER(_red));
persistMgr->transferByte(TMEMBER(_sourceAlpha));
persistMgr->transferUint32(TMEMBER(_startTime));
persistMgr->transferByte(TMEMBER(_targetAlpha));
persistMgr->transferBool(TMEMBER(_system));
if (_system && !persistMgr->getIsSaving()) {
_startTime = 0;
}
return STATUS_OK;
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FADER_H
#define WINTERMUTE_BASE_FADER_H
#include "engines/wintermute/base/base_object.h"
namespace Wintermute {
class BaseFader : public BaseObject {
public:
bool _system;
uint32 getCurrentColor();
bool fadeOut(uint32 targetColor, uint32 duration, bool system = false);
bool fadeIn(uint32 sourceColor, uint32 duration, bool system = false);
bool deactivate();
bool display() override;
bool update() override;
DECLARE_PERSISTENT(BaseFader, BaseObject)
BaseFader(BaseGame *inGame);
~BaseFader() override;
bool _active;
byte _red;
byte _green;
byte _blue;
byte _currentAlpha;
byte _targetAlpha;
byte _sourceAlpha;
uint32 _duration;
uint32 _startTime;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,584 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/base/file/base_disk_file.h"
#include "engines/wintermute/base/file/base_savefile_manager_file.h"
#include "engines/wintermute/base/file/base_save_thumb_file.h"
#include "engines/wintermute/base/file/base_package.h"
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/dcgf.h"
#include "common/algorithm.h"
#include "common/array.h"
#include "common/debug.h"
#include "common/str.h"
#include "common/tokenizer.h"
#include "common/textconsole.h"
#include "common/util.h"
#include "common/config-manager.h"
#include "common/system.h"
#include "common/fs.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/fs.h"
#include "common/compression/unzip.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
BaseFileManager::BaseFileManager(Common::Language lang, bool detectionMode) {
_detectionMode = detectionMode;
_language = lang;
_resources = nullptr;
initResources();
initPaths();
registerPackages();
}
//////////////////////////////////////////////////////////////////////
BaseFileManager::~BaseFileManager() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::cleanup() {
// delete registered paths
_packagePaths.clear();
// close open files
for (uint32 i = 0; i < _openFiles.size(); i++) {
delete _openFiles[i];
}
_openFiles.clear();
// delete packages
_packages.clear();
// get rid of the resources:
SAFE_DELETE(_resources);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
byte *BaseFileManager::readWholeFile(const Common::String &filename, uint32 *size, bool mustExist) {
byte *buffer = nullptr;
Common::SeekableReadStream *file = openFile(filename);
if (!file) {
if (mustExist) {
debugC(kWintermuteDebugFileAccess, "Error opening file '%s'", filename.c_str());
}
return nullptr;
}
buffer = new byte[file->size() + 1];
if (buffer == nullptr) {
debugC(kWintermuteDebugFileAccess, "Error allocating buffer for file '%s' (%d bytes)", filename.c_str(), (int)file->size() + 1);
closeFile(file);
return nullptr;
}
if (file->read(buffer, (uint32)file->size()) != (uint32)file->size()) {
debugC(kWintermuteDebugFileAccess, "Error reading file '%s'", filename.c_str());
closeFile(file);
delete[] buffer;
return nullptr;
};
buffer[file->size()] = '\0';
if (size != nullptr) {
*size = file->size();
}
closeFile(file);
return buffer;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::addPath(TPathType type, const Common::FSNode &path) {
if (!path.exists()) {
return STATUS_FAILED;
}
switch (type) {
case PATH_SINGLE:
default:
// _singlePaths.push_back(path);
error("TODO: Allow adding single-paths");
break;
case PATH_PACKAGE:
_packagePaths.push_back(path);
break;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::reloadPaths() {
// delete registered paths
//_singlePaths.clear();
_packagePaths.clear();
return initPaths();
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::initPaths() {
// Removed: Config-based file-path choice.
// package files paths
const Common::FSNode gameData(ConfMan.getPath("path"));
addPath(PATH_PACKAGE, gameData);
Common::FSNode dataSubFolder = gameData.getChild("data");
if (dataSubFolder.exists()) {
addPath(PATH_PACKAGE, dataSubFolder);
}
Common::FSNode languageSubFolder = gameData.getChild("language");
if (languageSubFolder.exists()) {
addPath(PATH_PACKAGE, languageSubFolder);
}
// Also add languages/ for Reversion1.
languageSubFolder = gameData.getChild("languages");
if (languageSubFolder.exists()) {
addPath(PATH_PACKAGE, languageSubFolder);
}
// Special paths init for the SD/HD combo multi-language versions of sotv:
// such versions include a launcher which allows selecting the SD/HD
// version and mixing any combination of available voices and subtitles
bool use_sd_assets = ConfMan.getBool("use_sd_assets"); // if false: hd
bool use_it_voices = ConfMan.getBool("use_it_voices"); // if false: en
Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
switch (lang) {
case Common::DE_DEU:
case Common::EN_ANY:
case Common::ES_ESP:
case Common::FR_FRA:
case Common::IT_ITA:
case Common::PL_POL:
case Common::RU_RUS:
// supported (in terms of subtitles) language selected, all good
break;
default:
// unsupported language selected, fallback to English subtitles
lang = Common::EN_ANY;
break;
}// switch(lang)
// Now that we have values for the three options needed (SD/HD, voices
// language and subtitles language), we can emulate the SotV launcher logic,
// which, according to the options selected via its UI, writes to the
// Windows registry a suitable "PackagePaths" entry. Such entry is then used
// by WME on startup to load only the subset of the available packages which
// is relevant to the selected options, avoiding incorrect overrides.
const char *gameVersion = use_sd_assets ? "sd" : "hd";
const char *voicesLang = use_it_voices ? "it" : "en";
const char *subtitleLang = Common::getLanguageCode(lang);
Common::Array<Common::String> sotvSubfolders;
sotvSubfolders.push_back("common");
sotvSubfolders.push_back(Common::String::format("common_%s", gameVersion));
sotvSubfolders.push_back(Common::String::format("i18n_audio_%s", voicesLang));
sotvSubfolders.push_back(Common::String::format("i18n_audio_%s_%s", voicesLang, gameVersion));
sotvSubfolders.push_back(Common::String::format("i18n_%s", subtitleLang));
sotvSubfolders.push_back(Common::String::format("i18n_%s_%s", subtitleLang, gameVersion));
for (const auto &sotvSubfolder : sotvSubfolders) {
Common::FSNode subFolder = gameData.getChild(sotvSubfolder);
if (subFolder.exists()) {
addPath(PATH_PACKAGE, subFolder);
}
}
// end of special sotv1/sotv2 paths init
return STATUS_OK;
}
bool BaseFileManager::registerPackages(const Common::FSList &fslist) {
for (Common::FSList::const_iterator it = fslist.begin(); it != fslist.end(); ++it) {
debugC(kWintermuteDebugFileAccess, "Adding %s", it->getName().c_str());
if (it->getName().contains(".dcp")) {
if (registerPackage(*it, it->getName())) {
addPath(PATH_PACKAGE, *it);
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::registerPackages() {
debugC(kWintermuteDebugFileAccess, "Scanning packages");
// We need game flags to perform some game-specific hacks.
uint32 flags = BaseEngine::instance().getFlags();
// Register without using SearchMan, as otherwise the FSNode-based lookup in openPackage will fail
// and that has to be like that to support the detection-scheme.
Common::FSList files;
for (Common::FSList::const_iterator it = _packagePaths.begin(); it != _packagePaths.end(); ++it) {
debugC(kWintermuteDebugFileAccess, "Should register folder: %s %s", it->getPath().toString(Common::Path::kNativeSeparator).c_str(), it->getName().c_str());
if (!it->getChildren(files, Common::FSNode::kListFilesOnly)) {
warning("getChildren() failed for path: %s", it->getName().c_str());
}
for (Common::FSList::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
if (!fileIt)
continue;
// To prevent any case sensitivity issues we make the filename
// all lowercase here. This makes the code slightly prettier
// than the equivalent of using equalsIgnoreCase.
Common::String fileName = fileIt->getName();
fileName.toLowercase();
bool searchSignature = false;
if (!fileName.hasSuffix(".dcp") && !fileName.hasSuffix(".exe")) {
continue;
}
if (fileName.hasSuffix(".exe")) {
searchSignature = true;
}
// Again, make the parent's name all lowercase to avoid any case
// issues.
Common::String parentName = it->getName();
parentName.toLowercase();
// Avoid registering all the resolutions for SD/HD games
if (flags & GF_IGNORE_HD_FILES && fileName.hasSuffix("_hd.dcp")) {
continue;
} else if (flags & GF_IGNORE_SD_FILES && fileName.hasSuffix("_sd.dcp")) {
continue;
}
// Avoid registering all the language files
// TODO: Select based on the gameDesc.
if (_language != Common::UNK_LANG) {
// English
if (fileName == "english.dcp" || fileName == "xlanguage_en.dcp" || fileName == "english_language_pack.dcp") {
if (_language != Common::EN_ANY) {
continue;
}
// Chinese
} else if (fileName == "chinese.dcp" || fileName == "xlanguage_nz.dcp" || fileName == "chinese_language_pack.dcp") {
if (_language != Common::ZH_ANY) {
continue;
}
// Simplified Chinese
} else if (fileName == "xlanguage_zh_s.dcp") {
if (_language != Common::ZH_CHN) {
continue;
}
// Traditional Chinese
} else if (fileName == "xlanguage_zh_t.dcp") {
if (_language != Common::ZH_TWN) {
continue;
}
// Czech
} else if (fileName == "czech.dcp" || fileName == "xlanguage_cz.dcp" || fileName == "czech_language_pack.dcp") {
if (_language != Common::CS_CZE) {
continue;
}
// French
} else if (fileName == "french.dcp" || fileName == "xlanguage_fr.dcp" || fileName == "french_language_pack.dcp") {
if (_language != Common::FR_FRA) {
continue;
}
// German
} else if (fileName == "german.dcp" || fileName == "xlanguage_de.dcp" || fileName == "german_language_pack.dcp") {
if (_language != Common::DE_DEU) {
continue;
}
// Italian
} else if (fileName == "italian.dcp" || fileName == "xlanguage_it.dcp" || fileName == "italian_language_pack.dcp") {
if (_language != Common::IT_ITA) {
continue;
}
// Latvian
} else if (fileName == "latvian.dcp" || fileName == "xlanguage_lv.dcp" || fileName == "latvian_language_pack.dcp") {
if (_language != Common::LV_LVA) {
continue;
}
// Persian
} else if (fileName == "persian.dcp" || fileName == "xlanguage_fa.dcp" || fileName == "persian_language_pack.dcp") {
if (_language != Common::FA_IRN) {
continue;
}
// Polish
} else if (fileName == "polish.dcp" || fileName == "xlanguage_pl.dcp" || fileName == "polish_language_pack.dcp") {
if (_language != Common::PL_POL) {
continue;
}
// Portuguese
} else if (fileName == "portuguese.dcp" || fileName == "xlanguage_pt.dcp" || fileName == "portuguese_language_pack.dcp") {
if (_language != Common::PT_BRA) {
continue;
}
// Russian
} else if (fileName == "russian.dcp" || fileName == "xlanguage_ru.dcp" || fileName == "russian_language_pack.dcp") {
if (_language != Common::RU_RUS) {
continue;
}
// Serbian
} else if (fileName == "serbian.dcp" || fileName == "xlanguage_sr.dcp" || fileName == "serbian_language_pack.dcp") {
if (_language != Common::SR_SRB) {
continue;
}
// Spanish
} else if (fileName == "spanish.dcp" || fileName == "xlanguage_es.dcp" || fileName == "spanish_language_pack.dcp") {
if (_language != Common::ES_ESP) {
continue;
}
// generic
} else if (fileName.hasPrefix("xlanguage_")) {
warning("Unknown language package: %s", fileName.c_str());
continue;
}
}
debugC(kWintermuteDebugFileAccess, "Registering %s %s", fileIt->getPath().toString(Common::Path::kNativeSeparator).c_str(), fileIt->getName().c_str());
registerPackage((*fileIt), fileName, searchSignature);
}
}
// debugC(kWintermuteDebugFileAccess, " Registered %d files in %d package(s)", _files.size(), _packages.size());
return STATUS_OK;
}
bool BaseFileManager::registerPackage(Common::FSNode file, const Common::String &filename, bool searchSignature) {
if (_packages.hasArchive(filename.c_str())) {
debugC(kWintermuteDebugFileAccess, "BaseFileManager::registerPackage - file %s already added to archive", filename.c_str());
return STATUS_FAILED;
}
PackageSet *pack = new PackageSet(file, filename, searchSignature);
_packages.add(filename, pack, pack->getPriority() , true);
_versions[filename] = pack->getVersion();
return STATUS_OK;
}
void BaseFileManager::initResources() {
_resources = Common::makeZipArchive("wintermute.zip");
if (!_resources && !_detectionMode) { // Wintermute.zip is unavailable during detection
error("Couldn't load wintermute.zip");
}
if (_resources) {
assert(_resources->hasFile("syste_font.bmp"));
assert(_resources->hasFile("invalid.bmp"));
assert(_resources->hasFile("invalid_debug.bmp"));
}
}
//////////////////////////////////////////////////////////////////////////
Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &filename) {
Common::String upcName = filename;
upcName.toUppercase();
Common::SeekableReadStream *file = nullptr;
// correct slashes
for (uint32 i = 0; i < upcName.size(); i++) {
if (upcName[(int32)i] == '/') {
upcName.setChar('\\', (uint32)i);
}
}
Common::ArchiveMemberPtr entry = _packages.getMember(Common::Path(upcName, '\\'));
if (!entry) {
return nullptr;
}
file = entry->createReadStream();
return file;
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseFileManager::getPackageVersion(const Common::String &filename) {
Common::HashMap<Common::String, uint32>::iterator it = _versions.find(filename);
if (it != _versions.end()) {
return it->_value;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::hasFile(const Common::String &filename) {
Common::String backslashPath(filename);
for (uint32 i = 0; i < backslashPath.size(); i++) {
if (backslashPath[(int32)i] == '/') {
backslashPath.setChar('\\', (uint32)i);
}
}
Common::Path path(backslashPath, '\\');
if (scumm_strnicmp(filename.c_str(), "savegame:", 9) == 0) {
BasePersistenceManager pm(BaseEngine::instance().getGameTargetName());
if (filename.size() <= 9) {
return false;
}
int slot = atoi(filename.c_str() + 9);
return pm.getSaveExists(slot);
}
if (sfmFileExists(filename)) {
return true;
}
if (diskFileExists(filename)) {
return true;
}
if (_packages.hasFile(path)) {
return true; // We don't bother checking if the file can actually be opened, something bigger is wrong if that is the case.
}
if (!_detectionMode && _resources->hasFile(path)) {
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
int BaseFileManager::listMatchingPackageMembers(Common::ArchiveMemberList &list, const Common::String &pattern) {
return _packages.listMatchingMembers(list, Common::Path(pattern));
}
//////////////////////////////////////////////////////////////////////////
int BaseFileManager::listMatchingFiles(Common::StringArray &list, const Common::String &pattern) {
list = sfmFileList(pattern);
Common::ArchiveMemberList files;
listMatchingDiskFileMembers(files, pattern);
for (Common::ArchiveMemberList::const_iterator it = files.begin(); it != files.end(); ++it) {
list.push_back((*it)->getName());
}
return list.size();
}
//////////////////////////////////////////////////////////////////////////
Common::SeekableReadStream *BaseFileManager::openFile(const Common::String &filename, bool absPathWarning, bool keepTrackOf) {
if (filename.empty()) {
return nullptr;
}
debugC(kWintermuteDebugFileAccess, "Open file %s", filename.c_str());
Common::SeekableReadStream *file = openFileRaw(filename);
if (file && keepTrackOf) {
_openFiles.push_back(file);
}
return file;
}
//////////////////////////////////////////////////////////////////////////
Common::WriteStream *BaseFileManager::openFileForWrite(const Common::String &filename) {
if (filename.empty()) {
return nullptr;
}
debugC(kWintermuteDebugFileAccess, "Open file %s for write", filename.c_str());
return openFileForWriteRaw(filename);
}
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::closeFile(Common::SeekableReadStream *File) {
for (uint32 i = 0; i < _openFiles.size(); i++) {
if (_openFiles[i] == File) {
delete _openFiles[i];
_openFiles.remove_at(i);
return STATUS_OK;
}
}
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
Common::SeekableReadStream *BaseFileManager::openFileRaw(const Common::String &filename) {
Common::SeekableReadStream *ret = nullptr;
if (scumm_strnicmp(filename.c_str(), "savegame:", 9) == 0) {
if (!BaseEngine::instance().getGameRef()) {
error("Attempt to load filename: %s without BaseEngine-object, this is unsupported", filename.c_str());
}
return openThumbFile(filename);
}
ret = openSfmFile(filename);
if (ret) {
return ret;
}
ret = openDiskFile(filename);
if (ret) {
return ret;
}
ret = openPkgFile(filename);
if (ret) {
return ret;
}
if (!_detectionMode) {
ret = _resources->createReadStreamForMember(Common::Path(filename));
}
if (ret) {
return ret;
}
debugC(kWintermuteDebugFileAccess ,"BFileManager::OpenFileRaw - Failed to open %s", filename.c_str());
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
Common::WriteStream *BaseFileManager::openFileForWriteRaw(const Common::String &filename) {
Common::WriteStream *ret = nullptr;
ret = openSfmFileForWrite(filename);
if (ret) {
return ret;
}
debugC(kWintermuteDebugFileAccess ,"BFileManager::OpenFileRaw - Failed to open %s", filename.c_str());
return nullptr;
}
BaseFileManager *BaseFileManager::getEngineInstance() {
if (BaseEngine::instance().getFileManager()) {
return BaseEngine::instance().getFileManager();
}
return nullptr;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,85 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FILE_MANAGER_H
#define WINTERMUTE_BASE_FILE_MANAGER_H
#include "common/archive.h"
#include "common/str.h"
#include "common/str-array.h"
#include "common/fs.h"
#include "common/file.h"
#include "common/language.h"
namespace Wintermute {
class BaseFileManager {
public:
bool cleanup();
bool closeFile(Common::SeekableReadStream *File);
bool hasFile(const Common::String &filename);
int listMatchingPackageMembers(Common::ArchiveMemberList &list, const Common::String &pattern);
int listMatchingFiles(Common::StringArray &list, const Common::String &pattern);
Common::SeekableReadStream *openFile(const Common::String &filename, bool absPathWarning = true, bool keepTrackOf = true);
Common::WriteStream *openFileForWrite(const Common::String &filename);
byte *readWholeFile(const Common::String &filename, uint32 *size = nullptr, bool mustExist = true);
uint32 getPackageVersion(const Common::String &filename);
BaseFileManager(Common::Language lang, bool detectionMode = false);
virtual ~BaseFileManager();
// Used only for detection
bool registerPackages(const Common::FSList &fslist);
static BaseFileManager *getEngineInstance();
private:
typedef enum {
PATH_PACKAGE,
PATH_SINGLE
} TPathType;
bool reloadPaths();
bool initPaths();
bool addPath(TPathType type, const Common::FSNode &path);
bool registerPackages();
void initResources();
Common::SeekableReadStream *openFileRaw(const Common::String &filename);
Common::WriteStream *openFileForWriteRaw(const Common::String &filename);
Common::SeekableReadStream *openPkgFile(const Common::String &filename);
Common::FSList _packagePaths;
bool registerPackage(Common::FSNode package, const Common::String &filename = "", bool searchSignature = false);
bool _detectionMode;
Common::SearchSet _packages;
Common::Array<Common::SeekableReadStream *> _openFiles;
Common::Language _language;
Common::Archive *_resources;
Common::HashMap<Common::String, uint32> _versions;
// This class is intentionally not a subclass of Base, as it needs to be used by
// the detector too, without launching the entire engine:
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,772 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_object.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/dcgf.h"
#include "common/str.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseFrame, false)
//////////////////////////////////////////////////////////////////////
BaseFrame::BaseFrame(BaseGame *inGame) : BaseScriptable(inGame, true) {
_delay = 0;
_moveX = _moveY = 0;
_sound = nullptr;
_killSound = false;
_editorExpanded = false;
_keyframe = false;
}
//////////////////////////////////////////////////////////////////////
BaseFrame::~BaseFrame() {
SAFE_DELETE(_sound);
for (int32 i = 0; i < _subframes.getSize(); i++) {
delete _subframes[i];
}
_subframes.removeAll();
for (int32 i = 0; i < _applyEvent.getSize(); i++) {
SAFE_DELETE_ARRAY(_applyEvent[i]);
}
_applyEvent.removeAll();
}
//////////////////////////////////////////////////////////////////////
bool BaseFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, bool allFrames, float rotate, Graphics::TSpriteBlendMode blendMode) {
bool res;
for (int32 i = 0; i < _subframes.getSize(); i++) {
// filter out subframes unsupported by current renderer
//
// This is not present in original Lite version of WME.
// It's in assumption Lite support only 2D games.
// Our 3D renderer has full 2D capability, so not filter 2D only subframes.
if (!allFrames) {
if (/*(_subframes[i]->_2DOnly && _game->_useD3D) || */(_subframes[i]->_3DOnly && !_game->_useD3D))
continue;
}
res = _subframes[i]->draw(x, y, registerOwner, zoomX, zoomY, precise, alpha, rotate, blendMode);
if (DID_FAIL(res)) {
return res;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::oneTimeDisplay(BaseObject *owner, bool muted) {
if (_sound && !muted) {
if (owner) {
owner->updateOneSound(_sound);
}
_sound->play();
/*
if (_game->_state == GAME_FROZEN) {
_sound->pause(true);
}
*/
}
if (owner) {
for (int32 i = 0; i < _applyEvent.getSize(); i++) {
owner->applyEvent(_applyEvent[i]);
}
}
return STATUS_OK;
}
TOKEN_DEF_START
TOKEN_DEF(DELAY)
TOKEN_DEF(IMAGE)
TOKEN_DEF(TRANSPARENT)
TOKEN_DEF(RECT)
TOKEN_DEF(HOTSPOT)
TOKEN_DEF(2D_ONLY)
TOKEN_DEF(3D_ONLY)
TOKEN_DEF(MIRROR_X)
TOKEN_DEF(MIRROR_Y)
TOKEN_DEF(MOVE)
TOKEN_DEF(ALPHA_COLOR)
TOKEN_DEF(ALPHA)
TOKEN_DEF(SUBFRAME)
TOKEN_DEF(SOUND)
TOKEN_DEF(KEYFRAME)
TOKEN_DEF(DECORATION)
TOKEN_DEF(APPLY_EVENT)
TOKEN_DEF(EDITOR_SELECTED)
TOKEN_DEF(EDITOR_EXPANDED)
TOKEN_DEF(EDITOR_PROPERTY)
TOKEN_DEF(KILL_SOUND)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
bool BaseFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(DELAY)
TOKEN_TABLE(IMAGE)
TOKEN_TABLE(TRANSPARENT)
TOKEN_TABLE(RECT)
TOKEN_TABLE(HOTSPOT)
TOKEN_TABLE(2D_ONLY)
TOKEN_TABLE(3D_ONLY)
TOKEN_TABLE(MIRROR_X)
TOKEN_TABLE(MIRROR_Y)
TOKEN_TABLE(MOVE)
TOKEN_TABLE(ALPHA_COLOR)
TOKEN_TABLE(ALPHA)
TOKEN_TABLE(SUBFRAME)
TOKEN_TABLE(SOUND)
TOKEN_TABLE(KEYFRAME)
TOKEN_TABLE(DECORATION)
TOKEN_TABLE(APPLY_EVENT)
TOKEN_TABLE(EDITOR_SELECTED)
TOKEN_TABLE(EDITOR_EXPANDED)
TOKEN_TABLE(EDITOR_PROPERTY)
TOKEN_TABLE(KILL_SOUND)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
Common::Rect32 rect;
int r = 255, g = 255, b = 255;
int ar = 255, ag = 255, ab = 255, alpha = 255;
int hotspotX = 0, hotspotY = 0;
bool customTrans = false;
bool editorSelected = false;
bool is2DOnly = false;
bool is3DOnly = false;
bool decoration = false;
bool mirrorX = false;
bool mirrorY = false;
BasePlatform::setRectEmpty(&rect);
char *surface_file = nullptr;
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_DELAY:
parser.scanStr(params, "%d", &_delay);
break;
case TOKEN_IMAGE:
surface_file = params;
break;
case TOKEN_TRANSPARENT:
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
customTrans = true;
break;
case TOKEN_RECT:
parser.scanStr(params, "%d,%d,%d,%d", &rect.left, &rect.top, &rect.right, &rect.bottom);
break;
case TOKEN_HOTSPOT:
parser.scanStr(params, "%d,%d", &hotspotX, &hotspotY);
break;
case TOKEN_MOVE:
parser.scanStr(params, "%d,%d", &_moveX, &_moveY);
break;
case TOKEN_2D_ONLY:
parser.scanStr(params, "%b", &is2DOnly);
break;
case TOKEN_3D_ONLY:
parser.scanStr(params, "%b", &is3DOnly);
break;
case TOKEN_MIRROR_X:
parser.scanStr(params, "%b", &mirrorX);
break;
case TOKEN_MIRROR_Y:
parser.scanStr(params, "%b", &mirrorY);
break;
case TOKEN_ALPHA_COLOR:
parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab);
break;
case TOKEN_ALPHA:
parser.scanStr(params, "%d", &alpha);
break;
case TOKEN_EDITOR_SELECTED:
parser.scanStr(params, "%b", &editorSelected);
break;
case TOKEN_EDITOR_EXPANDED:
parser.scanStr(params, "%b", &_editorExpanded);
break;
case TOKEN_KILL_SOUND:
parser.scanStr(params, "%b", &_killSound);
break;
case TOKEN_SUBFRAME: {
BaseSubFrame *subframe = new BaseSubFrame(_game);
if (!subframe || DID_FAIL(subframe->loadBuffer(params, lifeTime, keepLoaded))) {
delete subframe;
cmd = PARSERR_GENERIC;
} else {
_subframes.add(subframe);
}
}
break;
case TOKEN_SOUND: {
if (_sound) {
SAFE_DELETE(_sound);
}
_sound = new BaseSound(_game);
if (!_sound || DID_FAIL(_sound->setSound(params, TSoundType::SOUND_SFX, false))) {
if (_game->_soundMgr->_soundAvailable) {
_game->LOG(0, "Error loading sound '%s'.", params);
}
SAFE_DELETE(_sound);
}
}
break;
case TOKEN_APPLY_EVENT: {
size_t eventSize = strlen(params) + 1;
char *event = new char[eventSize];
Common::strcpy_s(event, eventSize, params);
_applyEvent.add(event);
}
break;
case TOKEN_KEYFRAME:
parser.scanStr(params, "%b", &_keyframe);
break;
case TOKEN_DECORATION:
parser.scanStr(params, "%b", &decoration);
break;
case TOKEN_EDITOR_PROPERTY:
parseEditorProperty(params, false);
break;
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
_game->LOG(0, "Syntax error in FRAME definition");
return STATUS_FAILED;
}
if (cmd == PARSERR_GENERIC) {
_game->LOG(0, "Error loading FRAME definition");
return STATUS_FAILED;
}
BaseSubFrame *sub = new BaseSubFrame(_game);
if (surface_file != nullptr) {
if (customTrans) {
sub->setSurface(surface_file, false, r, g, b, lifeTime, keepLoaded);
} else {
sub->setSurface(surface_file, true, 0, 0, 0, lifeTime, keepLoaded);
}
if (!sub->_surface) {
delete sub;
_game->LOG(0, "Error loading SUBFRAME");
return STATUS_FAILED;
}
sub->_alpha = BYTETORGBA(ar, ag, ab, alpha);
if (customTrans) {
sub->_transparent = BYTETORGBA(r, g, b, 0xFF);
}
}
if (BasePlatform::isRectEmpty(&rect)) {
sub->setDefaultRect();
} else {
sub->_rect = rect;
}
sub->_hotspotX = hotspotX;
sub->_hotspotY = hotspotY;
sub->_2DOnly = is2DOnly;
sub->_3DOnly = is3DOnly;
sub->_decoration = decoration;
sub->_mirrorX = mirrorX;
sub->_mirrorY = mirrorY;
sub->_editorSelected = editorSelected;
_subframes.insertAt(0, sub);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::getBoundingRect(Common::Rect32 *rect, int x, int y, float scaleX, float scaleY) {
if (!rect) {
return false;
}
BasePlatform::setRectEmpty(rect);
Common::Rect32 subRect;
for (int32 i = 0; i < _subframes.getSize(); i++) {
_subframes[i]->getBoundingRect(&subRect, x, y, scaleX, scaleY);
BasePlatform::unionRect(rect, rect, &subRect);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::saveAsText(BaseDynamicBuffer *buffer, int indent) {
buffer->putTextIndent(indent, "FRAME {\n");
buffer->putTextIndent(indent + 2, "DELAY = %d\n", _delay);
if (_moveX != 0 || _moveY != 0) {
buffer->putTextIndent(indent + 2, "MOVE {%d, %d}\n", _moveX, _moveY);
}
if (_sound && _sound->_soundFilename && _sound->_soundFilename[0]) {
buffer->putTextIndent(indent + 2, "SOUND=\"%s\"\n", _sound->_soundFilename);
}
buffer->putTextIndent(indent + 2, "KEYFRAME=%s\n", _keyframe ? "TRUE" : "FALSE");
if (_killSound) {
buffer->putTextIndent(indent + 2, "KILL_SOUND=%s\n", _killSound ? "TRUE" : "FALSE");
}
if (_editorExpanded) {
buffer->putTextIndent(indent + 2, "EDITOR_EXPANDED=%s\n", _editorExpanded ? "TRUE" : "FALSE");
}
if (_subframes.getSize() > 0) {
_subframes[0]->saveAsText(buffer, indent, false);
}
for (int32 i = 1; i < _subframes.getSize(); i++) {
_subframes[i]->saveAsText(buffer, indent + 2);
}
for (int32 i = 0; i < _applyEvent.getSize(); i++) {
buffer->putTextIndent(indent + 2, "APPLY_EVENT=\"%s\"\n", _applyEvent[i]);
}
BaseClass::saveAsText(buffer, indent + 2);
buffer->putTextIndent(indent, "}\n\n");
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
_applyEvent.persist(persistMgr);
persistMgr->transferUint32(TMEMBER(_delay));
persistMgr->transferBool(TMEMBER(_editorExpanded));
persistMgr->transferBool(TMEMBER(_keyframe));
persistMgr->transferBool(TMEMBER(_killSound));
persistMgr->transferSint32(TMEMBER(_moveX));
persistMgr->transferSint32(TMEMBER(_moveY));
persistMgr->transferPtr(TMEMBER_PTR(_sound));
_subframes.persist(persistMgr);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// GetSound
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "GetSound") == 0) {
stack->correctParams(0);
if (_sound && _sound->_soundFilename && _sound->_soundFilename[0]) {
stack->pushString(_sound->_soundFilename);
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetSound
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "SetSound") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
SAFE_DELETE(_sound);
if (!val->isNULL()) {
_sound = new BaseSound(_game);
if (!_sound || DID_FAIL(_sound->setSound(val->getString(), TSoundType::SOUND_SFX, false))) {
stack->pushBool(false);
SAFE_DELETE(_sound);
} else {
stack->pushBool(true);
}
} else {
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetSubframe
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "GetSubframe") == 0) {
stack->correctParams(1);
int index = stack->pop()->getInt(-1);
if (index < 0 || index >= _subframes.getSize()) {
script->runtimeError("Frame.GetSubframe: Subframe index %d is out of range.", index);
stack->pushNULL();
} else {
stack->pushNative(_subframes[index], true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// DeleteSubframe
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "DeleteSubframe") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
if (val->isInt()) {
int index = val->getInt(-1);
if (index < 0 || index >= _subframes.getSize()) {
script->runtimeError("Frame.DeleteSubframe: Subframe index %d is out of range.", index);
}
} else {
BaseSubFrame *sub = (BaseSubFrame *)val->getNative();
for (int32 i = 0; i < _subframes.getSize(); i++) {
if (_subframes[i] == sub) {
delete _subframes[i];
_subframes.removeAt(i);
break;
}
}
}
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// AddSubframe
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "AddSubframe") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
const char *filename = nullptr;
if (!val->isNULL()) {
filename = val->getString();
}
BaseSubFrame *sub = new BaseSubFrame(_game);
if (filename != nullptr) {
sub->setSurface(filename);
sub->setDefaultRect();
}
_subframes.add(sub);
stack->pushNative(sub, true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// InsertSubframe
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "InsertSubframe") == 0) {
stack->correctParams(2);
int index = stack->pop()->getInt();
if (index < 0) {
index = 0;
}
ScValue *val = stack->pop();
const char *filename = nullptr;
if (!val->isNULL()) {
filename = val->getString();
}
BaseSubFrame *sub = new BaseSubFrame(_game);
if (filename != nullptr) {
sub->setSurface(filename);
}
if (index >= _subframes.getSize()) {
_subframes.add(sub);
} else {
_subframes.insertAt(index, sub);
}
stack->pushNative(sub, true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetEvent
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetSubframe") == 0) {
stack->correctParams(1);
int index = stack->pop()->getInt(-1);
if (index < 0 || index >= _applyEvent.getSize()) {
script->runtimeError("Frame.GetEvent: Event index %d is out of range.", index);
stack->pushNULL();
} else {
stack->pushString(_applyEvent[index]);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// AddEvent
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "AddEvent") == 0) {
stack->correctParams(1);
const char *event = stack->pop()->getString();
for (int32 i = 0; i < _applyEvent.getSize(); i++) {
if (scumm_stricmp(_applyEvent[i], event) == 0) {
stack->pushNULL();
return STATUS_OK;
}
}
_applyEvent.add(event);
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// DeleteEvent
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "DeleteEvent") == 0) {
stack->correctParams(1);
const char *event = stack->pop()->getString();
for (int32 i = 0; i < _applyEvent.getSize(); i++) {
if (scumm_stricmp(_applyEvent[i], event) == 0) {
delete[] _applyEvent[i];
_applyEvent.removeAt(i);
break;
}
}
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
else {
if (_subframes.getSize() == 1) {
return _subframes[0]->scCallMethod(script, stack, thisStack, name);
} else {
return BaseScriptable::scCallMethod(script, stack, thisStack, name);
}
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseFrame::scGetProperty(const char *name) {
if (!_scValue) {
_scValue = new ScValue(_game);
}
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("frame");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Delay
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Delay") == 0) {
_scValue->setInt(_delay);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Keyframe
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Keyframe") == 0) {
_scValue->setBool(_keyframe);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// KillSounds
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "KillSounds") == 0) {
_scValue->setBool(_killSound);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// MoveX
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveX") == 0) {
_scValue->setInt(_moveX);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// MoveY
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveY") == 0) {
_scValue->setInt(_moveY);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// NumSubframes (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "NumSubframes") == 0) {
_scValue->setInt(_subframes.getSize());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// NumEvents (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "NumEvents") == 0) {
_scValue->setInt(_applyEvent.getSize());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
else {
if (_subframes.getSize() == 1) {
return _subframes[0]->scGetProperty(name);
} else {
return BaseScriptable::scGetProperty(name);
}
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Delay
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Delay") == 0) {
_delay = MAX(0, value->getInt());
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Keyframe
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Keyframe") == 0) {
_keyframe = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// KillSounds
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "KillSounds") == 0) {
_killSound = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MoveX
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveX") == 0) {
_moveX = value->getInt();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MoveY
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveY") == 0) {
_moveY = value->getInt();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
else {
if (_subframes.getSize() == 1) {
return _subframes[0]->scSetProperty(name, value);
} else {
return BaseScriptable::scSetProperty(name, value);
}
}
}
//////////////////////////////////////////////////////////////////////////
const char *BaseFrame::scToString() {
return "[frame]";
}
Common::String BaseFrame::debuggerToString() const {
return Common::String::format("%p: Frame \"%s\": #subframes %d ", (const void *)this, _name, _subframes.getSize());
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FRAME_H
#define WINTERMUTE_BASE_FRAME_H
#include "engines/wintermute/base/base_scriptable.h"
#include "engines/wintermute/coll_templ.h"
#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSound;
class BaseSubFrame;
class BaseObject;
class ScScript;
class ScStack;
class BaseFrame : public BaseScriptable {
public:
bool _killSound;
bool _keyframe;
bool oneTimeDisplay(BaseObject *owner, bool muted = false);
DECLARE_PERSISTENT(BaseFrame, BaseScriptable)
BaseSound *_sound;
bool _editorExpanded;
bool getBoundingRect(Common::Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override;
int32 _moveY;
int32 _moveX;
uint32 _delay;
BaseArray<BaseSubFrame *> _subframes;
bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, bool allFrames = false, float rotate = 0.0f, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL);
bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded);
BaseFrame(BaseGame *inGame);
~BaseFrame() override;
BaseArray<const char *> _applyEvent;
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
Common::String debuggerToString() const override;
};
} // End of namespace Wintermute
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,473 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_GAME_H
#define WINTERMUTE_BASE_GAME_H
#include "engines/wintermute/base/base_object.h"
#include "engines/wintermute/base/base_game_custom_actions.h"
#include "engines/wintermute/base/base_string_table.h"
#include "engines/wintermute/ext/plugin_event.h"
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/debugger.h"
#if EXTENDED_DEBUGGER_ENABLED
#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h"
#endif
#include "common/events.h"
#include "common/random.h"
namespace Wintermute {
typedef void (*ENGINE_LOG_CALLBACK)(char *text, bool result, void *data);
class BaseSoundMgr;
class BaseFader;
class BaseFont;
class BaseFileManager;
class BaseTransitionMgr;
class BaseFontStorage;
class BaseGameMusic;
class BaseQuickMsg;
class BaseViewport;
class BaseRenderer;
class BaseRegistry;
class BaseSurfaceStorage;
class BaseKeyboardState;
class BaseGameSettings;
class BaseAccessMgr;
class ScEngine;
class SXMath;
class SXDirectory;
class UIWindow;
class VideoPlayer;
class VideoTheoraPlayer;
class SaveThumbHelper;
#ifdef ENABLE_WME3D
class BaseRenderer3D;
struct FogParameters;
#endif
#define NUM_MUSIC_CHANNELS 5
class BaseGame : public BaseObject {
public:
DECLARE_PERSISTENT(BaseGame, BaseObject)
virtual bool onScriptShutdown(ScScript *script);
virtual bool getLayerSize(int *LayerWidth, int *LayerHeight, Common::Rect32 *viewport, bool *customViewport);
#ifdef ENABLE_WME3D
virtual uint32 getAmbientLightColor();
virtual bool getFogParams(bool *fogEnabled, uint32 *fogColor, float *start, float *end);
#endif
virtual BaseObject *getNextAccessObject(BaseObject *currObject);
virtual BaseObject *getPrevAccessObject(BaseObject *currObject);
virtual bool onActivate(bool activate, bool refreshMouse);
virtual bool onMouseLeftDown();
virtual bool onMouseLeftUp();
virtual bool onMouseLeftDblClick();
virtual bool onMouseRightDblClick();
virtual bool onMouseRightDown();
virtual bool onMouseRightUp();
virtual bool onMouseMiddleDown();
virtual bool onMouseMiddleUp();
virtual bool onPaint();
virtual bool onWindowClose();
bool isLeftDoubleClick();
bool isRightDoubleClick();
bool _autorunDisabled;
uint32 _lastMiniUpdate;
bool _miniUpdateEnabled;
virtual bool miniUpdate();
void getMousePos(Common::Point32 *pos);
Common::Rect32 _mouseLockRect;
bool _shuttingDown;
virtual bool displayDebugInfo();
bool _debugShowFPS;
bool _suspendedRendering;
int32 _soundBufferSizeSec;
virtual bool renderShadowGeometry();
TTextEncoding _textEncoding;
bool _textRTL;
BaseSprite *_loadingIcon;
int32 _loadingIconX;
int32 _loadingIconY;
int32 _loadingIconPersistent;
virtual bool resetContent();
void DEBUG_DumpClassRegistry();
bool setWaitCursor(const char *filename);
char *_localSaveDir;
bool _saveDirChecked;
#ifdef ENABLE_WME3D
bool _supportsRealTimeShadows;
TShadowType _maxShadowType;
bool setMaxShadowType(TShadowType maxShadowType);
virtual TShadowType getMaxShadowType(BaseObject *object = nullptr);
#endif
bool _indicatorDisplay;
uint32 _indicatorColor;
int32 _indicatorProgress;
int32 _indicatorX;
int32 _indicatorY;
int32 _indicatorWidth;
int32 _indicatorHeight;
bool _richSavedGames;
char *_savedGameExt;
int32 _editorResolutionWidth;
int32 _editorResolutionHeight;
char *_loadImageName;
char *_saveImageName;
int32 _saveImageX;
int32 _saveImageY;
int32 _loadImageX;
int32 _loadImageY;
BaseSurface *_saveLoadImage;
bool _hasDrawnSaveLoadImage;
bool displayIndicator();
#ifdef ENABLE_FOXTAIL
bool displayIndicatorFoxTail();
#endif
uint32 _thumbnailWidth;
uint32 _thumbnailHeight;
bool _reportTextureFormat;
void setEngineLogCallback(ENGINE_LOG_CALLBACK callback = nullptr, void *data = nullptr);
ENGINE_LOG_CALLBACK _engineLogCallback;
void *_engineLogCallbackData;
bool _editorMode;
void getOffset(int *offsetX, int *offsetY) const;
void setOffset(int32 offsetX, int32 offsetY);
int getSequence();
int32 _offsetY;
int32 _offsetX;
float _offsetPercentX;
float _offsetPercentY;
BaseObject *_mainObject;
bool initInput();
bool initLoop();
uint32 _currentTime{};
uint32 _deltaTime;
BaseFont *_systemFont;
BaseFont *_videoFont;
bool initConfManSettings();
bool initRenderer();
bool initialize1();
bool initialize2();
bool initialize3();
BaseAccessMgr *_accessMgr;
BaseFileManager *_fileManager;
BaseTransitionMgr *_transMgr;
void LOG(bool res, const char *fmt, ...);
BaseRenderer *_renderer;
#ifdef ENABLE_WME3D
BaseRenderer3D *_renderer3D;
bool _playing3DGame;
#endif
BaseSoundMgr *_soundMgr;
#if EXTENDED_DEBUGGER_ENABLED
DebuggableScEngine *_scEngine;
#else
ScEngine *_scEngine;
#endif
BaseScriptable *_mathClass;
BaseScriptable *_directoryClass;
BaseSurfaceStorage *_surfaceStorage;
BaseFontStorage *_fontStorage;
BaseGame(const Common::String &targetName);
~BaseGame() override;
void debugDisable();
void debugEnable(const char *filename = nullptr);
bool _debugMode;
void *_debugLogFile;
int32 _sequence;
virtual bool loadFile(const char *filename);
virtual bool loadBuffer(char *buffer, bool complete = true);
BaseArray<BaseQuickMsg *> _quickMessages;
BaseArray<UIWindow *> _windows;
BaseArray<BaseViewport *> _viewportStack;
int32 _viewportSP;
bool _mouseLeftDown;
bool _mouseRightDown;
bool _mouseMidlleDown;
BaseStringTable *_stringTable;
int _settingsResWidth;
int _settingsResHeight;
bool _settingsRequireAcceleration;
bool _settingsAllowWindowed;
bool _settingsAllowAdvanced;
bool _settingsAllowAccessTab;
bool _settingsAllowAboutTab;
bool _settingsRequireSound;
bool _settingsAllowDesktopRes;
int32 _settingsTLMode;
char *_settingsGameFile;
BaseFader *_fader;
bool _suppressScriptErrors;
bool invalidateDeviceObjects() override;
bool restoreDeviceObjects() override;
virtual bool externalCall(ScScript *script, ScStack *stack, ScStack *thisStack, char *name);
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
// compatibility bits
bool _compatKillMethodThreads;
private:
// FPS stuff
uint32 _lastTime;
uint32 _fpsTime;
uint32 _framesRendered;
public:
uint32 _surfaceGCCycleTime;
bool _smartCache; // RO
bool _videoSubtitles;
bool _subtitles; // RO
uint32 _musicStartTime[NUM_MUSIC_CHANNELS];
bool _compressedSavegames;
int32 _scheduledLoadSlot;
bool _loading;
bool _personalizedSave;
static bool emptySaveSlot(int slot);
static bool isSaveSlotUsed(int slot);
static bool getSaveSlotDescription(int slot, Common::String &desc);
static void getSaveSlotTimestamp(int slot, TimeDate *time);
static bool getSaveSlotFilename(int slot, Common::String &desc);
void setWindowTitle();
bool handleMouseWheel(int32 delta) override;
bool _quitting;
virtual bool getVersion(byte *verMajor, byte *verMinor, byte *extMajor, byte *extMinor);
bool handleKeypress(Common::Event *event, bool printable = false) override;
virtual void handleKeyRelease(Common::Event *event);
bool handleAccessKey(Common::Event *event, bool printable);
virtual bool handleCustomActionStart(BaseGameCustomAction action);
virtual bool handleCustomActionEnd(BaseGameCustomAction action);
int32 _freezeLevel;
bool unfreeze();
bool freeze(bool includingMusic = true);
bool focusWindow(UIWindow *window);
VideoPlayer *_videoPlayer;
VideoTheoraPlayer *_theoraPlayer;
bool _loadInProgress;
UIWindow *_focusedWindow;
bool _editorForceScripts;
static void afterLoadRegion(void *region, void *data);
static void afterLoadSubFrame(void *subframe, void *data);
static void afterLoadSound(void *sound, void *data);
static void afterLoadFont(void *font, void *data);
#ifdef ENABLE_WME3D
static void afterLoadXModel(void *model, void *data);
#endif
static void afterLoadScript(void *script, void *data);
static void afterLoadScene(void *scene, void *data);
static void invalidateValues(void *value, void *data);
bool loadSettings(const char *filename);
bool resumeMusic(int channel);
bool setMusicStartTime(int channel, uint32 time);
bool pauseMusic(int channel);
bool stopMusic(int channel);
bool playMusic(int channel, const char *filename, bool looping = true, uint32 loopStart = 0, uint32 privVolume = 100);
BaseSound *_music[NUM_MUSIC_CHANNELS];
bool _musicCrossfadeRunning;
bool _musicCrossfadeSwap;
uint32 _musicCrossfadeStartTime;
uint32 _musicCrossfadeLength;
int32 _musicCrossfadeChannel1;
int32 _musicCrossfadeChannel2;
int32 _musicCrossfadeVolume1;
int32 _musicCrossfadeVolume2;
bool displayWindows(bool inGame = false);
Common::String readRegistryString(const Common::String &key, const Common::String &initValue) const;
bool _useD3D;
virtual bool cleanup();
bool loadGame(uint32 slot);
bool loadGame(const char *filename);
bool saveGame(int32 slot, const char *desc, bool quickSave = false);
bool showCursor() override;
BaseSprite *_cursorNoninteractive;
BaseObject *_activeObject;
BaseKeyboardState *_keyboardState;
bool _interactive;
TGameState _state;
TGameState _origState;
bool _origInteractive;
uint32 _timer;
uint32 _timerDelta;
uint32 _timerLast;
uint32 _liveTimer;
uint32 _liveTimerDelta;
uint32 _liveTimerLast;
BaseObject *_capturedObject;
Common::Point32 _mousePos;
bool validObject(BaseObject *object);
bool unregisterObject(BaseObject *object);
bool registerObject(BaseObject *object);
void quickMessage(const char *text);
void quickMessageForm(char *fmt, ...);
bool displayQuickMsg();
uint32 _fps;
bool updateMusicCrossfade();
bool isVideoPlaying();
bool stopVideo();
BaseArray<BaseObject *> _regObjects;
// accessibility flags
bool _accessTTSEnabled;
bool _accessTTSTalk;
bool _accessTTSCaptions;
bool _accessTTSKeypress;
bool _accessKeyboardEnabled;
bool _accessKeyboardCursorSkip;
bool _accessKeyboardPause;
bool _accessGlobalPaused;
UIWindow *_accessShieldWin;
bool accessPause();
bool accessUnpause();
public:
virtual bool displayContent(bool update = true, bool displayAll = false);
virtual bool displayContentSimple();
bool _forceNonStreamedSounds;
void resetMousePos();
int32 _subtitlesSpeed;
void setInteractive(bool state);
virtual bool windowLoadHook(UIWindow *win, char **buf, char **params);
virtual bool windowScriptMethodHook(UIWindow *win, ScScript *script, ScStack *stack, const char *name);
bool getCurrentViewportOffset(int *offsetX = nullptr, int *offsetY = nullptr);
bool getCurrentViewportRect(Common::Rect32 *rect, bool *custom = nullptr);
bool popViewport();
bool pushViewport(BaseViewport *viewport);
bool setActiveObject(BaseObject *obj);
BaseSprite *_lastCursor;
bool drawCursor(BaseSprite *cursor);
virtual bool initAfterLoad();
SaveThumbHelper *_cachedThumbnail;
private:
bool getSaveDir(char *Buffer);
public:
BaseGameMusic *_musicSystem;
Common::String _targetName;
void setIndicatorVal(int value);
bool getBilinearFiltering() { return _bilinearFiltering; }
void addMem(int32 bytes);
bool _touchInterface;
bool _bilinearFiltering{};
#ifdef ENABLE_WME3D
bool _force2dRenderer{};
#endif
AnsiString getDeviceType() const;
struct LastClickInfo {
LastClickInfo() {
posX = posY = 0;
time = 0;
}
int32 posX;
int32 posY;
uint32 time;
};
LastClickInfo _lastClick[2];
bool isDoubleClick(int32 buttonIndex);
uint32 _usedMem;
protected:
// WME Lite specific
bool _autoSaveOnExit;
uint32 _autoSaveSlot;
bool _cursorHidden;
public:
void autoSaveOnExit();
PluginEvent &pluginEvents() { return _pluginEvents; }
private:
#ifdef ENABLE_HEROCRAFT
// HeroCraft games specific random source with ability a in-script function to set the seed
Common::RandomSource *_rndHc;
// HeroCraft games specific checksum function, used in Papa's Daughters 2 selfcheck
uint8 getFilePartChecksumHc(const char *filename, uint32 begin, uint32 end);
#endif
PluginEvent _pluginEvents;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,44 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_GAME_CUSTOM_ACTION_H
#define WINTERMUTE_BASE_GAME_CUSTOM_ACTION_H
namespace Wintermute {
enum BaseGameCustomAction {
kClickAtCenter = 0,
kClickAtLeft = 1,
kClickAtRight = 2,
kClickAtTop = 3,
kClickAtBottom = 4,
kClickAtEntityNearestToCenter = 5
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,565 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_keyboard_state.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "common/system.h"
#include "common/keyboard.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseKeyboardState, false)
// Used in WME 1.x
// See "MSDN: Virtual-Key Codes" for more details on original WME keycodes
const keyCodeMapping wmeOriginalMapping[] = {
{ Common::KEYCODE_BACKSPACE, 8 },
{ Common::KEYCODE_TAB, 9 },
{ Common::KEYCODE_RETURN, 13 },
{ Common::KEYCODE_CAPSLOCK, 20 },
{ Common::KEYCODE_ESCAPE, 27 },
{ Common::KEYCODE_SPACE, 32 },
{ Common::KEYCODE_LSHIFT, 16 },
{ Common::KEYCODE_RSHIFT, 16 },
{ Common::KEYCODE_LCTRL, 17 },
{ Common::KEYCODE_RCTRL, 17 },
// WME 1.x does not produce events for LALT & RALT
{ Common::KEYCODE_PAUSE, 19 },
{ Common::KEYCODE_PAGEUP, 33 },
{ Common::KEYCODE_PAGEDOWN, 34 },
{ Common::KEYCODE_END, 35 },
{ Common::KEYCODE_HOME, 36 },
{ Common::KEYCODE_LEFT, 37 },
{ Common::KEYCODE_UP, 38 },
{ Common::KEYCODE_RIGHT, 39 },
{ Common::KEYCODE_DOWN, 40 },
{ Common::KEYCODE_PRINT, 42 },
{ Common::KEYCODE_INSERT, 45 },
{ Common::KEYCODE_DELETE, 46 },
{ Common::KEYCODE_SCROLLOCK, 145 },
{ Common::KEYCODE_0, 48 },
{ Common::KEYCODE_1, 49 },
{ Common::KEYCODE_2, 50 },
{ Common::KEYCODE_3, 51 },
{ Common::KEYCODE_4, 52 },
{ Common::KEYCODE_5, 53 },
{ Common::KEYCODE_6, 54 },
{ Common::KEYCODE_7, 55 },
{ Common::KEYCODE_8, 56 },
{ Common::KEYCODE_9, 57 },
{ Common::KEYCODE_a, 65 },
{ Common::KEYCODE_b, 66 },
{ Common::KEYCODE_c, 67 },
{ Common::KEYCODE_d, 68 },
{ Common::KEYCODE_e, 69 },
{ Common::KEYCODE_f, 70 },
{ Common::KEYCODE_g, 71 },
{ Common::KEYCODE_h, 72 },
{ Common::KEYCODE_i, 73 },
{ Common::KEYCODE_j, 74 },
{ Common::KEYCODE_k, 75 },
{ Common::KEYCODE_l, 76 },
{ Common::KEYCODE_m, 77 },
{ Common::KEYCODE_n, 78 },
{ Common::KEYCODE_o, 79 },
{ Common::KEYCODE_p, 80 },
{ Common::KEYCODE_q, 81 },
{ Common::KEYCODE_r, 82 },
{ Common::KEYCODE_s, 83 },
{ Common::KEYCODE_t, 84 },
{ Common::KEYCODE_u, 85 },
{ Common::KEYCODE_v, 86 },
{ Common::KEYCODE_w, 87 },
{ Common::KEYCODE_x, 88 },
{ Common::KEYCODE_y, 89 },
{ Common::KEYCODE_z, 90 },
{ Common::KEYCODE_CLEAR, 12 },
{ Common::KEYCODE_KP_ENTER, 13 },
{ Common::KEYCODE_KP0, 96 },
{ Common::KEYCODE_KP1, 97 },
{ Common::KEYCODE_KP2, 98 },
{ Common::KEYCODE_KP3, 99 },
{ Common::KEYCODE_KP4, 100 },
{ Common::KEYCODE_KP5, 101 },
{ Common::KEYCODE_KP6, 102 },
{ Common::KEYCODE_KP7, 103 },
{ Common::KEYCODE_KP8, 104 },
{ Common::KEYCODE_KP9, 105 },
{ Common::KEYCODE_KP_MULTIPLY, 106 },
{ Common::KEYCODE_KP_PLUS, 107 },
{ Common::KEYCODE_KP_MINUS, 109 },
{ Common::KEYCODE_KP_PERIOD, 110 },
{ Common::KEYCODE_KP_DIVIDE, 111 },
{ Common::KEYCODE_NUMLOCK, 144 },
{ Common::KEYCODE_F1, 112 },
{ Common::KEYCODE_F2, 113 },
{ Common::KEYCODE_F3, 114 },
{ Common::KEYCODE_F4, 115 },
{ Common::KEYCODE_F5, 116 },
{ Common::KEYCODE_F6, 117 },
{ Common::KEYCODE_F7, 118 },
{ Common::KEYCODE_F8, 119 },
{ Common::KEYCODE_F9, 120 },
{ Common::KEYCODE_F10, 121 },
{ Common::KEYCODE_F11, 122 },
{ Common::KEYCODE_F12, 123 },
{ Common::KEYCODE_INVALID, 0 }
};
// Used in WME Lite & FoxTail
// See "SDL_Keycode" for more details on new WME keycodes
const keyCodeMapping wmeSdlMapping[] = {
{ Common::KEYCODE_BACKSPACE, 8 },
{ Common::KEYCODE_TAB, 9 },
{ Common::KEYCODE_RETURN, 13 },
{ Common::KEYCODE_ESCAPE, 27 },
{ Common::KEYCODE_SPACE, 32 },
{ Common::KEYCODE_CAPSLOCK, 1073741881 },
{ Common::KEYCODE_LCTRL, 1073742048 },
{ Common::KEYCODE_LSHIFT, 1073742049 },
{ Common::KEYCODE_LALT, 1073742050 },
{ Common::KEYCODE_RCTRL, 1073742052 },
{ Common::KEYCODE_RSHIFT, 1073742053 },
{ Common::KEYCODE_RALT, 1073742054 },
{ Common::KEYCODE_DELETE, 127 },
{ Common::KEYCODE_PRINT, 1073741894 },
{ Common::KEYCODE_SCROLLOCK, 1073741895 },
{ Common::KEYCODE_PAUSE, 1073741896 },
{ Common::KEYCODE_INSERT, 1073741897 },
{ Common::KEYCODE_HOME, 1073741898 },
{ Common::KEYCODE_PAGEUP, 1073741899 },
{ Common::KEYCODE_END, 1073741901 },
{ Common::KEYCODE_PAGEDOWN, 1073741902 },
{ Common::KEYCODE_RIGHT, 1073741903 },
{ Common::KEYCODE_LEFT, 1073741904 },
{ Common::KEYCODE_DOWN, 1073741905 },
{ Common::KEYCODE_UP, 1073741906 },
{ Common::KEYCODE_0, 48 },
{ Common::KEYCODE_1, 49 },
{ Common::KEYCODE_2, 50 },
{ Common::KEYCODE_3, 51 },
{ Common::KEYCODE_4, 52 },
{ Common::KEYCODE_5, 53 },
{ Common::KEYCODE_6, 54 },
{ Common::KEYCODE_7, 55 },
{ Common::KEYCODE_8, 56 },
{ Common::KEYCODE_9, 57 },
{ Common::KEYCODE_a, 97 },
{ Common::KEYCODE_b, 98 },
{ Common::KEYCODE_c, 99 },
{ Common::KEYCODE_d, 100 },
{ Common::KEYCODE_e, 101 },
{ Common::KEYCODE_f, 102 },
{ Common::KEYCODE_g, 103 },
{ Common::KEYCODE_h, 104 },
{ Common::KEYCODE_i, 105 },
{ Common::KEYCODE_j, 106 },
{ Common::KEYCODE_k, 107 },
{ Common::KEYCODE_l, 108 },
{ Common::KEYCODE_m, 109 },
{ Common::KEYCODE_n, 110 },
{ Common::KEYCODE_o, 111 },
{ Common::KEYCODE_p, 112 },
{ Common::KEYCODE_q, 113 },
{ Common::KEYCODE_r, 114 },
{ Common::KEYCODE_s, 115 },
{ Common::KEYCODE_t, 116 },
{ Common::KEYCODE_u, 117 },
{ Common::KEYCODE_v, 118 },
{ Common::KEYCODE_w, 119 },
{ Common::KEYCODE_x, 120 },
{ Common::KEYCODE_y, 121 },
{ Common::KEYCODE_z, 122 },
{ Common::KEYCODE_KP_ENTER, 13 },
{ Common::KEYCODE_NUMLOCK, 1073741907 },
{ Common::KEYCODE_KP_DIVIDE, 1073741908 },
{ Common::KEYCODE_KP_MULTIPLY, 1073741909 },
{ Common::KEYCODE_KP_MINUS, 1073741910 },
{ Common::KEYCODE_KP_PLUS, 1073741911 },
{ Common::KEYCODE_KP1, 1073741913 },
{ Common::KEYCODE_KP2, 1073741914 },
{ Common::KEYCODE_KP3, 1073741915 },
{ Common::KEYCODE_KP4, 1073741916 },
{ Common::KEYCODE_KP5, 1073741917 },
{ Common::KEYCODE_KP6, 1073741918 },
{ Common::KEYCODE_KP7, 1073741919 },
{ Common::KEYCODE_KP8, 1073741920 },
{ Common::KEYCODE_KP9, 1073741921 },
{ Common::KEYCODE_KP0, 1073741922 },
{ Common::KEYCODE_KP_PERIOD, 1073741923 },
{ Common::KEYCODE_CLEAR, 1073741980 },
{ Common::KEYCODE_F1, 1073741882 },
{ Common::KEYCODE_F2, 1073741883 },
{ Common::KEYCODE_F3, 1073741884 },
{ Common::KEYCODE_F4, 1073741885 },
{ Common::KEYCODE_F5, 1073741886 },
{ Common::KEYCODE_F6, 1073741887 },
{ Common::KEYCODE_F7, 1073741888 },
{ Common::KEYCODE_F8, 1073741889 },
{ Common::KEYCODE_F9, 1073741890 },
{ Common::KEYCODE_F10, 1073741891 },
{ Common::KEYCODE_F11, 1073741892 },
{ Common::KEYCODE_F12, 1073741893 },
{ Common::KEYCODE_INVALID, 0 }
};
//////////////////////////////////////////////////////////////////////////
BaseKeyboardState::BaseKeyboardState(BaseGame *inGame) : BaseScriptable(inGame) {
init();
}
//////////////////////////////////////////////////////////////////////////
void BaseKeyboardState::init() {
_currentPrintable = false;
_currentCharCode = 0;
_currentKeyData = 0;
_currentShift = false;
_currentAlt = false;
_currentControl = false;
_keyStates = new uint8[Common::KEYCODE_LAST];
for (int i = 0; i < Common::KEYCODE_LAST; i++) {
_keyStates[i] = false;
}
if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
_mapping = wmeOriginalMapping;
_mappingSize = ARRAYSIZE(wmeOriginalMapping);
} else {
_mapping = wmeSdlMapping;
_mappingSize = ARRAYSIZE(wmeSdlMapping);
}
}
//////////////////////////////////////////////////////////////////////////
BaseKeyboardState::~BaseKeyboardState() {
delete[] _keyStates;
}
void BaseKeyboardState::handleKeyPress(Common::Event *event) {
if (event->type == Common::EVENT_KEYDOWN) {
_keyStates[event->kbd.keycode] = true;
}
}
void BaseKeyboardState::handleKeyRelease(Common::Event *event) {
if (event->type == Common::EVENT_KEYUP) {
_keyStates[event->kbd.keycode] = false;
}
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// IsKeyDown
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "IsKeyDown") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
uint32 vKeyCode;
if (val->_type == VAL_STRING && strlen(val->getString()) > 0) {
// IsKeyDown(strings) checks if a key with given ASCII code is pressed
// Only 1st character of given string is used for the check
// This check must be case insensitive, which means that
// IsKeyDown("a") & IsKeyDown("A") are either both true or both false
const char *str = val->getString();
char temp = str[0];
if (temp >= 'A' && temp <= 'Z') {
temp += ('a' - 'A');
}
// Common::KeyCode is equal to ASCII code for any lowercase ASCII character
if (temp >= ' ' && temp <= '~') {
vKeyCode = (int)temp;
} else {
warning("Unhandled IsKeyDown(string): check for non-ASCII character");
vKeyCode = 0;
}
} else {
// IsKeyDown(int) checks if a key with given keycode is pressed
// For letters, single keycode is used for upper and lower case
// This mean that IsKeyDown(65) is true for both 'a' and Shift+'a'
vKeyCode = Common::KEYCODE_INVALID;
uint32 temp = (uint32)val->getInt();
for (uint32 i = 0; i < _mappingSize; i++) {
if (_mapping[i].engineKeycode == temp) {
vKeyCode = _mapping[i].commonKeycode;
}
}
if (vKeyCode == Common::KEYCODE_INVALID) {
warning("Unknown VKEY: %d", temp);
}
if (BaseEngine::instance().getTargetExecutable() < WME_LITE && temp == 16) {
stack->pushBool(_keyStates[Common::KEYCODE_LSHIFT] || _keyStates[Common::KEYCODE_RSHIFT]);
return STATUS_OK;
}
if (BaseEngine::instance().getTargetExecutable() < WME_LITE && temp == 17) {
stack->pushBool(_keyStates[Common::KEYCODE_LCTRL] || _keyStates[Common::KEYCODE_RCTRL]);
return STATUS_OK;
}
}
bool isDown = _keyStates[vKeyCode];
stack->pushBool(isDown);
return STATUS_OK;
} else {
return BaseScriptable::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseKeyboardState::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("keyboard");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Key
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Key") == 0) {
if (_currentPrintable) {
char key[2];
key[0] = (char)_currentCharCode;
key[1] = '\0';
_scValue->setString(key);
} else {
_scValue->setString("");
}
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Printable
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Printable") == 0) {
_scValue->setBool(_currentPrintable);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// KeyCode
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "KeyCode") == 0) {
_scValue->setInt(_currentCharCode);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// IsShift
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "IsShift") == 0) {
_scValue->setBool(_currentShift);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// IsAlt
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "IsAlt") == 0) {
_scValue->setBool(_currentAlt);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// IsControl
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "IsControl") == 0) {
_scValue->setBool(_currentControl);
return _scValue;
} else {
return BaseScriptable::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::scSetProperty(const char *name, ScValue *value) {
/*
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Name") == 0) {
setName(value->getString());
if (_renderer) SetWindowText(_renderer->_window, _name);
return STATUS_OK;
}
else*/ return BaseScriptable::scSetProperty(name, value);
}
//////////////////////////////////////////////////////////////////////////
const char *BaseKeyboardState::scToString() {
return "[keyboard state]";
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::readKey(Common::Event *event) {
Common::KeyCode code = event->kbd.keycode;
if (event->type != Common::EVENT_KEYDOWN) {
_currentCharCode = 0;
_currentPrintable = false;
}
// use ASCII value if key pressed is an alphanumeric or punctuation key
// keys pressed on numpad are handled in next 2 blocks
else if (code >= Common::KEYCODE_SPACE && code < Common::KEYCODE_DELETE) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
#ifdef ENABLE_FOXTAIL
if (BaseEngine::instance().isFoxTail()) {
_currentCharCode = tolower(_currentCharCode);
}
#endif
}
// use ASCII value for numpad '/', '*', '-', '+'
else if (code >= Common::KEYCODE_KP_DIVIDE && code <= Common::KEYCODE_KP_PLUS) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
}
// if NumLock is active, use ASCII for numpad keys '0'~'9' and '.'
// keys pressed on numpad without NumLock are considered as normal keycodes, handled in the next block
else if ((code >= Common::KEYCODE_KP0 && code <= Common::KEYCODE_KP_PERIOD) && ((event->kbd.flags & Common::KBD_NUM) != 0)) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
}
// use _mapping for all other events
else {
_currentCharCode = 0;
for (uint32 i = 0; i < _mappingSize; i++) {
if (_mapping[i].commonKeycode == event->kbd.keycode) {
_currentCharCode = _mapping[i].engineKeycode;
}
}
if (!_currentCharCode && (event->kbd.flags & Common::KBD_NON_STICKY) == 0) {
warning("Key pressed (%d '%c') is not recognized, ASCII returned (%d '%c').", event->kbd.keycode, event->kbd.keycode, event->kbd.ascii, event->kbd.ascii);
}
if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
_currentPrintable = code == Common::KEYCODE_BACKSPACE ||
code == Common::KEYCODE_TAB ||
code == Common::KEYCODE_RETURN ||
code == Common::KEYCODE_KP_ENTER ||
code == Common::KEYCODE_ESCAPE;
} else {
_currentPrintable = false;
}
}
_currentControl = event->kbd.flags & Common::KBD_CTRL;
_currentAlt = event->kbd.flags & Common::KBD_ALT;
_currentShift = event->kbd.flags & Common::KBD_SHIFT;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::persist(BasePersistenceManager *persistMgr) {
//if (!persistMgr->getIsSaving()) cleanup();
BaseScriptable::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_currentAlt));
persistMgr->transferUint32(TMEMBER(_currentCharCode));
persistMgr->transferBool(TMEMBER(_currentControl));
persistMgr->transferUint32(TMEMBER(_currentKeyData));
persistMgr->transferBool(TMEMBER(_currentPrintable));
persistMgr->transferBool(TMEMBER(_currentShift));
if (!persistMgr->getIsSaving()) {
init();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isShiftDown() {
int mod = g_system->getEventManager()->getModifierState();
return (mod & Common::KBD_SHIFT);
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isControlDown() {
int mod = g_system->getEventManager()->getModifierState();
return (mod & Common::KBD_CTRL);
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isAltDown() {
int mod = g_system->getEventManager()->getModifierState();
return (mod & Common::KBD_ALT);
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isCurrentPrintable() const {
return _currentPrintable;
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_KEYBOARD_STATE_H
#define WINTERMUTE_BASE_KEYBOARD_STATE_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_scriptable.h"
#include "common/keyboard.h"
#include "common/events.h"
namespace Wintermute {
struct keyCodeMapping {
Common::KeyCode commonKeycode;
uint32 engineKeycode;
};
class BaseKeyboardState : public BaseScriptable {
public:
uint32 _currentKeyData;
uint32 _currentCharCode;
bool _currentPrintable;
bool _currentShift;
bool _currentAlt;
bool _currentControl;
DECLARE_PERSISTENT(BaseKeyboardState, BaseScriptable)
BaseKeyboardState(BaseGame *inGame);
~BaseKeyboardState() override;
bool readKey(Common::Event *event);
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
void handleKeyPress(Common::Event *event);
void handleKeyRelease(Common::Event *event);
static bool isShiftDown();
static bool isControlDown();
static bool isAltDown();
bool isCurrentPrintable() const;
private:
void init();
uint8 *_keyStates;
const keyCodeMapping *_mapping;
uint32 _mappingSize;
};
} // End of namespace Wintermute
#endif

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseNamedObject::BaseNamedObject(BaseGame *inGame) : BaseClass(inGame) {
_name = nullptr;
}
//////////////////////////////////////////////////////////////////////////
BaseNamedObject::BaseNamedObject() : BaseClass() {
_name = nullptr;
}
//////////////////////////////////////////////////////////////////////////
BaseNamedObject::BaseNamedObject(TDynamicConstructor, TDynamicConstructor) {
_name = nullptr;
}
//////////////////////////////////////////////////////////////////////////
BaseNamedObject::~BaseNamedObject() {
SAFE_DELETE_ARRAY(_name);
}
//////////////////////////////////////////////////////////////////////
void BaseNamedObject::setName(const char *name) {
SAFE_DELETE_ARRAY(_name);
if (name == nullptr) {
return;
}
size_t nameSize = strlen(name) + 1;
_name = new char [nameSize];
Common::strcpy_s(_name, nameSize, name);
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_NAMED_OBJECT_H
#define WINTERMUTE_BASE_NAMED_OBJECT_H
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BaseNamedObject : public BaseClass {
public:
BaseNamedObject(BaseGame *inGame);
BaseNamedObject();
~BaseNamedObject() override;
BaseNamedObject(TDynamicConstructor, TDynamicConstructor);
char *_name;
void setName(const char *name);
};
} // End of namespace Wintermute
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_OBJECT_H
#define WINTERMUTE_BASE_OBJECT_H
#include "engines/wintermute/base/base_script_holder.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/wintermute/persistent.h"
#include "common/events.h"
#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSprite;
class BaseSound;
class BaseSurface;
class BaseScriptHolder;
class ScValue;
class ScStack;
class ScScript;
class XModel;
class BaseObject : public BaseScriptHolder {
public:
char *_accessCaption;
virtual const char *getAccessCaption();
Graphics::TSpriteBlendMode _blendMode;
#ifdef ENABLE_WME3D
virtual bool renderModel();
#endif
virtual bool afterMove();
float _relativeRotate;
bool _rotateValid;
float _rotate;
void setSoundEvent(const char *eventName);
bool _rotatable;
uint32 _alphaColor;
float _scale;
float _scaleX;
float _scaleY;
float _relativeScale;
virtual bool isReady();
virtual bool getExtendedFlag(const char *flagName);
virtual bool resetSoundPan();
virtual bool updateSounds();
bool updateOneSound(BaseSound *sound);
bool _autoSoundPanning;
uint32 _sFXStart;
int32 _sFXVolume;
bool setSFXTime(uint32 time);
bool setSFXVolume(int volume);
bool resumeSFX();
bool pauseSFX();
bool stopSFX(bool deleteSound = true);
bool playSFX(const char *filename, bool looping = false, bool playNow = true, const char *eventName = nullptr, uint32 loopStart = 0);
BaseSound *_sFX;
TSFXType _sFXType;
float _sFXParam1;
float _sFXParam2;
float _sFXParam3;
float _sFXParam4;
virtual bool handleMouseWheel(int32 delta);
virtual bool handleMouse(TMouseEvent event, TMouseButton button);
virtual bool handleKeypress(Common::Event *event, bool printable = false);
virtual int32 getHeight();
bool setCursor(const char *filename);
bool setActiveCursor(const char *filename);
bool cleanup();
const char *getCaption(int caseVal = 1);
void setCaption(const char *caption, int caseVal = 1);
bool _editorSelected;
bool _editorAlwaysRegister;
bool _editorOnly;
bool _is3D;
DECLARE_PERSISTENT(BaseObject, BaseScriptHolder)
virtual bool showCursor();
BaseSprite *_cursor;
bool _sharedCursors;
BaseSprite *_activeCursor;
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override;
bool listen(BaseScriptHolder *param1, uint32 param2) override;
bool _ready;
bool _registrable;
bool _zoomable;
bool _shadowable;
Common::Rect32 _rect;
bool _rectSet;
int32 _id;
bool _movable;
BaseObject(BaseGame *inGame);
~BaseObject() override;
char *_caption[7];
char *_soundEvent;
int32 _posY;
int32 _posX;
bool _saveState;
// base
virtual bool update() {
return STATUS_FAILED;
};
virtual bool display() {
return STATUS_FAILED;
};
virtual bool invalidateDeviceObjects() {
return STATUS_OK;
};
virtual bool restoreDeviceObjects() {
return STATUS_OK;
};
bool _nonIntMouseEvents;
#ifdef ENABLE_WME3D
float _angle;
XModel *_xmodel;
XModel *_shadowModel;
DXMatrix _worldMatrix;
DXVector3 _posVector;
bool getMatrix(DXMatrix *modelMatrix, DXVector3 *posVect = nullptr);
uint32 _shadowColor;
BaseSurface *_shadowImage;
float _shadowSize;
float _scale3D;
DXVector3 _shadowLightPos;
bool _drawBackfaces;
TShadowType _shadowType;
virtual uint32 getAnimTransitionTime(const char *from, const char *to) {
return 0;
};
#endif
public:
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,472 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
#include "common/util.h"
#define WHITESPACE " \t\n\r"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
BaseParser::BaseParser(BaseGame *inGame) : BaseClass(inGame) {
_whiteSpace = new char [sizeof(WHITESPACE)];
Common::strcpy_s(_whiteSpace, sizeof(WHITESPACE), WHITESPACE);
}
//////////////////////////////////////////////////////////////////////
BaseParser::~BaseParser() {
if (_whiteSpace != nullptr) {
delete[] _whiteSpace;
}
}
//////////////////////////////////////////////////////////////////////
char *BaseParser::getLastOffender() {
return _lastOffender;
}
//////////////////////////////////////////////////////////////////////
int32 BaseParser::getObject(char **buf, const TokenDesc *tokens, char **name, char **data) {
skipCharacters(buf, _whiteSpace);
// skip comment lines.
while (**buf == ';') {
*buf = strchr(*buf, '\n');
if (!*buf) {
return PARSERR_EOF;
}
_parserLine++;
skipCharacters(buf, _whiteSpace);
}
if (!**buf) { // at end of file
return PARSERR_EOF;
}
// find the token.
// TODO: for now just use brute force. Improve later.
while (tokens->id != 0) {
if (!scumm_strnicmp(tokens->token, *buf, strlen(tokens->token))) {
// here we could be matching PART of a string
// we could detect this here or the token list
// could just have the longer tokens first in the list
break;
}
++tokens;
}
if (tokens->id == 0) {
char *p = strchr(*buf, '\n');
if (p && p > *buf) {
strncpy(_lastOffender, *buf, MIN((uint32)255, (uint32)(p - *buf)));
} else {
_lastOffender[0] = '\0';
}
return PARSERR_TOKENNOTFOUND;
}
// skip the token
*buf += strlen(tokens->token);
skipCharacters(buf, _whiteSpace);
// get optional name
*name = getSubText(buf, '\'', '\''); // single quotes
skipCharacters(buf, _whiteSpace);
// get optional data
if (**buf == '=') { // An assignment rather than a command/object.
*data = getAssignmentText(buf);
} else {
*data = getSubText(buf, '{', '}');
}
return tokens->id;
}
//////////////////////////////////////////////////////////////////////
int32 BaseParser::getCommand(char **buf, const TokenDesc *tokens, char **params) {
if (!*buf) {
return PARSERR_TOKENNOTFOUND;
}
_game->miniUpdate();
char *name;
return getObject(buf, tokens, &name, params);
}
//////////////////////////////////////////////////////////////////////
void BaseParser::skipCharacters(char **buf, const char *toSkip) {
char ch;
while ((ch = **buf) != 0) {
if (ch == '\n') {
_parserLine++;
}
if (strchr(toSkip, ch) == nullptr) {
return;
}
++*buf; // skip this character
}
// we must be at the end of the buffer if we get here
}
//////////////////////////////////////////////////////////////////////
char *BaseParser::getSubText(char **buf, char open, char close) {
if (**buf == 0 || **buf != open) {
return 0;
}
++*buf; // skip opening delimiter
char *result = *buf;
// now find the closing delimiter
char theChar;
int32 skip = 1;
if (open == close) { // we can't nest identical delimiters
open = 0;
}
while ((theChar = **buf) != 0) {
if (theChar == open) {
++skip;
}
if (theChar == close) {
if (--skip == 0) {
**buf = 0; // null terminate the result string
++*buf; // move past the closing delimiter
break;
}
}
++*buf; // try next character
}
return result;
}
//////////////////////////////////////////////////////////////////////
char *BaseParser::getAssignmentText(char **buf) {
++*buf; // skip the '='
skipCharacters(buf, _whiteSpace);
char *result = *buf;
if (*result == '"') {
result = getSubText(buf, '"', '"');
} else {
// now, we need to find the next whitespace to end the data
char theChar;
while ((theChar = **buf) != 0) {
if (theChar <= 0x20) { // space and control chars
break;
}
++*buf;
}
**buf = 0; // null terminate it
if (theChar) { // skip the terminator
++*buf;
}
}
return result;
}
//////////////////////////////////////////////////////////////////////
char *BaseParser::getToken(char **buf) {
static char token[100];
char *b = *buf, *t = token;
while (true) {
while (*b && (*b == ' ' || *b == '\n' || *b == 13 || *b == 10 || *b == '\t')) {
b++;
}
if (*b == ';') {
while (*b && *b != '\n' && *b != 13 && *b != 10) {
b++;
}
} else {
break;
}
}
if (*b == '\'') {
b++;
while (*b && *b != '\'') {
*t++ = *b++;
}
*t++ = 0;
if (*b == '\'') {
b++;
}
} else if (*b == '(' || *b == ')' || *b == '=' || *b == ',' || *b == '[' || *b == ']' ||
*b == '%' || *b == ':' || *b == '{' || *b == '}') {
*t++ = *b++;
*t++ = 0;
} else if (*b == '.' && (*(b + 1) < '0' || *(b + 1) > '9')) {
*t++ = *b++;
*t++ = 0;
} else if ((*b >= '0' && *b <= '9') || *b == '.' || *b == '-') {
while (*b && ((*b >= '0' && *b <= '9') || *b == '.' || *b == '-')) {
*t++ = *b++;
}
*t++ = 0;
} else if ((*b >= 'A' && *b <= 'Z') || (*b >= 'a' && *b <= 'z') || *b == '_') {
while (*b && ((*b >= 'A' && *b <= 'Z') || (*b >= 'a' && *b <= 'z') || *b == '_')) {
*t++ = *b++;
}
*t++ = 0;
} else if (*b == 0) {
*buf = b;
return nullptr;
} else {
// Error.
return nullptr;
}
*buf = b;
return token;
}
//////////////////////////////////////////////////////////////////////
float BaseParser::getTokenFloat(char **buf) {
const char *t = getToken(buf);
if (!((*t >= '0' && *t <= '9') || *t == '-' || *t == '.')) {
// Error situation. We handle this by return 0.
return 0.;
}
float rc = (float)atof(t);
return rc;
}
//////////////////////////////////////////////////////////////////////
int32 BaseParser::getTokenInt(char **buf) {
const char *t = getToken(buf);
if (!((*t >= '0' && *t <= '9') || *t == '-')) {
// Error situation. We handle this by return 0.
return 0;
}
int rc = atoi(t);
return rc;
}
//////////////////////////////////////////////////////////////////////
void BaseParser::skipToken(char **buf, char *tok, char * /*msg*/) {
const char *t = getToken(buf);
if (strcmp(t, tok)) {
return; // Error
}
}
//////////////////////////////////////////////////////////////////////
int32 BaseParser::scanStr(const char *in, const char *format, ...) {
va_list arg;
va_start(arg, format);
int32 num = 0;
in += strspn(in, " \t\n\f");
while (*format && *in) {
if (*format == '%') {
format++;
switch (*format) {
case 'd': {
int *a = va_arg(arg, int *);
in += strspn(in, " \t\n\f");
*a = atoi(in);
in += strspn(in, "0123456789+- \t\n\f");
num++;
break;
}
case 'D': {
int i;
int *list = va_arg(arg, int *);
int *nr = va_arg(arg, int *);
in += strspn(in, " \t\n\f");
i = 0;
while ((*in >= '0' && *in <= '9') || *in == '+' || *in == '-') {
list[i++] = atoi(in);
in += strspn(in, "0123456789+-");
in += strspn(in, " \t\n\f");
if (*in != ',') {
break;
}
in++;
in += strspn(in, " \t\n\f");
}
*nr = i;
num++;
break;
}
case 'b': {
bool *a = va_arg(arg, bool *);
in += strspn(in, " \t\n\f");
const char *in2 = in + strspn(in, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
int l = (int)(in2 - in);
*a = (bool)(!scumm_strnicmp(in, "yes", l) || !scumm_strnicmp(in, "true", l) || !scumm_strnicmp(in, "on", l) ||
!scumm_strnicmp(in, "1", l));
in = in2 + strspn(in2, " \t\n\f");
num++;
break;
}
case 'f': {
float *a = va_arg(arg, float *);
in += strspn(in, " \t\n\f");
*a = (float)atof(in);
in += strspn(in, "0123456789.eE+- \t\n\f");
num++;
break;
}
case 'F': {
int i;
float *list = va_arg(arg, float *);
int *nr = va_arg(arg, int *);
in += strspn(in, " \t\n\f");
i = 0;
while ((*in >= '0' && *in <= '9') || *in == '.' || *in == '+' || *in == '-' || *in == 'e' || *in == 'E') {
list[i++] = (float)atof(in);
in += strspn(in, "0123456789.eE+-");
in += strspn(in, " \t\n\f");
if (*in != ',') {
break;
}
in++;
in += strspn(in, " \t\n\f");
}
*nr = i;
num++;
break;
}
case 's': {
char *a = va_arg(arg, char *);
in += strspn(in, " \t\n\f");
if (*in == '\'') {
in++;
const char *in2 = strchr(in, '\'');
if (in2) {
strncpy(a, in, (int)(in2 - in));
a[(int)(in2 - in)] = 0;
in = in2 + 1;
} else {
// FIXME: Use a sensible value here
// Happily this is not used
Common::strcpy_s(a, 4096, in);
in = strchr(in, 0);
}
} else {
const char *in2 = in + strspn(in, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789.");
strncpy(a, in, (int)(in2 - in));
a[(int)(in2 - in)] = 0;
in = in2;
}
in += strspn(in, " \t\n\f");
num++;
break;
}
case 'S': {
char *a = va_arg(arg, char *);
in += strspn(in, " \t\n\f");
if (*in == '\"') {
in++;
while (*in != '\"') {
if (*in == '\\') {
in++;
switch (*in) {
case '\\':
*a++ = '\\';
break;
case 'n':
*a++ = '\n';
break;
case 'r':
*a++ = '\r';
break;
case 't':
*a++ = '\t';
break;
case '"':
*a++ = '"';
break;
default:
*a++ = '\\';
*a++ = *in;
break;
} //switch
in++;
} else {
*a++ = *in++;
}
} //while in string
in++;
num++;
} //if string started
//terminate string
*a = '\0';
break;
}
default:
break;
}
if (*format) {
format++;
}
} else if (*format == ' ') {
format++;
in += strspn(in, " \t\n\f");
} else if (*in == *format) {
in++;
format++;
} else {
num = -1;
break;
}
}
va_end(arg);
return num;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,86 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_PARSER_H
#define WINTERMUTE_BASE_PARSER_H
#define TOKEN_DEF_START \
enum { \
TOKEN_NONE = 0,
#define TOKEN_DEF(name) \
TOKEN_ ## name,
#define TOKEN_DEF_END \
TOKEN_TOTAL_COUNT \
};
#define TOKEN_TABLE_START(name) \
static const BaseParser::TokenDesc name [] = \
{
#define TOKEN_TABLE(name) \
{ TOKEN_ ## name, #name },
#define TOKEN_TABLE_END \
{ 0, 0 } \
};
#define PARSERR_GENERIC -3
#define PARSERR_EOF -2
#define PARSERR_TOKENNOTFOUND -1
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BaseParser : public BaseClass {
public:
struct TokenDesc {
int32 id;
const char *token;
};
public:
int32 scanStr(const char *in, const char *format, ...);
char *getLastOffender();
void skipToken(char **buf, char *tok, char *msg = nullptr);
int32 getTokenInt(char **buf);
float getTokenFloat(char **buf);
char *getToken(char **buf);
char *getAssignmentText(char **buf);
char *getSubText(char **buf, char open, char close);
void skipCharacters(char **buf, const char *toSkip);
int32 getCommand(char **buf, const TokenDesc *tokens, char **params);
int32 getObject(char **buf, const TokenDesc *tokens, char **name, char **data);
int32 _parserLine = 0;
char _lastOffender[255];
BaseParser(BaseGame *inGame = nullptr);
virtual ~BaseParser();
char *_whiteSpace;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,956 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/dcgf.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/save_thumb_helper.h"
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/wintermute.h"
#include "graphics/scaler.h"
#include "image/bmp.h"
#include "common/memstream.h"
#include "common/str.h"
#include "common/system.h"
#include "common/savefile.h"
namespace Wintermute {
// The original WME-Lite savegames had the following:
//#define SAVE_MAGIC 0x45564153
//#define SAVE_MAGIC_2 0x32564153
// In case anyone tries to load original savegames, or for that matter
// in case we ever want to attempt to support original savegames, we
// avoid those numbers, and use this instead:
#define SAVE_MAGIC_3 0x12564154
//////////////////////////////////////////////////////////////////////////
BasePersistenceManager::BasePersistenceManager(const Common::String &savePrefix, bool deleteSingleton) {
_saving = false;
_offset = 0;
_saveStream = nullptr;
_loadStream = nullptr;
_deleteSingleton = deleteSingleton;
if (BaseEngine::instance().getGameRef()) {
_game = BaseEngine::instance().getGameRef();
} else {
_game = nullptr;
}
_richBuffer = nullptr;
_richBufferSize = 0;
_scummVMThumbnailData = nullptr;
_scummVMThumbSize = 0;
_savedDescription = nullptr;
// _savedTimestamp = 0;
_savedVerMajor = _savedVerMinor = _savedVerBuild = 0;
_savedExtMajor = _savedExtMinor = 0;
_savedTimestamp.tm_sec = 0;
_savedTimestamp.tm_min = 0;
_savedTimestamp.tm_hour = 0;
_savedTimestamp.tm_mday = 0;
_savedTimestamp.tm_mon = 0;
_savedTimestamp.tm_year = 0;
_savedTimestamp.tm_wday = 0;
_savedPlayTime = 0;
_thumbnailDataSize = 0;
_thumbnailData = nullptr;
if (savePrefix != "") {
_savePrefix = savePrefix;
} else if (_game) {
_savePrefix = _game->_targetName.c_str();
} else {
_savePrefix = "wmesav";
}
}
//////////////////////////////////////////////////////////////////////////
BasePersistenceManager::~BasePersistenceManager() {
cleanup();
if (_deleteSingleton && BaseEngine::instance().getGameRef() == nullptr)
BaseEngine::destroy();
}
//////////////////////////////////////////////////////////////////////////
void BasePersistenceManager::cleanup() {
_offset = 0;
delete[] _richBuffer;
_richBuffer = nullptr;
_richBufferSize = 0;
delete[] _savedDescription;
_savedDescription = nullptr; // ref to buffer
// _savedTimestamp = 0;
_savedVerMajor = _savedVerMinor = _savedVerBuild = 0;
_savedExtMajor = _savedExtMinor = 0;
_thumbnailDataSize = 0;
if (_thumbnailData) {
SAFE_DELETE_ARRAY(_thumbnailData);
}
_scummVMThumbSize = 0;
if (_scummVMThumbnailData) {
SAFE_DELETE_ARRAY(_scummVMThumbnailData);
}
SAFE_DELETE(_loadStream);
SAFE_DELETE(_saveStream);
}
Common::String BasePersistenceManager::getFilenameForSlot(int slot) const {
// 3 Digits, to allow for one save-slot for autosave + slot 1 - 100 (which will be numbered 0-99 filename-wise)
return Common::String::format("%s.%03d", _savePrefix.c_str(), slot);
}
void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &desc) {
Common::String filename = getFilenameForSlot(slot);
debugC(kWintermuteDebugSaveGame, "Trying to list savegame %s in slot %d", filename.c_str(), slot);
if (DID_FAIL(readHeader(filename))) {
debugC(kWintermuteDebugSaveGame, "getSavedDesc(%d) - Failed for %s", slot, filename.c_str());
return;
}
if (BaseEngine::instance().getFlags() & GF_3D) {
if (_savedVerMajor == 1 && _savedVerMinor < 5) {
return;
}
}
desc.setSaveSlot(slot);
desc.setDescription(_savedDescription);
desc.setDeletableFlag(true);
desc.setWriteProtectedFlag(false);
int thumbSize = 0;
byte *thumbData = nullptr;
if (_scummVMThumbSize > 0) {
thumbSize = _scummVMThumbSize;
thumbData = _scummVMThumbnailData;
} else if (_thumbnailDataSize > 0) {
thumbSize = _thumbnailDataSize;
thumbData = _thumbnailData;
}
if (thumbSize > 0) {
Common::MemoryReadStream thumbStream(thumbData, thumbSize, DisposeAfterUse::NO);
Image::BitmapDecoder bmpDecoder;
if (bmpDecoder.loadStream(thumbStream)) {
const Graphics::Surface *bmpSurface = bmpDecoder.getSurface();
Graphics::Surface *scaled = bmpSurface->scale(kThumbnailWidth, kThumbnailHeight2);
Graphics::Surface *thumb = scaled->convertTo(g_system->getOverlayFormat());
desc.setThumbnail(thumb);
scaled->free();
delete scaled;
}
}
desc.setSaveDate(_savedTimestamp.tm_year + 1900, _savedTimestamp.tm_mon + 1, _savedTimestamp.tm_mday);
desc.setSaveTime(_savedTimestamp.tm_hour, _savedTimestamp.tm_min);
desc.setPlayTime(0);
}
bool BasePersistenceManager::deleteSaveSlot(int slot) {
Common::String filename = getFilenameForSlot(slot);
return g_system->getSavefileManager()->removeSavefile(filename);
}
uint32 BasePersistenceManager::getMaxUsedSlot() {
Common::String saveMask = Common::String::format("%s.???", _savePrefix.c_str());
Common::StringArray saves = g_system->getSavefileManager()->listSavefiles(saveMask);
Common::StringArray::iterator it = saves.begin();
int ret = -1;
for (; it != saves.end(); ++it) {
int num = -1;
sscanf(it->c_str(), ".%d", &num);
ret = MAX(ret, num);
}
return ret;
}
bool BasePersistenceManager::getSaveExists(int slot) {
Common::String filename = getFilenameForSlot(slot);
if (DID_FAIL(readHeader(filename))) {
return false;
}
if (BaseEngine::instance().getFlags() & GF_3D) {
if (_savedVerMajor == 1 && _savedVerMinor < 5) {
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BasePersistenceManager::initSave(const Common::String &desc) {
if (desc == "") {
return STATUS_FAILED;
}
cleanup();
_saving = true;
_saveStream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
if (_saveStream) {
// get thumbnails
if (!_game->_cachedThumbnail) {
_game->_cachedThumbnail = new SaveThumbHelper(_game);
if (DID_FAIL(_game->_cachedThumbnail->storeThumbnail(true))) {
SAFE_DELETE(_game->_cachedThumbnail);
}
}
uint32 magic = DCGF_MAGIC;
putDWORD(magic);
magic = SAVE_MAGIC_3;
putDWORD(magic);
byte verMajor, verMinor, extMajor, extMinor;
_game->getVersion(&verMajor, &verMinor, &extMajor, &extMinor);
_saveStream->writeByte(verMajor);
_saveStream->writeByte(verMinor);
_saveStream->writeByte(extMajor);
_saveStream->writeByte(extMinor);
// new in ver 2
putDWORD((uint32)DCGF_VER_BUILD);
putString(_game->_name);
// thumbnail data size
bool thumbnailOK = false;
if (_game->_cachedThumbnail) {
if (_game->_cachedThumbnail->_thumbnail) {
Common::MemoryWriteStreamDynamic thumbStream(DisposeAfterUse::YES);
if (_game->_cachedThumbnail->_thumbnail->writeBMPToStream(&thumbStream)) {
_saveStream->writeUint32LE(thumbStream.size());
_saveStream->write(thumbStream.getData(), thumbStream.size());
} else {
_saveStream->writeUint32LE(0);
}
thumbnailOK = true;
}
}
if (!thumbnailOK) {
putDWORD(0);
}
thumbnailOK = false;
// Again for the ScummVM-thumb:
if (_game->_cachedThumbnail) {
if (_game->_cachedThumbnail->_scummVMThumb) {
Common::MemoryWriteStreamDynamic scummVMthumbStream(DisposeAfterUse::YES);
if (_game->_cachedThumbnail->_scummVMThumb->writeBMPToStream(&scummVMthumbStream)) {
_saveStream->writeUint32LE(scummVMthumbStream.size());
_saveStream->write(scummVMthumbStream.getData(), scummVMthumbStream.size());
} else {
_saveStream->writeUint32LE(0);
}
thumbnailOK = true;
}
}
if (!thumbnailOK) {
putDWORD(0);
}
// in any case, destroy the cached thumbnail once used
SAFE_DELETE(_game->_cachedThumbnail);
uint32 dataOffset = _offset +
sizeof(uint32) + // data offset
sizeof(uint32) + strlen(desc.c_str()) + 1 + // description
sizeof(uint32); // timestamp
putDWORD(dataOffset);
putString(desc.c_str());
g_system->getTimeAndDate(_savedTimestamp);
putTimeDate(_savedTimestamp);
_savedPlayTime = BasePlatform::getTime();
_saveStream->writeUint32LE(_savedPlayTime);
}
return STATUS_OK;
}
bool BasePersistenceManager::readHeader(const Common::String &filename) {
cleanup();
_saving = false;
_loadStream = g_system->getSavefileManager()->openForLoading(filename);
if (_loadStream) {
uint32 magic;
magic = getDWORD();
if (magic != DCGF_MAGIC) {
cleanup();
return STATUS_FAILED;
}
magic = getDWORD();
if (magic == SAVE_MAGIC_3) {
_savedVerMajor = _loadStream->readByte();
_savedVerMinor = _loadStream->readByte();
_savedExtMajor = _loadStream->readByte();
_savedExtMinor = _loadStream->readByte();
_savedVerBuild = (byte)getDWORD();
_savedName = getStringObj();
// load thumbnail
_thumbnailDataSize = getDWORD();
if (_thumbnailDataSize > 0) {
_thumbnailData = new byte[_thumbnailDataSize];
if (_thumbnailData) {
getBytes(_thumbnailData, _thumbnailDataSize);
} else {
_thumbnailDataSize = 0;
}
}
_scummVMThumbSize = getDWORD();
_scummVMThumbnailData = new byte[_scummVMThumbSize];
if (_scummVMThumbnailData) {
getBytes(_scummVMThumbnailData, _scummVMThumbSize);
} else {
_scummVMThumbSize = 0;
}
uint32 dataOffset = getDWORD();
_savedDescription = getString();
_savedTimestamp = getTimeDate();
_savedPlayTime = _loadStream->readUint32LE();
_offset = dataOffset;
return STATUS_OK;
}
}
cleanup();
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BasePersistenceManager::initLoad(const Common::String &filename) {
if (DID_FAIL(readHeader(filename))) {
cleanup();
return STATUS_FAILED;
}
_saving = false;
if (_savedName == "" || scumm_stricmp(_savedName.c_str(), _game->_name) != 0) {
debugC(kWintermuteDebugSaveGame, "ERROR: Saved game name doesn't match current game");
cleanup();
return STATUS_FAILED;
}
if (BaseEngine::instance().getFlags() & GF_3D) {
if (_savedVerMajor == 1 && _savedVerMinor < 5) {
debugC(kWintermuteDebugSaveGame, "ERROR: Saved game version is too old for 3D game");
cleanup();
return STATUS_FAILED;
}
}
// if save is newer version than we are, fail
if (_savedVerMajor > DCGF_VER_MAJOR ||
(_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor > DCGF_VER_MINOR) ||
(_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor == DCGF_VER_MINOR && _savedVerBuild > DCGF_VER_BUILD)
) {
debugC(kWintermuteDebugSaveGame, "ERROR: Saved game version is newer than current game");
debugC(kWintermuteDebugSaveGame, "ERROR: Expected %d.%d.%d got %d.%d.%d", DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, _savedVerMajor, _savedVerMinor, _savedVerBuild);
cleanup();
return STATUS_FAILED;
}
// if save is older than the minimal version we support
if (_savedVerMajor < SAVEGAME_VER_MAJOR ||
(_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor < SAVEGAME_VER_MINOR) ||
(_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor == SAVEGAME_VER_MINOR && _savedVerBuild < SAVEGAME_VER_BUILD)
) {
debugC(kWintermuteDebugSaveGame, "ERROR: Saved game is too old and cannot be used by this version of game engine");
debugC(kWintermuteDebugSaveGame, "ERROR: Expected %d.%d.%d got %d.%d.%d", DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, _savedVerMajor, _savedVerMinor, _savedVerBuild);
cleanup();
return STATUS_FAILED;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BasePersistenceManager::saveFile(const Common::String &filename) {
byte *prefixBuffer = _richBuffer;
uint32 prefixSize = _richBufferSize;
byte *buffer = ((Common::MemoryWriteStreamDynamic *)_saveStream)->getData();
uint32 bufferSize = ((Common::MemoryWriteStreamDynamic *)_saveStream)->size();
Common::SaveFileManager *saveMan = ((WintermuteEngine *)g_engine)->getSaveFileMan();
Common::OutSaveFile *file = saveMan->openForSaving(filename);
file->write(prefixBuffer, prefixSize);
file->write(buffer, bufferSize);
bool retVal = !file->err();
file->finalize();
delete file;
return retVal;
}
//////////////////////////////////////////////////////////////////////////
bool BasePersistenceManager::putBytes(byte *buffer, uint32 size) {
_saveStream->write(buffer, size);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BasePersistenceManager::getBytes(byte *buffer, uint32 size) {
_loadStream->read(buffer, size);
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BasePersistenceManager::putDWORD(uint32 val) {
_saveStream->writeUint32LE(val);
}
//////////////////////////////////////////////////////////////////////////
uint32 BasePersistenceManager::getDWORD() {
uint32 ret = _loadStream->readUint32LE();
return ret;
}
//////////////////////////////////////////////////////////////////////////
void BasePersistenceManager::putString(const char *val) {
if (!val) {
_saveStream->writeUint32LE(0);
return;
}
uint32 len = strlen(val);
_saveStream->writeUint32LE(len + 1);
_saveStream->write(val, len);
}
Common::String BasePersistenceManager::getStringObj() {
return getString();
}
//////////////////////////////////////////////////////////////////////////
char *BasePersistenceManager::getString() {
uint32 len = _loadStream->readUint32LE();
if (checkVersion(1,2,2)) {
// Version 1.2.2 and above: len == strlen() + 1, NULL has len == 0
if (len == 0)
return nullptr;
char *ret = new char[len];
_loadStream->read(ret, len - 1);
ret[len - 1] = '\0';
return ret;
} else {
// Version 1.2.1 and older: NULL strings are represented as "(null)"
char *ret = new char[len + 1];
_loadStream->read(ret, len);
ret[len] = '\0';
if (!strcmp(ret, "(null)")) {
delete[] ret;
return nullptr;
}
return ret;
}
}
bool BasePersistenceManager::putTimeDate(const TimeDate &t) {
_saveStream->writeSint32LE(t.tm_sec);
_saveStream->writeSint32LE(t.tm_min);
_saveStream->writeSint32LE(t.tm_hour);
_saveStream->writeSint32LE(t.tm_mday);
_saveStream->writeSint32LE(t.tm_mon);
_saveStream->writeSint32LE(t.tm_year);
_saveStream->writeSint32LE(t.tm_wday);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
TimeDate BasePersistenceManager::getTimeDate() {
TimeDate t;
t.tm_sec = _loadStream->readSint32LE();
t.tm_min = _loadStream->readSint32LE();
t.tm_hour = _loadStream->readSint32LE();
t.tm_mday = _loadStream->readSint32LE();
t.tm_mon = _loadStream->readSint32LE();
t.tm_year = _loadStream->readSint32LE();
t.tm_wday = _loadStream->readSint32LE();
return t;
}
void BasePersistenceManager::putFloat(float val) {
if (checkVersion(1, 8, 1)) {
_saveStream->writeFloatLE(val);
}
}
float BasePersistenceManager::getFloat() {
if (checkVersion(1, 8, 1)) {
return _loadStream->readFloatLE();
} else {
char *str = getString();
float value = 0.0f;
float significand = 0.0f;
int32 exponent = _loadStream->readSint32LE();
int ret = sscanf(str, "FS%f", &significand);
value = ldexp(significand, exponent);
if (ret != 1) {
warning("%s not parsed as float", str);
}
delete[] str;
return value;
}
}
void BasePersistenceManager::putDouble(double val) {
if (checkVersion(1, 8, 1)) {
_saveStream->writeDoubleLE(val);
}
}
double BasePersistenceManager::getDouble() {
if (checkVersion(1, 8, 1)) {
return _loadStream->readDoubleLE();
} else {
char *str = getString();
double value = 0.0f;
float significand = 0.0f;
int32 exponent = _loadStream->readSint32LE();
int ret = sscanf(str, "DS%f", &significand);
value = ldexp(significand, exponent);
if (ret != 1) {
warning("%s not parsed as double", str);
}
delete[] str;
return value;
}
}
//////////////////////////////////////////////////////////////////////////
// bool
bool BasePersistenceManager::transferBool(const char *name, bool *val) {
if (_saving) {
_saveStream->writeByte(*val);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
*val = _loadStream->readByte();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// int
bool BasePersistenceManager::transferSint32(const char *name, int32 *val) {
if (_saving) {
_saveStream->writeSint32LE(*val);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
*val = _loadStream->readSint32LE();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// DWORD
bool BasePersistenceManager::transferUint32(const char *name, uint32 *val) {
if (_saving) {
_saveStream->writeUint32LE(*val);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
*val = _loadStream->readUint32LE();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// float
bool BasePersistenceManager::transferFloat(const char *name, float *val) {
if (_saving) {
putFloat(*val);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
*val = getFloat();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// double
bool BasePersistenceManager::transferDouble(const char *name, double *val) {
if (_saving) {
putDouble(*val);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
*val = getDouble();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// char*
bool BasePersistenceManager::transferCharPtr(const char *name, char **val) {
if (_saving) {
putString(*val);
return STATUS_OK;
} else {
char *str = getString();
if (_loadStream->err()) {
delete[] str;
return STATUS_FAILED;
}
*val = str;
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// const char*
bool BasePersistenceManager::transferConstChar(const char *name, const char **val) {
if (_saving) {
putString(*val);
return STATUS_OK;
} else {
char *str = getString();
if (_loadStream->err()) {
delete[] str;
return STATUS_FAILED;
}
*val = str;
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// Common::String
bool BasePersistenceManager::transferString(const char *name, Common::String *val) {
if (_saving) {
putString(val->c_str());
return STATUS_OK;
} else {
char *str = getString();
if (_loadStream->err()) {
delete[] str;
return STATUS_FAILED;
}
if (str) {
*val = str;
delete[] str;
} else {
*val = "";
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// BYTE
bool BasePersistenceManager::transferByte(const char *name, byte *val) {
if (_saving) {
_saveStream->writeByte(*val);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
*val = _loadStream->readByte();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// RECT
bool BasePersistenceManager::transferRect32(const char *name, Common::Rect32 *val) {
if (_saving) {
_saveStream->writeSint32LE(val->left);
_saveStream->writeSint32LE(val->top);
_saveStream->writeSint32LE(val->right);
_saveStream->writeSint32LE(val->bottom);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
val->left = _loadStream->readSint32LE();
val->top = _loadStream->readSint32LE();
val->right = _loadStream->readSint32LE();
val->bottom = _loadStream->readSint32LE();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// POINT
bool BasePersistenceManager::transferPoint32(const char *name, Common::Point32 *val) {
if (_saving) {
_saveStream->writeSint32LE(val->x);
_saveStream->writeSint32LE(val->y);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
val->x = _loadStream->readSint32LE();
val->y = _loadStream->readSint32LE();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// Vector2
bool BasePersistenceManager::transferVector2(const char *name, DXVector2 *val) {
if (_saving) {
putFloat(val->_x);
putFloat(val->_y);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
val->_x = getFloat();
val->_y = getFloat();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// Vector3
bool BasePersistenceManager::transferVector3d(const char *name, DXVector3 *val) {
if (_saving) {
putFloat(val->_x);
putFloat(val->_y);
putFloat(val->_z);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
val->_x = getFloat();
val->_y = getFloat();
val->_z = getFloat();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// Vector4
bool BasePersistenceManager::transferVector4d(const char *name, DXVector4 *val) {
if (_saving) {
putFloat(val->_x);
putFloat(val->_y);
putFloat(val->_z);
putFloat(val->_w);
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
val->_x = getFloat();
val->_y = getFloat();
val->_z = getFloat();
val->_w = getFloat();
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// Matrix4
bool BasePersistenceManager::transferMatrix4(const char *name, DXMatrix *val) {
if (_saving) {
for (int i = 0; i < 16; ++i) {
putFloat(val->_m4x4[i]);
}
if (_saveStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
} else {
for (int i = 0; i < 16; ++i) {
val->_m4x4[i] = getFloat();
}
if (_loadStream->err()) {
return STATUS_FAILED;
}
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
// generic pointer
bool BasePersistenceManager::transferPtr(const char *name, void *val) {
int classID = -1, instanceID = -1;
if (_saving) {
SystemClassRegistry::getInstance()->getPointerID(*(void **)val, &classID, &instanceID);
if (*(void **)val != nullptr && (classID == -1 || instanceID == -1)) {
debugC(kWintermuteDebugSaveGame, "Warning: invalid instance '%s'", name);
}
_saveStream->writeUint32LE(classID);
_saveStream->writeUint32LE(instanceID);
} else {
classID = _loadStream->readUint32LE();
instanceID = _loadStream->readUint32LE();
*(void **)val = SystemClassRegistry::getInstance()->idToPointer(classID, instanceID);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BasePersistenceManager::checkVersion(byte verMajor, byte verMinor, byte verBuild) {
if (_saving) {
return true;
}
// it's ok if we are same or newer than the saved game
if (verMajor > _savedVerMajor ||
(verMajor == _savedVerMajor && verMinor > _savedVerMinor) ||
(verMajor == _savedVerMajor && verMinor == _savedVerMinor && verBuild > _savedVerBuild)
) {
return false;
}
return true;
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_PERSISTENCE_MANAGER_H
#define WINTERMUTE_BASE_PERSISTENCE_MANAGER_H
#include "engines/wintermute/dctypes.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/savestate.h"
#include "common/stream.h"
#include "common/str.h"
#include "common/system.h"
#include "common/rect.h"
namespace Wintermute {
class BaseGame;
class BasePersistenceManager {
public:
char *_savedDescription;
Common::String _savePrefix;
Common::String _savedName;
bool saveFile(const Common::String &filename);
uint32 getDWORD();
void putDWORD(uint32 val);
char *getString();
Common::String getStringObj();
void putString(const char *val);
float getFloat();
void putFloat(float val);
double getDouble();
void putDouble(double val);
void cleanup();
void getSaveStateDesc(int slot, SaveStateDescriptor &desc);
bool deleteSaveSlot(int slot);
uint32 getMaxUsedSlot();
bool getSaveExists(int slot);
bool initLoad(const Common::String &filename);
bool initSave(const Common::String &desc);
bool getBytes(byte *buffer, uint32 size);
bool putBytes(byte *buffer, uint32 size);
uint32 _offset;
bool getIsSaving() { return _saving; }
TimeDate getSavedTimestamp() { return _savedTimestamp; }
uint32 _richBufferSize;
byte *_richBuffer;
bool transferPtr(const char *name, void *val);
bool transferSint32(const char *name, int32 *val);
bool transferUint32(const char *name, uint32 *val);
bool transferFloat(const char *name, float *val);
bool transferDouble(const char *name, double *val);
bool transferBool(const char *name, bool *val);
bool transferByte(const char *name, byte *val);
bool transferRect32(const char *name, Common::Rect32 *val);
bool transferPoint32(const char *name, Common::Point32 *val);
bool transferConstChar(const char *name, const char **val);
bool transferCharPtr(const char *name, char **val);
bool transferString(const char *name, Common::String *val);
bool transferVector2(const char *name, DXVector2 *val);
bool transferVector3d(const char *name, DXVector3 *val);
bool transferVector4d(const char *name, DXVector4 *val);
bool transferMatrix4(const char *name, DXMatrix *val);
BasePersistenceManager(const Common::String &savePrefix = "", bool deleteSingleton = false);
virtual ~BasePersistenceManager();
bool checkVersion(byte verMajor, byte verMinor, byte verBuild);
uint32 _thumbnailDataSize;
byte *_thumbnailData;
uint32 _scummVMThumbSize;
byte *_scummVMThumbnailData;
Common::String getFilenameForSlot(int slot) const;
private:
bool _deleteSingleton;
bool readHeader(const Common::String &filename);
TimeDate getTimeDate();
bool putTimeDate(const TimeDate &t);
Common::WriteStream *_saveStream;
Common::SeekableReadStream *_loadStream;
TimeDate _savedTimestamp;
uint32 _savedPlayTime;
byte _savedVerMajor;
byte _savedVerMinor;
byte _savedVerBuild;
byte _savedExtMajor;
byte _savedExtMinor;
bool _saving;
BaseGame *_game;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,62 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_point.h"
#include "engines/wintermute/base/base_persistence_manager.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BasePoint, false)
//////////////////////////////////////////////////////////////////////////
BasePoint::BasePoint() {
x = y = 0;
}
//////////////////////////////////////////////////////////////////////////
BasePoint::~BasePoint() {
}
//////////////////////////////////////////////////////////////////////////
BasePoint::BasePoint(int initX, int initY) {
x = initX;
y = initY;
}
//////////////////////////////////////////////////////////////////////////
bool BasePoint::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferSint32(TMEMBER(x));
persistMgr->transferSint32(TMEMBER(y));
return STATUS_OK;
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_POINT_H
#define WINTERMUTE_BASE_POINT_H
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BasePoint : public BaseClass {
public:
DECLARE_PERSISTENT(BasePoint, BaseClass)
BasePoint();
BasePoint(int initX, int initY);
int32 y;
int32 x;
~BasePoint() override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,54 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_quick_msg.h"
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseQuickMsg::BaseQuickMsg(BaseGame *inGame, const char *text) : BaseClass(inGame) {
size_t textSize = strlen(text) + 1;
_text = new char[textSize];
Common::strcpy_s(_text, textSize, text);
_startTime = _game->_currentTime;
}
//////////////////////////////////////////////////////////////////////////
BaseQuickMsg::~BaseQuickMsg() {
delete[] _text;
}
//////////////////////////////////////////////////////////////////////////
const char *BaseQuickMsg::getText() {
return _text;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,46 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_QUICKMSG_H
#define WINTERMUTE_BASE_QUICKMSG_H
#include "common/str.h"
namespace Wintermute {
class BaseQuickMsg : public BaseClass {
public:
const char *getText();
uint32 _startTime;
char *_text;
BaseQuickMsg(BaseGame *inGame, const char *text);
virtual ~BaseQuickMsg();
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,545 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseRegion, false)
//////////////////////////////////////////////////////////////////////////
BaseRegion::BaseRegion(BaseGame *inGame) : BaseObject(inGame) {
_active = true;
_editorSelectedPoint = -1;
_lastMimicScale = -1;
_lastMimicX = _lastMimicY = INT_MIN_VALUE;
BasePlatform::setRectEmpty(&_rect);
}
//////////////////////////////////////////////////////////////////////////
BaseRegion::~BaseRegion() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void BaseRegion::cleanup() {
for (int32 i = 0; i < _points.getSize(); i++) {
delete _points[i];
}
_points.removeAll();
BasePlatform::setRectEmpty(&_rect);
_editorSelectedPoint = -1;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::createRegion() {
return DID_SUCCEED(getBoundingRect(&_rect));
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::pointInRegion(int x, int y) {
if (_points.getSize() < 3) {
return false;
}
Common::Point32 pt;
pt.x = x;
pt.y = y;
Common::Rect32 rect;
rect.left = x - 1;
rect.right = x + 2;
rect.top = y - 1;
rect.bottom = y + 2;
if (BasePlatform::ptInRect(&_rect, pt)) {
return ptInPolygon(x, y);
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::loadFile(const char *filename) {
char *buffer = (char *)_game->_fileManager->readWholeFile(filename);
if (buffer == nullptr) {
_game->LOG(0, "BaseRegion::loadFile failed for file '%s'", filename);
return STATUS_FAILED;
}
bool ret;
setFilename(filename);
if (DID_FAIL(ret = loadBuffer(buffer, true))) {
_game->LOG(0, "Error parsing REGION file '%s'", filename);
}
delete[] buffer;
return ret;
}
TOKEN_DEF_START
TOKEN_DEF(REGION)
TOKEN_DEF(TEMPLATE)
TOKEN_DEF(NAME)
TOKEN_DEF(ACTIVE)
TOKEN_DEF(POINT)
TOKEN_DEF(CAPTION)
TOKEN_DEF(SCRIPT)
TOKEN_DEF(EDITOR_SELECTED_POINT)
TOKEN_DEF(PROPERTY)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::loadBuffer(char *buffer, bool complete) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(REGION)
TOKEN_TABLE(TEMPLATE)
TOKEN_TABLE(NAME)
TOKEN_TABLE(ACTIVE)
TOKEN_TABLE(POINT)
TOKEN_TABLE(CAPTION)
TOKEN_TABLE(SCRIPT)
TOKEN_TABLE(EDITOR_SELECTED_POINT)
TOKEN_TABLE(PROPERTY)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
if (complete) {
if (parser.getCommand(&buffer, commands, &params) != TOKEN_REGION) {
_game->LOG(0, "'REGION' keyword expected.");
return STATUS_FAILED;
}
buffer = params;
}
for (int32 i = 0; i < _points.getSize(); i++) {
delete _points[i];
}
_points.removeAll();
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_TEMPLATE:
if (DID_FAIL(loadFile(params))) {
cmd = PARSERR_GENERIC;
}
break;
case TOKEN_NAME:
setName(params);
break;
case TOKEN_CAPTION:
setCaption(params);
break;
case TOKEN_ACTIVE:
parser.scanStr(params, "%b", &_active);
break;
case TOKEN_POINT: {
int x, y;
parser.scanStr(params, "%d,%d", &x, &y);
_points.add(new BasePoint(x, y));
}
break;
case TOKEN_SCRIPT:
addScript(params);
break;
case TOKEN_EDITOR_SELECTED_POINT:
parser.scanStr(params, "%d", &_editorSelectedPoint);
break;
case TOKEN_PROPERTY:
parseProperty(params, false);
break;
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
_game->LOG(0, "Syntax error in REGION definition");
return STATUS_FAILED;
}
createRegion();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// AddPoint
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "AddPoint") == 0) {
stack->correctParams(2);
int x = stack->pop()->getInt();
int y = stack->pop()->getInt();
_points.add(new BasePoint(x, y));
createRegion();
stack->pushBool(true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// InsertPoint
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "InsertPoint") == 0) {
stack->correctParams(3);
int index = stack->pop()->getInt();
int x = stack->pop()->getInt();
int y = stack->pop()->getInt();
if (index >= 0 && index < _points.getSize()) {
_points.insertAt(index, new BasePoint(x, y));
createRegion();
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetPoint
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetPoint") == 0) {
stack->correctParams(3);
int index = stack->pop()->getInt();
int x = stack->pop()->getInt();
int y = stack->pop()->getInt();
if (index >= 0 && index < _points.getSize()) {
_points[index]->x = x;
_points[index]->y = y;
createRegion();
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// RemovePoint
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "RemovePoint") == 0) {
stack->correctParams(1);
int index = stack->pop()->getInt();
if (index >= 0 && index < _points.getSize()) {
SAFE_DELETE(_points[index]);
_points.removeAt(index);
createRegion();
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetPoint
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetPoint") == 0) {
stack->correctParams(1);
int index = stack->pop()->getInt();
if (index >= 0 && index < _points.getSize()) {
ScValue *val = stack->getPushValue();
if (val) {
val->setProperty("X", _points[index]->x);
val->setProperty("Y", _points[index]->y);
}
} else {
stack->pushNULL();
}
return STATUS_OK;
} else {
return BaseObject::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseRegion::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("region");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Name") == 0) {
_scValue->setString(_name);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Active
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Active") == 0) {
_scValue->setBool(_active);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// NumPoints
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "NumPoints") == 0) {
_scValue->setInt(_points.getSize());
return _scValue;
} else {
return BaseObject::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Name") == 0) {
setName(value->getString());
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Active
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Active") == 0) {
_active = value->getBool();
return STATUS_OK;
} else {
return BaseObject::scSetProperty(name, value);
}
}
//////////////////////////////////////////////////////////////////////////
const char *BaseRegion::scToString() {
return "[region]";
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::saveAsText(BaseDynamicBuffer *buffer, int indent, const char *nameOverride) {
if (!nameOverride) {
buffer->putTextIndent(indent, "REGION {\n");
} else {
buffer->putTextIndent(indent, "%s {\n", nameOverride);
}
buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
buffer->putTextIndent(indent + 2, "CAPTION=\"%s\"\n", getCaption());
buffer->putTextIndent(indent + 2, "ACTIVE=%s\n", _active ? "TRUE" : "FALSE");
buffer->putTextIndent(indent + 2, "EDITOR_SELECTED_POINT=%d\n", _editorSelectedPoint);
for (int32 i = 0; i < _scripts.getSize(); i++) {
buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
}
for (int32 i = 0; i < _points.getSize(); i++) {
buffer->putTextIndent(indent + 2, "POINT {%d,%d}\n", _points[i]->x, _points[i]->y);
}
if (_scProp) {
_scProp->saveAsText(buffer, indent + 2);
}
buffer->putTextIndent(indent, "}\n\n");
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::persist(BasePersistenceManager *persistMgr) {
BaseObject::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_active));
persistMgr->transferSint32(TMEMBER(_editorSelectedPoint));
persistMgr->transferFloat(TMEMBER(_lastMimicScale));
persistMgr->transferSint32(TMEMBER(_lastMimicX));
persistMgr->transferSint32(TMEMBER(_lastMimicY));
_points.persist(persistMgr);
// initialise to default
if (!persistMgr->getIsSaving()) {
BasePlatform::setRectEmpty(&_rect);
}
return STATUS_OK;
}
typedef struct {
double x, y;
} dPoint;
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::ptInPolygon(int32 x, int32 y) {
if (_points.getSize() < 3) {
return false;
}
int counter = 0;
double xinters;
dPoint p, p1, p2;
p.x = (double)x;
p.y = (double)y;
p1.x = (double)_points[0]->x;
p1.y = (double)_points[0]->y;
for (int32 i = 1; i <= _points.getSize(); i++) {
p2.x = (double)_points[i % _points.getSize()]->x;
p2.y = (double)_points[i % _points.getSize()]->y;
if (p.y > MIN(p1.y, p2.y)) {
if (p.y <= MAX(p1.y, p2.y)) {
if (p.x <= MAX(p1.x, p2.x)) {
if (p1.y != p2.y) {
xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
if (p1.x == p2.x || p.x <= xinters) {
counter++;
}
}
}
}
}
p1 = p2;
}
if (counter % 2 == 0) {
return false;
} else {
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::getBoundingRect(Common::Rect32 *rect) {
if (_points.getSize() == 0) {
BasePlatform::setRectEmpty(rect);
} else {
int32 minX = INT_MAX_VALUE, minY = INT_MAX_VALUE, maxX = INT_MIN_VALUE, maxY = INT_MIN_VALUE;
for (int32 i = 0; i < _points.getSize(); i++) {
minX = MIN(minX, _points[i]->x);
minY = MIN(minY, _points[i]->y);
maxX = MAX(maxX, _points[i]->x);
maxY = MAX(maxY, _points[i]->y);
}
BasePlatform::setRect(rect, minX, minY, maxX, maxY);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRegion::mimic(BaseRegion *region, float scale, int x, int y) {
if (scale == _lastMimicScale && x == _lastMimicX && y == _lastMimicY) {
return STATUS_OK;
}
cleanup();
for (int32 i = 0; i < region->_points.getSize(); i++) {
int xVal, yVal;
xVal = (int)((float)region->_points[i]->x * scale / 100.0f);
yVal = (int)((float)region->_points[i]->y * scale / 100.0f);
_points.add(new BasePoint(xVal + x, yVal + y));
}
_lastMimicScale = scale;
_lastMimicX = x;
_lastMimicY = y;
return createRegion() ? STATUS_OK : STATUS_FAILED;
}
Common::String BaseRegion::debuggerToString() const {
return Common::String::format("%p: Region \"%s\": Rect (top, right, bottom, left): (%d, %d, %d, %d), active: %d ", (const void *)this, _name, _rect.top, _rect.right, _rect.bottom, _rect.left, _active);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,70 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_REGION_H
#define WINTERMUTE_BASE_REGION_H
#include "engines/wintermute/base/base_point.h"
#include "engines/wintermute/base/base_object.h"
namespace Wintermute {
class BaseRegion : public BaseObject {
public:
float _lastMimicScale;
int32 _lastMimicX;
int32 _lastMimicY;
void cleanup();
bool mimic(BaseRegion *region, float scale = 100.0f, int x = 0, int y = 0);
bool getBoundingRect(Common::Rect32 *rect);
bool ptInPolygon(int32 x, int32 y);
DECLARE_PERSISTENT(BaseRegion, BaseObject)
bool _active;
int32 _editorSelectedPoint;
BaseRegion(BaseGame *inGame);
~BaseRegion() override;
bool pointInRegion(int x, int y);
bool createRegion();
bool loadFile(const char *filename);
bool loadBuffer(char *buffer, bool complete = true);
Common::Rect32 _rect;
BaseArray<BasePoint *> _points;
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override { return saveAsText(buffer, indent, nullptr); }
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent, const char *nameOverride);
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
Common::String debuggerToString() const override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,504 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/ad/ad_game.h"
#include "engines/wintermute/base/base_script_holder.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseScriptHolder, false)
//////////////////////////////////////////////////////////////////////
BaseScriptHolder::BaseScriptHolder(BaseGame *inGame) : BaseScriptable(inGame) {
setName("<unnamed>");
_freezable = true;
_filename = nullptr;
}
//////////////////////////////////////////////////////////////////////
BaseScriptHolder::~BaseScriptHolder() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::cleanup() {
SAFE_DELETE_ARRAY(_filename);
for (int32 i = 0; i < _scripts.getSize(); i++) {
_scripts[i]->finish(true);
_scripts[i]->_owner = nullptr;
}
_scripts.removeAll();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
void BaseScriptHolder::setFilename(const char *filename) {
if (_filename != nullptr) {
delete[] _filename;
_filename = nullptr;
}
if (filename == nullptr) {
return;
}
size_t filenameSize = strlen(filename) + 1;
_filename = new char [filenameSize];
Common::strcpy_s(_filename, filenameSize, filename);
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::applyEvent(const char *eventName, bool unbreakable) {
int numHandlers = 0;
bool ret = STATUS_FAILED;
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (!_scripts[i]->_thread) {
ScScript *handler = _scripts[i]->invokeEventHandler(eventName, unbreakable);
if (handler) {
//_scripts.add(handler);
numHandlers++;
ret = STATUS_OK;
}
}
}
if (numHandlers > 0 && unbreakable) {
_game->_scEngine->tickUnbreakable();
}
return ret;
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::listen(BaseScriptHolder *param1, uint32 param2) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// DEBUG_CrashMe
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "DEBUG_CrashMe") == 0) {
stack->correctParams(0);
byte *p = 0;
*p = 10;
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ApplyEvent
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ApplyEvent") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
bool ret;
ret = applyEvent(val->getString());
if (DID_SUCCEED(ret)) {
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// CanHandleEvent
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "CanHandleEvent") == 0) {
stack->correctParams(1);
stack->pushBool(canHandleEvent(stack->pop()->getString()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// CanHandleMethod
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "CanHandleMethod") == 0) {
stack->correctParams(1);
stack->pushBool(canHandleMethod(stack->pop()->getString()));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// AttachScript
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "AttachScript") == 0) {
stack->correctParams(1);
stack->pushBool(DID_SUCCEED(addScript(stack->pop()->getString())));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// DetachScript
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "DetachScript") == 0) {
stack->correctParams(2);
const char *filename = stack->pop()->getString();
bool killThreads = stack->pop()->getBool(false);
bool ret = false;
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (scumm_stricmp(_scripts[i]->_filename, filename) == 0) {
_scripts[i]->finish(killThreads);
ret = true;
break;
}
}
stack->pushBool(ret);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// IsScriptRunning
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "IsScriptRunning") == 0) {
stack->correctParams(1);
const char *filename = stack->pop()->getString();
bool ret = false;
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (scumm_stricmp(_scripts[i]->_filename, filename) == 0 && _scripts[i]->_state != SCRIPT_FINISHED && _scripts[i]->_state != SCRIPT_ERROR) {
ret = true;
break;
}
}
stack->pushBool(ret);
return STATUS_OK;
} else {
return BaseScriptable::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseScriptHolder::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("script_holder");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Name") == 0) {
_scValue->setString(_name);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Filename (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Filename") == 0) {
_scValue->setString(_filename);
return _scValue;
} else {
return BaseScriptable::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Name") == 0) {
setName(value->getString());
return STATUS_OK;
} else {
return BaseScriptable::scSetProperty(name, value);
}
}
//////////////////////////////////////////////////////////////////////////
const char *BaseScriptHolder::scToString() {
return "[script_holder]";
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::saveAsText(BaseDynamicBuffer *buffer, int indent) {
return BaseClass::saveAsText(buffer, indent);
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
persistMgr->transferCharPtr(TMEMBER(_filename));
persistMgr->transferBool(TMEMBER(_freezable));
if (persistMgr->getIsSaving()) {
const char *name = _name;
persistMgr->transferConstChar(TMEMBER(name));
} else {
char *name;
persistMgr->transferCharPtr(TMEMBER(name));
setName(name);
delete[] name;
}
_scripts.persist(persistMgr);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::addScript(const char *filename) {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (scumm_stricmp(_scripts[i]->_filename, filename) == 0) {
if (_scripts[i]->_state != SCRIPT_FINISHED) {
_game->LOG(0, "BaseScriptHolder::addScript - trying to add script '%s' mutiple times (obj: '%s')", filename, _name);
return STATUS_OK;
}
}
}
ScScript *scr = _game->_scEngine->runScript(filename, this);
if (!scr) {
if (_game->_editorForceScripts) {
// editor hack
#if EXTENDED_DEBUGGER_ENABLED
scr = new DebuggableScript(_game, _game->_scEngine);
#else
scr = new ScScript(_game, _game->_scEngine);
#endif
size_t filenameSize = strlen(filename) + 1;
scr->_filename = new char[filenameSize];
Common::strcpy_s(scr->_filename, filenameSize, filename);
scr->_state = SCRIPT_ERROR;
scr->_owner = this;
_scripts.add(scr);
_game->_scEngine->_scripts.add(scr);
return STATUS_OK;
}
return STATUS_FAILED;
} else {
scr->_freezable = _freezable;
_scripts.add(scr);
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::removeScript(ScScript *script) {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (_scripts[i] == script) {
_scripts.removeAt(i);
break;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::canHandleEvent(const char *eventName) {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (!_scripts[i]->_thread && _scripts[i]->canHandleEvent(eventName)) {
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::canHandleMethod(const char *methodName) {
for (int32 i = 0; i < _scripts.getSize(); i++) {
if (!_scripts[i]->_thread && _scripts[i]->canHandleMethod(methodName)) {
return true;
}
}
return false;
}
TOKEN_DEF_START
TOKEN_DEF(PROPERTY)
TOKEN_DEF(NAME)
TOKEN_DEF(VALUE)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::parseProperty(char *buffer, bool complete) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(PROPERTY)
TOKEN_TABLE(NAME)
TOKEN_TABLE(VALUE)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
if (complete) {
if (parser.getCommand(&buffer, commands, &params) != TOKEN_PROPERTY) {
_game->LOG(0, "'PROPERTY' keyword expected.");
return STATUS_FAILED;
}
buffer = params;
}
char *propName = nullptr;
char *propValue = nullptr;
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_NAME: {
SAFE_DELETE_ARRAY(propName);
size_t propNameSize = strlen(params) + 1;
propName = new char[propNameSize];
Common::strcpy_s(propName, propNameSize, params);
break;
}
case TOKEN_VALUE: {
SAFE_DELETE_ARRAY(propValue);
size_t propValueSize = strlen(params) + 1;
propValue = new char[propValueSize];
Common::strcpy_s(propValue, propValueSize, params);
break;
}
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
SAFE_DELETE_ARRAY(propName);
SAFE_DELETE_ARRAY(propValue);
_game->LOG(0, "Syntax error in PROPERTY definition");
return STATUS_FAILED;
}
if (cmd == PARSERR_GENERIC || propName == nullptr || propValue == nullptr) {
SAFE_DELETE_ARRAY(propName);
SAFE_DELETE_ARRAY(propValue);
_game->LOG(0, "Error loading PROPERTY definition");
return STATUS_FAILED;
}
ScValue *val = new ScValue(_game);
val->setString(propValue);
scSetProperty(propName, val);
delete val;
SAFE_DELETE_ARRAY(propName);
SAFE_DELETE_ARRAY(propValue);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptHolder::makeFreezable(bool freezable) {
_freezable = freezable;
for (int32 i = 0; i < _scripts.getSize(); i++) {
_scripts[i]->_freezable = freezable;
}
}
//////////////////////////////////////////////////////////////////////////
ScScript *BaseScriptHolder::invokeMethodThread(const char *methodName) {
for (int32 i = _scripts.getSize() - 1; i >= 0; i--) {
if (_scripts[i]->canHandleMethod(methodName)) {
#if EXTENDED_DEBUGGER_ENABLED
DebuggableScEngine* debuggableEngine;
debuggableEngine = dynamic_cast<DebuggableScEngine*>(_scripts[i]->_engine);
// TODO: Not pretty
assert(debuggableEngine);
ScScript *thread = new DebuggableScript(_game, debuggableEngine);
#else
ScScript *thread = new ScScript(_game, _scripts[i]->_engine);
#endif
if (thread) {
bool ret = thread->createMethodThread(_scripts[i], methodName);
if (DID_SUCCEED(ret)) {
_scripts[i]->_engine->_scripts.add(thread);
return thread;
} else {
delete thread;
}
}
}
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptHolder::scDebuggerDesc(char *buf, int bufSize) {
Common::strcpy_s(buf, bufSize, scToString());
if (_name && _name[0] && strcmp(_name, "<unnamed>") != 0) {
Common::strcat_s(buf, bufSize, " Name: ");
Common::strcat_s(buf, bufSize, _name);
}
if (_filename && _filename[0]) {
Common::strcat_s(buf, bufSize, " File: ");
Common::strcat_s(buf, bufSize, _filename);
}
}
//////////////////////////////////////////////////////////////////////////
// IWmeObject
//////////////////////////////////////////////////////////////////////////
bool BaseScriptHolder::sendEvent(const char *eventName) {
return DID_SUCCEED(applyEvent(eventName));
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,76 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SCRIPTHOLDER_H
#define WINTERMUTE_BASE_SCRIPTHOLDER_H
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class BaseScriptHolder : public BaseScriptable {
public:
DECLARE_PERSISTENT(BaseScriptHolder, BaseScriptable)
BaseScriptHolder(BaseGame *inGame);
~BaseScriptHolder() override;
ScScript *invokeMethodThread(const char *methodName) override;
virtual void makeFreezable(bool freezable);
bool canHandleEvent(const char *eventName);
bool canHandleMethod(const char *eventMethod) override;
bool cleanup();
bool removeScript(ScScript *script);
bool addScript(const char *filename);
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override;
virtual bool listen(BaseScriptHolder *param1, uint32 param2);
bool applyEvent(const char *eventName, bool unbreakable = false);
void setFilename(const char *filename);
bool parseProperty(char *buffer, bool complete = true);
char *_filename;
bool _freezable;
bool _ready{};
BaseArray<ScScript *> _scripts;
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
void scDebuggerDesc(char *buf, int bufSize) override;
// IWmeObject
public:
virtual bool sendEvent(const char *eventName);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,194 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_scriptable.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseScriptable, false)
//////////////////////////////////////////////////////////////////////////
BaseScriptable::BaseScriptable(BaseGame *inGame, bool noValue, bool persistable) : BaseNamedObject(inGame) {
_refCount = 0;
if (noValue) {
_scValue = nullptr;
} else {
_scValue = new ScValue(_game);
}
_persistable = persistable;
_scProp = nullptr;
}
//////////////////////////////////////////////////////////////////////////
BaseScriptable::~BaseScriptable() {
//if (_refCount>0) BaseEngine::LOG(0, "Warning: Destroying object, _refCount=%d", _refCount);
SAFE_DELETE(_scValue);
SAFE_DELETE(_scProp);
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseScriptable::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
/*
stack->correctParams(0);
stack->pushNULL();
script->runtimeError("Call to undefined method '%s'.", name);
return STATUS_OK;
*/
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseScriptable::scGetProperty(const char *name) {
if (!_scProp) {
_scProp = new ScValue(_game);
}
if (_scProp) {
return _scProp->getProp(name);
} else {
return nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptable::scSetProperty(const char *name, ScValue *value) {
if (!_scProp) {
_scProp = new ScValue(_game);
}
if (_scProp) {
return _scProp->setProp(name, value);
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
const char *BaseScriptable::scToString() {
return "[native object]";
}
//////////////////////////////////////////////////////////////////////////
void *BaseScriptable::scToMemBuffer() {
return (void *)nullptr;
}
//////////////////////////////////////////////////////////////////////////
int BaseScriptable::scToInt() {
return 0;
}
//////////////////////////////////////////////////////////////////////////
double BaseScriptable::scToFloat() {
return 0.0f;
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptable::scToBool() {
return false;
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptable::scSetString(const char *val) {
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptable::scSetInt(int val) {
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptable::scSetFloat(double val) {
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptable::scSetBool(bool val) {
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptable::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferPtr(TMEMBER_PTR(_game));
persistMgr->transferSint32(TMEMBER(_refCount));
persistMgr->transferPtr(TMEMBER_PTR(_scProp));
persistMgr->transferPtr(TMEMBER_PTR(_scValue));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int BaseScriptable::scCompare(BaseScriptable *val) {
if (this < val) {
return -1;
} else if (this > val) {
return 1;
} else {
return 0;
}
}
//////////////////////////////////////////////////////////////////////////
void BaseScriptable::scDebuggerDesc(char *buf, int bufSize) {
Common::strcpy_s(buf, bufSize, scToString());
}
//////////////////////////////////////////////////////////////////////////
bool BaseScriptable::canHandleMethod(const char *eventMethod) {
return false;
}
//////////////////////////////////////////////////////////////////////////
ScScript *BaseScriptable::invokeMethodThread(const char *methodName) {
return nullptr;
}
Common::String BaseScriptable::debuggerToString() const {
return Common::String::format("%p: BaseScriptable %s", (const void *)this, _name);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,85 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SCRIPTABLE_H
#define WINTERMUTE_BASE_SCRIPTABLE_H
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/persistent.h"
namespace Wintermute {
class ScValue;
class ScStack;
class ScScript;
class BaseScriptable : public BaseNamedObject {
public:
virtual ScScript *invokeMethodThread(const char *methodName);
DECLARE_PERSISTENT(BaseScriptable, BaseNamedObject)
BaseScriptable(BaseGame *inGame, bool noValue = false, bool persistable = true);
~BaseScriptable() override;
// high level scripting interface
virtual bool canHandleMethod(const char *eventMethod);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual ScValue *scGetProperty(const char *name);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
virtual void *scToMemBuffer();
virtual int scToInt();
virtual double scToFloat();
virtual bool scToBool();
virtual void scSetString(const char *val);
virtual void scSetInt(int val);
virtual void scSetFloat(double val);
virtual void scSetBool(bool val);
virtual int scCompare(BaseScriptable *val);
virtual void scDebuggerDesc(char *buf, int bufSize);
int32 _refCount;
ScValue *_scValue;
ScValue *_scProp;
virtual Common::String debuggerToString() const;
};
// Implemented in their respective .cpp-files
BaseScriptable *makeSXArray(BaseGame *inGame, ScStack *stack);
BaseScriptable *makeSXDate(BaseGame *inGame, ScStack *stack);
BaseScriptable *makeSXFile(BaseGame *inGame, ScStack *stack);
BaseScriptable *makeSXDirectory(BaseGame *inGame);
BaseScriptable *makeSXMath(BaseGame *inGame);
BaseScriptable *makeSXMemBuffer(BaseGame *inGame, ScStack *stack);
BaseScriptable *makeSXObject(BaseGame *inGame, ScStack *stack);
BaseScriptable *makeSXStore(BaseGame *inGame);
BaseScriptable *makeSXString(BaseGame *inGame, ScStack *stack);
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,823 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/utils/path_util.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/detection.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseSprite, false)
//////////////////////////////////////////////////////////////////////
BaseSprite::BaseSprite(BaseGame *inGame, BaseObject *owner) : BaseScriptHolder(inGame) {
_editorAllFrames = false;
_owner = owner;
setDefaults();
}
//////////////////////////////////////////////////////////////////////
BaseSprite::~BaseSprite() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void BaseSprite::setDefaults() {
_currentFrame = -1;
_looping = false;
_lastFrameTime = 0;
setFilename(nullptr);
_finished = false;
_changed = false;
_paused = false;
_continuous = false;
_moveX = _moveY = 0;
_editorMuted = false;
_editorBgFile = nullptr;
_editorBgOffsetX = _editorBgOffsetY = 0;
_editorBgAlpha = 0xFF;
_streamed = false;
_streamedKeepLoaded = false;
setName("");
_precise = true;
}
//////////////////////////////////////////////////////////////////////////
void BaseSprite::cleanup() {
BaseScriptHolder::cleanup();
for (int32 i = 0; i < _frames.getSize(); i++) {
delete _frames[i];
}
_frames.removeAll();
SAFE_DELETE_ARRAY(_editorBgFile);
setDefaults();
}
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, uint32 alpha) {
getCurrentFrame(zoomX, zoomY);
if (_currentFrame < 0 || _currentFrame >= _frames.getSize()) {
return STATUS_OK;
}
// move owner if allowed to
if (_changed && _owner && _owner->_movable) {
_owner->_posX += _moveX;
_owner->_posY += _moveY;
_owner->afterMove();
x = _owner->_posX;
y = _owner->_posY;
}
// draw frame
return display(x, y, registerOwner, zoomX, zoomY, alpha);
}
//////////////////////////////////////////////////////////////////////
bool BaseSprite::loadFile(const char *filename, int lifeTime, TSpriteCacheType cacheType) {
if (!_game->_fileManager->hasFile(filename)) {
_game->LOG(0, "BaseSprite::loadFile failed for file '%s'", filename);
if (_game->_debugMode) {
return loadFile("invalid_debug.bmp", lifeTime, cacheType);
} else {
return loadFile("invalid.bmp", lifeTime, cacheType);
}
}
bool ret = STATUS_FAILED;
AnsiString filePrefix = filename;
AnsiString ext = PathUtil::getExtension(filename);
ext.toLowercase();
filePrefix.toLowercase();
if (filePrefix.hasPrefix("savegame:") || (ext == ".bmp") || (ext == ".tga") || (ext == ".png") || (ext == ".jpg")) {
BaseFrame *frame = new BaseFrame(_game);
BaseSubFrame *subframe = new BaseSubFrame(_game);
subframe->setSurface(filename, true, 0, 0, 0, lifeTime, true);
if (subframe->_surface == nullptr) {
_game->LOG(0, "Error loading simple sprite '%s'", filename);
ret = STATUS_FAILED;
delete frame;
delete subframe;
} else {
BasePlatform::setRect(&subframe->_rect, 0, 0, subframe->_surface->getWidth(), subframe->_surface->getHeight());
frame->_subframes.add(subframe);
_frames.add(frame);
_currentFrame = 0;
ret = STATUS_OK;
}
} else {
char *buffer = (char *)_game->_fileManager->readWholeFile(filename);
if (buffer) {
if (DID_FAIL(ret = loadBuffer(buffer, true, lifeTime, cacheType))) {
_game->LOG(0, "Error parsing SPRITE file '%s'", filename);
} else {
ret = STATUS_OK;
}
delete[] buffer;
}
}
setFilename(filename);
return ret;
}
TOKEN_DEF_START
TOKEN_DEF(CONTINUOUS)
TOKEN_DEF(SPRITE)
TOKEN_DEF(LOOPING)
TOKEN_DEF(FRAME)
TOKEN_DEF(NAME)
TOKEN_DEF(PRECISE)
TOKEN_DEF(EDITOR_MUTED)
TOKEN_DEF(STREAMED_KEEP_LOADED)
TOKEN_DEF(STREAMED)
TOKEN_DEF(SCRIPT)
TOKEN_DEF(EDITOR_BG_FILE)
TOKEN_DEF(EDITOR_BG_OFFSET_X)
TOKEN_DEF(EDITOR_BG_OFFSET_Y)
TOKEN_DEF(EDITOR_BG_ALPHA)
TOKEN_DEF(EDITOR_PROPERTY)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
bool BaseSprite::loadBuffer(char *buffer, bool complete, int lifeTime, TSpriteCacheType cacheType) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(CONTINUOUS)
TOKEN_TABLE(SPRITE)
TOKEN_TABLE(LOOPING)
TOKEN_TABLE(FRAME)
TOKEN_TABLE(NAME)
TOKEN_TABLE(PRECISE)
TOKEN_TABLE(EDITOR_MUTED)
TOKEN_TABLE(STREAMED_KEEP_LOADED)
TOKEN_TABLE(STREAMED)
TOKEN_TABLE(SCRIPT)
TOKEN_TABLE(EDITOR_BG_FILE)
TOKEN_TABLE(EDITOR_BG_OFFSET_X)
TOKEN_TABLE(EDITOR_BG_OFFSET_Y)
TOKEN_TABLE(EDITOR_BG_ALPHA)
TOKEN_TABLE(EDITOR_PROPERTY)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
cleanup();
if (complete) {
if (parser.getCommand(&buffer, commands, &params) != TOKEN_SPRITE) {
_game->LOG(0, "'SPRITE' keyword expected.");
return STATUS_FAILED;
}
buffer = params;
}
int frameCount = 1;
BaseFrame *frame;
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_CONTINUOUS:
parser.scanStr(params, "%b", &_continuous);
break;
case TOKEN_EDITOR_MUTED:
parser.scanStr(params, "%b", &_editorMuted);
break;
case TOKEN_SCRIPT:
addScript(params);
break;
case TOKEN_LOOPING:
parser.scanStr(params, "%b", &_looping);
break;
case TOKEN_PRECISE:
parser.scanStr(params, "%b", &_precise);
break;
case TOKEN_STREAMED:
parser.scanStr(params, "%b", &_streamed);
if (_streamed && lifeTime == -1) {
lifeTime = 500;
cacheType = CACHE_ALL;
}
break;
case TOKEN_STREAMED_KEEP_LOADED:
parser.scanStr(params, "%b", &_streamedKeepLoaded);
break;
case TOKEN_NAME:
setName(params);
break;
case TOKEN_EDITOR_BG_FILE:
if (_game->_editorMode) {
SAFE_DELETE_ARRAY(_editorBgFile);
size_t editorBgFileSize = strlen(params) + 1;
_editorBgFile = new char[editorBgFileSize];
Common::strcpy_s(_editorBgFile, editorBgFileSize, params);
}
break;
case TOKEN_EDITOR_BG_OFFSET_X:
parser.scanStr(params, "%d", &_editorBgOffsetX);
break;
case TOKEN_EDITOR_BG_OFFSET_Y:
parser.scanStr(params, "%d", &_editorBgOffsetY);
break;
case TOKEN_EDITOR_BG_ALPHA:
parser.scanStr(params, "%d", &_editorBgAlpha);
_editorBgAlpha = MIN<int32>(_editorBgAlpha, 255);
_editorBgAlpha = MAX<int32>(_editorBgAlpha, 0);
break;
case TOKEN_FRAME: {
int frameLifeTime = lifeTime;
if (cacheType == CACHE_HALF && frameCount % 2 != 1) {
frameLifeTime = -1;
}
frame = new BaseFrame(_game);
if (DID_FAIL(frame->loadBuffer(params, frameLifeTime, _streamedKeepLoaded))) {
delete frame;
_game->LOG(0, "Error parsing frame %d", frameCount);
return STATUS_FAILED;
}
_frames.add(frame);
frameCount++;
if (_currentFrame == -1) {
_currentFrame = 0;
}
}
break;
case TOKEN_EDITOR_PROPERTY:
parseEditorProperty(params, false);
break;
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
_game->LOG(0, "Syntax error in SPRITE definition");
return STATUS_FAILED;
}
_canBreak = !_continuous;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
void BaseSprite::reset() {
if (_frames.getSize() > 0) {
_currentFrame = 0;
} else {
_currentFrame = -1;
}
if (BaseEngine::instance().getTargetExecutable() >= WME_1_8_6) {
/*
* This was added in WME 1.8.6
*
* 5MA and possibly other games ship with pre-1.8.6 WME, and
* depends (e.g.: menu sounds, etc) on this not being triggered.
*
* See bug #6647
*/
killAllSounds();
}
_lastFrameTime = 0;
_finished = false;
_moveX = _moveY = 0;
}
//////////////////////////////////////////////////////////////////////
bool BaseSprite::getCurrentFrame(float zoomX, float zoomY) {
//if (_owner && _owner->_freezable && _game->_state == GAME_FROZEN) return true;
if (_currentFrame == -1) {
return false;
}
uint32 timer;
if (_owner && _owner->_freezable) {
timer = _game->_timer;
} else {
timer = _game->_liveTimer;
}
int lastFrame = _currentFrame;
// get current frame
if (!_paused && !_finished && timer >= _lastFrameTime + _frames[_currentFrame]->_delay && _lastFrameTime != 0) {
if (_currentFrame < _frames.getSize() - 1) {
_currentFrame++;
if (_continuous) {
_canBreak = (_currentFrame == _frames.getSize() - 1);
}
} else {
if (_looping) {
_currentFrame = 0;
_canBreak = true;
} else {
_finished = true;
_canBreak = true;
}
}
_lastFrameTime = timer;
}
_changed = (lastFrame != _currentFrame || (_looping && _frames.getSize() == 1));
if (_lastFrameTime == 0) {
_lastFrameTime = timer;
_changed = true;
if (_continuous) {
_canBreak = (_currentFrame == _frames.getSize() - 1);
}
}
if (_changed) {
_moveX = _frames[_currentFrame]->_moveX;
_moveY = _frames[_currentFrame]->_moveY;
if (zoomX != 100 || zoomY != 100) {
_moveX = (int)((float)_moveX * (float)(zoomX / 100.0f));
_moveY = (int)((float)_moveY * (float)(zoomY / 100.0f));
}
}
return _changed;
}
//////////////////////////////////////////////////////////////////////
bool BaseSprite::display(int x, int y, BaseObject *registerVal, float zoomX, float zoomY, uint32 alpha, float rotate, Graphics::TSpriteBlendMode blendMode) {
if (_currentFrame < 0 || _currentFrame >= _frames.getSize()) {
return STATUS_OK;
}
// on change...
if (_changed) {
if (_frames[_currentFrame]->_killSound) {
killAllSounds();
}
applyEvent("FrameChanged");
_frames[_currentFrame]->oneTimeDisplay(_owner, _game->_editorMode && _editorMuted);
}
// draw frame
return _frames[_currentFrame]->draw(x - _game->_offsetX, y - _game->_offsetY, registerVal, zoomX, zoomY, _precise, alpha, _editorAllFrames, rotate, blendMode);
}
//////////////////////////////////////////////////////////////////////////
BaseSurface *BaseSprite::getSurface() {
// only used for animated textures for 3D models
if (_currentFrame < 0 || _currentFrame >= _frames.getSize()) {
return nullptr;
}
BaseFrame *frame = _frames[_currentFrame];
if (frame && frame->_subframes.getSize() > 0) {
BaseSubFrame *subframe = frame->_subframes[0];
if (subframe) {
return subframe->_surface;
} else {
return nullptr;
}
} else {
return nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::getBoundingRect(Common::Rect32 *rect, int x, int y, float scaleX, float scaleY) {
if (!rect) {
return false;
}
BasePlatform::setRectEmpty(rect);
for (int32 i = 0; i < _frames.getSize(); i++) {
Common::Rect32 frame;
Common::Rect32 temp;
BasePlatform::copyRect(&temp, rect);
_frames[i]->getBoundingRect(&frame, x, y, scaleX, scaleY);
BasePlatform::unionRect(rect, &temp, &frame);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::saveAsText(BaseDynamicBuffer *buffer, int indent) {
buffer->putTextIndent(indent, "SPRITE {\n");
buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
buffer->putTextIndent(indent + 2, "LOOPING=%s\n", _looping ? "TRUE" : "FALSE");
buffer->putTextIndent(indent + 2, "CONTINUOUS=%s\n", _continuous ? "TRUE" : "FALSE");
buffer->putTextIndent(indent + 2, "PRECISE=%s\n", _precise ? "TRUE" : "FALSE");
if (_streamed) {
buffer->putTextIndent(indent + 2, "STREAMED=%s\n", _streamed ? "TRUE" : "FALSE");
if (_streamedKeepLoaded) {
buffer->putTextIndent(indent + 2, "STREAMED_KEEP_LOADED=%s\n", _streamedKeepLoaded ? "TRUE" : "FALSE");
}
}
if (_editorMuted) {
buffer->putTextIndent(indent + 2, "EDITOR_MUTED=%s\n", _editorMuted ? "TRUE" : "FALSE");
}
if (_editorBgFile && _editorBgFile[0]) {
buffer->putTextIndent(indent + 2, "EDITOR_BG_FILE=\"%s\"\n", _editorBgFile);
buffer->putTextIndent(indent + 2, "EDITOR_BG_OFFSET_X=%d\n", _editorBgOffsetX);
buffer->putTextIndent(indent + 2, "EDITOR_BG_OFFSET_Y=%d\n", _editorBgOffsetY);
buffer->putTextIndent(indent + 2, "EDITOR_BG_ALPHA=%d\n", _editorBgAlpha);
}
BaseScriptHolder::saveAsText(buffer, indent + 2);
// scripts
for (int32 i = 0; i < _scripts.getSize(); i++) {
buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->saveAsText(buffer, indent + 2);
}
buffer->putTextIndent(indent, "}\n\n");
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::persist(BasePersistenceManager *persistMgr) {
BaseScriptHolder::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_canBreak));
persistMgr->transferBool(TMEMBER(_changed));
persistMgr->transferBool(TMEMBER(_paused));
persistMgr->transferBool(TMEMBER(_continuous));
persistMgr->transferSint32(TMEMBER(_currentFrame));
persistMgr->transferBool(TMEMBER(_editorAllFrames));
persistMgr->transferSint32(TMEMBER(_editorBgAlpha));
persistMgr->transferCharPtr(TMEMBER(_editorBgFile));
persistMgr->transferSint32(TMEMBER(_editorBgOffsetX));
persistMgr->transferSint32(TMEMBER(_editorBgOffsetY));
persistMgr->transferBool(TMEMBER(_editorMuted));
persistMgr->transferBool(TMEMBER(_finished));
_frames.persist(persistMgr);
persistMgr->transferUint32(TMEMBER(_lastFrameTime));
persistMgr->transferBool(TMEMBER(_looping));
persistMgr->transferSint32(TMEMBER(_moveX));
persistMgr->transferSint32(TMEMBER(_moveY));
persistMgr->transferPtr(TMEMBER_PTR(_owner));
persistMgr->transferBool(TMEMBER(_precise));
persistMgr->transferBool(TMEMBER(_streamed));
persistMgr->transferBool(TMEMBER(_streamedKeepLoaded));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// GetFrame
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "GetFrame") == 0) {
stack->correctParams(1);
int index = stack->pop()->getInt(-1);
if (index < 0 || index >= _frames.getSize()) {
script->runtimeError("Sprite.GetFrame: Frame index %d is out of range.", index);
stack->pushNULL();
} else {
stack->pushNative(_frames[index], true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// DeleteFrame
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "DeleteFrame") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
if (val->isInt()) {
int index = val->getInt(-1);
if (index < 0 || index >= _frames.getSize()) {
script->runtimeError("Sprite.DeleteFrame: Frame index %d is out of range.", index);
}
} else {
BaseFrame *frame = (BaseFrame *)val->getNative();
for (int32 i = 0; i < _frames.getSize(); i++) {
if (_frames[i] == frame) {
if (i == _currentFrame) {
_lastFrameTime = 0;
}
delete _frames[i];
_frames.removeAt(i);
break;
}
}
}
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Reset
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Reset") == 0) {
stack->correctParams(0);
reset();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// AddFrame
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "AddFrame") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
const char *filename = nullptr;
if (!val->isNULL()) {
filename = val->getString();
}
BaseFrame *frame = new BaseFrame(_game);
if (filename != nullptr) {
BaseSubFrame *sub = new BaseSubFrame(_game);
if (DID_SUCCEED(sub->setSurface(filename))) {
sub->setDefaultRect();
frame->_subframes.add(sub);
} else {
delete sub;
}
}
_frames.add(frame);
stack->pushNative(frame, true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// InsertFrame
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "InsertFrame") == 0) {
stack->correctParams(2);
int index = stack->pop()->getInt();
if (index < 0) {
index = 0;
}
ScValue *val = stack->pop();
const char *filename = nullptr;
if (!val->isNULL()) {
filename = val->getString();
}
BaseFrame *frame = new BaseFrame(_game);
if (filename != nullptr) {
BaseSubFrame *sub = new BaseSubFrame(_game);
if (DID_SUCCEED(sub->setSurface(filename))) {
frame->_subframes.add(sub);
} else {
delete sub;
}
}
if (index >= _frames.getSize()) {
_frames.add(frame);
} else {
_frames.insertAt(index, frame);
}
stack->pushNative(frame, true);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Pause
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Pause") == 0) {
stack->correctParams(0);
_paused = true;
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Play
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Play") == 0) {
stack->correctParams(0);
_paused = false;
stack->pushNULL();
return STATUS_OK;
} else {
return BaseScriptHolder::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseSprite::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("sprite");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// NumFrames (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "NumFrames") == 0) {
_scValue->setInt(_frames.getSize());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// CurrentFrame
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "CurrentFrame") == 0) {
_scValue->setInt(_currentFrame);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// PixelPerfect
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "PixelPerfect") == 0) {
_scValue->setBool(_precise);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Looping
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Looping") == 0) {
_scValue->setBool(_looping);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Owner (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Owner") == 0) {
if (_owner == nullptr) {
_scValue->setNULL();
} else {
_scValue->setNative(_owner, true);
}
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Finished (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Finished") == 0) {
_scValue->setBool(_finished);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Paused (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Paused") == 0) {
_scValue->setBool(_paused);
return _scValue;
} else {
return BaseScriptHolder::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// CurrentFrame
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "CurrentFrame") == 0) {
_currentFrame = value->getInt(0);
if (_currentFrame >= _frames.getSize() || _currentFrame < 0) {
_currentFrame = -1;
}
_lastFrameTime = 0;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// PixelPerfect
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "PixelPerfect") == 0) {
_precise = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Looping
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Looping") == 0) {
_looping = value->getBool();
return STATUS_OK;
} else {
return BaseScriptHolder::scSetProperty(name, value);
}
}
//////////////////////////////////////////////////////////////////////////
const char *BaseSprite::scToString() {
return "[sprite]";
}
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::killAllSounds() {
for (int32 i = 0; i < _frames.getSize(); i++) {
if (_frames[i]->_sound) {
_frames[i]->_sound->stop();
}
}
return STATUS_OK;
}
Common::String BaseSprite::debuggerToString() const {
return Common::String::format("%p: Sprite \"%s\"", (const void *)this, _name);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,92 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SPRITE_H
#define WINTERMUTE_BASE_SPRITE_H
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base_script_holder.h"
#include "graphics/transform_tools.h"
namespace Wintermute {
class BaseFrame;
class BaseSurface;
class BaseObject;
class BaseSprite : public BaseScriptHolder {
public:
bool killAllSounds();
BaseSurface *getSurface();
char *_editorBgFile;
int32 _editorBgOffsetX;
int32 _editorBgOffsetY;
int32 _editorBgAlpha;
bool _streamed;
bool _streamedKeepLoaded;
void cleanup();
void setDefaults();
bool _precise;
DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder)
bool _editorAllFrames;
bool getBoundingRect(Common::Rect32 *rect, int x, int y, float scaleX = Graphics::kDefaultZoomX, float scaleY = Graphics::kDefaultZoomY);
int32 _moveY;
int32 _moveX;
bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY, uint32 alpha = Graphics::kDefaultRgbaMod, float rotate = Graphics::kDefaultAngle, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL);
bool getCurrentFrame(float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY);
bool _canBreak{};
bool _editorMuted;
bool _continuous;
void reset();
BaseObject *_owner;
bool _changed;
bool _paused;
bool _finished;
bool loadBuffer(char *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
bool loadFile(const char *filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
uint32 _lastFrameTime;
bool draw(int x, int y, BaseObject *registerVal = nullptr, float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY, uint32 alpha = Graphics::kDefaultRgbaMod);
bool _looping;
int32 _currentFrame;
bool addFrame(const char *filename, uint32 delay = 0, int hotspotX = 0, int hotspotY = 0, Common::Rect32 *rect = nullptr);
BaseSprite(BaseGame *inGame, BaseObject *owner = nullptr);
~BaseSprite() override;
BaseArray<BaseFrame *> _frames;
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override;
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
Common::String debuggerToString() const override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,317 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_string_table.h"
#include "common/str.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseStringTable::BaseStringTable(BaseGame *inGame) : BaseClass(inGame) {
}
//////////////////////////////////////////////////////////////////////////
BaseStringTable::~BaseStringTable() {
// delete strings
_strings.clear();
}
//////////////////////////////////////////////////////////////////////////
bool BaseStringTable::addString(const char *key, const char *val, bool reportDuplicities) {
if (key == nullptr || val == nullptr) {
return STATUS_FAILED;
}
if (scumm_stricmp(key, "@right-to-left") == 0) {
_game->_textRTL = true;
return STATUS_OK;
}
Common::String finalKey = key;
finalKey.toLowercase();
StringsIter it = _strings.find(finalKey);
if (it != _strings.end() && reportDuplicities) {
_game->LOG(0, " Warning: Duplicate definition of string '%s'.", finalKey.c_str());
}
_strings[finalKey] = val;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
char *BaseStringTable::getKey(const char *str) {
if (str == nullptr || str[0] != '/') {
return nullptr;
}
const char *value = strchr(str + 1, '/');
if (value == nullptr) {
return nullptr;
}
char *key = new char[value - str];
Common::strlcpy(key, str + 1, (size_t)(value - str));
BasePlatform::wintermute_strlwr(key);
char *newStr;
StringsIter it = _strings.find(key);
if (it != _strings.end()) {
size_t newStrSize = it->_value.size() + 1;
newStr = new char[newStrSize];
Common::strcpy_s(newStr, newStrSize, it->_value.c_str());
if (strlen(newStr) > 0 && newStr[0] == '/' && strchr(newStr + 1, '/')) {
delete[] key;
char *ret = getKey(newStr);
delete[] newStr;
return ret;
} else {
delete[] newStr;
return key;
}
} else {
return key;
}
}
void BaseStringTable::replaceExpand(char *key, char *newStr, size_t newStrSize) {
// W/A: Remove accented chars like input text in Polish version of Alpha Polaris
if (BaseEngine::instance().getGameId() == "alphapolaris" &&
BaseEngine::instance().getLanguage() == Common::PL_POL) {
if (strcmp(key, "hotspot0360") == 0)
Common::strcpy_s(newStr, newStrSize, "Skuter sniezny");
if (strcmp(key, "hotspot0361") == 0)
Common::strcpy_s(newStr, newStrSize, "Slizgacz");
if (strcmp(key, "hotspot0362") == 0)
Common::strcpy_s(newStr, newStrSize, "Sniezny");
if (strcmp(key, "hotspot0364") == 0)
Common::strcpy_s(newStr, newStrSize, "Plemie");
if (strcmp(key, "hotspot0369") == 0)
Common::strcpy_s(newStr, newStrSize, "Lad");
if (strcmp(key, "hotspot0370") == 0)
Common::strcpy_s(newStr, newStrSize, "Wschod");
if (strcmp(key, "hotspot0375") == 0)
Common::strcpy_s(newStr, newStrSize, "Krzeslo");
if (strcmp(key, "hotspot0373") == 0)
Common::strcpy_s(newStr, newStrSize, "Wladza");
if (strcmp(key, "hotspot0378") == 0)
Common::strcpy_s(newStr, newStrSize, "Czlowiek");
}
}
//////////////////////////////////////////////////////////////////////////
void BaseStringTable::expand(char **str) {
if (str == nullptr || *str == nullptr || *str[0] != '/') {
return;
}
char *value = strchr(*str + 1, '/');
if (value == nullptr) {
return;
}
char *key = new char[value - *str];
Common::strlcpy(key, *str + 1, (size_t)(value - *str));
BasePlatform::wintermute_strlwr(key);
value++;
char *newStr;
StringsIter it = _strings.find(key);
if (it != _strings.end()) {
size_t newStrSize = it->_value.size() + 1;
newStr = new char[newStrSize];
Common::strcpy_s(newStr, newStrSize, it->_value.c_str());
replaceExpand(key, newStr, newStrSize);
} else {
size_t newStrSize = strlen(value) + 1;
newStr = new char[newStrSize];
Common::strcpy_s(newStr, newStrSize, value);
}
delete[] key;
delete[] *str;
*str = newStr;
if (strlen(*str) > 0 && *str[0] == '/') {
expand(str);
}
}
//////////////////////////////////////////////////////////////////////////
void BaseStringTable::expand(Common::String &str) {
size_t tmpSize = str.size() + 1;
char *tmp = new char[tmpSize];
Common::strcpy_s(tmp, tmpSize, str.c_str());
expand(&tmp);
str = tmp;
delete[] tmp;
}
//////////////////////////////////////////////////////////////////////////
const char *BaseStringTable::expandStatic(const char *string) {
if (string == nullptr || string[0] == '\0' || string[0] != '/') {
return string;
}
const char *value = strchr(string + 1, '/');
if (value == nullptr) {
return string;
}
char *key = new char[value - string];
Common::strlcpy(key, string + 1, (size_t)(value - string - 1));
BasePlatform::wintermute_strlwr(key);
value++;
const char *newStr;
StringsIter it = _strings.find(key);
if (it != _strings.end()) {
newStr = it->_value.c_str();
} else {
newStr = value;
}
delete[] key;
if (strlen(newStr) > 0 && newStr[0] == '/') {
return expandStatic(newStr);
} else {
return newStr;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseStringTable::loadFile(const char *filename, bool clearOld) {
_game->LOG(0, "Loading string table...");
if (clearOld) {
_filenames.clear();
_strings.clear();
}
_filenames.push_back(Common::String(filename));
uint32 size;
char *buffer = (char *)_game->_fileManager->readWholeFile(filename, &size);
if (buffer == nullptr) {
_game->LOG(0, "BaseStringTable::loadFile failed for file '%s'", filename);
return STATUS_FAILED;
}
uint32 pos = 0;
if (size > 3 && buffer[0] == '\xEF' && buffer[1] == '\xBB' && buffer[2] == '\xBF') {
pos += 3;
if (_game->_textEncoding != TEXT_UTF8) {
_game->_textEncoding = TEXT_UTF8;
//_game->_textEncoding = TEXT_ANSI;
_game->LOG(0, " UTF8 file detected, switching to UTF8 text encoding");
}
} else {
_game->_textEncoding = TEXT_ANSI;
}
uint32 lineLength = 0;
while (pos < size) {
lineLength = 0;
while (pos + lineLength < size && buffer[pos + lineLength] != '\n' && buffer[pos + lineLength] != '\0') {
lineLength++;
}
uint32 realLength = lineLength - (pos + lineLength >= size ? 0 : 1);
char *line = new char[realLength + 1];
Common::strlcpy(line, &buffer[pos], realLength + 1);
char *value = strchr(line, '\t');
if (value == nullptr) {
value = strchr(line, ' ');
}
if (line[0] != ';') {
if (value != nullptr) {
value[0] = '\0';
value++;
for (uint32 i = 0; i < strlen(value); i++) {
if (value[i] == '|') {
value[i] = '\n';
}
}
addString(line, value, clearOld);
} else if (line[0] != '\0') {
addString(line, "", clearOld);
}
}
delete[] line;
pos += lineLength + 1;
}
delete[] buffer;
_game->LOG(0, " %d strings loaded", _strings.size());
return STATUS_OK;
}
bool BaseStringTable::persist(BasePersistenceManager *persistMgr) {
// Do nothing if the save game is too old.
if (!persistMgr->checkVersion(1, 3, 1)) {
return true;
}
uint32 numFiles = _filenames.size();
persistMgr->transferUint32("NumFiles", &numFiles);
if (persistMgr->getIsSaving()) {
for (uint i = 0; i < numFiles; i++) {
persistMgr->transferString("Filename", &_filenames[i]);
}
} else {
_strings.clear();
_filenames.clear();
for (uint i = 0; i < numFiles; i++) {
Common::String filename = "";
persistMgr->transferString("Filename", &filename);
loadFile(filename.c_str(), false);
}
}
return true;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,60 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_STRING_TABLE_H
#define WINTERMUTE_BASE_STRING_TABLE_H
#include "common/hashmap.h"
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BasePersistenceManager;
class BaseStringTable : public BaseClass {
public:
const char *expandStatic(const char *string);
bool loadFile(const char *filename, bool deleteAll = true);
void expand(char **str);
void expand(Common::String &str);
bool addString(const char *key, const char *val, bool reportDuplicities = true);
BaseStringTable(BaseGame *inGame);
~BaseStringTable() override;
Common::HashMap<Common::String, Common::String> _strings;
char *getKey(const char *str);
bool persist(BasePersistenceManager *persistMgr) override;
private:
Common::Array<Common::String> _filenames;
typedef Common::HashMap<Common::String, Common::String>::const_iterator StringsIter;
void replaceExpand(char *key, char *newStr, size_t newStrSize);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,780 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseSubFrame, false)
//////////////////////////////////////////////////////////////////////////
BaseSubFrame::BaseSubFrame(BaseGame *inGame) : BaseScriptable(inGame, true) {
_surface = nullptr;
_hotspotX = Graphics::kDefaultHotspotX;
_hotspotY = Graphics::kDefaultHotspotY;
_alpha = Graphics::kDefaultRgbaMod;
_transparent = 0xFFFF00FF;
BasePlatform::setRectEmpty(&_rect);
_editorSelected = false;
_surfaceFilename = nullptr;
_ckDefault = true;
_ckRed = _ckBlue = _ckGreen = 0;
_lifeTime = -1;
_keepLoaded = false;
_2DOnly = _3DOnly = false;
_decoration = false;
_mirrorX = _mirrorY = false;
}
//////////////////////////////////////////////////////////////////////////
BaseSubFrame::~BaseSubFrame() {
if (_surface) {
_game->_surfaceStorage->removeSurface(_surface);
}
SAFE_DELETE_ARRAY(_surfaceFilename);
}
TOKEN_DEF_START
TOKEN_DEF(IMAGE)
TOKEN_DEF(TRANSPARENT)
TOKEN_DEF(RECT)
TOKEN_DEF(HOTSPOT)
TOKEN_DEF(2D_ONLY)
TOKEN_DEF(3D_ONLY)
TOKEN_DEF(DECORATION)
TOKEN_DEF(ALPHA_COLOR)
TOKEN_DEF(ALPHA)
TOKEN_DEF(MIRROR_X)
TOKEN_DEF(MIRROR_Y)
TOKEN_DEF(EDITOR_SELECTED)
TOKEN_DEF(EDITOR_PROPERTY)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
bool BaseSubFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(IMAGE)
TOKEN_TABLE(TRANSPARENT)
TOKEN_TABLE(RECT)
TOKEN_TABLE(HOTSPOT)
TOKEN_TABLE(2D_ONLY)
TOKEN_TABLE(3D_ONLY)
TOKEN_TABLE(DECORATION)
TOKEN_TABLE(ALPHA_COLOR)
TOKEN_TABLE(ALPHA)
TOKEN_TABLE(MIRROR_X)
TOKEN_TABLE(MIRROR_Y)
TOKEN_TABLE(EDITOR_SELECTED)
TOKEN_TABLE(EDITOR_PROPERTY)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
Common::Rect32 rect;
int r = 255, g = 255, b = 255;
int ar = 255, ag = 255, ab = 255, alpha = 255;
bool customTrans = false;
BasePlatform::setRectEmpty(&rect);
char *surfaceFile = nullptr;
SAFE_DELETE(_surface);
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_IMAGE:
surfaceFile = params;
break;
case TOKEN_TRANSPARENT:
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
customTrans = true;
break;
case TOKEN_RECT:
parser.scanStr(params, "%d,%d,%d,%d", &rect.left, &rect.top, &rect.right, &rect.bottom);
break;
case TOKEN_HOTSPOT:
parser.scanStr(params, "%d,%d", &_hotspotX, &_hotspotY);
break;
case TOKEN_2D_ONLY:
parser.scanStr(params, "%b", &_2DOnly);
break;
case TOKEN_3D_ONLY:
parser.scanStr(params, "%b", &_3DOnly);
break;
case TOKEN_MIRROR_X:
parser.scanStr(params, "%b", &_mirrorX);
break;
case TOKEN_MIRROR_Y:
parser.scanStr(params, "%b", &_mirrorY);
break;
case TOKEN_DECORATION:
parser.scanStr(params, "%b", &_decoration);
break;
case TOKEN_ALPHA_COLOR:
parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab);
break;
case TOKEN_ALPHA:
parser.scanStr(params, "%d", &alpha);
break;
case TOKEN_EDITOR_SELECTED:
parser.scanStr(params, "%b", &_editorSelected);
break;
case TOKEN_EDITOR_PROPERTY:
parseEditorProperty(params, false);
break;
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
_game->LOG(0, "Syntax error in SUBFRAME definition");
return STATUS_FAILED;
}
if (surfaceFile != nullptr) {
if (customTrans) {
setSurface(surfaceFile, false, r, g, b, lifeTime, keepLoaded);
} else {
setSurface(surfaceFile, true, 0, 0, 0, lifeTime, keepLoaded);
}
}
_alpha = BYTETORGBA(ar, ag, ab, alpha);
if (customTrans) {
_transparent = BYTETORGBA(r, g, b, 0xFF);
}
/*
if (_surface == nullptr)
{
BaseEngine::LOG(0, "Error parsing sub-frame. Image not set.");
return STATUS_FAILED;
}
*/
if (BasePlatform::isRectEmpty(&rect)) {
setDefaultRect();
} else {
_rect = rect;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, Graphics::TSpriteBlendMode blendMode) {
rotate = fmod(rotate, 360.0f);
if (rotate < 0) {
rotate += 360.0f;
}
if (!_surface) {
return STATUS_OK;
}
if (registerOwner != nullptr && !_decoration) {
if (zoomX == Graphics::kDefaultZoomX && zoomY == Graphics::kDefaultZoomY) {
_game->_renderer->_rectList.add(new BaseActiveRect(_game, registerOwner, this, x - _hotspotX + _rect.left, y - _hotspotY + _rect.top, _rect.right - _rect.left, _rect.bottom - _rect.top, zoomX, zoomY, precise));
} else {
_game->_renderer->_rectList.add(new BaseActiveRect(_game, registerOwner, this, (int)(x - (_hotspotX + _rect.left) * (zoomX / 100)), (int)(y - (_hotspotY + _rect.top) * (zoomY / 100)), (int)((_rect.right - _rect.left) * (zoomX / 100)), (int)((_rect.bottom - _rect.top) * (zoomY / 100)), zoomX, zoomY, precise));
}
}
if (_game->_suspendedRendering) {
return STATUS_OK;
}
bool res;
//if (Alpha==0xFFFFFFFF) Alpha = _alpha; // TODO: better (combine owner's and self alpha)
if (_alpha != Graphics::kDefaultRgbaMod) {
alpha = _alpha;
}
if (rotate != Graphics::kDefaultAngle) {
res = _surface->displayTransRotate(x, y, rotate, _hotspotX, _hotspotY, _rect, zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);
} else {
if (zoomX == Graphics::kDefaultZoomX && zoomY == Graphics::kDefaultZoomY) {
res = _surface->displayTrans(x - _hotspotX, y - _hotspotY, _rect, alpha, blendMode, _mirrorX, _mirrorY);
} else {
res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / Graphics::kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / Graphics::kDefaultZoomY)), _rect, zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY);
}
}
return res;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::getBoundingRect(Common::Rect32 *rect, int x, int y, float scaleX, float scaleY) {
if (!rect) {
return false;
}
float ratioX = scaleX / 100.0f;
float ratioY = scaleY / 100.0f;
BasePlatform::setRect(rect,
(int)(x - _hotspotX * ratioX),
(int)(y - _hotspotY * ratioY),
(int)(x - _hotspotX * ratioX + (_rect.right - _rect.left) * ratioX),
(int)(y - _hotspotY * ratioY + (_rect.bottom - _rect.top) * ratioY));
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::saveAsText(BaseDynamicBuffer *buffer, int indent, bool complete) {
if (complete) {
buffer->putTextIndent(indent, "SUBFRAME {\n");
}
if (_surface && _surface->_filename && _surface->_filename[0]) {
buffer->putTextIndent(indent + 2, "IMAGE = \"%s\"\n", _surface->_filename);
}
if (_transparent != 0xFFFF00FF) {
buffer->putTextIndent(indent + 2, "TRANSPARENT { %d,%d,%d }\n", RGBCOLGetR(_transparent), RGBCOLGetG(_transparent), RGBCOLGetB(_transparent));
}
Common::Rect32 rect;
BasePlatform::setRectEmpty(&rect);
if (_surface) {
BasePlatform::setRect(&rect, 0, 0, _surface->getWidth(), _surface->getHeight());
}
if (!BasePlatform::equalRect(&rect, &_rect)) {
buffer->putTextIndent(indent + 2, "RECT { %d,%d,%d,%d }\n", _rect.left, _rect.top, _rect.right, _rect.bottom);
}
if (_hotspotX != 0 || _hotspotY != 0) {
buffer->putTextIndent(indent + 2, "HOTSPOT {%d, %d}\n", _hotspotX, _hotspotY);
}
if (_alpha != 0xFFFFFFFF) {
buffer->putTextIndent(indent + 2, "ALPHA_COLOR { %d,%d,%d }\n", RGBCOLGetR(_alpha), RGBCOLGetG(_alpha), RGBCOLGetB(_alpha));
buffer->putTextIndent(indent + 2, "ALPHA = %d\n", RGBCOLGetA(_alpha));
}
if (_mirrorX) {
buffer->putTextIndent(indent + 2, "MIRROR_X=%s\n", _mirrorX ? "TRUE" : "FALSE");
}
if (_mirrorY) {
buffer->putTextIndent(indent + 2, "MIRROR_Y=%s\n", _mirrorY ? "TRUE" : "FALSE");
}
if (_2DOnly) {
buffer->putTextIndent(indent + 2, "2D_ONLY=%s\n", _2DOnly ? "TRUE" : "FALSE");
}
if (_3DOnly) {
buffer->putTextIndent(indent + 2, "3D_ONLY=%s\n", _3DOnly ? "TRUE" : "FALSE");
}
if (_decoration) {
buffer->putTextIndent(indent + 2, "DECORATION=%s\n", _decoration ? "TRUE" : "FALSE");
}
if (_editorSelected) {
buffer->putTextIndent(indent + 2, "EDITOR_SELECTED=%s\n", _editorSelected ? "TRUE" : "FALSE");
}
BaseClass::saveAsText(buffer, indent + 2);
if (complete) {
buffer->putTextIndent(indent, "}\n\n");
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseSubFrame::setDefaultRect() {
if (_surface) {
BasePlatform::setRect(&_rect, 0, 0, _surface->getWidth(), _surface->getHeight());
} else {
BasePlatform::setRectEmpty(&_rect);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::persist(BasePersistenceManager *persistMgr) {
BaseScriptable::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_2DOnly));
persistMgr->transferBool(TMEMBER(_3DOnly));
persistMgr->transferUint32(TMEMBER(_alpha));
persistMgr->transferBool(TMEMBER(_decoration));
persistMgr->transferBool(TMEMBER(_editorSelected));
persistMgr->transferSint32(TMEMBER(_hotspotX));
persistMgr->transferSint32(TMEMBER(_hotspotY));
persistMgr->transferRect32(TMEMBER(_rect));
bool wantsDefaultRect = false;
if (!persistMgr->checkVersion(1, 9, 1)) {
persistMgr->transferBool(TMEMBER(wantsDefaultRect));
}
persistMgr->transferCharPtr(TMEMBER(_surfaceFilename));
persistMgr->transferBool(TMEMBER(_ckDefault));
persistMgr->transferByte(TMEMBER(_ckRed));
persistMgr->transferByte(TMEMBER(_ckGreen));
persistMgr->transferByte(TMEMBER(_ckBlue));
persistMgr->transferSint32(TMEMBER(_lifeTime));
persistMgr->transferBool(TMEMBER(_keepLoaded));
persistMgr->transferBool(TMEMBER(_mirrorX));
persistMgr->transferBool(TMEMBER(_mirrorY));
persistMgr->transferUint32(TMEMBER(_transparent));
// initialise to default
if (!persistMgr->getIsSaving()) {
_surface = nullptr;
}
// restore proper _rect values for older saves
if (!persistMgr->getIsSaving() && wantsDefaultRect) {
BaseImage img = BaseImage();
int32 width, height;
if (img.getImageInfo(_surfaceFilename, width, height)) {
BasePlatform::setRect(&_rect, 0, 0, width, height);
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// GetImage
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "GetImage") == 0) {
stack->correctParams(0);
if (!_surfaceFilename || !_surfaceFilename[0]) {
stack->pushNULL();
} else {
stack->pushString(_surfaceFilename);
}
return STATUS_OK;
}
#ifdef ENABLE_FOXTAIL
//////////////////////////////////////////////////////////////////////////
// [FoxTail] GetHeight
// Used to find sprite center at methods.script in fix_offset()
// Return value is integer
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetHeight") == 0) {
stack->correctParams(0);
if (_surface) {
stack->pushInt(_surface->getHeight());
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// [FoxTail] GetWidth
// Used to find sprite center at methods.script in fix_offset()
// Return value is integer
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetWidth") == 0) {
stack->correctParams(0);
if (_surface) {
stack->pushInt(_surface->getWidth());
} else {
stack->pushNULL();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// [FoxTail] GetPixelAt
// Used for dynamic light at mixing.script in make_RGB() and make_HSV()
// Return value is passed to Game.GetRValue(), Game.GetGValue(), etc...
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetPixelAt") == 0) {
stack->correctParams(2);
int x = stack->pop()->getInt();
int y = stack->pop()->getInt();
byte r, g, b, a;
if (_surface && _surface->startPixelOp()) {
if (_surface->getPixel(x, y, &r, &g, &b, &a)) {
uint32 pixel = BYTETORGBA(r, g, b, a);
stack->pushInt(pixel);
} else {
stack->pushNULL();
}
_surface->endPixelOp();
} else {
stack->pushNULL();
}
return STATUS_OK;
}
#endif
//////////////////////////////////////////////////////////////////////////
// SetImage
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetImage") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
if (val->isNULL()) {
if (_surface) {
_game->_surfaceStorage->removeSurface(_surface);
}
SAFE_DELETE_ARRAY(_surfaceFilename);
stack->pushBool(true);
} else {
const char *filename = val->getString();
if (DID_SUCCEED(setSurface(filename))) {
setDefaultRect();
stack->pushBool(true);
} else {
stack->pushBool(false);
}
}
return STATUS_OK;
} else {
return BaseScriptable::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseSubFrame::scGetProperty(const char *name) {
if (!_scValue) {
_scValue = new ScValue(_game);
}
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("subframe");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// AlphaColor
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "AlphaColor") == 0) {
_scValue->setInt((int)_alpha);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// TransparentColor (RO)
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "TransparentColor") == 0) {
_scValue->setInt((int)_transparent);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Is2DOnly
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Is2DOnly") == 0) {
_scValue->setBool(_2DOnly);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Is3DOnly
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Is3DOnly") == 0) {
_scValue->setBool(_3DOnly);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// MirrorX
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MirrorX") == 0) {
_scValue->setBool(_mirrorX);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// MirrorY
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MirrorY") == 0) {
_scValue->setBool(_mirrorY);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Decoration
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Decoration") == 0) {
_scValue->setBool(_decoration);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// HotspotX
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "HotspotX") == 0) {
_scValue->setInt(_hotspotX);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// HotspotY
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "HotspotY") == 0) {
_scValue->setInt(_hotspotY);
return _scValue;
} else {
return BaseScriptable::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// AlphaColor
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "AlphaColor") == 0) {
_alpha = (uint32)value->getInt();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Is2DOnly
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Is2DOnly") == 0) {
_2DOnly = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Is3DOnly
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Is3DOnly") == 0) {
_3DOnly = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MirrorX
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MirrorX") == 0) {
_mirrorX = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MirrorY
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MirrorY") == 0) {
_mirrorY = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Decoration
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Decoration") == 0) {
_decoration = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// HotspotX
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "HotspotX") == 0) {
_hotspotX = value->getInt();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// HotspotY
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "HotspotY") == 0) {
_hotspotY = value->getInt();
return STATUS_OK;
} else {
return BaseScriptable::scSetProperty(name, value);
}
}
//////////////////////////////////////////////////////////////////////////
const char *BaseSubFrame::scToString() {
return "[subframe]";
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::setSurface(const char *filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) {
if (_surface) {
_game->_surfaceStorage->removeSurface(_surface);
_surface = nullptr;
}
SAFE_DELETE_ARRAY(_surfaceFilename);
_surface = _game->_surfaceStorage->addSurface(filename, true, defaultCK, ckRed, ckGreen, ckBlue, lifeTime, keepLoaded);
if (_surface) {
size_t filenameSize = strlen(filename) + 1;
_surfaceFilename = new char[filenameSize];
Common::strcpy_s(_surfaceFilename, filenameSize, filename);
_ckDefault = defaultCK;
_ckRed = ckRed;
_ckGreen = ckGreen;
_ckBlue = ckBlue;
_lifeTime = lifeTime;
_keepLoaded = keepLoaded;
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::setSurfaceSimple() {
if (!_surfaceFilename || !_surfaceFilename[0]) {
_surface = nullptr;
return STATUS_OK;
}
_surface = _game->_surfaceStorage->addSurface(_surfaceFilename, true, _ckDefault, _ckRed, _ckGreen, _ckBlue, _lifeTime, _keepLoaded);
if (_surface) {
return STATUS_OK;
} else {
return STATUS_FAILED;
}
}
bool BaseSubFrame::startPixelOperations() {
if (_surface)
return _surface->startPixelOp();
else
return false;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::endPixelOperations() {
if (_surface)
return _surface->endPixelOp();
else
return false;
}
//////////////////////////////////////////////////////////////////////////
uint32 BaseSubFrame::getPixel(int32 x, int32 y) {
if (_surface) {
byte r, g, b, a;
_surface->getPixel(x, y, &r, &g, &b, &a);
return BYTETORGBA(r, g, b, a);
} else
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSubFrame::putPixel(int32 x, int32 y, uint32 pixel) {
if (_surface) {
byte r = RGBCOLGetR(pixel);
byte g = RGBCOLGetG(pixel);
byte b = RGBCOLGetB(pixel);
byte a = RGBCOLGetA(pixel);
return _surface->putPixel(x, y, r, g, b, a);
} else
return false;
}
//////////////////////////////////////////////////////////////////////////
int32 BaseSubFrame::getWidth() {
if (_surface)
return _surface->getWidth();
else
return 0;
}
//////////////////////////////////////////////////////////////////////////
int32 BaseSubFrame::getHeight() {
if (_surface)
return _surface->getHeight();
else
return 0;
}
Common::String BaseSubFrame::debuggerToString() const {
return Common::String::format("%p: BaseSubFrame \"%s\" - Mirror:(%d, %d), Hotspot:(%d, %d), ", (const void *)this, _name, _mirrorX, _mirrorY, _hotspotX, _hotspotY);
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SUBFRAME_H
#define WINTERMUTE_BASE_SUBFRAME_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/base_scriptable.h"
#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseObject;
class BaseSurface;
class BaseSubFrame : public BaseScriptable {
public:
bool _mirrorX;
bool _mirrorY;
bool _decoration;
bool setSurface(const char *filename, bool defaultCK = true, byte ckRed = 0, byte ckGreen = 0, byte ckBlue = 0, int lifeTime = -1, bool keepLoaded = false);
bool setSurfaceSimple();
DECLARE_PERSISTENT(BaseSubFrame, BaseScriptable)
void setDefaultRect();
uint32 _transparent;
bool saveAsText(BaseDynamicBuffer *buffer, int indent) override { return saveAsText(buffer, indent, true); }
bool saveAsText(BaseDynamicBuffer *buffer, int indent, bool complete);
bool _editorSelected;
BaseSubFrame(BaseGame *inGame);
~BaseSubFrame() override;
bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded);
bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL);
bool getBoundingRect(Common::Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
int32 _hotspotX;
int32 _hotspotY;
uint32 _alpha;
Common::Rect32 _rect;
bool _ckDefault;
byte _ckRed;
byte _ckGreen;
byte _ckBlue;
int32 _lifeTime;
bool _keepLoaded;
char *_surfaceFilename;
bool _2DOnly;
bool _3DOnly;
BaseSurface *_surface;
// scripting interface
ScValue *scGetProperty(const char *name) override;
bool scSetProperty(const char *name, ScValue *value) override;
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override;
const char *scToString() override;
Common::String debuggerToString() const override;
bool startPixelOperations();
bool endPixelOperations();
uint32 getPixel(int32 x, int32 y);
bool putPixel(int32 x, int32 y, uint32 pixel);
int32 getWidth();
int32 getHeight();
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,209 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/utils/utils.h"
#include "common/str.h"
namespace Wintermute {
//IMPLEMENT_PERSISTENT(BaseSurfaceStorage, true)
//////////////////////////////////////////////////////////////////////
BaseSurfaceStorage::BaseSurfaceStorage(BaseGame *inGame) : BaseClass(inGame) {
_lastCleanupTime = 0;
}
//////////////////////////////////////////////////////////////////////
BaseSurfaceStorage::~BaseSurfaceStorage() {
cleanup(true);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceStorage::cleanup(bool warn) {
for (int32 i = 0; i < _surfaces.getSize(); i++) {
if (warn) {
_game->LOG(0, "BaseSurfaceStorage warning: purging surface '%s', usage:%d", _surfaces[i]->_filename, _surfaces[i]->_referenceCount);
}
delete _surfaces[i];
}
_surfaces.removeAll();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceStorage::initLoop() {
if (_game->_smartCache && _game->_liveTimer - _lastCleanupTime >= _game->_surfaceGCCycleTime) {
_lastCleanupTime = _game->_liveTimer;
sortSurfaces();
for (int32 i = 0; i < _surfaces.getSize(); i++) {
if (_surfaces[i]->_lifeTime <= 0) {
break;
}
if (_surfaces[i]->_lifeTime > 0 && _surfaces[i]->_valid && (int32)(_game->_liveTimer - _surfaces[i]->_lastUsedTime) >= _surfaces[i]->_lifeTime) {
//_game->quickMessageForm("Invalidating: %s", _surfaces[i]->_filename);
_surfaces[i]->invalidate();
}
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
bool BaseSurfaceStorage::removeSurface(BaseSurface *surface) {
for (int32 i = 0; i < _surfaces.getSize(); i++) {
if (_surfaces[i] == surface) {
_surfaces[i]->_referenceCount--;
if (_surfaces[i]->_referenceCount <= 0) {
delete _surfaces[i];
_surfaces.removeAt(i);
}
break;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
BaseSurface *BaseSurfaceStorage::addSurface(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) {
for (int32 i = 0; i < _surfaces.getSize(); i++) {
if (scumm_stricmp(_surfaces[i]->_filename, filename) == 0) {
_surfaces[i]->_referenceCount++;
return _surfaces[i];
}
}
if (!_game->_fileManager->hasFile(filename)) {
if (filename) {
_game->LOG(0, "Missing image: '%s'", filename);
}
if (_game->_debugMode) {
return addSurface("invalid_debug.bmp", texture2D, defaultCK, ckRed, ckGreen, ckBlue, lifeTime, keepLoaded);
} else {
return addSurface("invalid.bmp", texture2D, defaultCK, ckRed, ckGreen, ckBlue, lifeTime, keepLoaded);
}
}
BaseSurface *surface;
surface = BaseEngine::getRenderer()->createSurface();
if (!surface) {
return nullptr;
}
if (DID_FAIL(surface->create(filename, texture2D, defaultCK, ckRed, ckGreen, ckBlue, lifeTime, keepLoaded))) {
delete surface;
return nullptr;
} else {
surface->_referenceCount = 1;
_surfaces.add(surface);
return surface;
}
}
//////////////////////////////////////////////////////////////////////
bool BaseSurfaceStorage::restoreAll() {
bool ret;
for (int32 i = 0; i < _surfaces.getSize(); i++) {
ret = _surfaces[i]->restore();
if (ret != STATUS_OK) {
_game->LOG(0, "BaseSurfaceStorage::restoreAll failed");
return ret;
}
}
return STATUS_OK;
}
/*
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceStorage::persist(BasePersistenceManager *persistMgr)
{
if (!persistMgr->getIsSaving()) cleanup(false);
persistMgr->transfer(TMEMBER(_game));
//_surfaces.persist(persistMgr);
return STATUS_OK;
}
*/
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceStorage::sortSurfaces() {
qsort_msvc(_surfaces.getData(), _surfaces.getSize(), sizeof(BaseSurface *), surfaceSortCB);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int32 BaseSurfaceStorage::surfaceSortCB(const void *arg1, const void *arg2) {
void *o1 = const_cast<void *>(arg1);
void *o2 = const_cast<void *>(arg2);
BaseSurface *s1 = *((BaseSurface **)o1);
BaseSurface *s2 = *((BaseSurface **)o2);
// sort by life time
if (s1->_lifeTime <= 0 && s2->_lifeTime > 0) {
return 1;
} else if (s1->_lifeTime > 0 && s2->_lifeTime <= 0) {
return -1;
}
// sort by validity
if (s1->_valid && !s2->_valid) {
return -1;
} else if (!s1->_valid && s2->_valid) {
return 1;
// sort by time
} else if (s1->_lastUsedTime > s2->_lastUsedTime) {
return 1;
} else if (s1->_lastUsedTime < s2->_lastUsedTime) {
return -1;
} else {
return 0;
}
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SURFACE_STORAGE_H
#define WINTERMUTE_BASE_SURFACE_STORAGE_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/coll_templ.h"
namespace Wintermute {
class BaseSurface;
class BaseSurfaceStorage : public BaseClass {
public:
uint32 _lastCleanupTime;
bool initLoop();
bool sortSurfaces();
static int32 surfaceSortCB(const void *arg1, const void *arg2);
bool cleanup(bool warn = false);
//DECLARE_PERSISTENT(BaseSurfaceStorage, BaseClass)
bool restoreAll();
BaseSurface *addSurface(const char *filename, bool texture2D = true, bool defaultCK = true, byte ckRed = 0, byte ckGreen = 0, byte ckBlue = 0, int lifeTime = -1, bool keepLoaded = false);
bool removeSurface(BaseSurface *surface);
BaseSurfaceStorage(BaseGame *inGame);
~BaseSurfaceStorage() override;
BaseArray<BaseSurface *> _surfaces;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,139 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_transition_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseTransitionMgr::BaseTransitionMgr(BaseGame *inGame) : BaseClass(inGame) {
_state = TRANS_MGR_READY;
_type = TRANSITION_NONE;
_origInteractive = false;
_preserveInteractive = false;
_lastTime = 0;
_started = false;
}
//////////////////////////////////////////////////////////////////////////
BaseTransitionMgr::~BaseTransitionMgr() {
}
//////////////////////////////////////////////////////////////////////////
bool BaseTransitionMgr::isReady() {
return (_state == TRANS_MGR_READY);
}
//////////////////////////////////////////////////////////////////////////
bool BaseTransitionMgr::start(TTransitionType type, bool nonInteractive) {
if (_state != TRANS_MGR_READY) {
return STATUS_OK;
}
if (type == TRANSITION_NONE || type >= NUM_TRANSITION_TYPES) {
_state = TRANS_MGR_READY;
return STATUS_OK;
}
if (nonInteractive) {
_preserveInteractive = true;
_origInteractive = _game->_interactive;
_game->_interactive = false;
} else {
_preserveInteractive = false;
}
_type = type;
_state = TRANS_MGR_RUNNING;
_started = false;
return STATUS_OK;
}
#define FADE_DURATION 200
//////////////////////////////////////////////////////////////////////////
bool BaseTransitionMgr::update() {
if (isReady()) {
return STATUS_OK;
}
if (!_started) {
_started = true;
_lastTime = BasePlatform::getTime();
}
switch (_type) {
case TRANSITION_NONE:
_state = TRANS_MGR_READY;
break;
case TRANSITION_FADE_OUT: {
uint32 time = BasePlatform::getTime() - _lastTime;
int alpha = (int)(255 - (float)time / (float)FADE_DURATION * 255);
alpha = MIN(255, MAX(alpha, 0));
_game->_renderer->fade((uint16)alpha);
if (time > FADE_DURATION) {
_state = TRANS_MGR_READY;
}
}
break;
case TRANSITION_FADE_IN: {
uint32 time = BasePlatform::getTime() - _lastTime;
int alpha = (int)((float)time / (float)FADE_DURATION * 255);
alpha = MIN(255, MAX(alpha, 0));
_game->_renderer->fade((uint16)alpha);
if (time > FADE_DURATION) {
_state = TRANS_MGR_READY;
}
}
break;
default:
break;
}
if (isReady()) {
if (_preserveInteractive) {
_game->_interactive = _origInteractive;
}
}
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,52 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_TRANSITION_MANAGER_H
#define WINTERMUTE_BASE_TRANSITION_MANAGER_H
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BaseTransitionMgr : public BaseClass {
public:
bool _started;
uint32 _lastTime;
bool _origInteractive;
bool _preserveInteractive;
bool update();
bool start(TTransitionType type, bool nonInteractive = false);
bool isReady();
TTransMgrState _state;
BaseTransitionMgr(BaseGame *inGame);
~BaseTransitionMgr() override;
TTransitionType _type;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,103 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_viewport.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseViewport, false)
//////////////////////////////////////////////////////////////////////////
BaseViewport::BaseViewport(BaseGame *inGame) : BaseClass(inGame) {
BasePlatform::setRectEmpty(&_rect);
_mainObject = nullptr;
_offsetX = _offsetY = 0;
}
//////////////////////////////////////////////////////////////////////////
BaseViewport::~BaseViewport() {
}
//////////////////////////////////////////////////////////////////////////
bool BaseViewport::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferPtr(TMEMBER_PTR(_game));
persistMgr->transferPtr(TMEMBER_PTR(_mainObject));
persistMgr->transferSint32(TMEMBER(_offsetX));
persistMgr->transferSint32(TMEMBER(_offsetY));
persistMgr->transferRect32(TMEMBER(_rect));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseViewport::setRect(int32 left, int32 top, int32 right, int32 bottom, bool noCheck) {
if (!noCheck) {
left = MAX<int32>(left, 0);
top = MAX<int32>(top, 0);
right = MIN(right, _game->_renderer->getWidth());
bottom = MIN(bottom, _game->_renderer->getHeight());
}
BasePlatform::setRect(&_rect, left, top, right, bottom);
_offsetX = left;
_offsetY = top;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
Common::Rect32 *BaseViewport::getRect() {
return &_rect;
}
//////////////////////////////////////////////////////////////////////////
int BaseViewport::getWidth() {
return _rect.right - _rect.left;
}
//////////////////////////////////////////////////////////////////////////
int BaseViewport::getHeight() {
return _rect.bottom - _rect.top;
}
Common::String BaseViewport::debuggerToString() const {
return Common::String::format("%p: BaseViewport: (top, right, bottom, left): (%d, %d, %d, %d)", (const void *)this, _rect.top, _rect.right, _rect.bottom, _rect.left);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,57 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_VIEWPORT_H
#define WINTERMUTE_BASE_VIEWPORT_H
#include "common/rect.h"
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/persistent.h"
namespace Wintermute {
class BaseObject;
class BaseViewport : public BaseClass {
public:
int getHeight();
int getWidth();
Common::Rect32 *getRect();
bool setRect(int32 left, int32 top, int32 right, int32 bottom, bool noCheck = false);
DECLARE_PERSISTENT(BaseViewport, BaseClass)
int32 _offsetY;
int32 _offsetX;
BaseObject *_mainObject;
BaseViewport(BaseGame *inGame = nullptr);
~BaseViewport() override;
virtual Common::String debuggerToString() const;
private:
Common::Rect32 _rect;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,227 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/dcgf.h"
#include "engines/wintermute/base/file/base_disk_file.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/utils/path_util.h"
#include "common/stream.h"
#include "common/memstream.h"
#include "common/file.h"
#include "common/compression/deflate.h"
#include "common/archive.h"
#include "common/tokenizer.h"
#include "common/config-manager.h"
namespace Wintermute {
Common::Path correctSlashes(const Common::String &fileName) {
Common::String ret(fileName);
for (size_t i = 0; i < ret.size(); i++) {
if (ret[i] == '\\') {
ret.setChar('/', i);
}
}
return Common::Path(ret);
}
// Parse a relative path in the game-folder, and if it exists, return a FSNode to it.
static Common::FSNode getNodeForRelativePath(const Common::String &filename) {
// The filename can be an explicit path, thus we need to chop it up, expecting the path the game
// specifies to follow the Windows-convention of folder\subfolder\file (absolute paths should not happen)
// Absolute path: These should have been handled in openDiskFile.
if (filename.contains(':')) {
// So just return an invalid node.
return Common::FSNode();
}
// Relative path:
Common::Path fixedFilename = correctSlashes(filename);
Common::Path absolutePath(ConfMan.getPath("path"));
absolutePath.joinInPlace(fixedFilename);
Common::FSNode node(absolutePath);
if (node.exists()) {
return node;
} else {
return Common::FSNode();
}
}
bool diskFileExists(const Common::String &filename) {
// Try directly from SearchMan first
Common::ArchiveMemberList files;
SearchMan.listMatchingMembers(files, Common::Path(filename));
for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); ++it) {
if ((*it)->getName() == filename) {
return true;
}
}
// File wasn't found in SearchMan, try to parse the path as a relative path.
Common::FSNode searchNode = getNodeForRelativePath(filename);
if (searchNode.exists() && !searchNode.isDirectory() && searchNode.isReadable()) {
return true;
}
return false;
}
int listMatchingDiskFileMembers(Common::ArchiveMemberList &list, const Common::String &pattern) {
return Common::FSDirectory(ConfMan.getPath("path")).listMatchingMembers(list, Common::Path(pattern));
}
Common::SeekableReadStream *openDiskFile(const Common::String &filename) {
uint32 prefixSize = 0;
Common::SeekableReadStream *file = nullptr;
Common::Path fixedFilename = correctSlashes(filename);
// HACK: There are a few games around which mistakenly refer to absolute paths in the scripts.
// The original interpreter on Windows usually simply ignores them when it can't find them.
// We try to turn the known ones into relative paths.
if (filename.contains(':')) {
const char* const knownPrefixes[] = { // Known absolute paths
"c:/documents and settings/radimk/plocha/projekt/", // Basis Octavus refers to several files named "c:\documents and settings\radimk\plocha\projekt\sprites\clock*.bmp"
"c:/program files/wme devkit beta/projects/amu/data/", // Five Magical Amulets refers to "c:\program files\wme devkit beta\projects\amu\data\scenes\prvnimenu\scr\scene_init.script"
"c:/users/mathieu/desktop/wintermute engine development kit/jeu verve/vervegame/data/", // Machu Mayu refers to "c:\users\mathieu\desktop\wintermute engine development kit\jeu verve\vervegame\data\interface\system\cr<0xE9>dits.script"
"c:/windows/fonts/", // East Side Story refers to "c:\windows\fonts\framd.ttf"
"c:/carol6/svn/data/", // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png"
("d:/engine/\322\303" "2/tg_ie_080128_1005/data/"), // Tanya Grotter and the Disappearing Floor refers to "d:\engine\<0xD2><0xC3>2\tg_ie_080128_1005\data\interface\pixel\pixel.png"
"e:/users/jonathan/onedrive/knossos/data/", // K'NOSSOS refers to "e:\users\jonathan\onedrive\knossos\data\entities\helprobot\helprobot.script"
"f:/dokument/spel 5/demo/data/", // Carol Reed 5 (non-demo) refers to "f:\dokument\spel 5\demo\data\scenes\credits\op_cred_00\op_cred_00.jpg"
"f:/quest!!!/engine/quest/data/" // Book of Gron Part One refers to several files named "f:\quest!!!\engine\quest\data\entities\dver\*"
};
// There are also some EDITOR_BG_FILE paths that refer to absolute paths
// However, EDITOR_BG_FILE is out of ScummVM scope, so there is currently no need to check for those prefixes:
// "c:\documents and settings\kumilanka\desktop\white.png" is used as EDITOR_BG_FILE at Alpha Polaris
// "c:\documents and settings\nir\desktop\untitled111.bmp" is used as EDITOR_BG_FILE at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest
// "c:\documents and settings\user\desktop\untitled111.bmp" is used as EDITOR_BG_FILE at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest
// "c:\dokumente und einstellungen\frank\desktop\position_qualm_auf_kaputter_jungfrau_2.png" is used as EDITOR_BG_FILE at 1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde
// "c:\tib_forest_d_2007120_111637000.jpg" is used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
// "c:\<0xC1><0xE5><0xE7><0xFB><0xEC><0xFF><0xED><0xFB><0xE9>.bmp" is used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
// "d:\projects\dirty split\tempfolder\background\sprite_help.png" is used as EDITOR_BG_FILE at Dirty Split
// "d:\<0xCE><0xE1><0xEC><0xE5><0xED>\*" are used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
// "e:\pictures\fraps screenshot\*" are used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
// "e:\work\!<0xC4><0xE5><0xEB><0xE0>\1 computergames\6 gamelet\work\*" are used as EDITOR_BG_FILE at Hamlet or the last game without MMORPG features, shaders and product placement
// "e:\<0xC4><0xE5><0xE5><0xE2>\graphics\*" are used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
// "f:\quest!!!\*" are used as EDITOR_BG_FILE at Book of Gron Part One
// "f:\<0xD2><0xE5><0xEA><0xF1><0xF2><0xF3><0xF0><0xFB>\<0xE1><0xEE><0xF2><0xE0><0xED><0xE8><0xEA><0xE0>\index\barks.jpg" is used as EDITOR_BG_FILE at Tanya Grotter and the Disappearing Floor
// "g:\<0xC4><0xEE><0xEA><0xF3><0xEC><0xE5><0xED><0xF2><0xFB>\<0xCF><0xF0><0xEE><0xE5><0xEA><0xF2><0xFB>\<0xD2><0xE8><0xC1>\*" are used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
// "untitled-1.jpg" & "untitled-1.png" with very various paths (including "c:\untitled-1.jpg" and "d:\untitled-1.jpg") are also used as EDITOR_BG_FILE at Fairy Tales About Toshechka and Boshechka
bool matched = false;
for (uint i = 0; i < ARRAYSIZE(knownPrefixes); i++) {
Common::Path root(knownPrefixes[i], '/');
if (fixedFilename.isRelativeTo(root)) {
fixedFilename = fixedFilename.relativeTo(root);
matched = true;
}
}
if (!matched) {
// fixedFilename is unchanged and thus still broken, none of the above workarounds worked.
// We can only bail out
error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str());
}
}
// Try directly from SearchMan first
Common::ArchiveMemberList files;
SearchMan.listMatchingMembers(files, fixedFilename);
for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); ++it) {
if ((*it)->getName().equalsIgnoreCase(fixedFilename.baseName())) {
file = (*it)->createReadStream();
break;
}
}
// File wasn't found in SearchMan, try to parse the path as a relative path.
if (!file) {
Common::FSNode searchNode = getNodeForRelativePath(PathUtil::normalizeFileName(filename));
if (searchNode.exists() && !searchNode.isDirectory() && searchNode.isReadable()) {
file = searchNode.createReadStream();
}
}
if (file) {
uint32 magic1, magic2;
magic1 = file->readUint32LE();
magic2 = file->readUint32LE();
bool compressed = false;
if (magic1 == DCGF_MAGIC && magic2 == COMPRESSED_FILE_MAGIC) {
compressed = true;
}
if (compressed) {
uint32 dataOffset, compSize;
unsigned long uncompSize;
dataOffset = file->readUint32LE();
compSize = file->readUint32LE();
uncompSize = file->readUint32LE();
byte *compBuffer = new byte[compSize];
if (!compBuffer) {
delete file;
error("Error allocating memory for compressed file '%s'", filename.c_str());
return nullptr;
}
byte *data = new byte[uncompSize];
if (!data) {
delete[] compBuffer;
delete file;
error("Error allocating buffer for file '%s'", filename.c_str());
return nullptr;
}
file->seek(dataOffset + prefixSize, SEEK_SET);
file->read(compBuffer, compSize);
if (Common::inflateZlib(data, &uncompSize, compBuffer, compSize) != true) {
delete[] compBuffer;
delete file;
error("Error uncompressing file '%s'", filename.c_str());
return nullptr;
}
delete[] compBuffer;
delete file;
return new Common::MemoryReadStream(data, uncompSize, DisposeAfterUse::YES);
} else {
file->seek(0, SEEK_SET);
return file;
}
return file;
}
return nullptr;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,42 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_DISKFILE_H
#define WINTERMUTE_BASE_DISKFILE_H
#include "common/archive.h"
#include "common/stream.h"
namespace Wintermute {
Common::SeekableReadStream *openDiskFile(const Common::String &filename);
bool diskFileExists(const Common::String &filename);
int listMatchingDiskFileMembers(Common::ArchiveMemberList &list, const Common::String &pattern);
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,76 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/file/base_file_entry.h"
#include "engines/wintermute/base/file/base_package.h"
#include "common/stream.h"
#include "common/substream.h"
#include "common/compression/deflate.h"
namespace Wintermute {
Common::SeekableReadStream *BaseFileEntry::createReadStream() const {
Common::SeekableReadStream *file = _package->getFilePointer();
if (!file) {
return nullptr;
}
bool compressed = (_compressedLength != 0);
if (compressed) {
file = Common::wrapCompressedReadStream(new Common::SeekableSubReadStream(file, _offset, _offset + _compressedLength, DisposeAfterUse::YES), DisposeAfterUse::YES, _length); //
} else {
file = new Common::SeekableSubReadStream(file, _offset, _offset + _length, DisposeAfterUse::YES);
}
file->seek(0);
return file;
}
Common::SeekableReadStream *BaseFileEntry::createReadStreamForAltStream(Common::AltStreamType altStreamType) const {
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
BaseFileEntry::BaseFileEntry() {
_package = nullptr;
_length = _compressedLength = _offset = _flags = 0;
_filename = "";
_timeDate1 = _timeDate2 = 0;
_journalTime = 0;
}
//////////////////////////////////////////////////////////////////////////
BaseFileEntry::~BaseFileEntry() {
_package = nullptr; // ref only
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,62 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FILEENTRY_H
#define WINTERMUTE_BASE_FILEENTRY_H
#include "common/archive.h"
#include "common/str.h"
#include "common/stream.h"
namespace Wintermute {
class BasePackage;
class BaseFileEntry : public Common::ArchiveMember {
public:
Common::SeekableReadStream *createReadStream() const override;
Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType) const override;
Common::String getName() const override { return _filename.baseName(); }
Common::Path getPathInArchive() const override { return _filename; }
Common::String getFileName() const override { return _filename.baseName(); }
uint32 _timeDate2;
uint32 _timeDate1;
uint32 _flags;
uint32 _journalTime;
Common::Path _filename;
uint32 _compressedLength;
uint32 _length;
uint32 _offset;
BasePackage *_package;
BaseFileEntry();
~BaseFileEntry() override;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,288 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/file/base_package.h"
#include "engines/wintermute/base/file/base_file_entry.h"
#include "engines/wintermute/base/file/dcpackage.h"
#include "engines/wintermute/wintermute.h"
#include "common/file.h"
#include "common/stream.h"
#include "common/debug.h"
namespace Wintermute {
BasePackage::BasePackage() {
_name = "";
_cd = 0;
_priority = 0;
_boundToExe = false;
}
Common::SeekableReadStream *BasePackage::getFilePointer() {
Common::SeekableReadStream *stream = _fsnode.createReadStream();
return stream;
}
static bool findPackageSignature(Common::SeekableReadStream *f, uint32 *offset) {
byte buf[32768];
byte signature[8];
WRITE_LE_UINT32(signature + 0, PACKAGE_MAGIC_1);
WRITE_LE_UINT32(signature + 4, PACKAGE_MAGIC_2);
uint32 fileSize = (uint32)f->size();
uint32 startPos = 1024 * 1024;
uint32 bytesRead = startPos;
while (bytesRead < fileSize - 16) {
uint32 toRead = MIN<unsigned int>((unsigned int)32768, fileSize - bytesRead);
f->seek((int32)startPos, SEEK_SET);
uint32 actuallyRead = f->read(buf, toRead);
if (actuallyRead != toRead) {
return false;
}
for (uint32 i = 0; i < toRead - 8; i++)
if (!memcmp(buf + i, signature, 8)) {
*offset = startPos + i;
return true;
}
bytesRead = bytesRead + toRead - 16;
startPos = startPos + toRead - 16;
}
return false;
}
void TPackageHeader::readFromStream(Common::ReadStream *stream) {
_magic1 = stream->readUint32LE();
_magic2 = stream->readUint32LE();
_packageVersion = stream->readUint32LE();
_gameVersion = stream->readUint32LE();
_priority = stream->readByte();
// HACK: reversion1 and reversion2 for Linux & Mac use some hacked Wintermute
// They provide "xlanguage_*.dcp" packages with 0x00 priority and change priority for a single package in runtime
// We already filter unwanted "xlanguage_*.dcp" packages at BaseFileManager::registerPackages()
// So, let's just raise the priority for all "xlanguage_*.dcp" here to the value of Windows version packages
if (_priority == 0 && BaseEngine::instance().getGameId().hasPrefix("reversion")) {
_priority = 0x02;
}
_cd = stream->readByte();
_masterIndex = stream->readByte();
stream->readByte(); // To align the next byte...
_creationTime = stream->readUint32LE();
stream->read(_desc, 100);
_numDirs = stream->readUint32LE();
}
PackageSet::PackageSet(Common::FSNode file, const Common::String &filename, bool searchSignature) {
uint32 absoluteOffset = 0;
_priority = 0;
bool boundToExe = false;
Common::SeekableReadStream *stream = file.createReadStream();
if (!stream) {
return;
}
if (searchSignature) {
uint32 offset;
if (!findPackageSignature(stream, &offset)) {
delete stream;
return;
} else {
stream->seek(offset, SEEK_SET);
absoluteOffset = offset;
boundToExe = true;
}
}
TPackageHeader hdr;
hdr.readFromStream(stream);
if (hdr._magic1 != PACKAGE_MAGIC_1 || hdr._magic2 != PACKAGE_MAGIC_2 || hdr._packageVersion > PACKAGE_VERSION) {
debugC(kWintermuteDebugFileAccess, " Invalid header in package file '%s'. Ignoring.", filename.c_str());
delete stream;
return;
}
if (hdr._packageVersion != PACKAGE_VERSION) {
debugC(kWintermuteDebugFileAccess, " Warning: package file '%s' is outdated.", filename.c_str());
}
_priority = hdr._priority;
_version = hdr._gameVersion;
// new in v2
if (hdr._packageVersion == PACKAGE_VERSION) {
uint32 dirOffset;
dirOffset = stream->readUint32LE();
dirOffset += absoluteOffset;
stream->seek(dirOffset, SEEK_SET);
}
assert(hdr._numDirs == 1);
for (uint32 i = 0; i < hdr._numDirs; i++) {
BasePackage *pkg = new BasePackage();
if (!pkg) {
return;
}
pkg->_fsnode = file;
pkg->_boundToExe = boundToExe;
// read package info
byte nameLength = stream->readByte();
char *pkgName = new char[nameLength];
stream->read(pkgName, nameLength);
pkg->_name = pkgName;
pkg->_cd = stream->readByte();
pkg->_priority = hdr._priority;
delete[] pkgName;
pkgName = nullptr;
if (!hdr._masterIndex) {
pkg->_cd = 0; // override CD to fixed disk
}
_packages.push_back(pkg);
// read file entries
uint32 numFiles = stream->readUint32LE();
for (uint32 j = 0; j < numFiles; j++) {
char *name;
uint32 offset, length, compLength, flags;/*, timeDate1, timeDate2;*/
nameLength = stream->readByte();
if (stream->eos()) {
debugC(kWintermuteDebugFileAccess, " Warning: end of package file '%s'.", filename.c_str());
break;
}
name = new char[nameLength];
stream->read(name, nameLength);
// v2 - xor name
if (hdr._packageVersion == PACKAGE_VERSION) {
for (int k = 0; k < nameLength; k++) {
((byte *)name)[k] ^= 'D';
}
}
debugC(kWintermuteDebugFileAccess, "Package contains %s", name);
Common::Path path(name, '\\');
delete[] name;
name = nullptr;
offset = stream->readUint32LE();
offset += absoluteOffset;
length = stream->readUint32LE();
compLength = stream->readUint32LE();
flags = stream->readUint32LE();
if (hdr._packageVersion == PACKAGE_VERSION) {
/* timeDate1 = */ stream->readUint32LE();
/* timeDate2 = */ stream->readUint32LE();
}
FilesMap::iterator _filesIter;
_filesIter = _files.find(path);
if (_filesIter == _files.end()) {
BaseFileEntry *fileEntry = new BaseFileEntry();
fileEntry->_package = pkg;
fileEntry->_offset = offset;
fileEntry->_length = length;
fileEntry->_compressedLength = compLength;
fileEntry->_flags = flags;
fileEntry->_filename = path;
_files[path] = Common::ArchiveMemberPtr(fileEntry);
} else {
// current package has higher priority than the registered
// TODO: This cast might be a bit ugly.
BaseFileEntry *filePtr = (BaseFileEntry *) &*(_filesIter->_value);
if (pkg->_priority > filePtr->_package->_priority) {
filePtr->_package = pkg;
filePtr->_offset = offset;
filePtr->_length = length;
filePtr->_compressedLength = compLength;
filePtr->_flags = flags;
}
}
}
}
debugC(kWintermuteDebugFileAccess, " Registered %d files in %d package(s)", _files.size(), _packages.size());
delete stream;
}
PackageSet::~PackageSet() {
for (Common::Array<BasePackage *>::iterator it = _packages.begin(); it != _packages.end(); ++it) {
delete *it;
}
_packages.clear();
}
bool PackageSet::hasFile(const Common::Path &path) const {
FilesMap::const_iterator it;
it = _files.find(path);
return (it != _files.end());
}
int PackageSet::listMembers(Common::ArchiveMemberList &list) const {
FilesMap::const_iterator it = _files.begin();
FilesMap::const_iterator end = _files.end();
int count = 0;
for (; it != end; ++it) {
const Common::ArchiveMemberPtr ptr(it->_value);
list.push_back(ptr);
count++;
}
return count;
}
const Common::ArchiveMemberPtr PackageSet::getMember(const Common::Path &path) const {
FilesMap::const_iterator it;
it = _files.find(path);
return Common::ArchiveMemberPtr(it->_value);
}
Common::SeekableReadStream *PackageSet::createReadStreamForMember(const Common::Path &path) const {
FilesMap::const_iterator it;
it = _files.find(path);
if (it != _files.end()) {
return it->_value->createReadStream();
}
return nullptr;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,92 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_PACKAGE_H
#define WINTERMUTE_BASE_PACKAGE_H
#include "common/archive.h"
#include "common/stream.h"
#include "common/fs.h"
namespace Wintermute {
class BasePackage {
public:
Common::SeekableReadStream *getFilePointer();
Common::FSNode _fsnode;
bool _boundToExe;
byte _priority;
Common::String _name;
int32 _cd;
BasePackage();
};
class PackageSet : public Common::Archive {
public:
~PackageSet() override;
PackageSet(Common::FSNode package, const Common::String &filename = "", bool searchSignature = false);
/**
* Check if a member with the given name is present in the Archive.
* Patterns are not allowed, as this is meant to be a quick File::exists()
* replacement.
*/
bool hasFile(const Common::Path &path) const override;
/**
* Add all members of the Archive to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of names added to list
*/
int listMembers(Common::ArchiveMemberList &list) const override;
/**
* Returns a ArchiveMember representation of the given file.
*/
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
/**
* Create a stream bound to a member with the specified name in the
* archive. If no member with this name exists, 0 is returned.
* @return the newly created input stream
*/
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
int getPriority() const { return _priority; }
uint32 getVersion() const { return _version; }
private:
byte _priority;
uint32 _version{};
Common::Array<BasePackage *> _packages;
typedef Common::HashMap<Common::Path, Common::ArchiveMemberPtr, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> FilesMap;
FilesMap _files;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,79 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/base/file/base_save_thumb_file.h"
#include "engines/wintermute/base/base.h"
#include "common/memstream.h"
namespace Wintermute {
Common::SeekableReadStream *openThumbFile(const Common::String &filename) {
if (scumm_strnicmp(filename.c_str(), "savegame:", 9) != 0) {
return nullptr;
}
size_t filenameSize = strlen(filename.c_str()) - 9 + 1;
char *tempFilename = new char[filenameSize];
Common::strcpy_s(tempFilename, filenameSize, filename.c_str() + 9);
for (uint32 i = 0; i < strlen(tempFilename); i++) {
if (tempFilename[i] < '0' || tempFilename[i] > '9') {
tempFilename[i] = '\0';
break;
}
}
// get slot number from name
int slot = atoi(tempFilename);
delete[] tempFilename;
BasePersistenceManager *pm = new BasePersistenceManager();
if (!pm) {
return nullptr;
}
Common::String slotFilename = pm->getFilenameForSlot(slot);
if (DID_FAIL(pm->initLoad(slotFilename))) {
delete pm;
return nullptr;
}
if (pm->_thumbnailDataSize == 0) {
delete pm;
return nullptr;
}
uint32 size = pm->_thumbnailDataSize;
byte *data = (byte *)malloc(size);
memcpy(data, pm->_thumbnailData, size);
delete pm;
return new Common::MemoryReadStream(data, size, DisposeAfterUse::YES);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,40 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SAVETHUMBFILE_H
#define WINTERMUTE_BASE_SAVETHUMBFILE_H
#include "common/str.h"
#include "common/stream.h"
namespace Wintermute {
Common::SeekableReadStream *openThumbFile(const Common::String &filename);
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,86 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/file/base_savefile_manager_file.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_engine.h"
#include "common/system.h"
#include "common/savefile.h"
namespace Wintermute {
Common::String makeSfmFilename(const Common::String &filename) {
Common::String smFilename = filename;
for (size_t i = 0; i < smFilename.size(); i++) {
if (smFilename[i] == '/' || smFilename[i] == '\\') {
smFilename.setChar('_', i);
}
}
while (smFilename.hasPrefix("._")) {
smFilename = smFilename.substr(2);
}
return BaseEngine::instance().getGameTargetName() + "." + smFilename;
}
bool sfmFileExists(const Common::String &filename) {
Common::String smFilename = makeSfmFilename(filename);
return g_system->getSavefileManager()->listSavefiles(smFilename).size() > 0;
}
Common::SeekableReadStream *openSfmFile(const Common::String &filename) {
Common::String smFilename = makeSfmFilename(filename);
return g_system->getSavefileManager()->openRawFile(smFilename);
}
Common::WriteStream *openSfmFileForWrite(const Common::String &filename) {
Common::String smFilename = makeSfmFilename(filename);
return g_system->getSavefileManager()->openForSaving(smFilename, false);
}
Common::StringArray sfmFileList(const Common::String &mask) {
Common::String prefix = BaseEngine::instance().getGameTargetName() + ".";
Common::String smMask = makeSfmFilename(mask);
Common::StringArray array = g_system->getSavefileManager()->listSavefiles(smMask);
for (uint32 i = 0; i < array.size(); i++) {
array[i] = array[i].substr(prefix.size());
}
return array;
}
bool sfmFileRemove(const Common::String &filename) {
Common::String smFilename = makeSfmFilename(filename);
return g_system->getSavefileManager()->removeSavefile(smFilename);
}
bool sfmFileRename(const Common::String &oldName, const Common::String &newName) {
Common::String smOldName = makeSfmFilename(oldName);
Common::String smNewName = makeSfmFilename(newName);
return g_system->getSavefileManager()->renameSavefile(smOldName, smNewName, false);
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,45 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SAVEFILEMANAGERFILE_H
#define WINTERMUTE_BASE_SAVEFILEMANAGERFILE_H
#include "common/str-array.h"
#include "common/stream.h"
namespace Wintermute {
Common::SeekableReadStream *openSfmFile(const Common::String &filename);
Common::WriteStream *openSfmFileForWrite(const Common::String &filename);
bool sfmFileExists(const Common::String &filename);
Common::StringArray sfmFileList(const Common::String &mask);
bool sfmFileRemove(const Common::String &filename);
bool sfmFileRename(const Common::String &oldName, const Common::String &newName);
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,79 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef _DCPACKAGE_H_
#define _DCPACKAGE_H_
#define PACKAGE_MAGIC_1 0xDEC0ADDE
#define PACKAGE_MAGIC_2 0x4B4E554A // "JUNK"
#define PACKAGE_VERSION 0x00000200
#define PACKAGE_EXTENSION "dcp"
#include "common/stream.h"
namespace Wintermute {
struct TPackageHeader {
uint32 _magic1;
uint32 _magic2;
uint32 _packageVersion;
uint32 _gameVersion;
byte _priority;
byte _cd;
bool _masterIndex;
uint32 _creationTime;
char _desc[100];
uint32 _numDirs;
// base_package.cpp:
void readFromStream(Common::ReadStream *stream);
};
/*
v2: uint32 DirOffset
Dir: byte NameLength
char Name [NameLength]
byte CD;
uint32 NumEntries
Entry: byte NameLength
char Name [NameLength]
uint32 Offset
uint32 Length
uint32 CompLength
uint32 Flags
v2: uint32 TimeDate1
uint32 TimeDate2 // not used
*/
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,140 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/font/base_font_bitmap.h"
#include "engines/wintermute/base/font/base_font_truetype.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(BaseFont, false)
//////////////////////////////////////////////////////////////////////
BaseFont::BaseFont(BaseGame *inGame) : BaseObject(inGame) {
}
//////////////////////////////////////////////////////////////////////
BaseFont::~BaseFont() {
}
//////////////////////////////////////////////////////////////////////
void BaseFont::drawText(const byte *text, int x, int y, int width, TTextAlign align, int maxHeight, int maxLength) {
}
//////////////////////////////////////////////////////////////////////
int BaseFont::getTextHeight(const byte *text, int width) {
return 0;
}
//////////////////////////////////////////////////////////////////////
int BaseFont::getTextWidth(const byte *text, int maxLength) {
return 0;
}
//////////////////////////////////////////////////////////////////////////
int BaseFont::getLetterHeight() {
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFont::persist(BasePersistenceManager *persistMgr) {
BaseObject::persist(persistMgr);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
BaseFont *BaseFont::createFromFile(BaseGame *game, const char *filename) {
if (isTrueType(game, filename)) {
BaseFontTT *font = new BaseFontTT(game);
if (font) {
if (DID_FAIL(font->loadFile(filename))) {
delete font;
return nullptr;
}
}
return font;
} else {
BaseFontBitmap *font = new BaseFontBitmap(game);
if (font) {
if (DID_FAIL(font->loadFile(filename))) {
delete font;
return nullptr;
}
}
return font;
}
}
TOKEN_DEF_START
TOKEN_DEF(FONT)
TOKEN_DEF(TTFONT)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////////
bool BaseFont::isTrueType(BaseGame *game, const char *filename) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(FONT)
TOKEN_TABLE(TTFONT)
TOKEN_TABLE_END
char *buffer = (char *)game->_fileManager->readWholeFile(filename);
if (buffer == nullptr) {
return false;
}
char *workBuffer = buffer;
char *params;
BaseParser parser(game);
bool ret = false;
if (parser.getCommand(&workBuffer, commands, &params) == TOKEN_TTFONT) {
ret = true;
}
delete[] buffer;
return ret;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,60 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FONT_H
#define WINTERMUTE_BASE_FONT_H
#include "engines/wintermute/base/base_object.h"
#define NUM_CHARACTERS 256
namespace Wintermute {
class BaseFont : public BaseObject {
public:
DECLARE_PERSISTENT(BaseFont, BaseObject)
virtual int getTextWidth(const byte *text, int maxLength = -1);
virtual int getTextHeight(const byte *text, int width);
virtual void drawText(const byte *text, int x, int y, int width, TTextAlign align = TAL_LEFT, int max_height = -1, int maxLength = -1);
virtual int getLetterHeight();
virtual void initLoop() {}
virtual void afterLoad() {}
BaseFont(BaseGame *inGame);
~BaseFont() override;
static BaseFont *createFromFile(BaseGame *game, const char *filename);
private:
//bool loadBuffer(char *buffer);
//bool loadFile(const char* Filename);
static bool isTrueType(BaseGame *game, const char *filename);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,628 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/font/base_font_bitmap.h"
#include "engines/wintermute/utils/string_util.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(BaseFontBitmap, false)
//////////////////////////////////////////////////////////////////////
BaseFontBitmap::BaseFontBitmap(BaseGame *inGame) : BaseFont(inGame) {
_subframe = nullptr;
_sprite = nullptr;
_widthsFrame = 0;
memset(_widths, 0, NUM_CHARACTERS);
_tileWidth = _tileHeight = _numColumns = 0;
_fontextFix = false;
_freezable = false;
_wholeCell = false;
}
//////////////////////////////////////////////////////////////////////
BaseFontBitmap::~BaseFontBitmap() {
SAFE_DELETE(_subframe);
SAFE_DELETE(_sprite);
}
//////////////////////////////////////////////////////////////////////
void BaseFontBitmap::drawText(const byte *text, int x, int y, int width, TTextAlign align, int maxHeight, int maxLength) {
textHeightDraw(text, x, y, width, align, true, maxHeight, maxLength);
}
//////////////////////////////////////////////////////////////////////
int BaseFontBitmap::getTextHeight(const byte *text, int width) {
return textHeightDraw(text, 0, 0, width, TAL_LEFT, false);
}
//////////////////////////////////////////////////////////////////////
int BaseFontBitmap::getTextWidth(const byte *text, int maxLength) {
AnsiString str;
if (_game->_textEncoding == TEXT_UTF8) {
WideString wstr = StringUtil::utf8ToWide(Utf8String((const char *)text));
str = StringUtil::wideToAnsi(wstr);
} else {
str = AnsiString((const char *)text);
}
if (maxLength >= 0 && (int)str.size() > maxLength) {
str = Common::String(str.c_str(), (uint32)maxLength);
}
//str.substr(0, maxLength); // TODO: Remove
int textWidth = 0;
for (int i = 0; (uint32)i < str.size(); i++) {
textWidth += getCharWidth((byte)str[i]);
}
return textWidth;
}
//////////////////////////////////////////////////////////////////////
int BaseFontBitmap::textHeightDraw(const byte *text, int x, int y, int width, TTextAlign align, bool draw, int maxHeight, int maxLength) {
if (maxLength == 0) {
return 0;
}
if (text == nullptr || text[0] == '\0') {
return _tileHeight;
}
AnsiString str;
if (_game->_textEncoding == TEXT_UTF8) {
WideString wstr = StringUtil::utf8ToWide(Utf8String((const char *)text));
str = StringUtil::wideToAnsi(wstr);
} else {
str = AnsiString((const char *)text);
}
if (str.empty()) {
return 0;
}
int lineLength = 0;
int realLength = 0;
int numLines = 0;
int i;
int index = -1;
int start = 0;
int end = 0;
int last_end = 0;
bool done = false;
bool newLine = false;
bool longLine = false;
#ifdef ENABLE_FOXTAIL
bool minimizeSpacing = BaseEngine::instance().isFoxTail();
#endif
if (draw) {
_game->_renderer->startSpriteBatch();
}
while (!done) {
if (maxHeight > 0 && (numLines + 1) * _tileHeight > maxHeight) {
if (draw) {
_game->_renderer->endSpriteBatch();
}
return numLines * _tileHeight;
}
index++;
if (str[index] == ' ' && (maxHeight < 0 || maxHeight / _tileHeight > 1)) {
end = index - 1;
realLength = lineLength;
}
if (str[index] == '\n') {
end = index - 1;
realLength = lineLength;
newLine = true;
}
if (lineLength + getCharWidth(str[index]) > width && last_end == end) {
end = index - 1;
realLength = lineLength;
newLine = true;
longLine = true;
}
if ((int)str.size() == (index + 1) || (maxLength >= 0 && index == maxLength - 1)) {
done = true;
if (!newLine) {
end = index;
lineLength += getCharWidth(str[index]);
realLength = lineLength;
}
} else {
lineLength += getCharWidth(str[index]);
}
if ((lineLength > width) || done || newLine) {
if (end < 0) {
done = true;
}
int startX = x;
switch (align) {
case TAL_CENTER:
startX = x + (width - realLength) / 2;
break;
case TAL_RIGHT:
startX = x + width - realLength;
break;
case TAL_LEFT:
startX = x;
break;
default:
break;
}
for (i = start; i < end + 1; i++) {
if (draw) {
drawChar(str[i], startX, y);
}
startX += getCharWidth(str[i]);
}
y += _tileHeight;
#ifdef ENABLE_FOXTAIL
if (minimizeSpacing) {
y -= 3;
}
#endif
last_end = end;
if (longLine) {
end--;
}
start = end + 2;
index = end + 1;
lineLength = 0;
newLine = false;
longLine = false;
numLines++;
}
}
if (draw) {
_game->_renderer->endSpriteBatch();
}
return numLines * _tileHeight;
}
//////////////////////////////////////////////////////////////////////
void BaseFontBitmap::drawChar(byte c, int x, int y) {
if (_fontextFix) {
c--;
}
int row, col;
row = c / _numColumns;
col = c % _numColumns;
Common::Rect32 rect;
/* l t r b */
int tileWidth;
if (_wholeCell) {
tileWidth = _tileWidth;
} else {
tileWidth = _widths[c];
}
BasePlatform::setRect(&rect, col * _tileWidth, row * _tileHeight, col * _tileWidth + tileWidth, (row + 1) * _tileHeight);
bool handled = false;
if (_sprite) {
_sprite->getCurrentFrame();
if (_sprite->_currentFrame >= 0 && _sprite->_currentFrame < _sprite->_frames.getSize() && _sprite->_frames[_sprite->_currentFrame]) {
if (_sprite->_frames[_sprite->_currentFrame]->_subframes.getSize() > 0) {
_sprite->_frames[_sprite->_currentFrame]->_subframes[0]->_surface->displayTrans(x, y, rect);
}
handled = true;
}
}
if (!handled && _subframe) {
_subframe->_surface->displayTrans(x, y, rect, _subframe->_alpha);
}
}
//////////////////////////////////////////////////////////////////////
bool BaseFontBitmap::loadFile(const char *filename) {
char *buffer = (char *)_game->_fileManager->readWholeFile(filename);
if (buffer == nullptr) {
_game->LOG(0, "BaseFontBitmap::loadFile failed for file '%s'", filename);
return STATUS_FAILED;
}
bool ret;
setFilename(filename);
if (DID_FAIL(ret = loadBuffer(buffer))) {
_game->LOG(0, "Error parsing FONT file '%s'", filename);
}
delete[] buffer;
return ret;
}
TOKEN_DEF_START
TOKEN_DEF(FONTEXT_FIX)
TOKEN_DEF(FONT)
TOKEN_DEF(IMAGE)
TOKEN_DEF(TRANSPARENT)
TOKEN_DEF(COLUMNS)
TOKEN_DEF(TILE_WIDTH)
TOKEN_DEF(TILE_HEIGHT)
TOKEN_DEF(DEFAULT_WIDTH)
TOKEN_DEF(WIDTHS)
TOKEN_DEF(AUTO_WIDTH)
TOKEN_DEF(SPACE_WIDTH)
TOKEN_DEF(EXPAND_WIDTH)
TOKEN_DEF(EDITOR_PROPERTY)
TOKEN_DEF(SPRITE)
TOKEN_DEF(WIDTHS_FRAME)
TOKEN_DEF(PAINT_WHOLE_CELL)
#ifdef ENABLE_FOXTAIL
TOKEN_DEF(COLOR)
#endif
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
bool BaseFontBitmap::loadBuffer(char *buffer) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(FONTEXT_FIX)
TOKEN_TABLE(FONT)
TOKEN_TABLE(IMAGE)
TOKEN_TABLE(TRANSPARENT)
TOKEN_TABLE(COLUMNS)
TOKEN_TABLE(TILE_WIDTH)
TOKEN_TABLE(TILE_HEIGHT)
TOKEN_TABLE(DEFAULT_WIDTH)
TOKEN_TABLE(WIDTHS)
TOKEN_TABLE(AUTO_WIDTH)
TOKEN_TABLE(SPACE_WIDTH)
TOKEN_TABLE(EXPAND_WIDTH)
TOKEN_TABLE(EDITOR_PROPERTY)
TOKEN_TABLE(SPRITE)
TOKEN_TABLE(WIDTHS_FRAME)
TOKEN_TABLE(PAINT_WHOLE_CELL)
#ifdef ENABLE_FOXTAIL
TOKEN_TABLE(COLOR)
#endif
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
if (parser.getCommand(&buffer, commands, &params) != TOKEN_FONT) {
_game->LOG(0, "'FONT' keyword expected.");
return STATUS_FAILED;
}
buffer = params;
int widths[300];
int num = 0, defaultWidth = 8;
int lastWidth = 0;
int i;
int r = 255, g = 255, b = 255;
bool customTrans = false;
#ifdef ENABLE_FOXTAIL
int ar = 255, ag = 255, ab = 255;
bool customAlpha = false;
#endif
char *surfaceFile = nullptr;
char *spriteFile = nullptr;
bool autoWidth = false;
int spaceWidth = 0;
int expandWidth = 0;
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_IMAGE:
surfaceFile = params;
break;
case TOKEN_SPRITE:
spriteFile = params;
break;
case TOKEN_TRANSPARENT:
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
customTrans = true;
break;
#ifdef ENABLE_FOXTAIL
case TOKEN_COLOR:
parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab);
customAlpha = true;
break;
#endif
case TOKEN_WIDTHS:
parser.scanStr(params, "%D", widths, &num);
for (i = 0; lastWidth < NUM_CHARACTERS && num > 0; lastWidth++, num--, i++) {
_widths[lastWidth] = (byte)widths[i];
}
break;
case TOKEN_DEFAULT_WIDTH:
parser.scanStr(params, "%d", &defaultWidth);
break;
case TOKEN_WIDTHS_FRAME:
parser.scanStr(params, "%d", &_widthsFrame);
break;
case TOKEN_COLUMNS:
parser.scanStr(params, "%d", &_numColumns);
break;
case TOKEN_TILE_WIDTH:
parser.scanStr(params, "%d", &_tileWidth);
break;
case TOKEN_TILE_HEIGHT:
parser.scanStr(params, "%d", &_tileHeight);
break;
case TOKEN_AUTO_WIDTH:
parser.scanStr(params, "%b", &autoWidth);
break;
case TOKEN_FONTEXT_FIX:
parser.scanStr(params, "%b", &_fontextFix);
break;
case TOKEN_PAINT_WHOLE_CELL:
parser.scanStr(params, "%b", &_wholeCell);
break;
case TOKEN_SPACE_WIDTH:
parser.scanStr(params, "%d", &spaceWidth);
break;
case TOKEN_EXPAND_WIDTH:
parser.scanStr(params, "%d", &expandWidth);
break;
case TOKEN_EDITOR_PROPERTY:
parseEditorProperty(params, false);
break;
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
_game->LOG(0, "Syntax error in FONT definition");
return STATUS_FAILED;
}
if (spriteFile != nullptr) {
SAFE_DELETE(_sprite);
_sprite = new BaseSprite(_game, this);
if (!_sprite || DID_FAIL(_sprite->loadFile(spriteFile))) {
SAFE_DELETE(_sprite);
}
}
if (surfaceFile != nullptr && !_sprite) {
_subframe = new BaseSubFrame(_game);
if (customTrans) {
_subframe->setSurface(surfaceFile, false, r, g, b);
} else {
_subframe->setSurface(surfaceFile);
}
#ifdef ENABLE_FOXTAIL
if (customAlpha) {
_subframe->_alpha = BYTETORGBA(ar, ag, ab, 255);
}
#endif
}
if (((_subframe == nullptr || _subframe->_surface == nullptr) && _sprite == nullptr) || _numColumns == 0 || _tileWidth == 0 || _tileHeight == 0) {
_game->LOG(0, "Incomplete font definition");
return STATUS_FAILED;
}
if (autoWidth) {
// calculate characters width
getWidths();
// do we need to modify widths?
if (expandWidth != 0) {
for (i = 0; i < NUM_CHARACTERS; i++) {
int newWidth = (int)_widths[i] + expandWidth;
if (newWidth < 0) {
newWidth = 0;
}
_widths[i] = (byte)newWidth;
}
}
// handle space character
uint32 spaceChar = ' ';
if (_fontextFix) {
spaceChar--;
}
if (spaceWidth != 0) {
_widths[spaceChar] = spaceWidth;
} else {
if (_widths[spaceChar] == expandWidth || _widths[spaceChar] == 0) {
_widths[spaceChar] = (_widths[(uint32)'m'] + _widths[(uint32)'i']) / 2;
}
}
} else {
for (i = lastWidth; i < NUM_CHARACTERS; i++) {
_widths[i] = defaultWidth;
}
}
#ifdef ENABLE_FOXTAIL
if (BaseEngine::instance().isFoxTail()) {
for (i = lastWidth; i < NUM_CHARACTERS; i++) {
_widths[i]--;
}
}
#endif
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontBitmap::persist(BasePersistenceManager *persistMgr) {
BaseFont::persist(persistMgr);
persistMgr->transferSint32(TMEMBER(_numColumns));
persistMgr->transferPtr(TMEMBER_PTR(_subframe));
persistMgr->transferSint32(TMEMBER(_tileHeight));
persistMgr->transferSint32(TMEMBER(_tileWidth));
persistMgr->transferPtr(TMEMBER_PTR(_sprite));
persistMgr->transferSint32(TMEMBER(_widthsFrame));
if (persistMgr->getIsSaving()) {
persistMgr->putBytes(_widths, sizeof(_widths));
} else {
persistMgr->getBytes(_widths, sizeof(_widths));
}
persistMgr->transferBool(TMEMBER(_fontextFix));
persistMgr->transferBool(TMEMBER(_wholeCell));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int BaseFontBitmap::getCharWidth(byte index) {
if (_fontextFix) {
index--;
}
return _widths[index];
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontBitmap::getWidths() {
BaseSurface *surf = nullptr;
if (_sprite) {
if (_widthsFrame >= 0 && _widthsFrame < _sprite->_frames.getSize()) {
if (_sprite->_frames[_widthsFrame] && _sprite->_frames[_widthsFrame]->_subframes.getSize() > 0) {
surf = _sprite->_frames[_widthsFrame]->_subframes[0]->_surface;
}
}
}
if (surf == nullptr && _subframe) {
surf = _subframe->_surface;
}
if (!surf || DID_FAIL(surf->startPixelOp())) {
return STATUS_FAILED;
}
for (int i = 0; i < NUM_CHARACTERS; i++) {
int xxx = (i % _numColumns) * _tileWidth;
int yyy = (i / _numColumns) * _tileHeight;
int minCol = -1;
for (int row = 0; row < _tileHeight; row++) {
for (int col = _tileWidth - 1; col >= minCol + 1; col--) {
if (xxx + col < 0 || xxx + col >= surf->getWidth() || yyy + row < 0 || yyy + row >= surf->getHeight()) {
continue;
}
if (!surf->isTransparentAtLite(xxx + col, yyy + row)) {
//min_col = col;
minCol = MAX(col, minCol);
break;
}
}
if (minCol == _tileWidth - 1) {
break;
}
}
_widths[i] = minCol + 1;
}
surf->endPixelOp();
/*
_game->LOG(0, "----- %s ------", _filename);
for(int j=0; j<16; j++)
{
_game->LOG(0, "%02d %02d %02d %02d %02d %02d %02d %02d %02d %02d %02d %02d %02d %02d %02d %02d", _widths[j*16+0], _widths[j*16+1], _widths[j*16+2], _widths[j*16+3], _widths[j*16+4], _widths[j*16+5], _widths[j*16+6], _widths[j*16+7], _widths[j*16+8], _widths[j*16+9], _widths[j*16+10], _widths[j*16+11], _widths[j*16+12], _widths[j*16+13], _widths[j*16+14], _widths[j*16+15]);
}
*/
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
int BaseFontBitmap::getLetterHeight() {
return _tileHeight;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,70 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FONTBITMAP_H
#define WINTERMUTE_BASE_FONTBITMAP_H
#include "engines/wintermute/base/font/base_font.h"
namespace Wintermute {
class BaseSubFrame;
class BaseFontBitmap : public BaseFont {
public:
DECLARE_PERSISTENT(BaseFontBitmap, BaseFont)
bool loadBuffer(char *buffer);
bool loadFile(const char *filename);
int getTextWidth(const byte *text, int maxLength = -1) override;
int getTextHeight(const byte *text, int width) override;
void drawText(const byte *text, int x, int y, int width, TTextAlign align = TAL_LEFT, int max_height = -1, int maxLength = -1) override;
int getLetterHeight() override;
BaseFontBitmap(BaseGame *inGame);
~BaseFontBitmap() override;
bool getWidths();
BaseSprite *_sprite;
int32 _widthsFrame;
bool _fontextFix;
int32 _numColumns;
int32 _tileHeight;
int32 _tileWidth;
byte _widths[NUM_CHARACTERS];
BaseSubFrame *_subframe;
bool _wholeCell;
private:
int getCharWidth(byte index);
void drawChar(byte c, int x, int y);
int textHeightDraw(const byte *text, int x, int y, int width, TTextAlign align, bool draw, int max_height = -1, int maxLength = -1);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,139 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/base_game.h"
#include "common/str.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_PERSISTENT(BaseFontStorage, true)
//////////////////////////////////////////////////////////////////////////
BaseFontStorage::BaseFontStorage(BaseGame *inGame) : BaseClass(inGame) {
}
//////////////////////////////////////////////////////////////////////////
BaseFontStorage::~BaseFontStorage() {
cleanup(true);
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontStorage::cleanup(bool warn) {
for (int32 i = 0; i < _fonts.getSize(); i++) {
if (warn)
_game->LOG(0, "Removing orphan font '%s'", _fonts[i]->_filename);
delete _fonts[i];
}
_fonts.removeAll();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontStorage::initLoop() {
for (int32 i = 0; i < _fonts.getSize(); i++) {
_fonts[i]->initLoop();
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
BaseFont *BaseFontStorage::addFont(const char *filename) {
if (!filename) {
return nullptr;
}
for (int32 i = 0; i < _fonts.getSize(); i++) {
if (scumm_stricmp(_fonts[i]->_filename, filename) == 0) {
_fonts[i]->_refCount++;
return _fonts[i];
}
}
/*
BaseFont* font = new BaseFont(_game);
if (!font) return nullptr;
if (DID_FAIL(font->loadFile(filename))) {
delete font;
return nullptr;
}
else {
font->_refCount = 1;
_fonts.add(font);
return font;
}
*/
BaseFont *font = BaseFont::createFromFile(_game, filename);
if (font) {
font->_refCount = 1;
_fonts.add(font);
}
return font;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontStorage::removeFont(BaseFont *font) {
if (!font) {
return STATUS_FAILED;
}
for (int32 i = 0; i < _fonts.getSize(); i++) {
if (_fonts[i] == font) {
_fonts[i]->_refCount--;
if (_fonts[i]->_refCount <= 0) {
delete _fonts[i];
_fonts.removeAt(i);
}
break;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontStorage::persist(BasePersistenceManager *persistMgr) {
if (!persistMgr->getIsSaving()) {
cleanup(false);
}
persistMgr->transferPtr(TMEMBER_PTR(_game));
_fonts.persist(persistMgr);
return STATUS_OK;
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FONTSTORAGE_H
#define WINTERMUTE_BASE_FONTSTORAGE_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/coll_templ.h"
namespace Wintermute {
class BaseFont;
class BaseFontStorage : public BaseClass {
public:
DECLARE_PERSISTENT(BaseFontStorage, BaseClass)
bool cleanup(bool warn = false);
bool removeFont(BaseFont *font);
BaseFont *addFont(const char *filename);
BaseFontStorage(BaseGame *inGame);
~BaseFontStorage() override;
BaseArray<BaseFont *> _fonts;
bool initLoop();
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,629 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/font/base_font_truetype.h"
#include "engines/wintermute/utils/string_util.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/dcgf.h"
#include "graphics/fonts/ttf.h"
#include "graphics/fontman.h"
#include "common/unicode-bidi.h"
#include "common/compression/unzip.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseFontTT, false)
//////////////////////////////////////////////////////////////////////////
BaseFontTT::BaseFontTT(BaseGame *inGame) : BaseFont(inGame) {
_fontHeight = 12;
_isBold = _isItalic = _isUnderline = _isStriked = false;
_charset = CHARSET_ANSI;
_fontFile = nullptr;
_font = nullptr;
_fallbackFont = nullptr;
_deletableFont = nullptr;
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
_cachedTexts[i] = nullptr;
}
_lineHeight = 0;
_maxCharWidth = _maxCharHeight = 0;
}
//////////////////////////////////////////////////////////////////////////
BaseFontTT::~BaseFontTT() {
clearCache();
for (int32 i = 0; i < _layers.getSize(); i++) {
delete _layers[i];
}
_layers.removeAll();
SAFE_DELETE_ARRAY(_fontFile);
SAFE_DELETE(_deletableFont);
_font = nullptr;
}
//////////////////////////////////////////////////////////////////////////
void BaseFontTT::clearCache() {
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
if (_cachedTexts[i]) {
delete _cachedTexts[i];
}
_cachedTexts[i] = nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
void BaseFontTT::initLoop() {
}
//////////////////////////////////////////////////////////////////////////
int BaseFontTT::getTextWidth(const byte *text, int maxLength) {
WideString textStr;
if (_game->_textEncoding == TEXT_UTF8) {
textStr = StringUtil::utf8ToWide((const char *)text);
} else {
textStr = StringUtil::ansiToWide((const char *)text, _charset);
}
if (maxLength >= 0 && (int)textStr.size() > maxLength) {
textStr = textStr.substr(0, (uint32)maxLength);
}
//text = text.substr(0, MaxLength); // TODO: Remove
int textWidth, textHeight;
measureText(textStr, -1, -1, textWidth, textHeight);
return textWidth;
}
//////////////////////////////////////////////////////////////////////////
int BaseFontTT::getTextHeight(const byte *text, int width) {
WideString textStr;
if (_game->_textEncoding == TEXT_UTF8) {
textStr = StringUtil::utf8ToWide((const char *)text);
} else {
textStr = StringUtil::ansiToWide((const char *)text, _charset);
}
int textWidth, textHeight;
measureText(textStr, width, -1, textWidth, textHeight);
return textHeight;
}
//////////////////////////////////////////////////////////////////////////
void BaseFontTT::drawText(const byte *text, int x, int y, int width, TTextAlign align, int maxHeight, int maxLength) {
if (text == nullptr || strcmp((const char *)text, "") == 0) {
return;
}
WideString textStr;
// TODO: Why do we still insist on Widestrings everywhere?
// HACK: J.U.L.I.A. uses CP1252, we need to fix that,
// And we still don't have any UTF8-support.
if (_game->_textEncoding == TEXT_UTF8) {
textStr = StringUtil::utf8ToWide((const char *)text);
} else {
textStr = StringUtil::ansiToWide((const char *)text, _charset);
}
if (maxLength >= 0 && textStr.size() > (uint32)maxLength) {
textStr = textStr.substr(0, (uint32)maxLength);
}
//text = text.substr(0, MaxLength); // TODO: Remove
BaseRenderer *renderer = _game->_renderer;
// find cached surface, if exists
uint32 minUseTime = INT_MAX_VALUE;
int minIndex = -1;
BaseSurface *surface = nullptr;
int textOffset = 0;
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
if (_cachedTexts[i] == nullptr) {
minUseTime = 0;
minIndex = i;
} else {
if (_cachedTexts[i]->_text == textStr && _cachedTexts[i]->_align == align && _cachedTexts[i]->_width == width && _cachedTexts[i]->_maxHeight == maxHeight && _cachedTexts[i]->_maxLength == maxLength) {
surface = _cachedTexts[i]->_surface;
textOffset = _cachedTexts[i]->_textOffset;
_cachedTexts[i]->_marked = true;
_cachedTexts[i]->_lastUsed = BasePlatform::getTime();
break;
} else {
if (_cachedTexts[i]->_lastUsed < minUseTime) {
minUseTime = _cachedTexts[i]->_lastUsed;
minIndex = i;
}
}
}
}
// not found, create one
if (!surface) {
debugC(kWintermuteDebugFont, "Draw text: %s", text);
surface = renderTextToTexture(textStr, width, align, maxHeight, textOffset);
if (surface) {
// write surface to cache
if (_cachedTexts[minIndex] != nullptr) {
delete _cachedTexts[minIndex];
}
_cachedTexts[minIndex] = new BaseCachedTTFontText;
_cachedTexts[minIndex]->_surface = surface;
_cachedTexts[minIndex]->_align = align;
_cachedTexts[minIndex]->_width = width;
_cachedTexts[minIndex]->_maxHeight = maxHeight;
_cachedTexts[minIndex]->_maxLength = maxLength;
_cachedTexts[minIndex]->_text = textStr;
_cachedTexts[minIndex]->_textOffset = textOffset;
_cachedTexts[minIndex]->_marked = true;
_cachedTexts[minIndex]->_lastUsed = BasePlatform::getTime();
}
}
// and paint it
if (surface) {
Common::Rect32 rc;
BasePlatform::setRect(&rc, 0, 0, surface->getWidth(), surface->getHeight());
for (int32 i = 0; i < _layers.getSize(); i++) {
uint32 color = _layers[i]->_color;
uint32 origForceAlpha = renderer->_forceAlphaColor;
if (renderer->_forceAlphaColor != 0) {
color = BYTETORGBA(RGBCOLGetR(color), RGBCOLGetG(color), RGBCOLGetB(color), RGBCOLGetA(renderer->_forceAlphaColor));
renderer->_forceAlphaColor = 0;
}
surface->displayTrans(x, y - textOffset, rc, color, Graphics::BLEND_NORMAL, false, false, _layers[i]->_offsetX, _layers[i]->_offsetY);
renderer->_forceAlphaColor = origForceAlpha;
}
}
}
//////////////////////////////////////////////////////////////////////////
BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width, TTextAlign align, int maxHeight, int &textOffset) {
//TextLineList lines;
// TODO: Use WideString-conversion here.
//WrapText(text, width, maxHeight, lines);
Common::Array<WideString> lines;
_font->wordWrapText(text, width, lines);
while (maxHeight > 0 && lines.size() * _lineHeight > maxHeight) {
lines.pop_back();
}
if (lines.size() == 0) {
return nullptr;
}
Graphics::TextAlign alignment = Graphics::kTextAlignInvalid;
if (align == TAL_LEFT) {
alignment = Graphics::kTextAlignLeft;
} else if (align == TAL_CENTER) {
alignment = Graphics::kTextAlignCenter;
} else if (align == TAL_RIGHT) {
alignment = Graphics::kTextAlignRight;
}
// TODO: This debug call does not work with WideString because text.c_str() returns an uint32 array.
//debugC(kWintermuteDebugFont, "%s %d %d %d %d", text.c_str(), RGBCOLGetR(_layers[0]->_color), RGBCOLGetG(_layers[0]->_color), RGBCOLGetB(_layers[0]->_color), RGBCOLGetA(_layers[0]->_color));
// void drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
Graphics::Surface *surface = new Graphics::Surface();
surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), _game->_renderer->getPixelFormat());
uint32 useColor = 0xffffffff;
Common::Array<WideString>::iterator it;
int heightOffset = 0;
for (it = lines.begin(); it != lines.end(); ++it) {
WideString str;
if (_game->_textRTL) {
str = Common::convertBiDiU32String(*it, Common::BIDI_PAR_RTL);
} else {
str = Common::convertBiDiU32String(*it, Common::BIDI_PAR_LTR);
}
_font->drawAlphaString(surface, str, 0, heightOffset, width, useColor, alignment);
heightOffset += (int)_lineHeight;
}
BaseSurface *retSurface = _game->_renderer->createSurface();
retSurface->create(surface->w, surface->h);
retSurface->putSurface(*surface, true);
surface->free();
delete surface;
return retSurface;
// TODO: _isUnderline, _isBold, _isItalic, _isStriked
}
//////////////////////////////////////////////////////////////////////////
int BaseFontTT::getLetterHeight() {
return (int)_lineHeight;
}
//////////////////////////////////////////////////////////////////////
bool BaseFontTT::loadFile(const char *filename) {
char *buffer = (char *)_game->_fileManager->readWholeFile(filename);
if (buffer == nullptr) {
_game->LOG(0, "BaseFontTT::loadFile failed for file '%s'", filename);
return STATUS_FAILED;
}
bool ret;
setFilename(filename);
if (DID_FAIL(ret = loadBuffer(buffer))) {
_game->LOG(0, "Error parsing TTFONT file '%s'", filename);
}
delete[] buffer;
return ret;
}
TOKEN_DEF_START
TOKEN_DEF(TTFONT)
TOKEN_DEF(SIZE)
TOKEN_DEF(FACE)
TOKEN_DEF(FILENAME)
TOKEN_DEF(BOLD)
TOKEN_DEF(ITALIC)
TOKEN_DEF(UNDERLINE)
TOKEN_DEF(STRIKE)
TOKEN_DEF(CHARSET)
TOKEN_DEF(COLOR)
TOKEN_DEF(ALPHA)
TOKEN_DEF(LAYER)
TOKEN_DEF(OFFSET_X)
TOKEN_DEF(OFFSET_Y)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
bool BaseFontTT::loadBuffer(char *buffer) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(TTFONT)
TOKEN_TABLE(SIZE)
TOKEN_TABLE(FACE)
TOKEN_TABLE(FILENAME)
TOKEN_TABLE(BOLD)
TOKEN_TABLE(ITALIC)
TOKEN_TABLE(UNDERLINE)
TOKEN_TABLE(STRIKE)
TOKEN_TABLE(CHARSET)
TOKEN_TABLE(COLOR)
TOKEN_TABLE(ALPHA)
TOKEN_TABLE(LAYER)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
if (parser.getCommand(&buffer, commands, &params) != TOKEN_TTFONT) {
_game->LOG(0, "'TTFONT' keyword expected.");
return STATUS_FAILED;
}
buffer = params;
uint32 baseColor = 0x00000000;
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_SIZE:
parser.scanStr(params, "%d", &_fontHeight);
break;
case TOKEN_FACE:
// we don't need this anymore
break;
case TOKEN_FILENAME:
BaseUtils::setString(&_fontFile, params);
break;
case TOKEN_BOLD:
parser.scanStr(params, "%b", &_isBold);
break;
case TOKEN_ITALIC:
parser.scanStr(params, "%b", &_isItalic);
break;
case TOKEN_UNDERLINE:
parser.scanStr(params, "%b", &_isUnderline);
break;
case TOKEN_STRIKE:
parser.scanStr(params, "%b", &_isStriked);
break;
case TOKEN_CHARSET:
parser.scanStr(params, "%d", &_charset);
break;
case TOKEN_COLOR: {
int r, g, b;
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
baseColor = BYTETORGBA(r, g, b, RGBCOLGetA(baseColor));
}
break;
case TOKEN_ALPHA: {
int a;
parser.scanStr(params, "%d", &a);
baseColor = BYTETORGBA(RGBCOLGetR(baseColor), RGBCOLGetG(baseColor), RGBCOLGetB(baseColor), a);
}
break;
case TOKEN_LAYER: {
BaseTTFontLayer *layer = new BaseTTFontLayer;
if (layer && DID_SUCCEED(parseLayer(layer, params))) {
_layers.add(layer);
} else {
SAFE_DELETE(layer);
cmd = PARSERR_TOKENNOTFOUND;
}
}
break;
default:
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
_game->LOG(0, "Syntax error in TTFONT definition");
return STATUS_FAILED;
}
// create at least one layer
if (_layers.getSize() == 0) {
BaseTTFontLayer *layer = new BaseTTFontLayer;
layer->_color = baseColor;
_layers.add(layer);
}
if (!_fontFile) {
BaseUtils::setString(&_fontFile, "arial.ttf");
}
return initFont();
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontTT::parseLayer(BaseTTFontLayer *layer, char *buffer) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(OFFSET_X)
TOKEN_TABLE(OFFSET_Y)
TOKEN_TABLE(COLOR)
TOKEN_TABLE(ALPHA)
TOKEN_TABLE_END
char *params;
int cmd;
BaseParser parser(_game);
while ((cmd = parser.getCommand(&buffer, commands, &params)) > 0) {
switch (cmd) {
case TOKEN_OFFSET_X:
parser.scanStr(params, "%d", &layer->_offsetX);
break;
case TOKEN_OFFSET_Y:
parser.scanStr(params, "%d", &layer->_offsetY);
break;
case TOKEN_COLOR: {
int r, g, b;
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
layer->_color = BYTETORGBA(r, g, b, RGBCOLGetA(layer->_color));
}
break;
case TOKEN_ALPHA: {
int a;
parser.scanStr(params, "%d", &a);
layer->_color = BYTETORGBA(RGBCOLGetR(layer->_color), RGBCOLGetG(layer->_color), RGBCOLGetB(layer->_color), a);
}
break;
default:
break;
}
}
if (cmd != PARSERR_EOF) {
return STATUS_FAILED;
} else {
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontTT::persist(BasePersistenceManager *persistMgr) {
BaseFont::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_isBold));
persistMgr->transferBool(TMEMBER(_isItalic));
persistMgr->transferBool(TMEMBER(_isUnderline));
persistMgr->transferBool(TMEMBER(_isStriked));
persistMgr->transferSint32(TMEMBER(_fontHeight));
persistMgr->transferCharPtr(TMEMBER(_fontFile));
persistMgr->transferSint32(TMEMBER_INT(_charset));
// persist layers
int32 numLayers;
if (persistMgr->getIsSaving()) {
numLayers = _layers.getSize();
persistMgr->transferSint32(TMEMBER(numLayers));
for (int i = 0; i < numLayers; i++) {
_layers[i]->persist(persistMgr);
}
} else {
numLayers = _layers.getSize();
persistMgr->transferSint32(TMEMBER(numLayers));
for (int i = 0; i < numLayers; i++) {
BaseTTFontLayer *layer = new BaseTTFontLayer;
layer->persist(persistMgr);
_layers.add(layer);
}
}
if (!persistMgr->getIsSaving()) {
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
_cachedTexts[i] = nullptr;
}
}
// initialise to defaults
if (!persistMgr->getIsSaving()) {
_fallbackFont = _font = _deletableFont = nullptr;
_lineHeight = 0;
_maxCharWidth = _maxCharHeight = 0;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseFontTT::afterLoad() {
initFont();
}
//////////////////////////////////////////////////////////////////////////
bool BaseFontTT::initFont() {
if (!_fontFile) {
return STATUS_FAILED;
}
#ifdef USE_FREETYPE2
const char *fallbackFilename;
// Handle Bold atleast for the fallback-case.
// TODO: Handle italic. (Needs a test-case)
if (_isBold) {
fallbackFilename = "LiberationSans-Bold.ttf";
} else {
fallbackFilename = "LiberationSans-Regular.ttf";
}
// Load a file, but avoid having the File-manager handle the disposal of it.
Common::SeekableReadStream *file = BaseFileManager::getEngineInstance()->openFile(_fontFile, true, false);
if (!file) {
if (Common::String(_fontFile) != "arial.ttf") {
warning("%s has no replacement font yet, using %s for now (if available)", _fontFile, fallbackFilename);
}
// Fallback1: Try to find the LiberationSans font
file = SearchMan.createReadStreamForMember(fallbackFilename);
}
if (file) {
_deletableFont = Graphics::loadTTFFont(file, DisposeAfterUse::YES, _fontHeight, Graphics::kTTFSizeModeCharacter, 96); // Use the same dpi as WME (96 vs 72).
_font = _deletableFont;
}
// Fallback2: Try load the font from the common fonts archive:
if (!_font) {
_deletableFont = Graphics::loadTTFFontFromArchive(fallbackFilename, _fontHeight, Graphics::kTTFSizeModeCharacter, 96); // Use the same dpi as WME (96 vs 72).
_font = _deletableFont;
}
#else
warning("BaseFontTT::InitFont - FreeType2-support not compiled in, TTF-fonts will not be loaded");
#endif // USE_FREETYPE2
// Fallback3: Just use the Big GUI-font. (REALLY undesirable)
if (!_font) {
_font = _fallbackFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
warning("BaseFontTT::InitFont - Couldn't load font: %s", _fontFile);
}
_lineHeight = _font->getFontHeight();
#ifdef ENABLE_FOXTAIL
if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_896, FOXTAIL_LATEST_VERSION)) {
_lineHeight -= 1;
}
#endif
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseFontTT::measureText(const WideString &text, int maxWidth, int maxHeight, int &textWidth, int &textHeight) {
//TextLineList lines;
if (maxWidth >= 0) {
Common::Array<WideString> lines;
_font->wordWrapText(text, maxWidth, lines);
Common::Array<WideString>::iterator it;
textWidth = 0;
for (it = lines.begin(); it != lines.end(); ++it) {
if (!it)
continue;
textWidth = MAX(textWidth, _font->getStringWidth(*it));
}
//WrapText(text, maxWidth, maxHeight, lines);
textHeight = (int)(lines.size() * _lineHeight);
} else {
textWidth = _font->getStringWidth(text);
textHeight = _fontHeight;
}
/*
TextLineList::iterator it;
for (it = lines.begin(); it != lines.end(); ++it) {
TextLine *line = (*it);
textWidth = MAX(textWidth, line->GetWidth());
delete line;
line = nullptr;
}*/
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,148 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_FONTTT_H
#define WINTERMUTE_BASE_FONTTT_H
#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "common/rect.h"
#include "graphics/surface.h"
#include "graphics/font.h"
#define NUM_CACHED_TEXTS 30
namespace Wintermute {
class BaseFontTT : public BaseFont {
private:
//////////////////////////////////////////////////////////////////////////
class BaseCachedTTFontText {
public:
WideString _text;
int32 _width;
TTextAlign _align;
int32 _maxHeight;
int32 _maxLength;
BaseSurface *_surface;
//int32 _priority;
int32 _textOffset;
bool _marked;
uint32 _lastUsed;
BaseCachedTTFontText() : _text() {
//_text = L"";
_width = _maxHeight = _maxLength = -1;
_align = TAL_LEFT;
_surface = nullptr;
//_priority = -1;
_textOffset = 0;
_lastUsed = 0;
_marked = false;
}
virtual ~BaseCachedTTFontText() {
if (_surface) {
delete _surface;
}
}
};
public:
//////////////////////////////////////////////////////////////////////////
class BaseTTFontLayer {
public:
BaseTTFontLayer() {
_offsetX = _offsetY = 0;
_color = 0x00000000;
}
bool persist(BasePersistenceManager *persistMgr) {
persistMgr->transferSint32(TMEMBER(_offsetX));
persistMgr->transferSint32(TMEMBER(_offsetY));
persistMgr->transferUint32(TMEMBER(_color));
return STATUS_OK;
}
int32 _offsetX;
int32 _offsetY;
uint32 _color;
};
public:
DECLARE_PERSISTENT(BaseFontTT, BaseFont)
BaseFontTT(BaseGame *inGame);
~BaseFontTT() override;
int getTextWidth(const byte *text, int maxLength = -1) override;
int getTextHeight(const byte *text, int width) override;
void drawText(const byte *text, int x, int y, int width, TTextAlign align = TAL_LEFT, int max_height = -1, int maxLength = -1) override;
int getLetterHeight() override;
bool loadBuffer(char *buffer);
bool loadFile(const char *filename);
void afterLoad() override;
void initLoop() override;
private:
bool parseLayer(BaseTTFontLayer *layer, char *buffer);
void measureText(const WideString &text, int maxWidth, int maxHeight, int &textWidth, int &textHeight);
BaseSurface *renderTextToTexture(const WideString &text, int width, TTextAlign align, int maxHeight, int &textOffset);
BaseCachedTTFontText *_cachedTexts[NUM_CACHED_TEXTS];
bool initFont();
Graphics::Font *_deletableFont;
const Graphics::Font *_font;
const Graphics::Font *_fallbackFont;
float _lineHeight;
size_t _maxCharWidth;
size_t _maxCharHeight;
private:
bool _isBold;
bool _isItalic;
bool _isUnderline;
bool _isStriked;
int32 _fontHeight;
char *_fontFile;
TTextCharset _charset;
BaseArray<BaseTTFontLayer *> _layers;
void clearCache();
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,111 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/gfx/3dcamera.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/base/gfx/3dutils.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Camera3D::Camera3D(BaseGame *inGame) : BaseNamedObject(inGame) {
_position = DXVector3(0.0f, 0.0f, 0.0f);
_target = DXVector3(0.0f, 0.0f, 0.0f);
_bank = 0.0f;
_fov = _origFov = degToRad(45.0f);
_nearClipPlane = _farClipPlane = -1.0f;
}
//////////////////////////////////////////////////////////////////////////
Camera3D::~Camera3D() {
}
//////////////////////////////////////////////////////////////////////////
bool Camera3D::getViewMatrix(DXMatrix *viewMatrix) {
DXVector3 up = DXVector3(0.0f, 1.0f, 0.0f);
if (_bank != 0) {
DXMatrix rot;
DXMatrixRotationZ(&rot, degToRad(_bank));
DXVec3TransformCoord(&up, &up, &rot);
}
DXMatrixLookAtLH(viewMatrix, &_position, &_target, &up);
return true;
}
//////////////////////////////////////////////////////////////////////////
void Camera3D::setupPos(DXVector3 pos, DXVector3 target, float bank) {
_position = pos;
_target = target;
_bank = bank;
}
//////////////////////////////////////////////////////////////////////////
void Camera3D::rotateView(float x, float y, float z) {
DXVector3 vVector; // Vector for the position/view.
// Get our view vector (The direciton we are facing)
vVector = _target - _position; // This gets the direction of the view
// Rotate the view along the desired axis
if (x) {
// Rotate the view vector up or down, then add it to our position
_target._z = (float)(_position._z + sin(x) * vVector._y + cos(x) * vVector._z);
_target._y = (float)(_position._y + cos(x) * vVector._y - sin(x) * vVector._z);
}
if (y) {
// Rotate the view vector right or left, then add it to our position
_target._z = (float)(_position._z + sin(y) * vVector._x + cos(y) * vVector._z);
_target._x = (float)(_position._x + cos(y) * vVector._x - sin(y) * vVector._z);
}
if (z) {
// Rotate the view vector diagnally right or diagnally down, then add it to our position
_target._x = (float)(_position._x + sin(z) * vVector._y + cos(z) * vVector._x);
_target._y = (float)(_position._y + cos(z) * vVector._y - sin(z) * vVector._x);
}
}
//////////////////////////////////////////////////////////////////////////
void Camera3D::move(float speed) {
DXVector3 vector; // Init a vector for our view
// Get our view vector (The direciton we are facing)
vector = _target - _position; // This gets the direction of the view
_position._x += vector._x * speed; // Add our acceleration to our position's X
_position._z += vector._z * speed; // Add our acceleration to our position's Z
_target._x += vector._x * speed; // Add our acceleration to our view's X
_target._z += vector._z * speed; // Add our acceleration to our view's Z
}
} // namespace Wintermute

View File

@@ -0,0 +1,58 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_CAMERA3D_H
#define WINTERMUTE_CAMERA3D_H
#include "common/memstream.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class Camera3D : public BaseNamedObject {
public:
void move(float speed);
void rotateView(float x, float y, float z);
void setupPos(DXVector3 pos, DXVector3 target, float bank = 0);
bool getViewMatrix(DXMatrix *viewMatrix);
Camera3D(BaseGame *inGame);
virtual ~Camera3D();
DXVector3 _position;
DXVector3 _target;
float _bank;
float _fov;
float _origFov;
float _nearClipPlane;
float _farClipPlane;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,78 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "common/crc.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/3deffect.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Effect3D::Effect3D(BaseGame *inGame) : BaseClass(inGame) {
_filename = nullptr;
_effectHash = 0xFFFFFFFF;
}
//////////////////////////////////////////////////////////////////////////
Effect3D::~Effect3D() {
SAFE_DELETE_ARRAY(_filename);
_effectHash = 0xFFFFFFFF;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3D::invalidateDeviceObjects() {
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3D::restoreDeviceObjects() {
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3D::createFromFile(const char *filename) {
uint32 size;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &size);
if (!buffer) {
return false;
}
BaseUtils::setString(&_filename, filename);
Common::CRC32 crc;
_effectHash = crc.crcFast(buffer, size);
delete[] buffer;
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,54 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_EFFECT_H
#define WINTERMUTE_3D_EFFECT_H
#include "engines/wintermute/base/base_named_object.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
class Effect3D : public BaseClass {
public:
Effect3D(BaseGame *inGame);
~Effect3D();
bool createFromFile(const char *filename);
uint32 getEffectHash() { return _effectHash; }
bool invalidateDeviceObjects();
bool restoreDeviceObjects();
const char *getFileName() { return _filename; }
private:
char *_filename;
uint32 _effectHash;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,203 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "common/crc.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/gfx/3deffect_params.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam::Effect3DParam() {
setDefaultValues();
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam::Effect3DParam(const char *paramName) {
setDefaultValues();
BaseUtils::setString(&_paramName, paramName);
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam::~Effect3DParam() {
SAFE_DELETE_ARRAY(_paramName);
SAFE_DELETE_ARRAY(_valString);
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(char *val) {
_type = EP_STRING;
BaseUtils::setString(&_valString, val);
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(int val) {
_type = EP_INT;
_valInt = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(float val) {
_type = EP_FLOAT;
_valFloat = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(bool val) {
_type = EP_BOOL;
_valBool = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(DXVector4 val) {
_type = EP_VECTOR;
_valVector = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setDefaultValues() {
_paramName = nullptr;
_valString = nullptr;
_valInt = 0;
_valFloat = 0;
_valBool = 0;
_valVector = DXVector4(0, 0, 0, 0);
_type = EP_UNKNOWN;
_initialized = false;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3DParams::Effect3DParam::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferCharPtr(TMEMBER(_paramName));
persistMgr->transferSint32(TMEMBER_INT(_type));
persistMgr->transferCharPtr(TMEMBER(_valString));
persistMgr->transferSint32(TMEMBER(_valInt));
persistMgr->transferFloat(TMEMBER(_valFloat));
persistMgr->transferVector4d(TMEMBER(_valVector));
persistMgr->transferBool(TMEMBER(_valBool));
if (!persistMgr->getIsSaving()) {
_initialized = false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParams() {
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::~Effect3DParams() {
clear();
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::clear() {
for (int32 i = 0; i < _params.getSize(); i++) {
SAFE_DELETE(_params[i]);
}
_params.removeAll();
}
//////////////////////////////////////////////////////////////////////////
bool Effect3DParams::persist(BasePersistenceManager *persistMgr) {
if (persistMgr->getIsSaving()) {
int32 numItems = _params.getSize();
persistMgr->transferSint32(TMEMBER(numItems));
for (int32 i = 0; i < numItems; i++) {
_params[i]->persist(persistMgr);
}
} else {
uint32 numItems = 0;
persistMgr->transferUint32(TMEMBER(numItems));
for (uint32 i = 0; i < numItems; i++) {
Effect3DParam *param = new Effect3DParam();
param->persist(persistMgr);
_params.add(param);
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::setParam(const char *paramName, ScValue *val) {
Effect3DParam *param = getParamByName(paramName);
switch (val->getType()) {
case VAL_INT:
param->setValue(val->getInt());
break;
case VAL_FLOAT:
param->setValue((float)val->getFloat());
break;
case VAL_BOOL:
param->setValue(val->getBool());
break;
default:
param->setValue(val->getString());
}
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::setParam(const char *paramName, DXVector4 val) {
Effect3DParam *param = getParamByName(paramName);
param->setValue(val);
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam *Effect3DParams::getParamByName(const char *paramName) {
Effect3DParam *param = nullptr;
for (int32 i = 0; i < _params.getSize(); i++) {
if (_params[i]->getParamName() && strcmp(paramName, _params[i]->getParamName()) == 0) {
param = _params[i];
break;
}
}
if (!param) {
param = new Effect3DParam(paramName);
_params.add(param);
}
return param;
}
} // namespace Wintermute

View File

@@ -0,0 +1,96 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_EFFECT_PARAMS_H
#define WINTERMUTE_3D_EFFECT_PARAMS_H
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
class Effect3DParams {
public:
//////////////////////////////////////////////////////////////////////////
class Effect3DParam {
public:
enum ParamType {
EP_UNKNOWN,
EP_STRING,
EP_FLOAT,
EP_INT,
EP_BOOL,
EP_VECTOR
};
Effect3DParam();
Effect3DParam(const char *paramName);
~Effect3DParam();
void setValue(char *val);
void setValue(int val);
void setValue(float val);
void setValue(bool val);
void setValue(DXVector4 val);
const char *getParamName() const { return _paramName; }
bool persist(BasePersistenceManager *persistMgr);
private:
void setDefaultValues();
ParamType _type;
char * _paramName;
bool _initialized;
char *_valString;
int32 _valInt;
float _valFloat;
DXVector4 _valVector;
bool _valBool;
};
//////////////////////////////////////////////////////////////////////////
Effect3DParams();
~Effect3DParams();
bool persist(BasePersistenceManager *persistMgr);
void clear();
void setParam(const char *paramName, ScValue *val);
void setParam(const char *paramName, DXVector4 Val);
private:
Effect3DParam *getParamByName(const char *paramName);
BaseArray<Effect3DParam *> _params;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,49 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/gfx/3dface.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Face3D::Face3D() {
for (int i = 0; i < 3; i++) {
_normals[i] = DXVector3(0, 0, 0);
_vertices[i] = 0;
}
}
//////////////////////////////////////////////////////////////////////////
Face3D::~Face3D() {
}
} // namespace Wintermute

View File

@@ -0,0 +1,45 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_FACE_H
#define WINTERMUTE_3D_FACE_H
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class Face3D {
public:
uint16 _vertices[3];
DXVector3 _normals[3];
Face3D();
virtual ~Face3D();
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,89 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/3dlight.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/math/math_util.h"
#include "engines/wintermute/wintypes.h"
#include "graphics/opengl/system_headers.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Light3D::Light3D(BaseGame *inGame) : BaseScriptable(inGame, false, false) {
_diffuseColor = BYTETORGBA(255, 255, 255, 255);
_pos = DXVector3(0, 0, 0);
_target = DXVector3(0, 0, 0);
_isSpotlight = false;
_falloff = 0;
_active = true;
_distance = 0.0f;
_isAvailable = false;
}
//////////////////////////////////////////////////////////////////////////
Light3D::~Light3D() {
}
//////////////////////////////////////////////////////////////////////////
bool Light3D::setLight(int index) {
DXVector4 diffuse;
diffuse._x = RGBCOLGetR(_diffuseColor) / 256.0f;
diffuse._y = RGBCOLGetG(_diffuseColor) / 256.0f;
diffuse._z = RGBCOLGetB(_diffuseColor) / 256.0f;
diffuse._w = 1.0f;
DXVector3 dir = _target - _pos;
DXVec3Normalize(&dir, &dir);
_game->_renderer3D->setLightParameters(index, _pos, dir, diffuse, _isSpotlight);
if (_active) {
_game->_renderer3D->lightEnable(index, true);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Light3D::getViewMatrix(DXMatrix *viewMatrix) {
DXVector3 up = DXVector3(0.0f, 1.0f, 0.0f);
DXMatrixLookAtLH(viewMatrix, &_pos, &_target, &up);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Light3D::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_active));
persistMgr->transferUint32(TMEMBER(_diffuseColor));
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,59 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_LIGHT_H
#define WINTERMUTE_3D_LIGHT_H
#include "common/memstream.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class Light3D : public BaseScriptable {
public:
bool persist(BasePersistenceManager *persistMgr);
bool getViewMatrix(DXMatrix *viewMatrix);
Light3D(BaseGame *inGame);
virtual ~Light3D();
uint32 _diffuseColor;
DXVector3 _pos;
DXVector3 _target;
bool _isSpotlight;
bool _active;
float _falloff;
float _distance;
bool _isAvailable;
bool setLight(int index = 0);
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,525 @@
/* 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 "engines/wintermute/dcgf.h"
#include "engines/wintermute/math/math_util.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/base/gfx/3dface.h"
#include "engines/wintermute/base/gfx/3dvertex.h"
#include "engines/wintermute/base/gfx/3dutils.h"
namespace Wintermute {
#define MAIN3DS 0x4D4D // level 1
#define EDIT3DS 0x3D3D // level 1
#define NAMED_OBJECT 0x4000 // level 2
#define TRIANGLE_MESH 0x4100 // level 3
#define TRIANGLE_VERTEXLIST 0x4110 // level 4
#define TRIANGLE_FACELIST 0x4120 // level 4
#define CHUNK_CAMERA 0x4700 // level 3
#define CHUNK_LIGHT 0x4600
#define LIGHT_SPOTLIGHT 0x4610
#define LIGHT_IS_OFF 0x4620
#define RGB_FLOAT 0x0010
#define RGB_BYTE 0x0011
#define KEYFRAMER 0xB000 // level 1
#define KEYFRAMER_AMBIENT_INFO 0xB001
#define KEYFRAMER_MESH_INFO 0xB002
#define KEYFRAMER_CAMERA_INFO 0xB003
#define KEYFRAMER_CAMERA_TARGET_INFO 0xB004
#define KEYFRAMER_OMNI_INFO 0xB005
#define KEYFRAMER_SPOT_TARGET_INFO 0xB006
#define KEYFRAMER_SPOT_INFO 0xB007
#define NODE_HDR 0xB010
#define ROLL_TRACK_TAG 0xB024
//////////////////////////////////////////////////////////////////////////
Loader3DS::Loader3DS(BaseGame *inGame) : BaseNamedObject(inGame) {
_filename = nullptr;
}
//////////////////////////////////////////////////////////////////////////
Loader3DS::~Loader3DS() {
for (int32 i = 0; i < _objects.getSize(); i++)
delete _objects[i];
_objects.removeAll();
SAFE_DELETE_ARRAY(_filename);
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
Loader3DS::FileObject3DS::FileObject3DS() {
_name = nullptr;
_type = OBJ_3DS_NONE;
_numVertices = 0;
_vertices = nullptr;
_numFaces = 0;
_faces = nullptr;
_lightOff = false;
_lightSpotlight = false;
_lightColor = 0;
_lightHotspot = false;
_lightFalloff = false;
_lightTarget._x = _lightTarget._y = _lightTarget._z = 0.0f;
_lightPos._x = _lightPos._y = _lightPos._z = 0.0f;
_cameraBank = 0;
_cameraLens = 0;
_cameraFOV = 0;
_cameraPos._x = _cameraPos._y = _cameraPos._z = 0.0f;
_hidden = false;
}
//////////////////////////////////////////////////////////////////////
Loader3DS::FileObject3DS::~FileObject3DS() {
if (_name != nullptr)
delete[] _name;
if (_vertices != nullptr)
delete[] _vertices;
if (_faces != nullptr)
delete[] _faces;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::parseFile(const char *filename) {
SAFE_DELETE_ARRAY(_filename);
size_t filenameSize = strlen(filename) + 1;
_filename = new char[filenameSize];
Common::strcpy_s(_filename, filenameSize, filename);
uint32 fileSize;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &fileSize);
if (!buffer)
return false;
uint16 keyframerSection = 0;
char *keyframerObject = nullptr;
FileObject3DS *obj = nullptr;
uint16 i;
Common::MemoryReadStream fileStream(buffer, fileSize);
while (fileStream.pos() < fileStream.size()) {
uint16 chunkId = fileStream.readUint16LE();
uint32 chunkLength = fileStream.readUint32LE();
bool handled = true;
switch (chunkId) {
case MAIN3DS:
break;
case EDIT3DS:
break;
//////////////////////////////////////////////////////////////////////
// object ////////////////////////////////////////////////////////////
case NAMED_OBJECT: {
obj = new FileObject3DS;
auto name = fileStream.readString();
size_t nameSize = name.size() + 1;
obj->_name = new char[nameSize];
Common::strcpy_s(obj->_name, nameSize, name.c_str());
_objects.add(obj);
}
break;
// mesh //////////////////////////////////////////////////////////////
case TRIANGLE_MESH:
if (obj == nullptr)
break;
obj->_type = OBJ_3DS_MESH;
break;
case TRIANGLE_VERTEXLIST:
if (obj == nullptr || obj->_type != OBJ_3DS_MESH)
break;
obj->_numVertices = fileStream.readUint16LE();
obj->_vertices = new DXVector3[obj->_numVertices];
for (i = 0; i < obj->_numVertices; i++) {
obj->_vertices[i]._x = fileStream.readFloatLE();
obj->_vertices[i]._z = fileStream.readFloatLE();
obj->_vertices[i]._y = fileStream.readFloatLE();
}
break;
case TRIANGLE_FACELIST:
if (obj == nullptr || obj->_type != OBJ_3DS_MESH)
break;
obj->_numFaces = fileStream.readUint16LE();
obj->_faces = new SFace[obj->_numFaces];
for (i = 0; i < obj->_numFaces; i++) {
obj->_faces[i]._a = fileStream.readUint16LE();
obj->_faces[i]._c = fileStream.readUint16LE();
obj->_faces[i]._b = fileStream.readUint16LE();
fileStream.readUint16LE(); // skip
}
break;
// camera //////////////////////////////////////////////////////////////
case CHUNK_CAMERA:
if (obj == nullptr)
break;
obj->_type = OBJ_3DS_CAMERA;
obj->_cameraPos._x = fileStream.readFloatLE();
obj->_cameraPos._z = fileStream.readFloatLE();
obj->_cameraPos._y = fileStream.readFloatLE();
obj->_cameraTarget._x = fileStream.readFloatLE();
obj->_cameraTarget._z = fileStream.readFloatLE();
obj->_cameraTarget._y = fileStream.readFloatLE();
obj->_cameraBank = fileStream.readFloatLE();
obj->_cameraLens = fileStream.readFloatLE();
if (obj->_cameraLens > 0)
obj->_cameraFOV = 1900.0f / obj->_cameraLens;
else
obj->_cameraFOV = 45.0f;
break;
// light //////////////////////////////////////////////////////////////
case CHUNK_LIGHT:
if (obj == nullptr)
break;
obj->_type = OBJ_3DS_LIGHT;
obj->_lightPos._x = fileStream.readFloatLE();
obj->_lightPos._z = fileStream.readFloatLE();
obj->_lightPos._y = fileStream.readFloatLE();
break;
case LIGHT_SPOTLIGHT:
if (obj == nullptr || obj->_type != OBJ_3DS_LIGHT)
break;
obj->_lightTarget._x = fileStream.readFloatLE();
obj->_lightTarget._z = fileStream.readFloatLE();
obj->_lightTarget._y = fileStream.readFloatLE();
obj->_lightHotspot = fileStream.readFloatLE();
obj->_lightFalloff = fileStream.readFloatLE();
obj->_lightSpotlight = true;
break;
case LIGHT_IS_OFF:
if (obj == nullptr || obj->_type != OBJ_3DS_LIGHT)
break;
obj->_lightOff = true;
break;
// colors ////////////////////////////////////////////////////////////////////////
case RGB_FLOAT:
if (obj && obj->_type == OBJ_3DS_LIGHT) {
float r, g, b;
r = fileStream.readFloatLE();
g = fileStream.readFloatLE();
b = fileStream.readFloatLE();
obj->_lightColor = BYTETORGBA((int)(r * 255), (int)(g * 255), (int)(b * 255), 255);
} else
handled = false;
break;
case RGB_BYTE:
if (obj && obj->_type == OBJ_3DS_LIGHT) {
byte r, g, b;
r = fileStream.readByte();
g = fileStream.readByte();
b = fileStream.readByte();
obj->_lightColor = BYTETORGBA(r, g, b, 255);
} else
handled = false;
break;
// keyframer stuff
case KEYFRAMER:
break;
case KEYFRAMER_AMBIENT_INFO:
case KEYFRAMER_MESH_INFO:
case KEYFRAMER_CAMERA_INFO:
case KEYFRAMER_CAMERA_TARGET_INFO:
case KEYFRAMER_OMNI_INFO:
case KEYFRAMER_SPOT_TARGET_INFO:
case KEYFRAMER_SPOT_INFO:
keyframerSection = chunkId;
break;
case NODE_HDR: {
// object name
SAFE_DELETE_ARRAY(keyframerObject);
auto keyname = fileStream.readString();
size_t keynameSize = keyname.size() + 1;
keyframerObject = new char[keynameSize];
Common::strcpy_s(keyframerObject, keynameSize, keyname.c_str());
// flags1
fileStream.readUint16LE();
// flags2
fileStream.readUint16LE();
// hierarchy
fileStream.readUint16LE();
}
break;
case ROLL_TRACK_TAG:
if (keyframerSection == KEYFRAMER_CAMERA_INFO && keyframerObject != nullptr) {
// flags
fileStream.readUint16LE();
// unknown
fileStream.readUint16LE();
fileStream.readUint16LE();
fileStream.readUint16LE();
fileStream.readUint16LE();
// keys
uint16 keys = fileStream.readUint16LE();
// unknown
fileStream.readUint16LE();
for (uint16 key = 0; key < keys; key++) {
// frame number
fileStream.readUint16LE();
// unknown
fileStream.readUint32LE();
// camera roll
float cameraRoll = fileStream.readFloatLE();
// inject this roll value to the camera
if (key == 0) {
for (int32 index = 0; index < _objects.getSize(); index++) {
if (_objects[index]->_type == OBJ_3DS_CAMERA && scumm_stricmp(_objects[index]->_name, keyframerObject) == 0) {
_objects[index]->_cameraBank = cameraRoll;
break;
}
}
}
}
} else
handled = false;
break;
default:
handled = false;
}
if (!handled)
fileStream.seek(chunkLength - 6, SEEK_CUR);
}
SAFE_DELETE_ARRAY(keyframerObject);
delete[] buffer;
return true;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int32 Loader3DS::getNumMeshes() {
int32 ret = 0;
for (int32 i = 0; i < _objects.getSize(); i++)
if (_objects[i]->_type == OBJ_3DS_MESH)
ret++;
return ret;
}
//////////////////////////////////////////////////////////////////////////
char *Loader3DS::getMeshName(int index) {
int32 pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_MESH)
pos++;
if (pos == index)
return _objects[i]->_name;
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::loadMesh(int index, Mesh3DS *mesh) {
if (!mesh)
return false;
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_MESH)
pos++;
if (pos == index){
FileObject3DS *obj = _objects[i];
mesh->cleanup();
mesh->_numVertices = obj->_numVertices;
mesh->_numFaces = obj->_numFaces;
int j;
mesh->_vertices = new Vertex3D[mesh->_numVertices];
for (j = 0; j < mesh->_numVertices; j++) {
mesh->_vertices[j]._pos._x = obj->_vertices[j]._x;
mesh->_vertices[j]._pos._y = obj->_vertices[j]._y;
mesh->_vertices[j]._pos._z = obj->_vertices[j]._z;
}
mesh->_faces = new Face3D[mesh->_numFaces];
for (j = 0; j < mesh->_numFaces; j++) {
mesh->_faces[j]._vertices[0] = obj->_faces[j]._a;
mesh->_faces[j]._vertices[1] = obj->_faces[j]._b;
mesh->_faces[j]._vertices[2] = obj->_faces[j]._c;
}
mesh->setName(obj->_name);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int32 Loader3DS::getNumLights() {
int ret = 0;
for (int32 i = 0; i < _objects.getSize(); i++)
if (_objects[i]->_type == OBJ_3DS_LIGHT)
ret++;
return ret;
}
//////////////////////////////////////////////////////////////////////////
char *Loader3DS::getLightName(int index) {
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_LIGHT)
pos++;
if (pos == index)
return _objects[i]->_name;
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::loadLight(int index, Light3D *light) {
if (!light)
return false;
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_LIGHT) {
pos++;
if (pos == index) {
light->setName(_objects[i]->_name);
light->_pos = _objects[i]->_lightPos;
light->_target = _objects[i]->_lightTarget;
light->_isSpotlight = _objects[i]->_lightSpotlight;
light->_active = !_objects[i]->_lightOff;
light->_diffuseColor = _objects[i]->_lightColor;
light->_falloff = _objects[i]->_lightFalloff;
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int32 Loader3DS::getNumCameras() {
int32 ret = 0;
for (int32 i = 0; i < _objects.getSize(); i++)
if (_objects[i]->_type == OBJ_3DS_CAMERA)
ret++;
return ret;
}
//////////////////////////////////////////////////////////////////////////
char *Loader3DS::getCameraName(int index) {
int32 pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_CAMERA)
pos++;
if (pos == index)
return _objects[i]->_name;
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::loadCamera(int index, Camera3D *camera) {
if (!camera)
return false;
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_CAMERA)
pos++;
if (pos == index) {
camera->setupPos(_objects[i]->_cameraPos, _objects[i]->_cameraTarget, _objects[i]->_cameraBank);
camera->setName(_objects[i]->_name);
camera->_fov = camera->_origFov = degToRad(_objects[i]->_cameraFOV);
return true;
}
}
return false;
}
} // namespace Wintermute

View File

@@ -0,0 +1,94 @@
/* 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 WINTERMUTE_3D_LOADER_3DS_H
#define WINTERMUTE_3D_LOADER_3DS_H
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/3dcamera.h"
#include "engines/wintermute/base/gfx/3dlight.h"
#include "engines/wintermute/base/gfx/3dmesh.h"
#include "common/str.h"
namespace Wintermute {
class Loader3DS : public BaseNamedObject {
public:
enum E3DSFileObjectType{
OBJ_3DS_NONE,
OBJ_3DS_MESH,
OBJ_3DS_CAMERA,
OBJ_3DS_LIGHT
};
struct SFace{
uint16 _a;
uint16 _b;
uint16 _c;
};
class FileObject3DS {
public:
DXVector3 _cameraTarget;
float _cameraBank;
float _cameraLens;
float _cameraFOV;
DXVector3 _cameraPos;
DXVector3 _lightTarget;
DXVector3 _lightPos;
uint32 _lightColor;
float _lightHotspot;
float _lightFalloff;
bool _lightOff;
bool _lightSpotlight;
bool _hidden;
uint16 _numFaces;
SFace *_faces;
DXVector3 *_vertices;
uint16 _numVertices;
char *_name;
E3DSFileObjectType _type;
virtual ~FileObject3DS();
FileObject3DS();
};
public:
char * getCameraName(int index);
char * getLightName(int index);
char * getMeshName(int index);
bool loadCamera(int index, Camera3D *camera);
int32 getNumCameras();
bool loadLight(int index, Light3D *light);
int32 getNumLights();
bool loadMesh(int index, Mesh3DS *mesh);
int32 getNumMeshes();
bool parseFile(const char *filename);
char *_filename;
Loader3DS(BaseGame *inGame);
virtual ~Loader3DS();
BaseArray<FileObject3DS *> _objects;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,172 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "common/file.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/base/gfx/3dmesh.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Mesh3DS::Mesh3DS(BaseGame *inGame) : BaseNamedObject(inGame) {
_vertices = nullptr;
_faces = nullptr;
_numFaces = _numVertices = 0;
_visible = true;
}
//////////////////////////////////////////////////////////////////////////
Mesh3DS::~Mesh3DS() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void Mesh3DS::cleanup() {
SAFE_DELETE_ARRAY(_vertices);
_numVertices = 0;
SAFE_DELETE_ARRAY(_faces);
_numFaces = 0;
_vb.free();
}
//////////////////////////////////////////////////////////////////////////
bool Mesh3DS::createVertexBuffer() {
_vb.free();
if (_numFaces == 0)
return true;
int vbSize = _numFaces * sizeof(Mesh3DSVertex) * 3;
_vb = DXBuffer(vbSize);
if (_vb.ptr() == nullptr) {
_game->LOG(0, "Error creating vertex buffer.");
return false;
} else
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Mesh3DS::fillVertexBuffer(uint32 color) {
_vb.free();
if (_numFaces == 0)
return true;
int vbSize = _numFaces * sizeof(Mesh3DSVertex) * 3;
_vb = DXBuffer(vbSize);
if (_vb.ptr() == nullptr) {
_game->LOG(0, "Error creating vertex buffer.");
return false;
}
Mesh3DSVertex *verts = (Mesh3DSVertex *)_vb.ptr();
for (int i = 0; i < _numFaces; i++) {
for (int j = 0; j < 3; j++) {
int outVert = i * 3 + j;
int vertex = _faces[i]._vertices[j];
verts[outVert]._x = _vertices[vertex]._pos._x;
verts[outVert]._y = _vertices[vertex]._pos._y;
verts[outVert]._z = _vertices[vertex]._pos._z;
verts[outVert]._nx = _faces[i]._normals[j]._x;
verts[outVert]._ny = _faces[i]._normals[j]._y;
verts[outVert]._nz = _faces[i]._normals[j]._z;
verts[outVert]._r = RGBCOLGetR(color) / 255.0f;
verts[outVert]._g = RGBCOLGetG(color) / 255.0f;
verts[outVert]._b = RGBCOLGetB(color) / 255.0f;
verts[outVert]._a = RGBCOLGetA(color) / 255.0f;
}
}
fillVertexBuffer();
return true;
}
//////////////////////////////////////////////////////////////////////////
void Mesh3DS::computeNormals() {
DXVector3 *normals = new DXVector3[_numVertices];
for (uint32 i = 0; i < _numVertices; i++) {
normals[i]._x = 0.0f;
normals[i]._y = 0.0f;
normals[i]._z = 0.0f;
}
for (uint32 i = 0; i < _numFaces; i++) {
uint16 a = _faces[i]._vertices[0];
uint16 b = _faces[i]._vertices[1];
uint16 c = _faces[i]._vertices[2];
DXVector3 *v1 = &_vertices[a]._pos;
DXVector3 *v2 = &_vertices[b]._pos;
DXVector3 *v3 = &_vertices[c]._pos;
DXVector3 edge1 = *v2 - *v1;
DXVector3 edge2 = *v3 - *v2;
DXVector3 normal;
DXVec3Cross(&normal, &edge1, &edge2);
DXVec3Normalize(&normal, &normal);
normals[a] += normal;
normals[b] += normal;
normals[c] += normal;
}
// Assign the newly computed normals back to the vertices
for (uint32 i = 0; i < _numFaces; i++) {
for (uint32 j = 0; j < 3; j++) {
DXVec3Normalize(&_faces[i]._normals[j], &normals[_faces[i]._vertices[j]]);
//_faces[i]._normals[j] = normals[_faces[i]._vertices[j]];
}
}
delete[] normals;
}
//////////////////////////////////////////////////////////////////////////
bool Mesh3DS::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_visible));
return true;
}
} // namespace Wintermute

View 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_MESH_H
#define WINTERMUTE_3D_MESH_H
#include "common/memstream.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/wintermute/base/gfx/xbuffer.h"
#include "engines/wintermute/base/gfx/3dface.h"
#include "engines/wintermute/base/gfx/3dvertex.h"
namespace Wintermute {
#if defined(SCUMMVM_USE_PRAGMA_PACK)
#pragma pack(4)
#endif
struct Mesh3DSVertex {
float _x, _y, _z;
float _nx, _ny, _nz;
float _r, _g, _b, _a;
};
#if defined(SCUMMVM_USE_PRAGMA_PACK)
#pragma pack()
#endif
class Mesh3DS : public BaseNamedObject {
public:
bool persist(BasePersistenceManager *persistMgr);
bool createVertexBuffer();
void computeNormals();
void cleanup();
Mesh3DS(BaseGame *inGame);
virtual ~Mesh3DS();
virtual void fillVertexBuffer() = 0;
bool fillVertexBuffer(uint32 color);
virtual void render(bool color = false) = 0;
Face3D *_faces;
uint16 _numFaces;
uint16 _numVertices;
Vertex3D *_vertices;
DXBuffer _vb;
bool _visible;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,176 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
#include "engines/wintermute/base/gfx/xskinmesh.h"
#include "engines/wintermute/dcgf.h"
#include "graphics/opengl/system_headers.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
ShadowVolume::ShadowVolume(BaseGame *inGame) : BaseClass(inGame), _color(0x7f000000) {
}
//////////////////////////////////////////////////////////////////////////
ShadowVolume::~ShadowVolume() {
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolume::reset() {
_vertices.removeAll();
return true;
}
//////////////////////////////////////////////////////////////////////////^M
bool ShadowVolume::addMesh(DXMesh *mesh, uint32 *adjacency, DXMatrix *modelMat, DXVector3 *light, float extrusionDepth) {
if (!mesh || !adjacency)
return false;
DXVector3 invLight;
DXMatrix matInverseModel;
DXMatrixInverse(&matInverseModel, nullptr, modelMat);
DXVec3TransformNormal(&invLight, light, &matInverseModel);
float *points = (float *)mesh->getVertexBuffer().ptr();
if (points == nullptr) {
return false;
}
uint32 *indices = (uint32 *)mesh->getIndexBuffer().ptr();
if (indices == nullptr) {
return false;
}
uint32 numFaces = mesh->getNumFaces();
// Allocate a temporary edge list
uint32 *edges = new uint32[numFaces * 6];
if (edges == nullptr) {
return false;
}
uint32 numEdges = 0;
uint32 fvfSize = DXGetFVFVertexSize(mesh->getFVF()) / sizeof(float);
bool *isFront = new bool[numFaces];
// First pass : for each face, record if it is front or back facing the light
for (uint32 i = 0; i < numFaces; i++) {
uint32 index0 = indices[3 * i + 0];
uint32 index1 = indices[3 * i + 1];
uint32 index2 = indices[3 * i + 2];
DXVector3 v0(points + index0 * fvfSize);
DXVector3 v1(points + index1 * fvfSize);
DXVector3 v2(points + index2 * fvfSize);
// Transform vertices or transform light?
DXVector3 vNormal, vec1, vec2;
vec1 = v2 - v1;
vec2 = v1 - v0;
DXVec3Cross(&vNormal, &vec1, &vec2);
if (DXVec3Dot(&vNormal, &invLight) >= 0.0f) {
isFront[i] = false; // back face
} else {
isFront[i] = true; // front face
}
}
// First pass : for each face, record if it is front or back facing the light
for (uint32 i = 0; i < numFaces; i++) {
if (isFront[i]) {
uint32 wFace0 = indices[3 * i + 0];
uint32 wFace1 = indices[3 * i + 1];
uint32 wFace2 = indices[3 * i + 2];
uint32 adjacent0 = adjacency[3 * i + 0];
uint32 adjacent1 = adjacency[3 * i + 1];
uint32 adjacent2 = adjacency[3 * i + 2];
if (adjacent0 == 0xFFFFFFFF || isFront[adjacent0] == false) {
// add edge v0-v1
edges[2 * numEdges + 0] = wFace0;
edges[2 * numEdges + 1] = wFace1;
numEdges++;
}
if (adjacent1 == 0xFFFFFFFF || isFront[adjacent1] == false) {
// add edge v1-v2
edges[2 * numEdges + 0] = wFace1;
edges[2 * numEdges + 1] = wFace2;
numEdges++;
}
if (adjacent2 == 0xFFFFFFFF || isFront[adjacent2] == false) {
// add edge v2-v0
edges[2 * numEdges + 0] = wFace2;
edges[2 * numEdges + 1] = wFace0;
numEdges++;
}
}
}
for (uint32 i = 0; i < numEdges; i++) {
DXVector3 v1(points + edges[2 * i + 0] * fvfSize);
DXVector3 v2(points + edges[2 * i + 1] * fvfSize);
DXVector3 v3 = v1 - invLight * extrusionDepth;
DXVector3 v4 = v2 - invLight * extrusionDepth;
// Add a quad (two triangles) to the vertex list
addVertex(v1);
addVertex(v2);
addVertex(v3);
addVertex(v2);
addVertex(v4);
addVertex(v3);
}
// Delete the temporary edge list
delete[] edges;
delete[] isFront;
return true;
}
//////////////////////////////////////////////////////////////////////////
void ShadowVolume::addVertex(DXVector3 &vertex) {
_vertices.add(vertex);
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolume::setColor(uint32 color) {
if (color != _color) {
_color = color;
return initMask();
} else {
return true;
}
}
} // namespace Wintermute

View File

@@ -0,0 +1,73 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_SHADOW_VOLUME_H
#define WINTERMUTE_3D_SHADOW_VOLUME_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/gfx/xbuffer.h"
#include "engines/wintermute/base/gfx/xmesh.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/wintermute/coll_templ.h"
namespace Wintermute {
struct ShadowVertex {
float x;
float y;
float z;
uint8 r;
uint8 g;
uint8 b;
uint8 a;
};
class ShadowVolume : public BaseClass {
public:
ShadowVolume(BaseGame *inGame);
virtual ~ShadowVolume();
bool addMesh(DXMesh *mesh, uint32 *adjacency, DXMatrix *modelMat, DXVector3 *light, float extrusionDepth);
void addVertex(DXVector3 &vertex);
bool reset();
virtual bool renderToStencilBuffer() = 0;
virtual bool renderToScene() = 0;
bool setColor(uint32 color);
protected:
BaseArray<DXVector3> _vertices; // Vertex data for rendering shadow volume
uint32 _color;
private:
virtual bool initMask() = 0;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,188 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/gfx/3dutils.h"
#include "common/scummsys.h"
#ifdef ENABLE_WME3D
#include "common/util.h"
#endif
namespace Wintermute {
#ifdef ENABLE_WME3D
bool C3DUtils::intersectTriangle(const DXVector3 &orig, const DXVector3 &dir,
DXVector3 &v0, DXVector3 &v1, DXVector3 &v2,
float *t, float *u, float *v) {
// Find vectors for two edges sharing vert0
DXVector3 edge1 = v1 - v0;
DXVector3 edge2 = v2 - v0;
// Begin calculating determinant - also used to calculate U parameter
DXVector3 pvec;
DXVec3Cross(&pvec, &dir, &edge2);
// If determinant is near zero, ray lies in plane of triangle
float det = DXVec3Dot(&edge1, &pvec);
if (det < 0.0001f)
return false;
// Calculate distance from vert0 to ray origin
DXVector3 tvec = orig - v0;
// Calculate U parameter and test bounds
*u = DXVec3Dot(&tvec, &pvec);
if (*u < 0.0f || *u > det)
return false;
// Prepare to test V parameter
DXVector3 qvec;
DXVec3Cross(&qvec, &tvec, &edge1);
// Calculate V parameter and test bounds
*v = DXVec3Dot(&dir, &qvec);
if (*v < 0.0f || *u + *v > det)
return false;
// Calculate t, scale parameters, ray intersects triangle
*t = DXVec3Dot(&edge2, &qvec);
float fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
DXVector3 intersection;
DXVector3 dest = orig + dir;
DXPlane plane;
DXPlaneFromPoints(&plane, &v0, &v1, &v2);
DXPlaneIntersectLine(&intersection, &plane, &orig, &dest);
*t = intersection._x;
*u = intersection._y;
*v = intersection._z;
return true;
}
DXMatrix *C3DUtils::matrixSetTranslation(DXMatrix *mat, DXVector3 *vec) {
mat->matrix._41 = vec->_x;
mat->matrix._42 = vec->_y;
mat->matrix._43 = vec->_z;
return mat;
}
DXMatrix *C3DUtils::matrixSetRotation(DXMatrix *mat, DXVector3 *vec) {
double cr = cos(vec->_x);
double sr = sin(vec->_x);
double cp = cos(vec->_y);
double sp = sin(vec->_y);
double cy = cos(vec->_z);
double sy = sin(vec->_z);
mat->matrix._11 = (float)(cp * cy);
mat->matrix._12 = (float)(cp * sy);
mat->matrix._13 = (float)(-sp);
double srsp = sr * sp;
double crsp = cr * sp;
mat->matrix._21 = (float)(srsp * cy - cr * sy);
mat->matrix._22 = (float)(srsp * sy + cr * cy);
mat->matrix._23 = (float)(sr * cp);
mat->matrix._31 = (float)(crsp * cy + sr * sy);
mat->matrix._32 = (float)(crsp * sy - sr * cy);
mat->matrix._33 = (float)(cr * cp);
return mat;
}
bool C3DUtils::pickGetIntersect(DXVector3 lineStart, DXVector3 lineEnd,
DXVector3 v0, DXVector3 v1, DXVector3 v2,
DXVector3 *intersection, float *distance) {
// compute plane's normal
DXVector3 vertex;
DXVector3 normal;
DXVector3 edge1 = v1 - v0;
DXVector3 edge2 = v2 - v1;
DXVec3Cross(&normal, &edge1, &edge2);
DXVec3Normalize(&normal, &normal);
vertex = v0;
DXVector3 direction, l1;
float lineLength, distFromPlane, percentage;
direction._x = lineEnd._x - lineStart._x; // calculate the lines direction vector
direction._y = lineEnd._y - lineStart._y;
direction._z = lineEnd._z - lineStart._z;
lineLength = DXVec3Dot(&direction, &normal); // This gives us the line length (the blue dot L3 + L4 in figure d)
if (fabsf(lineLength) < 0.00001f)
return false;
l1._x = vertex._x - lineStart._x; // calculate vector L1 (the PINK line in figure d)
l1._y = vertex._y - lineStart._y;
l1._z = vertex._z - lineStart._z;
distFromPlane = DXVec3Dot(&l1, &normal); // gives the distance from the plane (ORANGE Line L3 in figure d)
percentage = distFromPlane / lineLength; // How far from Linestart , intersection is as a percentage of 0 to 1
if (percentage < 0.0)
return false;
else if (percentage > 1.0)
return false;
*distance = percentage; //record the distance from beginning of ray (0.0 -1.0)
intersection->_x = lineStart._x + direction._x * percentage; // add the percentage of the line to line start
intersection->_y = lineStart._y + direction._y * percentage;
intersection->_z = lineStart._z + direction._z * percentage;
return true;
}
void C3DUtils::decomposeMatrixSimple(const DXMatrix *mat, DXVector3 *transVec, DXVector3 *scaleVec, DXQuaternion *rotQ) {
*transVec = DXVector3(mat->matrix._41, mat->matrix._42, mat->matrix._43);
*scaleVec = DXVector3(sqrtf(mat->matrix._11 * mat->matrix._11 + mat->matrix._21 * mat->matrix._21 + mat->matrix._31 * mat->matrix._31),
sqrtf(mat->matrix._12 * mat->matrix._12 + mat->matrix._22 * mat->matrix._22 + mat->matrix._32 * mat->matrix._32),
sqrtf(mat->matrix._13 * mat->matrix._13 + mat->matrix._23 * mat->matrix._23 + mat->matrix._33 * mat->matrix._33));
DXQuaternion q;
DXQuaternionRotationMatrix(&q, mat);
*rotQ = q;
}
#endif
} // End of namespace Wintermute

View File

@@ -0,0 +1,57 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3DUTILS_H
#define WINTERMUTE_3DUTILS_H
#ifdef ENABLE_WME3D
#include "engines/wintermute/base/gfx/xmath.h"
#endif
namespace Wintermute {
#define DX_PI ((float)3.141592654f)
#define degToRad(_val) (_val * DX_PI * (1.0f / 180.0f))
#define radToDeg(_val) (_val * (180.0f / DX_PI))
class C3DUtils {
public:
static bool intersectTriangle(const DXVector3 &orig, const DXVector3 &dir,
DXVector3 &v0, DXVector3 &v1, DXVector3 &v2,
float *t, float *u, float *v);
static bool pickGetIntersect(DXVector3 linestart, DXVector3 lineend,
DXVector3 v0, DXVector3 v1, DXVector3 v2,
DXVector3 *intersection, float *distance);
static DXMatrix *matrixSetTranslation(DXMatrix *mat, DXVector3 *vec);
static DXMatrix *matrixSetRotation(DXMatrix *mat, DXVector3 *vec);
static void decomposeMatrixSimple(const DXMatrix *mat, DXVector3 *transVec,
DXVector3 *scaleVec, DXQuaternion *rotQ);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,46 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/base/gfx/3dvertex.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Vertex3D::Vertex3D() {
_pos = DXVector3(0, 0, 0);
}
//////////////////////////////////////////////////////////////////////////
Vertex3D::~Vertex3D() {
}
} // namespace Wintermute

View File

@@ -0,0 +1,44 @@
/* 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 file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#ifndef WINTERMUTE_3D_VERTEX_H
#define WINTERMUTE_3D_VERTEX_H
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class Vertex3D {
public:
DXVector3 _pos;
Vertex3D();
virtual ~Vertex3D();
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,296 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/file/base_savefile_manager_file.h"
#include "graphics/surface.h"
#include "image/png.h"
#include "image/jpeg.h"
#include "image/bmp.h"
#include "image/tga.h"
#include "common/textconsole.h"
#include "common/stream.h"
#include "common/system.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseImage::BaseImage() {
_fileManager = BaseFileManager::getEngineInstance();
_palette = nullptr;
_paletteCount = 0;
_surface = nullptr;
_decoder = nullptr;
_deletableSurface = nullptr;
}
//////////////////////////////////////////////////////////////////////
BaseImage::~BaseImage() {
delete _decoder;
if (_deletableSurface) {
_deletableSurface->free();
}
delete _deletableSurface;
}
bool BaseImage::getImageInfo(const Common::String &filename, int32 &width, int32 &height) {
bool ret = false;
Common::String file = filename;
file.toLowercase();
if (file.hasPrefix("savegame:") || file.hasSuffix(".bmp")) {
ret = getImageInfoBMP(filename, width, height);
} else if (file.hasSuffix(".tga")) {
ret = getImageInfoTGA(filename, width, height);
} else if (file.hasSuffix(".png")) {
ret = getImageInfoPNG(filename, width, height);
} else if (file.hasSuffix(".jpg")) {
ret = getImageInfoJPG(filename, width, height);
} else {
warning("BaseImage::loadFile : Unsupported fileformat %s", filename.c_str());
}
return ret;
}
bool BaseImage::getImageInfoBMP(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
uint16 fileType = stream->readUint16BE();
if (fileType != MKTAG16('B', 'M')) {
_fileManager->closeFile(stream);
return false;
}
stream->skip(16);
width = stream->readSint32LE();
height = stream->readSint32LE();
_fileManager->closeFile(stream);
return true;
}
bool BaseImage::getImageInfoTGA(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
stream->skip(12);
width = stream->readSint16LE();
height = stream->readSint16LE();
_fileManager->closeFile(stream);
return true;
}
bool BaseImage::getImageInfoPNG(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
if (stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) {
_fileManager->closeFile(stream);
return false;
}
stream->skip(4);
uint32 headerLen = stream->readUint32BE();
uint32 headerType = stream->readUint32BE();
if (headerType != MKTAG('I', 'H', 'D', 'R') || headerLen != 13) {
_fileManager->closeFile(stream);
return false;
}
width = stream->readSint32BE();
height = stream->readSint32BE();
_fileManager->closeFile(stream);
return true;
}
bool BaseImage::getImageInfoJPG(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
uint16 fileType = stream->readSint16BE();
if (fileType != 0xFFD8) {
_fileManager->closeFile(stream);
return false;
}
while (1) {
byte markerPrefix = stream->readByte();
if (stream->eos() || stream->err()) {
break;
}
if (markerPrefix != 0xff) {
continue;
}
byte marker = stream->readByte();
while (marker == 0xff) {
marker = stream->readByte();
if (stream->eos() || stream->err()) {
_fileManager->closeFile(stream);
return false;
}
}
if (marker == 0xd9 || marker == 0xda) {
break;
}
uint16 segLength = stream->readUint16BE();
if (segLength < 2) {
break;
}
if ((marker >= 0xc0 && marker <= 0xc3) ||
(marker >= 0xc9 && marker <= 0xcb)) {
stream->skip(1);
height = stream->readUint16BE();
width = stream->readUint16BE();
_fileManager->closeFile(stream);
return true;
} else {
stream->skip(segLength - 2);
if (stream->eos() || stream->err()) {
break;
}
}
}
_fileManager->closeFile(stream);
return false;
}
bool BaseImage::loadFile(const Common::String &filename) {
_filename = filename;
_filename.toLowercase();
if (filename.hasPrefix("savegame:") || _filename.hasSuffix(".bmp")) {
_decoder = new Image::BitmapDecoder();
} else if (_filename.hasSuffix(".png")) {
if (BaseEngine::instance().getGameId() == "satanandsons" &&
_filename.hasSuffix("\\plein\\kaars.1.png")) {
debug(2, "BaseImage::loadFile : Buggy PNG bitmap %s, skipping...", filename.c_str());
return false;
}
_decoder = new Image::PNGDecoder();
} else if (_filename.hasSuffix(".tga")) {
_decoder = new Image::TGADecoder();
} else if (_filename.hasSuffix(".jpg")) {
Image::JPEGDecoder *jpeg = new Image::JPEGDecoder();
jpeg->setOutputPixelFormat(BaseEngine::getRenderer()->getPixelFormat());
_decoder = jpeg;
} else {
warning("BaseImage::loadFile : Unsupported fileformat %s", filename.c_str());
}
_filename = filename;
Common::SeekableReadStream *file = _fileManager->openFile(filename);
if (!file) {
return false;
}
_decoder->loadStream(*file);
_surface = _decoder->getSurface();
_palette = _decoder->getPalette().data();
_paletteCount = _decoder->getPalette().size();
_fileManager->closeFile(file);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseImage::saveBMPFile(const char *filename) const {
Common::WriteStream *stream = openSfmFileForWrite(filename);
if (stream) {
bool ret = writeBMPToStream(stream);
delete stream;
return ret;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool BaseImage::writeBMPToStream(Common::WriteStream *stream) const {
if (!stream || !_surface) {
return false;
}
return Image::writeBMP(*stream, *_surface, _palette);
}
//////////////////////////////////////////////////////////////////////////
void BaseImage::copyFrom(const Graphics::Surface *surface, int newWidth, int newHeight, byte flip) {
if (newWidth == 0)
newWidth = surface->w;
if (newHeight == 0)
newHeight = surface->h;
Graphics::Surface *temp;
if (newWidth == surface->w && newHeight == surface->h && flip == 0) {
temp = new Graphics::Surface();
temp->copyFrom(*surface);
} else {
temp = surface->scale((uint16)newWidth, (uint16)newHeight, true, flip);
}
if (_deletableSurface) {
_deletableSurface->free();
delete _deletableSurface;
_deletableSurface = nullptr;
}
_surface = _deletableSurface = temp;
}
} // End of namespace Wintermute

View 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_IMAGE_H
#define WINTERMUTE_BASE_IMAGE_H
#include "graphics/surface.h"
#include "graphics/pixelformat.h"
#include "common/endian.h"
#include "common/str.h"
#include "common/stream.h"
namespace Image {
class ImageDecoder;
}
namespace Wintermute {
class BaseSurface;
class BaseFileManager;
class BaseImage {
public:
BaseImage();
~BaseImage();
bool getImageInfo(const Common::String &filename, int32 &width, int32 &height);
bool loadFile(const Common::String &filename);
const Graphics::Surface *getSurface() const {
return _surface;
};
const byte *getPalette() const {
return _palette;
}
uint16 getPaletteCount() const {
return _paletteCount;
}
bool writeBMPToStream(Common::WriteStream *stream) const;
bool saveBMPFile(const char *filename) const;
void copyFrom(const Graphics::Surface *surface, int newWidth = 0, int newHeight = 0, byte flip = 0);
private:
Common::String _filename;
Image::ImageDecoder *_decoder;
const Graphics::Surface *_surface;
Graphics::Surface *_deletableSurface;
const byte *_palette;
uint16 _paletteCount;
BaseFileManager *_fileManager;
bool getImageInfoBMP(const Common::String &filename, int32 &width, int32 &height);
bool getImageInfoTGA(const Common::String &filename, int32 &width, int32 &height);
bool getImageInfoPNG(const Common::String &filename, int32 &width, int32 &height);
bool getImageInfoJPG(const Common::String &filename, int32 &width, int32 &height);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,243 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/dcgf.h"
#ifdef ENABLE_WME3D
#include "engines/wintermute/base/gfx/xmodel.h"
#endif
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseRenderer::BaseRenderer(BaseGame *inGame) : BaseClass(inGame) {
_window = 0;
_clipperWindow = 0;
_active = false;
_ready = false;
_windowed = true;
_forceAlphaColor = 0x00;
_width = _height = _bPP = 0;
BasePlatform::setRectEmpty(&_monitorRect);
_realWidth = _realHeight = 0;
_drawOffsetX = _drawOffsetY = 0;
}
//////////////////////////////////////////////////////////////////////
BaseRenderer::~BaseRenderer() {
deleteRectList();
unclipCursor();
}
//////////////////////////////////////////////////////////////////////
void BaseRenderer::initLoop() {
deleteRectList();
}
//////////////////////////////////////////////////////////////////////
BaseObject *BaseRenderer::getObjectAt(int x, int y) {
Common::Point32 point;
point.x = x;
point.y = y;
for (int32 i = _rectList.getSize() - 1; i >= 0; i--) {
if (BasePlatform::ptInRect(&_rectList[i]->_rect, point)) {
if (_rectList[i]->_precise) {
// frame
if (_rectList[i]->_frame) {
int xx = (int)((_rectList[i]->_frame->_rect.left + x - _rectList[i]->_rect.left + _rectList[i]->_offsetX) / (float)((float)_rectList[i]->_zoomX / (float)100));
int yy = (int)((_rectList[i]->_frame->_rect.top + y - _rectList[i]->_rect.top + _rectList[i]->_offsetY) / (float)((float)_rectList[i]->_zoomY / (float)100));
if (_rectList[i]->_frame->_mirrorX) {
int width = _rectList[i]->_frame->_rect.right - _rectList[i]->_frame->_rect.left;
xx = width - xx;
}
if (_rectList[i]->_frame->_mirrorY) {
int height = _rectList[i]->_frame->_rect.bottom - _rectList[i]->_frame->_rect.top;
yy = height - yy;
}
if (!_rectList[i]->_frame->_surface->isTransparentAt(xx, yy)) {
return _rectList[i]->_owner;
}
}
#ifdef ENABLE_WME3D
else if (_rectList[i]->_xmodel) {
if (!_rectList[i]->_xmodel->isTransparentAt(x, y)) {
return _rectList[i]->_owner;
}
}
#endif
// region
else if (_rectList[i]->_region) {
if (_rectList[i]->_region->pointInRegion(x + _rectList[i]->_offsetX, y + _rectList[i]->_offsetY)) {
return _rectList[i]->_owner;
}
}
} else {
return _rectList[i]->_owner;
}
}
}
return (BaseObject *)nullptr;
}
//////////////////////////////////////////////////////////////////////////
void BaseRenderer::deleteRectList() {
for (int32 i = 0; i < _rectList.getSize(); i++) {
delete _rectList[i];
}
_rectList.removeAll();
}
//////////////////////////////////////////////////////////////////////
bool BaseRenderer::initRenderer(int width, int height, bool windowed) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////
void BaseRenderer::onWindowChange() {
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::windowedBlt() {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setup2D(bool force) {
return STATUS_FAILED;
}
#ifdef ENABLE_WME3D
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setup3D(Camera3D *camera, bool force) {
return STATUS_FAILED;
}
#endif
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::drawRect(int x1, int y1, int x2, int y2, uint32 color, int width) {
for (int i = 0; i < width; i++) {
drawLine(x1 + i, y1 + i, x2 - i, y1 + i, color); // up
drawLine(x1 + i, y2 - i, x2 - i + 1, y2 - i, color); // down
drawLine(x1 + i, y1 + i, x1 + i, y2 - i, color); // left
drawLine(x2 - i, y1 + i, x2 - i, y2 - i + 1, color); // right
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::fillRect(int x, int y, int w, int h, uint32 color) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setViewport(int left, int top, int right, int bottom) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setScreenViewport() {
return setViewport(_drawOffsetX, _drawOffsetY, _width + _drawOffsetX, _height + _drawOffsetY);
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setViewport(Common::Rect32 *rect) {
return setViewport(rect->left + _drawOffsetX,
rect->top + _drawOffsetY,
rect->right + _drawOffsetX,
rect->bottom + _drawOffsetY);
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::clipCursor() {
// TODO: Reimplement this. (Currently aspect-indpendence isn't quite finished)
/*
if (!_windowed) {
Common::Rect32 rc;
GetWindowRect(_window, &rc);
// if "maintain aspect ratio" is in effect, lock mouse to visible area
rc.left = _drawOffsetX;
rc.top = _drawOffsetY;
rc.right = rc.left + _width;
rc.bottom = rc.top + _height;
::ClipCursor(&rc);
}
*/
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::unclipCursor() {
/*
if (!_windowed) ::ClipCursor(nullptr);
*/
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::pointInViewport(Common::Point32 *p) {
if (p->x < _drawOffsetX) {
return false;
}
if (p->y < _drawOffsetY) {
return false;
}
if (p->x > _drawOffsetX + _width) {
return false;
}
if (p->y > _drawOffsetY + _height) {
return false;
}
return true;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,206 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_RENDERER_H
#define WINTERMUTE_BASE_RENDERER_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/coll_templ.h"
#include "common/rect.h"
#include "common/array.h"
namespace Wintermute {
class BaseImage;
class BaseActiveRect;
class BaseObject;
class BaseSurface;
class BasePersistenceManager;
#ifdef ENABLE_WME3D
class Camera3D;
#endif
/**
* @class BaseRenderer a common interface for the rendering portion of WME
* this interface is mainly intended to wrap away any differencies between
* software-rendering/hardware-rendering.
*/
class BaseRenderer : public BaseClass {
public:
int _realWidth;
int _realHeight;
int _drawOffsetX;
int _drawOffsetY;
void dumpData(const char *filename) {};
/**
* Take a screenshot of the current screenstate
*
* @return a BaseImage containing the current screen-buffer.
*/
virtual BaseImage *takeScreenshot(int newWidth = 0, int newHeight = 0) = 0;
virtual bool setViewport(int left, int top, int right, int bottom);
virtual bool setViewport(Common::Rect32 *rect);
virtual bool setScreenViewport();
virtual void setWindowed(bool windowed) = 0;
virtual Graphics::PixelFormat getPixelFormat() const = 0;
/**
* Fade the screen to black
*
* @param alpha amount to fade by (alpha value of black)
*/
virtual bool fade(uint16 alpha) = 0;
/**
* Fade a portion of the screen to a specific color
*
* @param r the red component to fade too.
* @param g the green component to fade too.
* @param b the blue component to fade too.
* @param a the alpha component to fade too.
* @param rect the portion of the screen to fade (if nullptr, the entire screen will be faded).
*/
virtual bool fadeToColor(byte r, byte g, byte b, byte a) = 0;
virtual bool drawLine(int x1, int y1, int x2, int y2, uint32 color);
virtual bool drawRect(int x1, int y1, int x2, int y2, uint32 color, int width = 1);
virtual bool fillRect(int x, int y, int w, int h, uint32 color); // Unused outside indicator-display
BaseRenderer(BaseGame *inGame = nullptr);
~BaseRenderer() override;
virtual bool setProjection() {
return STATUS_OK;
};
virtual bool windowedBlt();
/**
* Clear the screen
*/
virtual bool clear() = 0;
virtual void onWindowChange();
virtual bool initRenderer(int width, int height, bool windowed);
/**
* Flip the backbuffer onto the screen-buffer
* The screen will NOT be updated before calling this function.
*
* @return true if successful, false on error.
*/
virtual bool flip() = 0;
/**
* Special flip for the indicator drawn during save/load
* essentially, just copies the region defined by the indicator rectangle.
*/
virtual bool indicatorFlip(int32 x, int32 y, int32 width, int32 height) = 0;
virtual bool forcedFlip() = 0;
virtual void initLoop();
virtual bool setup2D(bool force = false);
#ifdef ENABLE_WME3D
virtual bool setup3D(Camera3D *camera = nullptr, bool force = false);
#endif
/**
* Get the name of the current renderer
*
* @return the name of the renderer.
*/
virtual Common::String getName() const = 0;
virtual bool displayDebugInfo() {
return STATUS_FAILED;
};
virtual bool drawShaderQuad() {
return STATUS_FAILED;
}
virtual float getScaleRatioX() const {
return 1.0f;
}
virtual float getScaleRatioY() const {
return 1.0f;
}
/**
* Create a Surface fit for use with the renderer.
* As diverse implementations of BaseRenderer might have different solutions for storing surfaces
* this allows for a common interface for creating surface-handles. (Mostly useful to ease future
* implementation of hw-accelerated rendering, or readding 3D-support at some point).
*
* @return a surface that can be used with this renderer
*/
virtual BaseSurface *createSurface() = 0;
bool clipCursor();
bool unclipCursor();
BaseObject *getObjectAt(int x, int y);
void deleteRectList();
virtual bool startSpriteBatch() {
return STATUS_OK;
};
virtual bool endSpriteBatch() {
return STATUS_OK;
};
bool pointInViewport(Common::Point32 *P);
uint32 _forceAlphaColor;
uint32 _window;
uint32 _clipperWindow;
bool _active;
bool _ready;
bool isReady() const { return _ready; }
bool isWindowed() const { return _windowed; }
int32 getBPP() const { return _bPP; }
int32 getWidth() const { return _width; }
int32 getHeight() const { return _height; }
virtual void endSaveLoad() {};
bool _windowed;
Common::Rect32 _windowRect;
Common::Rect32 _viewportRect;
Common::Rect32 _screenRect;
Common::Rect32 _monitorRect;
int32 _bPP;
int32 _height;
int32 _width;
BaseArray<BaseActiveRect *> _rectList;
};
BaseRenderer *makeOSystemRenderer(BaseGame *inGame);
#ifdef ENABLE_WME3D
class BaseRenderer3D;
BaseRenderer3D *makeOpenGL3DRenderer(BaseGame *inGame);
BaseRenderer3D *makeOpenGL3DShaderRenderer(BaseGame *inGame);
BaseRenderer3D *makeTinyGL3DRenderer(BaseGame *inGame);
#endif
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,175 @@
/* 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 "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/3dutils.h"
#include "common/config-manager.h"
namespace Wintermute {
BaseRenderer3D::BaseRenderer3D(Wintermute::BaseGame *inGame) : BaseRenderer(inGame) {
_camera = nullptr;
_state = RSTATE_NONE;
_fov = (float)DX_PI / 4;
_nearClipPlane = DEFAULT_NEAR_PLANE;
_farClipPlane = DEFAULT_FAR_PLANE;
_lastTexture = nullptr;
_ambientLightColor = 0x00000000;
_ambientLightOverride = false;
DXMatrixIdentity(&_worldMatrix);
DXMatrixIdentity(&_viewMatrix);
DXMatrixIdentity(&_projectionMatrix);
}
BaseRenderer3D::~BaseRenderer3D() {
_camera = nullptr; // ref only
}
void BaseRenderer3D::initLoop() {
BaseRenderer::initLoop();
setup2D();
}
bool BaseRenderer3D::drawSprite(BaseSurface *texture, const Common::Rect32 &rect,
float zoomX, float zoomY, const DXVector2 &pos,
uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode,
bool mirrorX, bool mirrorY) {
DXVector2 scale(zoomX / 100.0f, zoomY / 100.0f);
return drawSpriteEx(texture, rect, pos, DXVector2(0.0f, 0.0f), scale, 0.0f, color, alphaDisable, blendMode, mirrorX, mirrorY);
}
bool BaseRenderer3D::getProjectionParams(float *resWidth, float *resHeight, float *layerWidth, float *layerHeight,
float *modWidth, float *modHeight, bool *customViewport) {
*resWidth = _width;
*resHeight = _height;
if (_game->_editorResolutionWidth > 0)
*resWidth = _game->_editorResolutionWidth;
if (_game->_editorResolutionHeight > 0)
*resHeight = _game->_editorResolutionHeight;
int lWidth, lHeight;
Common::Rect32 sceneViewport;
_game->getLayerSize(&lWidth, &lHeight, &sceneViewport, customViewport);
*layerWidth = (float)lWidth;
*layerHeight = (float)lHeight;
*modWidth = 0.0f;
*modHeight = 0.0f;
if (*layerWidth > *resWidth)
*modWidth = (*layerWidth - *resWidth) / 2.0f;
if (*layerHeight > *resHeight)
*modHeight = (*layerHeight - *resHeight) / 2.0f;
// new in 1.7.2.1
// if layer height is smaller than resolution, we assume that we don't want to scroll
// and that the camera overviews the entire resolution
if (*layerHeight < *resHeight) {
*modHeight -= (*resHeight - *layerHeight) / 2;
*layerHeight = *resHeight;
}
return true;
}
bool BaseRenderer3D::fade(uint16 alpha) {
return fadeToColor(0, 0, 0, (byte)(255 - alpha));
}
bool BaseRenderer3D::setAmbientLightColor(uint32 color) {
_ambientLightColor = color;
_ambientLightOverride = true;
setAmbientLightRenderState();
return true;
}
bool BaseRenderer3D::setDefaultAmbientLightColor() {
_ambientLightColor = 0x00000000;
_ambientLightOverride = false;
setAmbientLightRenderState();
return true;
}
bool BaseRenderer3D::setup3DCustom(DXMatrix &viewMat, DXMatrix &projMat) {
setup3D();
_state = RSTATE_3D;
if (viewMat)
setViewTransform(viewMat);
if (projMat)
setProjectionTransform(projMat);
return true;
}
DXViewport BaseRenderer3D::getViewPort() {
return _viewport;
}
Graphics::PixelFormat BaseRenderer3D::getPixelFormat() const {
return Graphics::PixelFormat::createFormatRGBA32();
}
bool BaseRenderer3D::flip() {
_lastTexture = nullptr;
g_system->updateScreen();
return true;
}
bool BaseRenderer3D::indicatorFlip(int32 x, int32 y, int32 width, int32 height) {
flip();
return true;
}
bool BaseRenderer3D::forcedFlip() {
flip();
return true;
}
bool BaseRenderer3D::windowedBlt() {
flip();
return true;
}
void BaseRenderer3D::onWindowChange() {
_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
}
void BaseRenderer3D::setWindowed(bool windowed) {
ConfMan.setBool("fullscreen", !windowed);
g_system->beginGFXTransaction();
g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
g_system->endGFXTransaction();
}
void BaseRenderer3D::endSaveLoad() {
BaseRenderer::endSaveLoad();
}
} // namespace Wintermute

View 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/>.
*
*/
#ifndef WINTERMUTE_BASE_RENDERER_3D_H
#define WINTERMUTE_BASE_RENDERER_3D_H
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/dctypes.h"
#include "graphics/transform_struct.h"
#include "graphics/surface.h"
#if defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/system_headers.h"
#include "engines/wintermute/base/gfx/xmath.h"
#endif
namespace Wintermute {
class AdBlock;
class AdGeneric;
class AdWalkplane;
class BaseSurfaceOpenGL3D;
class Light3D;
class Mesh3DS;
class XMesh;
class ShadowVolume;
#define DEFAULT_NEAR_PLANE 90.0f
#define DEFAULT_FAR_PLANE 10000.0f
enum PostFilter {
kPostFilterOff,
kPostFilterBlackAndWhite,
kPostFilterSepia
};
class BaseRenderer3D : public BaseRenderer {
public:
BaseRenderer3D(BaseGame *inGame = nullptr);
~BaseRenderer3D() override;
bool getProjectionParams(float *resWidth, float *resHeight, float *layerWidth, float *layerHeight,
float *modWidth, float *modHeight, bool *customViewport);
virtual int getMaxActiveLights() = 0;
bool setAmbientLightColor(uint32 color);
bool setDefaultAmbientLightColor();
uint32 _ambientLightColor;
bool _ambientLightOverride;
void dumpData(const char *filename) {};
bool setup3DCustom(DXMatrix &viewMat, DXMatrix &projMat);
virtual bool enableShadows() = 0;
virtual bool disableShadows() = 0;
virtual bool shadowVolumeSupported() = 0;
virtual bool invalidateTexture(BaseSurface *texture) = 0;
virtual void setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode, bool forceChange = false) = 0;
virtual bool invalidateDeviceObjects() = 0;
virtual bool restoreDeviceObjects() = 0;
BaseSurface *_lastTexture;
bool fade(uint16 alpha) override;
bool drawSprite(BaseSurface *texture, const Common::Rect32 &rect, float zoomX, float zoomY, const DXVector2 &pos,
uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY);
virtual bool drawSpriteEx(BaseSurface *texture, const Common::Rect32 &rect, const DXVector2 &pos, const DXVector2 &rot, const DXVector2 &scale,
float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) = 0;
Camera3D *_camera;
virtual bool resetDevice() = 0;
void initLoop() override;
bool windowedBlt() override;
virtual bool startSpriteBatch() override = 0;
virtual bool endSpriteBatch() override = 0;
virtual bool commitSpriteBatch() = 0;
// ScummVM specific methods -->
virtual void lightEnable(int index, bool enable) = 0;
virtual void setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction,
const DXVector4 &diffuse, bool spotlight) = 0;
virtual void enableCulling() = 0;
virtual void disableCulling() = 0;
DXViewport getViewPort();
void setWindowed(bool windowed) override;
void onWindowChange() override;
Graphics::PixelFormat getPixelFormat() const override;
virtual bool setWorldTransform(const DXMatrix &transform) = 0;
virtual bool setViewTransform(const DXMatrix &transform) = 0;
virtual bool setProjectionTransform(const DXMatrix &transform) = 0;
void getWorldTransform(DXMatrix *transform) {
*transform = _worldMatrix;
}
void getViewTransform(DXMatrix *transform) {
*transform = _viewMatrix;
}
void getProjectionTransform(DXMatrix *transform) {
*transform = _projectionMatrix;
}
virtual Mesh3DS *createMesh3DS() = 0;
virtual XMesh *createXMesh() = 0;
virtual ShadowVolume *createShadowVolume() = 0;
virtual void renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) = 0;
virtual void renderShadowGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks, const BaseArray<AdGeneric *> &generics, Camera3D *camera) = 0;
virtual void displaySimpleShadow(BaseObject *object) = 0;
virtual void postfilter() = 0;
virtual void setPostfilter(PostFilter postFilter) = 0;
bool flip() override;
bool indicatorFlip(int32 x, int32 y, int32 width, int32 height) override;
bool forcedFlip() override;
virtual bool setViewport3D(DXViewport *viewport) = 0;
void invalidateLastTexture() {
_lastTexture = nullptr;
}
void endSaveLoad() override;
// ScummVM specific methods <--
protected:
DXMatrix _worldMatrix;
DXMatrix _viewMatrix;
DXMatrix _projectionMatrix;
DXViewport _viewport{};
float _fov;
float _nearClipPlane;
float _farClipPlane;
TRendererState _state;
PostFilter _postFilterMode;
bool _flipInProgress;
virtual void setAmbientLightRenderState() = 0;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,122 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/wintypes.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/dcgf.h"
#include "common/str.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseSurface::BaseSurface(BaseGame *inGame) : BaseClass(inGame) {
_referenceCount = 0;
_width = _height = 0;
_filename = nullptr;
_ckDefault = true;
_ckRed = _ckGreen = _ckBlue = 0;
_lifeTime = 0;
_keepLoaded = false;
_lastUsedTime = 0;
_valid = false;
}
//////////////////////////////////////////////////////////////////////
BaseSurface::~BaseSurface() {
if (_filename) {
SAFE_DELETE_ARRAY(_filename);
}
}
//////////////////////////////////////////////////////////////////////
bool BaseSurface::restore() {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////
bool BaseSurface::isTransparentAt(int x, int y) {
if (startPixelOp()) {
bool retval = isTransparentAtLite(x, y);
endPixelOp();
return retval;
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////
bool BaseSurface::displayHalfTrans(int x, int y, Common::Rect32 rect) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurface::create(int width, int height) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurface::invalidate() {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurface::prepareToDraw() {
_lastUsedTime = _game->_liveTimer;
if (!_valid) {
//_game->LOG(0, "Reviving: %s", _filename);
return create(_filename, _ckDefault, _ckRed, _ckGreen, _ckBlue, _lifeTime, _keepLoaded);
} else {
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
void BaseSurface::setFilename(const char *filename) {
SAFE_DELETE_ARRAY(_filename);
if (!filename) {
return;
}
size_t nameSize = strlen(filename) + 1;
_filename = new char[nameSize];
Common::strcpy_s(_filename, nameSize, filename);
}
//////////////////////////////////////////////////////////////////////////
void BaseSurface::setSize(int width, int height) {
_width = width;
_height = height;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,98 @@
/* 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 file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SURFACE_H
#define WINTERMUTE_BASE_SURFACE_H
#include "engines/wintermute/base/base.h"
#include "graphics/surface.h"
#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSurface : public BaseClass {
public:
virtual bool invalidate();
virtual bool prepareToDraw();
bool _ckDefault;
byte _ckRed;
byte _ckGreen;
byte _ckBlue;
uint32 _lastUsedTime;
bool _valid;
int32 _lifeTime;
bool _keepLoaded;
BaseSurface(BaseGame *inGame);
~BaseSurface() override;
virtual bool displayHalfTrans(int x, int y, Common::Rect32 rect);
virtual bool isTransparentAt(int x, int y);
virtual bool displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0;
virtual bool display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) = 0;
virtual bool restore();
virtual bool create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0;
virtual bool create(int width, int height);
virtual bool setAlphaImage(const char *filename) {
return STATUS_FAILED;
}
virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) {
return STATUS_FAILED;
}
virtual bool startPixelOp() = 0;
virtual bool endPixelOp() = 0;
virtual bool putPixel(int x, int y, byte r, byte g, byte b, byte a) = 0;
virtual bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a = nullptr) const = 0;
virtual bool isTransparentAtLite(int x, int y) const = 0;
void setFilename(const char *filename);
void setSize(int width, int height);
int _referenceCount;
char *_filename;
virtual int getWidth() {
return _width;
}
virtual int getHeight() {
return _height;
}
//void SetWidth(int Width) { _width = Width; }
//void SetHeight(int Height){ _height = Height; }
protected:
int32 _height;
int32 _width;
};
} // End of namespace Wintermute
#endif

Some files were not shown because too many files have changed in this diff Show More