Initial commit
This commit is contained in:
177
engines/wintermute/base/base.cpp
Normal file
177
engines/wintermute/base/base.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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, ¶ms) != 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, ¶ms)) > 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
|
||||
64
engines/wintermute/base/base.h
Normal file
64
engines/wintermute/base/base.h
Normal 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
|
||||
221
engines/wintermute/base/base_access_mgr.cpp
Normal file
221
engines/wintermute/base/base_access_mgr.cpp
Normal 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
|
||||
73
engines/wintermute/base/base_access_mgr.h
Normal file
73
engines/wintermute/base/base_access_mgr.h
Normal 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
|
||||
138
engines/wintermute/base/base_active_rect.cpp
Normal file
138
engines/wintermute/base/base_active_rect.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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, ®ion->_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
|
||||
67
engines/wintermute/base/base_active_rect.h
Normal file
67
engines/wintermute/base/base_active_rect.h
Normal 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
|
||||
68
engines/wintermute/base/base_animation_transition_time.cpp
Normal file
68
engines/wintermute/base/base_animation_transition_time.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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;
|
||||
}
|
||||
|
||||
}
|
||||
49
engines/wintermute/base/base_animation_transition_time.h
Normal file
49
engines/wintermute/base/base_animation_transition_time.h
Normal 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
|
||||
204
engines/wintermute/base/base_dynamic_buffer.cpp
Normal file
204
engines/wintermute/base/base_dynamic_buffer.cpp
Normal 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
|
||||
64
engines/wintermute/base/base_dynamic_buffer.h
Normal file
64
engines/wintermute/base/base_dynamic_buffer.h
Normal 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
|
||||
118
engines/wintermute/base/base_engine.cpp
Normal file
118
engines/wintermute/base/base_engine.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
95
engines/wintermute/base/base_engine.h
Normal file
95
engines/wintermute/base/base_engine.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
196
engines/wintermute/base/base_fader.cpp
Normal file
196
engines/wintermute/base/base_fader.cpp
Normal 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
|
||||
61
engines/wintermute/base/base_fader.h
Normal file
61
engines/wintermute/base/base_fader.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
584
engines/wintermute/base/base_file_manager.cpp
Normal file
584
engines/wintermute/base/base_file_manager.cpp
Normal 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
|
||||
85
engines/wintermute/base/base_file_manager.h
Normal file
85
engines/wintermute/base/base_file_manager.h
Normal 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
|
||||
772
engines/wintermute/base/base_frame.cpp
Normal file
772
engines/wintermute/base/base_frame.cpp
Normal 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, ¶ms)) > 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
|
||||
74
engines/wintermute/base/base_frame.h
Normal file
74
engines/wintermute/base/base_frame.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
5990
engines/wintermute/base/base_game.cpp
Normal file
5990
engines/wintermute/base/base_game.cpp
Normal file
File diff suppressed because it is too large
Load Diff
473
engines/wintermute/base/base_game.h
Normal file
473
engines/wintermute/base/base_game.h
Normal 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
|
||||
44
engines/wintermute/base/base_game_custom_actions.h
Normal file
44
engines/wintermute/base/base_game_custom_actions.h
Normal 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
|
||||
565
engines/wintermute/base/base_keyboard_state.cpp
Normal file
565
engines/wintermute/base/base_keyboard_state.cpp
Normal 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
|
||||
82
engines/wintermute/base/base_keyboard_state.h
Normal file
82
engines/wintermute/base/base_keyboard_state.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
68
engines/wintermute/base/base_named_object.cpp
Normal file
68
engines/wintermute/base/base_named_object.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
50
engines/wintermute/base/base_named_object.h
Normal file
50
engines/wintermute/base/base_named_object.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
1431
engines/wintermute/base/base_object.cpp
Normal file
1431
engines/wintermute/base/base_object.cpp
Normal file
File diff suppressed because it is too large
Load Diff
171
engines/wintermute/base/base_object.h
Normal file
171
engines/wintermute/base/base_object.h
Normal 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
|
||||
472
engines/wintermute/base/base_parser.cpp
Normal file
472
engines/wintermute/base/base_parser.cpp
Normal 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
|
||||
86
engines/wintermute/base/base_parser.h
Normal file
86
engines/wintermute/base/base_parser.h
Normal 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
|
||||
956
engines/wintermute/base/base_persistence_manager.cpp
Normal file
956
engines/wintermute/base/base_persistence_manager.cpp
Normal 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
|
||||
120
engines/wintermute/base/base_persistence_manager.h
Normal file
120
engines/wintermute/base/base_persistence_manager.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
62
engines/wintermute/base/base_point.cpp
Normal file
62
engines/wintermute/base/base_point.cpp
Normal 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
|
||||
48
engines/wintermute/base/base_point.h
Normal file
48
engines/wintermute/base/base_point.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
54
engines/wintermute/base/base_quick_msg.cpp
Normal file
54
engines/wintermute/base/base_quick_msg.cpp
Normal 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
|
||||
46
engines/wintermute/base/base_quick_msg.h
Normal file
46
engines/wintermute/base/base_quick_msg.h
Normal 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
|
||||
545
engines/wintermute/base/base_region.cpp
Normal file
545
engines/wintermute/base/base_region.cpp
Normal 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, ¶ms) != 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, ¶ms)) > 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
|
||||
70
engines/wintermute/base/base_region.h
Normal file
70
engines/wintermute/base/base_region.h
Normal 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
|
||||
504
engines/wintermute/base/base_script_holder.cpp
Normal file
504
engines/wintermute/base/base_script_holder.cpp
Normal 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, ¶ms) != 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, ¶ms)) > 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
|
||||
76
engines/wintermute/base/base_script_holder.h
Normal file
76
engines/wintermute/base/base_script_holder.h
Normal 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
|
||||
194
engines/wintermute/base/base_scriptable.cpp
Normal file
194
engines/wintermute/base/base_scriptable.cpp
Normal 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
|
||||
85
engines/wintermute/base/base_scriptable.h
Normal file
85
engines/wintermute/base/base_scriptable.h
Normal 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
|
||||
823
engines/wintermute/base/base_sprite.cpp
Normal file
823
engines/wintermute/base/base_sprite.cpp
Normal 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, ¶ms) != TOKEN_SPRITE) {
|
||||
_game->LOG(0, "'SPRITE' keyword expected.");
|
||||
return STATUS_FAILED;
|
||||
}
|
||||
buffer = params;
|
||||
}
|
||||
|
||||
int frameCount = 1;
|
||||
BaseFrame *frame;
|
||||
while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 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
|
||||
92
engines/wintermute/base/base_sprite.h
Normal file
92
engines/wintermute/base/base_sprite.h
Normal 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
|
||||
317
engines/wintermute/base/base_string_table.cpp
Normal file
317
engines/wintermute/base/base_string_table.cpp
Normal 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
|
||||
60
engines/wintermute/base/base_string_table.h
Normal file
60
engines/wintermute/base/base_string_table.h
Normal 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
|
||||
780
engines/wintermute/base/base_sub_frame.cpp
Normal file
780
engines/wintermute/base/base_sub_frame.cpp
Normal 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, ¶ms)) > 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
|
||||
95
engines/wintermute/base/base_sub_frame.h
Normal file
95
engines/wintermute/base/base_sub_frame.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
209
engines/wintermute/base/base_surface_storage.cpp
Normal file
209
engines/wintermute/base/base_surface_storage.cpp
Normal 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
|
||||
56
engines/wintermute/base/base_surface_storage.h
Normal file
56
engines/wintermute/base/base_surface_storage.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
139
engines/wintermute/base/base_transition_manager.cpp
Normal file
139
engines/wintermute/base/base_transition_manager.cpp
Normal 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
|
||||
52
engines/wintermute/base/base_transition_manager.h
Normal file
52
engines/wintermute/base/base_transition_manager.h
Normal 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
|
||||
103
engines/wintermute/base/base_viewport.cpp
Normal file
103
engines/wintermute/base/base_viewport.cpp
Normal 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
|
||||
57
engines/wintermute/base/base_viewport.h
Normal file
57
engines/wintermute/base/base_viewport.h
Normal 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
|
||||
227
engines/wintermute/base/file/base_disk_file.cpp
Normal file
227
engines/wintermute/base/file/base_disk_file.cpp
Normal 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
|
||||
42
engines/wintermute/base/file/base_disk_file.h
Normal file
42
engines/wintermute/base/file/base_disk_file.h
Normal 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
|
||||
76
engines/wintermute/base/file/base_file_entry.cpp
Normal file
76
engines/wintermute/base/file/base_file_entry.cpp
Normal 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
|
||||
62
engines/wintermute/base/file/base_file_entry.h
Normal file
62
engines/wintermute/base/file/base_file_entry.h
Normal 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
|
||||
288
engines/wintermute/base/file/base_package.cpp
Normal file
288
engines/wintermute/base/file/base_package.cpp
Normal 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
|
||||
92
engines/wintermute/base/file/base_package.h
Normal file
92
engines/wintermute/base/file/base_package.h
Normal 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
|
||||
79
engines/wintermute/base/file/base_save_thumb_file.cpp
Normal file
79
engines/wintermute/base/file/base_save_thumb_file.cpp
Normal 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
|
||||
40
engines/wintermute/base/file/base_save_thumb_file.h
Normal file
40
engines/wintermute/base/file/base_save_thumb_file.h
Normal 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
|
||||
86
engines/wintermute/base/file/base_savefile_manager_file.cpp
Normal file
86
engines/wintermute/base/file/base_savefile_manager_file.cpp
Normal 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
|
||||
45
engines/wintermute/base/file/base_savefile_manager_file.h
Normal file
45
engines/wintermute/base/file/base_savefile_manager_file.h
Normal 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
|
||||
79
engines/wintermute/base/file/dcpackage.h
Normal file
79
engines/wintermute/base/file/dcpackage.h
Normal 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
|
||||
140
engines/wintermute/base/font/base_font.cpp
Normal file
140
engines/wintermute/base/font/base_font.cpp
Normal 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, ¶ms) == TOKEN_TTFONT) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // End of namespace Wintermute
|
||||
60
engines/wintermute/base/font/base_font.h
Normal file
60
engines/wintermute/base/font/base_font.h
Normal 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
|
||||
628
engines/wintermute/base/font/base_font_bitmap.cpp
Normal file
628
engines/wintermute/base/font/base_font_bitmap.cpp
Normal 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, ¶ms) != 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, ¶ms)) > 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
|
||||
70
engines/wintermute/base/font/base_font_bitmap.h
Normal file
70
engines/wintermute/base/font/base_font_bitmap.h
Normal 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
|
||||
139
engines/wintermute/base/font/base_font_storage.cpp
Normal file
139
engines/wintermute/base/font/base_font_storage.cpp
Normal 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
|
||||
55
engines/wintermute/base/font/base_font_storage.h
Normal file
55
engines/wintermute/base/font/base_font_storage.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
629
engines/wintermute/base/font/base_font_truetype.cpp
Normal file
629
engines/wintermute/base/font/base_font_truetype.cpp
Normal 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, ¶ms) != TOKEN_TTFONT) {
|
||||
_game->LOG(0, "'TTFONT' keyword expected.");
|
||||
return STATUS_FAILED;
|
||||
}
|
||||
buffer = params;
|
||||
|
||||
uint32 baseColor = 0x00000000;
|
||||
|
||||
while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 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, ¶ms)) > 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
|
||||
148
engines/wintermute/base/font/base_font_truetype.h
Normal file
148
engines/wintermute/base/font/base_font_truetype.h
Normal 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
|
||||
111
engines/wintermute/base/gfx/3dcamera.cpp
Normal file
111
engines/wintermute/base/gfx/3dcamera.cpp
Normal 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
|
||||
58
engines/wintermute/base/gfx/3dcamera.h
Normal file
58
engines/wintermute/base/gfx/3dcamera.h
Normal 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
|
||||
78
engines/wintermute/base/gfx/3deffect.cpp
Normal file
78
engines/wintermute/base/gfx/3deffect.cpp
Normal 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
|
||||
54
engines/wintermute/base/gfx/3deffect.h
Normal file
54
engines/wintermute/base/gfx/3deffect.h
Normal 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
|
||||
203
engines/wintermute/base/gfx/3deffect_params.cpp
Normal file
203
engines/wintermute/base/gfx/3deffect_params.cpp
Normal 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
|
||||
96
engines/wintermute/base/gfx/3deffect_params.h
Normal file
96
engines/wintermute/base/gfx/3deffect_params.h
Normal 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
|
||||
49
engines/wintermute/base/gfx/3dface.cpp
Normal file
49
engines/wintermute/base/gfx/3dface.cpp
Normal 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
|
||||
45
engines/wintermute/base/gfx/3dface.h
Normal file
45
engines/wintermute/base/gfx/3dface.h
Normal 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
|
||||
89
engines/wintermute/base/gfx/3dlight.cpp
Normal file
89
engines/wintermute/base/gfx/3dlight.cpp
Normal 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
|
||||
59
engines/wintermute/base/gfx/3dlight.h
Normal file
59
engines/wintermute/base/gfx/3dlight.h
Normal 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
|
||||
525
engines/wintermute/base/gfx/3dloader_3ds.cpp
Normal file
525
engines/wintermute/base/gfx/3dloader_3ds.cpp
Normal 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
|
||||
94
engines/wintermute/base/gfx/3dloader_3ds.h
Normal file
94
engines/wintermute/base/gfx/3dloader_3ds.h
Normal 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
|
||||
172
engines/wintermute/base/gfx/3dmesh.cpp
Normal file
172
engines/wintermute/base/gfx/3dmesh.cpp
Normal 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
|
||||
77
engines/wintermute/base/gfx/3dmesh.h
Normal file
77
engines/wintermute/base/gfx/3dmesh.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
176
engines/wintermute/base/gfx/3dshadow_volume.cpp
Normal file
176
engines/wintermute/base/gfx/3dshadow_volume.cpp
Normal 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
|
||||
73
engines/wintermute/base/gfx/3dshadow_volume.h
Normal file
73
engines/wintermute/base/gfx/3dshadow_volume.h
Normal 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
|
||||
188
engines/wintermute/base/gfx/3dutils.cpp
Normal file
188
engines/wintermute/base/gfx/3dutils.cpp
Normal 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
|
||||
57
engines/wintermute/base/gfx/3dutils.h
Normal file
57
engines/wintermute/base/gfx/3dutils.h
Normal 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
|
||||
46
engines/wintermute/base/gfx/3dvertex.cpp
Normal file
46
engines/wintermute/base/gfx/3dvertex.cpp
Normal 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
|
||||
44
engines/wintermute/base/gfx/3dvertex.h
Normal file
44
engines/wintermute/base/gfx/3dvertex.h
Normal 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
|
||||
296
engines/wintermute/base/gfx/base_image.cpp
Normal file
296
engines/wintermute/base/gfx/base_image.cpp
Normal 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
|
||||
82
engines/wintermute/base/gfx/base_image.h
Normal file
82
engines/wintermute/base/gfx/base_image.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This 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
|
||||
243
engines/wintermute/base/gfx/base_renderer.cpp
Normal file
243
engines/wintermute/base/gfx/base_renderer.cpp
Normal 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
|
||||
206
engines/wintermute/base/gfx/base_renderer.h
Normal file
206
engines/wintermute/base/gfx/base_renderer.h
Normal 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
|
||||
175
engines/wintermute/base/gfx/base_renderer3d.cpp
Normal file
175
engines/wintermute/base/gfx/base_renderer3d.cpp
Normal 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
|
||||
177
engines/wintermute/base/gfx/base_renderer3d.h
Normal file
177
engines/wintermute/base/gfx/base_renderer3d.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
122
engines/wintermute/base/gfx/base_surface.cpp
Normal file
122
engines/wintermute/base/gfx/base_surface.cpp
Normal 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
|
||||
98
engines/wintermute/base/gfx/base_surface.h
Normal file
98
engines/wintermute/base/gfx/base_surface.h
Normal 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
Reference in New Issue
Block a user