ALL: Merge branch 'tlj'
This commit is contained in:
commit
5c73d0083d
192 changed files with 25561 additions and 4 deletions
|
@ -141,6 +141,9 @@ public:
|
||||||
#if defined(USE_TIMIDITY)
|
#if defined(USE_TIMIDITY)
|
||||||
LINK_PLUGIN(TIMIDITY)
|
LINK_PLUGIN(TIMIDITY)
|
||||||
#endif
|
#endif
|
||||||
|
#if PLUGIN_ENABLED_STATIC(STARK)
|
||||||
|
LINK_PLUGIN(STARK)
|
||||||
|
#endif
|
||||||
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
4
configure
vendored
4
configure
vendored
|
@ -4438,6 +4438,10 @@ if test `get_engine_build myst3` = yes && test ! "$_bink" = yes ; then
|
||||||
engine_disable myst3
|
engine_disable myst3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test `get_engine_build stark` = yes && test ! "$_opengl_shaders" = yes ; then
|
||||||
|
echo "...disabling STARK engine. OpenGL with shaders is required"
|
||||||
|
engine_disable stark
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Figure out installation directories
|
# Figure out installation directories
|
||||||
|
|
3
engines/stark/configure.engine
Normal file
3
engines/stark/configure.engine
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This file is included from the main "configure" script
|
||||||
|
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
|
||||||
|
add_engine stark "The Longest Journey" yes "" "" "freetype2"
|
407
engines/stark/console.cpp
Normal file
407
engines/stark/console.cpp
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/console.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xarc.h"
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resources/level.h"
|
||||||
|
#include "engines/stark/resources/location.h"
|
||||||
|
#include "engines/stark/resources/knowledge.h"
|
||||||
|
#include "engines/stark/resources/root.h"
|
||||||
|
#include "engines/stark/resources/script.h"
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/services/dialogplayer.h"
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/resourceprovider.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/services/staticprovider.h"
|
||||||
|
|
||||||
|
#include "common/file.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
Console::Console() : GUI::Debugger() {
|
||||||
|
registerCmd("dumpArchive", WRAP_METHOD(Console, Cmd_DumpArchive));
|
||||||
|
registerCmd("dumpRoot", WRAP_METHOD(Console, Cmd_DumpRoot));
|
||||||
|
registerCmd("dumpStatic", WRAP_METHOD(Console, Cmd_DumpStatic));
|
||||||
|
registerCmd("dumpGlobal", WRAP_METHOD(Console, Cmd_DumpGlobal));
|
||||||
|
registerCmd("dumpLevel", WRAP_METHOD(Console, Cmd_DumpLevel));
|
||||||
|
registerCmd("dumpKnowledge", WRAP_METHOD(Console, Cmd_DumpKnowledge));
|
||||||
|
registerCmd("dumpLocation", WRAP_METHOD(Console, Cmd_DumpLocation));
|
||||||
|
registerCmd("listScripts", WRAP_METHOD(Console, Cmd_ListScripts));
|
||||||
|
registerCmd("enableScript", WRAP_METHOD(Console, Cmd_EnableScript));
|
||||||
|
registerCmd("forceScript", WRAP_METHOD(Console, Cmd_ForceScript));
|
||||||
|
registerCmd("listInventory", WRAP_METHOD(Console, Cmd_ListInventory));
|
||||||
|
registerCmd("listLocations", WRAP_METHOD(Console, Cmd_ListLocations));
|
||||||
|
registerCmd("location", WRAP_METHOD(Console, Cmd_Location));
|
||||||
|
registerCmd("chapter", WRAP_METHOD(Console, Cmd_Chapter));
|
||||||
|
registerCmd("changeLocation", WRAP_METHOD(Console, Cmd_ChangeLocation));
|
||||||
|
registerCmd("changeChapter", WRAP_METHOD(Console, Cmd_ChangeChapter));
|
||||||
|
registerCmd("changeKnowledge", WRAP_METHOD(Console, Cmd_ChangeKnowledge));
|
||||||
|
registerCmd("selectDialogOption", WRAP_METHOD(Console, Cmd_SelectDialogOption));
|
||||||
|
registerCmd("enableInventoryItem", WRAP_METHOD(Console, Cmd_EnableInventoryItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::~Console() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpArchive(int argc, const char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
debugPrintf("Extract all the files from a game archive.\n");
|
||||||
|
debugPrintf("The destination folder, named 'dump', must exist.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("dumpArchive [archive name]\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formats::XARCArchive xarc;
|
||||||
|
if (!xarc.open(argv[1])) {
|
||||||
|
debugPrintf("Can't open archive with name '%s'\n", argv[1]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ArchiveMemberList members;
|
||||||
|
xarc.listMembers(members);
|
||||||
|
|
||||||
|
for (Common::ArchiveMemberList::const_iterator it = members.begin(); it != members.end(); it++) {
|
||||||
|
Common::String fileName = Common::String::format("dump/%s", it->get()->getName().c_str());
|
||||||
|
|
||||||
|
// Open the output file
|
||||||
|
Common::DumpFile outFile;
|
||||||
|
if (!outFile.open(fileName)) {
|
||||||
|
debugPrintf("Unable to open file '%s' for writing\n", fileName.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the archive content to the output file using a temporary buffer
|
||||||
|
Common::SeekableReadStream *inStream = it->get()->createReadStream();
|
||||||
|
uint8 *buf = new uint8[inStream->size()];
|
||||||
|
|
||||||
|
inStream->read(buf, inStream->size());
|
||||||
|
outFile.write(buf, inStream->size());
|
||||||
|
|
||||||
|
delete[] buf;
|
||||||
|
delete inStream;
|
||||||
|
outFile.close();
|
||||||
|
|
||||||
|
debugPrintf("Extracted '%s'\n", it->get()->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpRoot(int argc, const char **argv) {
|
||||||
|
StarkGlobal->getRoot()->print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpGlobal(int argc, const char **argv) {
|
||||||
|
StarkGlobal->getLevel()->print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpStatic(int argc, const char **argv) {
|
||||||
|
StarkStaticProvider->getLevel()->print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpLevel(int argc, const char **argv) {
|
||||||
|
StarkGlobal->getCurrent()->getLevel()->print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpKnowledge(int argc, const char **argv) {
|
||||||
|
Resources::Level *level = StarkGlobal->getCurrent()->getLevel();
|
||||||
|
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||||
|
Common::Array<Resources::Knowledge *> knowledge = level->listChildrenRecursive<Resources::Knowledge>();
|
||||||
|
knowledge.insert_at(knowledge.size(), location->listChildrenRecursive<Resources::Knowledge>());
|
||||||
|
Common::Array<Resources::Knowledge *>::iterator it;
|
||||||
|
for (it = knowledge.begin(); it != knowledge.end(); ++it) {
|
||||||
|
(*it)->print();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_ChangeKnowledge(int argc, const char **argv) {
|
||||||
|
uint index = 0;
|
||||||
|
char type = 0;
|
||||||
|
|
||||||
|
if (argc >= 4) {
|
||||||
|
index = atoi(argv[1]);
|
||||||
|
type = argv[2][0];
|
||||||
|
if (type == 'b' || type == 'i') {
|
||||||
|
Resources::Level *level = StarkGlobal->getCurrent()->getLevel();
|
||||||
|
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||||
|
Common::Array<Resources::Knowledge *> knowledgeArr = level->listChildrenRecursive<Resources::Knowledge>();
|
||||||
|
knowledgeArr.insert_at(knowledgeArr.size(), location->listChildrenRecursive<Resources::Knowledge>());
|
||||||
|
if (index < knowledgeArr.size() ) {
|
||||||
|
Resources::Knowledge *knowledge = knowledgeArr[index];
|
||||||
|
if (type == 'b') {
|
||||||
|
knowledge->setBooleanValue(atoi(argv[3]));
|
||||||
|
} else if (type == 'i') {
|
||||||
|
knowledge->setIntegerValue(atoi(argv[3]));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
debugPrintf("Invalid index %d, only %d indices available\n", index, knowledgeArr.size());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugPrintf("Invalid type: %c, only b and i are available\n", type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugPrintf("Too few args\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrintf("Change the value of some knowledge. Use dumpKnowledge to get an id\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("changeKnowledge [id] [type] [value]\n");
|
||||||
|
debugPrintf("available types: b(inary), i(nteger)\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_ListScripts(int argc, const char **argv) {
|
||||||
|
Resources::Level *level = StarkGlobal->getCurrent()->getLevel();
|
||||||
|
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||||
|
Common::Array<Resources::Script *> scriptArr = level->listChildrenRecursive<Resources::Script>();
|
||||||
|
scriptArr.insert_at(scriptArr.size(), location->listChildrenRecursive<Resources::Script>());
|
||||||
|
Common::Array<Resources::Script *>::iterator it;
|
||||||
|
int i = 0;
|
||||||
|
for (it = scriptArr.begin(); it != scriptArr.end(); ++it) {
|
||||||
|
debugPrintf("%d: %s - enabled: %d\n", i++, (*it)->getName().c_str(), (*it)->isEnabled());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_EnableScript(int argc, const char **argv) {
|
||||||
|
uint index = 0;
|
||||||
|
|
||||||
|
if (argc >= 2) {
|
||||||
|
index = atoi(argv[1]);
|
||||||
|
|
||||||
|
bool value = true;
|
||||||
|
if (argc >= 3) {
|
||||||
|
value = atoi(argv[2]);
|
||||||
|
}
|
||||||
|
Resources::Level *level = StarkGlobal->getCurrent()->getLevel();
|
||||||
|
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||||
|
Common::Array<Resources::Script *> scriptArr = level->listChildrenRecursive<Resources::Script>();
|
||||||
|
scriptArr.insert_at(scriptArr.size(), location->listChildrenRecursive<Resources::Script>());
|
||||||
|
if (index < scriptArr.size() ) {
|
||||||
|
Resources::Script *script = scriptArr[index];
|
||||||
|
script->enable(value);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
debugPrintf("Invalid index %d, only %d indices available\n", index, scriptArr.size());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugPrintf("Too few args\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrintf("Change the value of some knowledge. Use dumpKnowledge to get an id\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("enableScript [id] (value)\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_ForceScript(int argc, const char **argv) {
|
||||||
|
uint index = 0;
|
||||||
|
|
||||||
|
if (argc >= 2) {
|
||||||
|
index = atoi(argv[1]);
|
||||||
|
|
||||||
|
bool value = true;
|
||||||
|
if (argc >= 3) {
|
||||||
|
value = atoi(argv[2]);
|
||||||
|
}
|
||||||
|
Resources::Level *level = StarkGlobal->getCurrent()->getLevel();
|
||||||
|
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||||
|
Common::Array<Resources::Script *> scriptArr = level->listChildrenRecursive<Resources::Script>();
|
||||||
|
scriptArr.insert_at(scriptArr.size(), location->listChildrenRecursive<Resources::Script>());
|
||||||
|
if (index < scriptArr.size() ) {
|
||||||
|
Resources::Script *script = scriptArr[index];
|
||||||
|
script->enable(value);
|
||||||
|
script->goToNextCommand(); // Skip the begin command to avoid checks
|
||||||
|
script->execute(Resources::Script::kCallModePlayerAction);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
debugPrintf("Invalid index %d, only %d indices available\n", index, scriptArr.size());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugPrintf("Too few args\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrintf("Change the value of some knowledge. Use dumpKnowledge to get an id\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("enableScript [id] (value)\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Console::Cmd_DumpLocation(int argc, const char **argv) {
|
||||||
|
StarkGlobal->getCurrent()->getLocation()->print();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_ListInventory(int argc, const char **argv) {
|
||||||
|
StarkGlobal->printInventory(argc != 2);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_EnableInventoryItem(int argc, const char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
debugPrintf("Enable a specific inventory item.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("changeLocation [level] [location]\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
StarkGlobal->enableInventoryItem(atoi(argv[1]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Console::Cmd_ListLocations(int argc, const char **argv) {
|
||||||
|
ArchiveLoader *archiveLoader = new ArchiveLoader();
|
||||||
|
|
||||||
|
// Temporarily replace the global archive loader with our instance
|
||||||
|
ArchiveLoader *gameArchiveLoader = StarkArchiveLoader;
|
||||||
|
StarkArchiveLoader = archiveLoader;
|
||||||
|
|
||||||
|
archiveLoader->load("x.xarc");
|
||||||
|
Resources::Root *root = archiveLoader->useRoot<Resources::Root>("x.xarc");
|
||||||
|
|
||||||
|
// Find all the levels
|
||||||
|
Common::Array<Resources::Level *> levels = root->listChildren<Resources::Level>();
|
||||||
|
|
||||||
|
// Loop over the levels
|
||||||
|
for (uint i = 0; i < levels.size(); i++) {
|
||||||
|
Resources::Level *level = levels[i];
|
||||||
|
|
||||||
|
Common::String levelArchive = archiveLoader->buildArchiveName(level);
|
||||||
|
debugPrintf("%s - %s\n", levelArchive.c_str(), level->getName().c_str());
|
||||||
|
|
||||||
|
// Load the detailed level archive
|
||||||
|
archiveLoader->load(levelArchive);
|
||||||
|
level = archiveLoader->useRoot<Resources::Level>(levelArchive);
|
||||||
|
|
||||||
|
Common::Array<Resources::Location *> locations = level->listChildren<Resources::Location>();
|
||||||
|
|
||||||
|
// Loop over the locations
|
||||||
|
for (uint j = 0; j < locations.size(); j++) {
|
||||||
|
Resources::Location *location = locations[j];
|
||||||
|
|
||||||
|
Common::String roomArchive = archiveLoader->buildArchiveName(level, location);
|
||||||
|
debugPrintf("%s - %s\n", roomArchive.c_str(), location->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
archiveLoader->returnRoot(levelArchive);
|
||||||
|
archiveLoader->unloadUnused();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the global archive loader
|
||||||
|
StarkArchiveLoader = gameArchiveLoader;
|
||||||
|
|
||||||
|
delete archiveLoader;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_ChangeLocation(int argc, const char **argv) {
|
||||||
|
if (argc != 3) {
|
||||||
|
debugPrintf("Change the current location.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("changeLocation [level] [location]\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint levelIndex = strtol(argv[1] , nullptr, 16);
|
||||||
|
uint locationIndex = strtol(argv[2] , nullptr, 16);
|
||||||
|
|
||||||
|
StarkResourceProvider->requestLocationChange(levelIndex, locationIndex);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_ChangeChapter(int argc, const char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
debugPrintf("Change the current chapter.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("changeChapter [value]\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 value = atoi(argv[1]);
|
||||||
|
|
||||||
|
StarkGlobal->setCurrentChapter(value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_SelectDialogOption(int argc, const char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
debugPrintf("Select a dialog option.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("selectDialogOption [option]\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
StarkDialogPlayer->selectOption(atoi(argv[1]));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_Location(int argc, const char **argv) {
|
||||||
|
if (argc != 1) {
|
||||||
|
debugPrintf("Display the current location.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("location\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Current *current = StarkGlobal->getCurrent();
|
||||||
|
|
||||||
|
debugPrintf("location: %02x %02x\n", current->getLevel()->getIndex(), current->getLocation()->getIndex());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Cmd_Chapter(int argc, const char **argv) {
|
||||||
|
if (argc != 1) {
|
||||||
|
debugPrintf("Display the current chapter.\n");
|
||||||
|
debugPrintf("Usage :\n");
|
||||||
|
debugPrintf("chapter\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 value = StarkGlobal->getCurrentChapter();
|
||||||
|
|
||||||
|
debugPrintf("chapter: %d\n", value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
61
engines/stark/console.h
Normal file
61
engines/stark/console.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONSOLE_H_
|
||||||
|
#define CONSOLE_H_
|
||||||
|
|
||||||
|
#include "gui/debugger.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class Resource;
|
||||||
|
|
||||||
|
class Console : public GUI::Debugger {
|
||||||
|
public:
|
||||||
|
Console();
|
||||||
|
virtual ~Console();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool Cmd_DumpArchive(int argc, const char **argv);
|
||||||
|
bool Cmd_DumpRoot(int argc, const char **argv);
|
||||||
|
bool Cmd_DumpStatic(int argc, const char **argv);
|
||||||
|
bool Cmd_DumpGlobal(int argc, const char **argv);
|
||||||
|
bool Cmd_DumpKnowledge(int argc, const char **argv);
|
||||||
|
bool Cmd_DumpLevel(int argc, const char **argv);
|
||||||
|
bool Cmd_DumpLocation(int argc, const char **argv);
|
||||||
|
bool Cmd_ForceScript(int argc, const char **argv);
|
||||||
|
bool Cmd_ListInventory(int argc, const char **argv);
|
||||||
|
bool Cmd_EnableInventoryItem(int argc, const char **argv);
|
||||||
|
bool Cmd_ListLocations(int argc, const char** argv);
|
||||||
|
bool Cmd_ListScripts(int argc, const char** argv);
|
||||||
|
bool Cmd_EnableScript(int argc, const char** argv);
|
||||||
|
bool Cmd_Location(int argc, const char **argv);
|
||||||
|
bool Cmd_Chapter(int argc, const char **argv);
|
||||||
|
bool Cmd_ChangeLocation(int argc, const char **argv);
|
||||||
|
bool Cmd_ChangeChapter(int argc, const char **argv);
|
||||||
|
bool Cmd_ChangeKnowledge(int argc, const char **argv);
|
||||||
|
bool Cmd_SelectDialogOption(int argc, const char **argv);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // CONSOLE_H_
|
33
engines/stark/debug.h
Normal file
33
engines/stark/debug.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_DEBUG_H
|
||||||
|
#define STARK_DEBUG_H
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kDebugArchive = 1 << 0,
|
||||||
|
kDebugXMG = 1 << 1,
|
||||||
|
kDebugXRC = 1 << 2,
|
||||||
|
kDebugUnknown = 1 << 3
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STARK_DEBUG_H
|
277
engines/stark/detection.cpp
Normal file
277
engines/stark/detection.cpp
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/advancedDetector.h"
|
||||||
|
#include "engines/stark/stark.h"
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
|
||||||
|
#include "common/savefile.h"
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
static const PlainGameDescriptor starkGames[] = {
|
||||||
|
{"stark", "Stark Game"},
|
||||||
|
{"tlj", "The Longest Journey"},
|
||||||
|
{0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ADGameDescription gameDescriptions[] = {
|
||||||
|
// The Longest Journey
|
||||||
|
// English DVD
|
||||||
|
{
|
||||||
|
"tlj", "DVD", {
|
||||||
|
{"x.xarc", 0, "de8327850d7bba90b690b141eaa23f61", 3032},
|
||||||
|
{"chapters.ini", 0, "5b5a1f1dd2297d9ce0d3d12216d5d2c5", 485},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
GF_DVD,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// GOG edition
|
||||||
|
{
|
||||||
|
"tlj", "GOG", {
|
||||||
|
{"x.xarc", 0, "a0559457126caadab0cadac02d35f26f", 3032},
|
||||||
|
{"chapters.ini", 0, "5b5a1f1dd2297d9ce0d3d12216d5d2c5", 485},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_NO_FLAGS,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// English Old Demo
|
||||||
|
{
|
||||||
|
"tlj", "Old Demo", {
|
||||||
|
{"x.xarc", 0, "97abc1bb9239dee4c208e533f3c97e1c", 98},
|
||||||
|
{"chapters.ini", 0, "5b5a1f1dd2297d9ce0d3d12216d5d2c5", 485},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_DEMO,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// English v1.61 Demo
|
||||||
|
{
|
||||||
|
"tlj", "v1.61 Demo", {
|
||||||
|
{"x.xarc", 0, "61093bcd499b386ed5c0345c52f48909", 98},
|
||||||
|
{"chapters.ini", 0, "5b5a1f1dd2297d9ce0d3d12216d5d2c5", 485},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_DEMO | GF_DVD,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// French Demo
|
||||||
|
{
|
||||||
|
"tlj", "Demo", {
|
||||||
|
{"x.xarc", 0, "97abc1bb9239dee4c208e533f3c97e1c", 98},
|
||||||
|
{"chapters.ini", 0, "e54f6370dca06496069790840409cf95", 506},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::FR_FRA,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_DEMO,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// Norwegian Demo
|
||||||
|
{
|
||||||
|
"tlj", "Demo", {
|
||||||
|
{"x.xarc", 0, "97abc1bb9239dee4c208e533f3c97e1c", 98},
|
||||||
|
{"chapters.ini", 0, "f358f604abd1aa1476ed05d6d271ac70", 473},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::NB_NOR,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_DEMO,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// Norwegian DLC-edition (DVD?)
|
||||||
|
{
|
||||||
|
"tlj", "DVD", {
|
||||||
|
{"x.xarc", 0, "de8327850d7bba90b690b141eaa23f61", 3032},
|
||||||
|
{"chapters.ini", 0, "f358f604abd1aa1476ed05d6d271ac70", 473},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::NB_NOR,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_NO_FLAGS,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// Spanish 4CD
|
||||||
|
{
|
||||||
|
"tlj", "4 CD", {
|
||||||
|
{"x.xarc", 0, "a0559457126caadab0cadac02d35f26f", 3032},
|
||||||
|
{"chapters.ini", 0, "3640df6d536b186bff228337284d9631", 525},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::ES_ESP,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_NO_FLAGS,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// French 2CD
|
||||||
|
{
|
||||||
|
"tlj", "2 CD", {
|
||||||
|
{"x.xarc", 0, "de8327850d7bba90b690b141eaa23f61", 3032},
|
||||||
|
{"chapters.ini", 0, "e54f6370dca06496069790840409cf95", 506},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::FR_FRA,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_NO_FLAGS,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// The Longest Journey
|
||||||
|
// Swedish Demo
|
||||||
|
{
|
||||||
|
"tlj", "Demo", {
|
||||||
|
{"x.xarc", 0, "97abc1bb9239dee4c208e533f3c97e1c", 98},
|
||||||
|
{"chapters.ini", 0, "f6a2007300209492b7b90b4c0467832d", 462},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::SE_SWE,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_DEMO,
|
||||||
|
GUIO_NONE
|
||||||
|
},
|
||||||
|
|
||||||
|
AD_TABLE_END_MARKER
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
// File based fallback game description
|
||||||
|
static const ADGameDescription fallbackDescription = {
|
||||||
|
"tlj", "Unknown", {
|
||||||
|
{"x.xarc", 0, NULL, -1},
|
||||||
|
{"chapters.ini", 0, NULL, -1},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
},
|
||||||
|
Common::UNK_LANG,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
ADGF_NO_FLAGS,
|
||||||
|
GUIO_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ADFileBasedFallback fileBasedFallback[] = {
|
||||||
|
{&fallbackDescription, {"x.xarc", "chapters.ini", "w_world.ini", NULL}},
|
||||||
|
{NULL, {NULL}}
|
||||||
|
};*/
|
||||||
|
|
||||||
|
class StarkMetaEngine : public AdvancedMetaEngine {
|
||||||
|
public:
|
||||||
|
StarkMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), starkGames) {
|
||||||
|
_singleid = "stark";
|
||||||
|
_guioptions = GUIO1(GUIO_NOMIDI);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *getName() const override {
|
||||||
|
return "Stark Engine";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *getOriginalCopyright() const override {
|
||||||
|
return "(C) Funcom";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasFeature(MetaEngineFeature f) const override {
|
||||||
|
return
|
||||||
|
(f == kSupportsListSaves) ||
|
||||||
|
(f == kSupportsLoadingDuringStartup) ||
|
||||||
|
(f == kSupportsDeleteSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMaximumSaveSlot() const override {
|
||||||
|
return 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmpSave(const SaveStateDescriptor &x, const SaveStateDescriptor &y) {
|
||||||
|
return x.getSaveSlot() < y.getSaveSlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveStateList listSaves(const char *target) const override {
|
||||||
|
SaveStateList saveList;
|
||||||
|
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("Save??.tlj");
|
||||||
|
|
||||||
|
char slot[3];
|
||||||
|
for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
|
||||||
|
// Extract the slot number from the filename
|
||||||
|
slot[0] = filename->c_str()[4];
|
||||||
|
slot[1] = filename->c_str()[5];
|
||||||
|
slot[2] = '\0';
|
||||||
|
|
||||||
|
// Read the description from the save
|
||||||
|
Common::String description;
|
||||||
|
Common::InSaveFile *save = g_system->getSavefileManager()->openForLoading(*filename);
|
||||||
|
if (save) {
|
||||||
|
StateReadStream *stream = new StateReadStream(save);
|
||||||
|
description = stream->readString();
|
||||||
|
delete stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveList.push_back(SaveStateDescriptor(atoi(slot), description));
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::sort(saveList.begin(), saveList.end(), cmpSave);
|
||||||
|
return saveList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSaveState(const char *target, int slot) const override {
|
||||||
|
Common::String filename = Common::String::format("Save%02d.tlj", slot);
|
||||||
|
g_system->getSavefileManager()->removeSavefile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override {
|
||||||
|
if (desc)
|
||||||
|
*engine = new StarkEngine(syst, desc);
|
||||||
|
|
||||||
|
return desc != 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#if PLUGIN_ENABLED_DYNAMIC(STARK)
|
||||||
|
REGISTER_PLUGIN_DYNAMIC(STARK, PLUGIN_TYPE_ENGINE, Stark::StarkMetaEngine);
|
||||||
|
#else
|
||||||
|
REGISTER_PLUGIN_STATIC(STARK, PLUGIN_TYPE_ENGINE, Stark::StarkMetaEngine);
|
||||||
|
#endif
|
124
engines/stark/formats/biff.cpp
Normal file
124
engines/stark/formats/biff.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/formats/biff.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
BiffArchive::BiffArchive(ArchiveReadStream *stream, ObjectBuilder objectBuilder) :
|
||||||
|
_objectBuilder(objectBuilder) {
|
||||||
|
read(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffArchive::~BiffArchive() {
|
||||||
|
for (uint i = 0; i < _rootObjects.size(); i++) {
|
||||||
|
delete _rootObjects[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiffArchive::read(ArchiveReadStream *stream) {
|
||||||
|
uint32 id = stream->readUint32BE();
|
||||||
|
if (id != MKTAG('B', 'I', 'F', 'F')) {
|
||||||
|
error("Wrong magic while reading biff archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
_version = stream->readUint32LE();
|
||||||
|
/*uint32 u1 = */stream->readUint32LE();
|
||||||
|
/*uint32 u2 = */stream->readUint32LE();
|
||||||
|
|
||||||
|
uint32 len = stream->readUint32LE();
|
||||||
|
for (uint32 i = 0; i < len; i++) {
|
||||||
|
BiffObject *object = readObject(stream, nullptr);
|
||||||
|
|
||||||
|
_rootObjects.push_back(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffObject *BiffArchive::readObject(ArchiveReadStream *stream, BiffObject *parent) {
|
||||||
|
uint32 marker = stream->readUint32LE();
|
||||||
|
if (marker != 0xf0f0f0f0) {
|
||||||
|
error("Wrong magic while reading biff archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 type = stream->readUint32LE();
|
||||||
|
BiffObject *object = _objectBuilder(type);
|
||||||
|
if (!object) {
|
||||||
|
error("Unimplemented BIFF object type %x", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
object->_parent = parent;
|
||||||
|
object->_u3 = stream->readUint32LE();
|
||||||
|
uint32 size = stream->readUint32LE();
|
||||||
|
|
||||||
|
if (_version >= 2) {
|
||||||
|
object->_version = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
object->readData(stream, size);
|
||||||
|
|
||||||
|
marker = stream->readUint32LE();
|
||||||
|
if (marker != 0x0f0f0f0f) {
|
||||||
|
error("Wrong magic while reading biff archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 len = stream->readUint32LE();
|
||||||
|
for (uint32 i = 0; i < len; ++i) {
|
||||||
|
BiffObject *child = readObject(stream, object);
|
||||||
|
object->addChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Array<BiffObject *> BiffArchive::listObjects() {
|
||||||
|
return _rootObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffObject::BiffObject() :
|
||||||
|
_u3(0),
|
||||||
|
_version(0),
|
||||||
|
_parent(nullptr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 BiffObject::getType() const {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiffObject::addChild(BiffObject *child) {
|
||||||
|
_children.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffObject::~BiffObject() {
|
||||||
|
// Delete the children objects
|
||||||
|
Common::Array<BiffObject *>::iterator i = _children.begin();
|
||||||
|
while (i != _children.end()) {
|
||||||
|
delete *i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
136
engines/stark/formats/biff.h
Normal file
136
engines/stark/formats/biff.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_FORMATS_BIFF_H
|
||||||
|
#define STARK_FORMATS_BIFF_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class ArchiveReadStream;
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
class BiffObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tree-style container for BiffObjects
|
||||||
|
*
|
||||||
|
* Users of this class must provide a factory method for the BiffObject subclasses
|
||||||
|
* contained in the archive. This class can only read the archive's structure
|
||||||
|
* and not specific object types.
|
||||||
|
*/
|
||||||
|
class BiffArchive {
|
||||||
|
public:
|
||||||
|
typedef BiffObject *(*ObjectBuilder)(uint32 type);
|
||||||
|
|
||||||
|
BiffArchive(ArchiveReadStream *stream, ObjectBuilder objectBuilder);
|
||||||
|
~BiffArchive();
|
||||||
|
|
||||||
|
/** List the objects at the root level of the archive */
|
||||||
|
Common::Array<BiffObject *> listObjects();
|
||||||
|
|
||||||
|
/** List objects recursively matching the template parameter type */
|
||||||
|
template<class T>
|
||||||
|
Common::Array<T *> listObjectsRecursive();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read(ArchiveReadStream *stream);
|
||||||
|
BiffObject *readObject(ArchiveReadStream *stream, BiffObject *parent);
|
||||||
|
|
||||||
|
ObjectBuilder _objectBuilder;
|
||||||
|
uint32 _version;
|
||||||
|
|
||||||
|
Common::Array<BiffObject *> _rootObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object which can be read from a BiffArchive
|
||||||
|
*
|
||||||
|
* Each object has a list of children objects, resulting in a tree structure
|
||||||
|
*/
|
||||||
|
class BiffObject {
|
||||||
|
public:
|
||||||
|
BiffObject();
|
||||||
|
virtual ~BiffObject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to read the object data from the stream
|
||||||
|
*/
|
||||||
|
virtual void readData(ArchiveReadStream *stream, uint32 dataLength) = 0;
|
||||||
|
|
||||||
|
/** Get the object type */
|
||||||
|
uint32 getType() const;
|
||||||
|
|
||||||
|
/** List children recursively matching the template parameter type */
|
||||||
|
template<class T>
|
||||||
|
Common::Array<T *> listChildrenRecursive();
|
||||||
|
|
||||||
|
/** Add an object to the children list */
|
||||||
|
void addChild(BiffObject *child);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32 _type;
|
||||||
|
uint32 _u3;
|
||||||
|
uint32 _version;
|
||||||
|
|
||||||
|
BiffObject *_parent;
|
||||||
|
Common::Array<BiffObject *> _children;
|
||||||
|
|
||||||
|
friend class BiffArchive;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
Common::Array<T *> BiffArchive::listObjectsRecursive() {
|
||||||
|
Common::Array<BiffObject *> objects = listObjects();
|
||||||
|
|
||||||
|
Common::Array<T *> array;
|
||||||
|
for (uint i = 0; i < objects.size(); i++) {
|
||||||
|
array.push_back(objects[i]->listChildrenRecursive<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
Common::Array<T *> BiffObject::listChildrenRecursive() {
|
||||||
|
Common::Array<T *> list;
|
||||||
|
|
||||||
|
for (uint i = 0; i < _children.size(); i++) {
|
||||||
|
if (_children[i]->getType() == T::TYPE) {
|
||||||
|
// Found a matching child
|
||||||
|
list.push_back(static_cast<T *>(_children[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for matching resources in the child's children
|
||||||
|
list.push_back(_children[i]->listChildrenRecursive<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_FORMATS_BIFF_H
|
424
engines/stark/formats/biffmesh.cpp
Normal file
424
engines/stark/formats/biffmesh.cpp
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/formats/biffmesh.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/biff.h"
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
|
||||||
|
#include "common/hashmap.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
enum BiffMeshObjectType {
|
||||||
|
kMeshObjectSceneData = 0x5a4aa94,
|
||||||
|
kMeshObjectBase = 0x5a4aa89,
|
||||||
|
kMeshObjectTri = 0x5a4aa8d,
|
||||||
|
kMeshObjectMaterial = 0x5a4aa8e
|
||||||
|
};
|
||||||
|
|
||||||
|
class MeshObjectSceneData : public BiffObject {
|
||||||
|
public:
|
||||||
|
static const uint32 TYPE = kMeshObjectSceneData;
|
||||||
|
|
||||||
|
MeshObjectSceneData() :
|
||||||
|
BiffObject() {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BiffObject API
|
||||||
|
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
|
||||||
|
_animStart = stream->readUint32LE();
|
||||||
|
_animEnd = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 _animStart;
|
||||||
|
uint32 _animEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MeshObjectBase : public BiffObject {
|
||||||
|
public:
|
||||||
|
static const uint32 TYPE = kMeshObjectBase;
|
||||||
|
|
||||||
|
MeshObjectBase() :
|
||||||
|
BiffObject() {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BiffObject API
|
||||||
|
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
|
||||||
|
_name = stream->readString16();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::String _name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MeshObjectTri : public BiffObject {
|
||||||
|
public:
|
||||||
|
static const uint32 TYPE = kMeshObjectTri;
|
||||||
|
|
||||||
|
MeshObjectTri() :
|
||||||
|
BiffObject() {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KeyFrame {
|
||||||
|
uint32 time;
|
||||||
|
Math::Quaternion essentialRotation;
|
||||||
|
float determinant;
|
||||||
|
Math::Quaternion stretchRotation;
|
||||||
|
Math::Vector3d scale;
|
||||||
|
Math::Vector3d translation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
Common::String animName1;
|
||||||
|
Common::String animName2;
|
||||||
|
float animInfluence1;
|
||||||
|
float animInfluence2;
|
||||||
|
Math::Vector3d position;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Face {
|
||||||
|
uint32 vertexIndex[3];
|
||||||
|
uint32 normalIndex[3];
|
||||||
|
uint32 textureVertexIndex[3];
|
||||||
|
uint32 materialId;
|
||||||
|
uint32 smoothingGroup;
|
||||||
|
};
|
||||||
|
|
||||||
|
// BiffObject API
|
||||||
|
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
|
||||||
|
_name = stream->readString16();
|
||||||
|
|
||||||
|
uint32 keyFrameCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < keyFrameCount; i++) {
|
||||||
|
KeyFrame keyFrame;
|
||||||
|
keyFrame.time = stream->readUint32LE();
|
||||||
|
keyFrame.essentialRotation = stream->readQuaternion();
|
||||||
|
keyFrame.determinant = stream->readFloat();
|
||||||
|
keyFrame.stretchRotation = stream->readQuaternion();
|
||||||
|
keyFrame.scale = stream->readVector3();
|
||||||
|
keyFrame.translation = stream->readVector3();
|
||||||
|
|
||||||
|
_keyFrames.push_back(keyFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_version >= 2) {
|
||||||
|
uint32 uvKeyFrameCount = stream->readUint32LE();
|
||||||
|
assert(uvKeyFrameCount == 0); // Reading the uv keyframes is not implemented
|
||||||
|
uint32 attributeCount = stream->readUint32LE();
|
||||||
|
assert(attributeCount == 0); // Reading the attributes is not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 vertexCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < vertexCount; i++) {
|
||||||
|
Vertex vertex;
|
||||||
|
vertex.animName1 = stream->readString16();
|
||||||
|
vertex.animName2 = stream->readString16();
|
||||||
|
vertex.animInfluence1 = stream->readFloat();
|
||||||
|
vertex.animInfluence2 = stream->readFloat();
|
||||||
|
vertex.position = stream->readVector3();
|
||||||
|
|
||||||
|
_rawVertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 normalCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < normalCount; i++) {
|
||||||
|
_rawNormals.push_back(stream->readVector3());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 textureVertexCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < textureVertexCount; i++) {
|
||||||
|
_rawTexturePositions.push_back(stream->readVector3());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 faceCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < faceCount; i++) {
|
||||||
|
Face face;
|
||||||
|
face.vertexIndex[0] = stream->readUint32LE();
|
||||||
|
face.vertexIndex[1] = stream->readUint32LE();
|
||||||
|
face.vertexIndex[2] = stream->readUint32LE();
|
||||||
|
face.normalIndex[0] = stream->readUint32LE();
|
||||||
|
face.normalIndex[1] = stream->readUint32LE();
|
||||||
|
face.normalIndex[2] = stream->readUint32LE();
|
||||||
|
face.textureVertexIndex[0] = stream->readUint32LE();
|
||||||
|
face.textureVertexIndex[1] = stream->readUint32LE();
|
||||||
|
face.textureVertexIndex[2] = stream->readUint32LE();
|
||||||
|
face.materialId = stream->readUint32LE();
|
||||||
|
face.smoothingGroup = stream->readUint32LE();
|
||||||
|
|
||||||
|
_rawFaces.push_back(face);
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasPhysics = stream->readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reindex() {
|
||||||
|
// The raw data loaded from the BIFF archive needs to be split into faces of identical material.
|
||||||
|
// Reserve enough faces in our faces array
|
||||||
|
for (uint i = 0; i < _rawFaces.size(); i++) {
|
||||||
|
if (_rawFaces[i].materialId >= _faces.size()) {
|
||||||
|
_faces.resize(_rawFaces[i].materialId + 1);
|
||||||
|
}
|
||||||
|
_faces[_rawFaces[i].materialId].materialId = _rawFaces[i].materialId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The raw data loaded from the BIFF archive is multi-indexed, which is not simple to use to draw.
|
||||||
|
// Here, we reindex the data so that each vertex owns all of its related attributes, hence requiring
|
||||||
|
// a single index list.
|
||||||
|
Common::HashMap<VertexKey, uint32, VertexKey::Hash, VertexKey::EqualTo> vertexIndexMap;
|
||||||
|
for (uint i = 0; i < _rawFaces.size(); i++) {
|
||||||
|
for (uint j = 0; j < 3; j++) {
|
||||||
|
VertexKey vertexKey(_rawFaces[i].vertexIndex[j], _rawFaces[i].normalIndex[j], _rawFaces[i].textureVertexIndex[j]);
|
||||||
|
if (!vertexIndexMap.contains(vertexKey)) {
|
||||||
|
BiffMesh::Vertex vertex;
|
||||||
|
vertex.position = _rawVertices[_rawFaces[i].vertexIndex[j]].position;
|
||||||
|
vertex.normal = _rawNormals[_rawFaces[i].vertexIndex[j]];
|
||||||
|
vertex.texturePosition = _rawTexturePositions[_rawFaces[i].vertexIndex[j]];
|
||||||
|
|
||||||
|
_vertices.push_back(vertex);
|
||||||
|
|
||||||
|
vertexIndexMap.setVal(vertexKey, _vertices.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 vertexIndex = vertexIndexMap.getVal(vertexKey);
|
||||||
|
|
||||||
|
// Add the index to a face according to its material
|
||||||
|
_faces[_rawFaces[i].materialId].vertexIndices.push_back(vertexIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the raw data
|
||||||
|
_rawVertices.clear();
|
||||||
|
_rawNormals.clear();
|
||||||
|
_rawTexturePositions.clear();
|
||||||
|
_rawFaces.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Matrix4 getTransform(uint keyframeIndex) const {
|
||||||
|
const KeyFrame &keyframe = _keyFrames[keyframeIndex];
|
||||||
|
|
||||||
|
Math::Matrix4 rotation = keyframe.essentialRotation.toMatrix();
|
||||||
|
|
||||||
|
Math::Matrix4 translation;
|
||||||
|
translation.setPosition(keyframe.translation);
|
||||||
|
|
||||||
|
Math::Matrix4 scale;
|
||||||
|
scale.setValue(0, 0, keyframe.scale.x());
|
||||||
|
scale.setValue(1, 1, keyframe.scale.y());
|
||||||
|
scale.setValue(2, 2, keyframe.scale.z());
|
||||||
|
|
||||||
|
return translation * rotation * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::Array<BiffMesh::Vertex> &getVertices() const {
|
||||||
|
return _vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::Array<BiffMesh::Face> &getFaces() const {
|
||||||
|
return _faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct VertexKey {
|
||||||
|
uint32 _vertexIndex;
|
||||||
|
uint32 _normalIndex;
|
||||||
|
uint32 _textureVertexIndex;
|
||||||
|
|
||||||
|
VertexKey(uint32 vertexIndex, uint32 normalIndex, uint32 textureVertexIndex) {
|
||||||
|
_vertexIndex = vertexIndex;
|
||||||
|
_normalIndex = normalIndex;
|
||||||
|
_textureVertexIndex = textureVertexIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Hash {
|
||||||
|
uint operator() (const VertexKey &x) const {
|
||||||
|
return x._vertexIndex + x._normalIndex + x._textureVertexIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EqualTo {
|
||||||
|
bool operator() (const VertexKey &x, const VertexKey &y) const {
|
||||||
|
return x._vertexIndex == y._vertexIndex &&
|
||||||
|
x._normalIndex == y._normalIndex &&
|
||||||
|
x._textureVertexIndex == y._textureVertexIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Common::String _name;
|
||||||
|
|
||||||
|
Common::Array<KeyFrame> _keyFrames;
|
||||||
|
|
||||||
|
Common::Array<Vertex> _rawVertices;
|
||||||
|
Common::Array<Face> _rawFaces;
|
||||||
|
Common::Array<Math::Vector3d> _rawNormals;
|
||||||
|
Common::Array<Math::Vector3d> _rawTexturePositions;
|
||||||
|
|
||||||
|
Common::Array<BiffMesh::Vertex> _vertices;
|
||||||
|
Common::Array<BiffMesh::Face> _faces;
|
||||||
|
|
||||||
|
bool _hasPhysics;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MeshObjectMaterial : public BiffObject {
|
||||||
|
public:
|
||||||
|
static const uint32 TYPE = kMeshObjectMaterial;
|
||||||
|
|
||||||
|
MeshObjectMaterial() :
|
||||||
|
BiffObject() {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BiffObject API
|
||||||
|
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
|
||||||
|
_name = stream->readString16();
|
||||||
|
_texture = stream->readString16();
|
||||||
|
_alpha = stream->readString16();
|
||||||
|
_environment = stream->readString16();
|
||||||
|
|
||||||
|
_shading = stream->readUint32LE();
|
||||||
|
_ambiant = stream->readVector3();
|
||||||
|
_diffuse = stream->readVector3();
|
||||||
|
_specular = stream->readVector3();
|
||||||
|
|
||||||
|
_shininess = stream->readFloat();
|
||||||
|
_opacity = stream->readFloat();
|
||||||
|
|
||||||
|
_doubleSided = stream->readByte();
|
||||||
|
_textureTiling = stream->readUint32LE();
|
||||||
|
_alphaTiling = stream->readUint32LE();
|
||||||
|
_environementTiling = stream->readUint32LE();
|
||||||
|
|
||||||
|
_isColorKey = stream->readByte();
|
||||||
|
_colorKey = stream->readUint32LE();
|
||||||
|
|
||||||
|
uint32 attributeCount = stream->readUint32LE();
|
||||||
|
assert(attributeCount == 0); // Reading the attributes is not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffMesh::Material toMaterial() const {
|
||||||
|
BiffMesh::Material material;
|
||||||
|
material.texture = _texture;
|
||||||
|
material.r = _diffuse.x();
|
||||||
|
material.g = _diffuse.y();
|
||||||
|
material.b = _diffuse.z();
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::String &getTexture() const {
|
||||||
|
return _texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::String _name;
|
||||||
|
Common::String _texture;
|
||||||
|
Common::String _alpha;
|
||||||
|
Common::String _environment;
|
||||||
|
|
||||||
|
uint32 _shading;
|
||||||
|
Math::Vector3d _ambiant;
|
||||||
|
Math::Vector3d _diffuse;
|
||||||
|
Math::Vector3d _specular;
|
||||||
|
|
||||||
|
float _shininess;
|
||||||
|
float _opacity;
|
||||||
|
|
||||||
|
bool _doubleSided;
|
||||||
|
uint32 _textureTiling;
|
||||||
|
uint32 _alphaTiling;
|
||||||
|
uint32 _environementTiling;
|
||||||
|
|
||||||
|
bool _isColorKey;
|
||||||
|
uint32 _colorKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
BiffMesh *BiffMeshReader::read(ArchiveReadStream *stream) {
|
||||||
|
BiffArchive archive = BiffArchive(stream, &biffObjectBuilder);
|
||||||
|
Common::Array<MeshObjectTri *> tris = archive.listObjectsRecursive<MeshObjectTri>();
|
||||||
|
Common::Array<MeshObjectMaterial *> materialObjects = archive.listObjectsRecursive<MeshObjectMaterial>();
|
||||||
|
|
||||||
|
if (tris.size() != 1) {
|
||||||
|
error("Unexpected tri count in BIFF archive: '%d'", tris.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
tris[0]->reindex();
|
||||||
|
|
||||||
|
Common::Array<BiffMesh::Material> materials;
|
||||||
|
for (uint i = 0; i < materialObjects.size(); i++) {
|
||||||
|
materials.push_back(materialObjects[i]->toMaterial());
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffMesh *mesh = new BiffMesh(tris[0]->getVertices(), tris[0]->getFaces(), materials);
|
||||||
|
mesh->setTransform(tris[0]->getTransform(0));
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffObject *BiffMeshReader::biffObjectBuilder(uint32 type) {
|
||||||
|
switch (type) {
|
||||||
|
case kMeshObjectSceneData:
|
||||||
|
return new MeshObjectSceneData();
|
||||||
|
case kMeshObjectBase:
|
||||||
|
return new MeshObjectBase();
|
||||||
|
case kMeshObjectTri:
|
||||||
|
return new MeshObjectTri();
|
||||||
|
case kMeshObjectMaterial:
|
||||||
|
return new MeshObjectMaterial();
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffMesh::BiffMesh(const Common::Array<Vertex> &vertices, const Common::Array<Face> &faces,
|
||||||
|
const Common::Array<Material> &materials) :
|
||||||
|
_vertices(vertices),
|
||||||
|
_faces(faces),
|
||||||
|
_materials(materials) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::Array<BiffMesh::Vertex> &BiffMesh::getVertices() const {
|
||||||
|
return _vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::Array<BiffMesh::Face> &BiffMesh::getFaces() const {
|
||||||
|
return _faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::Array<BiffMesh::Material> &BiffMesh::getMaterials() const {
|
||||||
|
return _materials;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiffMesh::setTransform(const Math::Matrix4 &transform) {
|
||||||
|
_transform = transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Matrix4 BiffMesh::getTransform() const {
|
||||||
|
return _transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
96
engines/stark/formats/biffmesh.h
Normal file
96
engines/stark/formats/biffmesh.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_FORMATS_BIFF_MESH_H
|
||||||
|
#define STARK_FORMATS_BIFF_MESH_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
|
||||||
|
#include "math/matrix4.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class ArchiveReadStream;
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
class BiffObject;
|
||||||
|
class BiffMesh;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mesh reader
|
||||||
|
*
|
||||||
|
* Reads a mesh out of a BIFF archive
|
||||||
|
*/
|
||||||
|
class BiffMeshReader {
|
||||||
|
public:
|
||||||
|
/** Read a mesh from a BIFF archive stream */
|
||||||
|
static BiffMesh *read(ArchiveReadStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static BiffObject *biffObjectBuilder(uint32 type);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mesh read out of a BIFF archive
|
||||||
|
*/
|
||||||
|
class BiffMesh {
|
||||||
|
public:
|
||||||
|
struct Vertex {
|
||||||
|
Math::Vector3d position;
|
||||||
|
Math::Vector3d normal;
|
||||||
|
Math::Vector3d texturePosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Face {
|
||||||
|
Common::Array<uint32> vertexIndices;
|
||||||
|
uint32 materialId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
Common::String texture;
|
||||||
|
float r, g, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
BiffMesh(const Common::Array<Vertex> &vertices, const Common::Array<Face> &faces, const Common::Array<Material> &materials);
|
||||||
|
|
||||||
|
const Common::Array<Vertex> &getVertices() const;
|
||||||
|
const Common::Array<Face> &getFaces() const;
|
||||||
|
const Common::Array<Material> &getMaterials() const;
|
||||||
|
Math::Matrix4 getTransform() const;
|
||||||
|
|
||||||
|
void setTransform(const Math::Matrix4 &transform);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::Array<Vertex> _vertices;
|
||||||
|
Common::Array<Face> _faces;
|
||||||
|
Common::Array<Material> _materials;
|
||||||
|
|
||||||
|
Math::Matrix4 _transform;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_FORMATS_BIFF_MESH_H
|
115
engines/stark/formats/iss.cpp
Normal file
115
engines/stark/formats/iss.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/formats/iss.h"
|
||||||
|
|
||||||
|
#include "audio/decoders/adpcm_intern.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ADPCM decoder for the .iss files
|
||||||
|
*/
|
||||||
|
class ISSADPCMStream : public Audio::Ima_ADPCMStream {
|
||||||
|
public:
|
||||||
|
ISSADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
|
||||||
|
: Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int readBuffer(int16 *buffer, const int numSamples) {
|
||||||
|
// Similar to MS IMA, but without the four-bytes-per-channel requirement
|
||||||
|
int samples;
|
||||||
|
|
||||||
|
assert(numSamples % 2 == 0);
|
||||||
|
|
||||||
|
for (samples = 0; samples < numSamples && !endOfData(); samples += 2) {
|
||||||
|
if (_blockPos[0] == _blockAlign) {
|
||||||
|
// read block header
|
||||||
|
for (byte i = 0; i < _channels; i++) {
|
||||||
|
_status.ima_ch[i].last = _stream->readSint16LE();
|
||||||
|
_status.ima_ch[i].stepIndex = _stream->readSint16LE();
|
||||||
|
}
|
||||||
|
_blockPos[0] = 4 * _channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte data = _stream->readByte();
|
||||||
|
buffer[samples + (isStereo() ? 1 : 0)] = decodeIMA(data & 0x0f, isStereo() ? 1 : 0);
|
||||||
|
buffer[samples + (isStereo() ? 0 : 1)] = decodeIMA((data >> 4) & 0x0f);
|
||||||
|
_blockPos[0]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Common::String readString(Common::SeekableReadStream *stream) {
|
||||||
|
Common::String ret = "";
|
||||||
|
byte ch;
|
||||||
|
while ((ch = stream->readByte()) != 0x20)
|
||||||
|
ret += ch;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Audio::RewindableAudioStream *makeISSStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
|
||||||
|
Common::String codec;
|
||||||
|
uint16 blockSize, channels, freq;
|
||||||
|
uint32 size;
|
||||||
|
|
||||||
|
codec = readString(stream);
|
||||||
|
|
||||||
|
if (codec.equals("IMA_ADPCM_Sound")) {
|
||||||
|
|
||||||
|
codec = readString(stream);
|
||||||
|
blockSize = (uint16)strtol(codec.c_str(), 0, 10);
|
||||||
|
|
||||||
|
readString(stream);
|
||||||
|
// name ?
|
||||||
|
|
||||||
|
readString(stream);
|
||||||
|
// ?
|
||||||
|
|
||||||
|
codec = readString(stream);
|
||||||
|
channels = (uint16)strtol(codec.c_str(), 0, 10) + 1;
|
||||||
|
|
||||||
|
readString(stream);
|
||||||
|
// ?
|
||||||
|
|
||||||
|
codec = readString(stream);
|
||||||
|
freq = 44100 / (uint16)strtol(codec.c_str(), 0, 10);
|
||||||
|
|
||||||
|
readString(stream);
|
||||||
|
|
||||||
|
readString(stream);
|
||||||
|
|
||||||
|
codec = readString(stream);
|
||||||
|
size = (uint32)strtol(codec.c_str(), 0, 10);
|
||||||
|
|
||||||
|
return new ISSADPCMStream(stream, DisposeAfterUse::YES, size, freq, channels, blockSize);
|
||||||
|
} else {
|
||||||
|
error("Unknown ISS codec '%s'", codec.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
46
engines/stark/formats/iss.h
Normal file
46
engines/stark/formats/iss.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_ISS_H
|
||||||
|
#define STARK_ISS_H
|
||||||
|
|
||||||
|
#include "common/stream.h"
|
||||||
|
|
||||||
|
#include "audio/audiostream.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RewindableAudioStream from the ISS data in the given stream.
|
||||||
|
* ISS is the file format used by the 4 CD version of the game.
|
||||||
|
*
|
||||||
|
* @param stream the SeekableReadStream from which to read the ISS data
|
||||||
|
* @param disposeAfterUse whether to delete the stream after use
|
||||||
|
* @return a new RewindableAudioStream, or NULL, if an error occurred
|
||||||
|
*/
|
||||||
|
Audio::RewindableAudioStream *makeISSStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_ISS_H
|
164
engines/stark/formats/tm.cpp
Normal file
164
engines/stark/formats/tm.cpp
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/formats/tm.h"
|
||||||
|
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/biff.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
enum TextureSetType {
|
||||||
|
kTextureSetGroup = 0x02faf082,
|
||||||
|
kTextureSetTexture = 0x02faf080
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureGroup : public BiffObject {
|
||||||
|
public:
|
||||||
|
static const uint32 TYPE = kTextureSetGroup;
|
||||||
|
|
||||||
|
TextureGroup() :
|
||||||
|
BiffObject(),
|
||||||
|
_palette(nullptr) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TextureGroup() {
|
||||||
|
delete[] _palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte *getPalette() {
|
||||||
|
return _palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BiffObject API
|
||||||
|
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
|
||||||
|
int entries = stream->readUint32LE();
|
||||||
|
_palette = new byte[entries * 3];
|
||||||
|
|
||||||
|
byte *ptr = _palette;
|
||||||
|
for (int i = 0; i < entries; ++i) {
|
||||||
|
*ptr++ = (byte) stream->readUint16LE();
|
||||||
|
*ptr++ = (byte) stream->readUint16LE();
|
||||||
|
*ptr++ = (byte) stream->readUint16LE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
byte *_palette;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Texture : public BiffObject {
|
||||||
|
public:
|
||||||
|
static const uint32 TYPE = kTextureSetTexture;
|
||||||
|
|
||||||
|
Texture() :
|
||||||
|
BiffObject(),
|
||||||
|
_texture(nullptr) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Texture() {
|
||||||
|
delete _texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String getName() const {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::Texture *acquireTexturePointer() {
|
||||||
|
Gfx::Texture *texture = _texture;
|
||||||
|
_texture = nullptr;
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BiffObject API
|
||||||
|
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
|
||||||
|
TextureGroup *textureGroup = static_cast<TextureGroup *>(_parent);
|
||||||
|
|
||||||
|
_name = stream->readString16();
|
||||||
|
_u = stream->readByte();
|
||||||
|
|
||||||
|
uint32 w = stream->readUint32LE();
|
||||||
|
uint32 h = stream->readUint32LE();
|
||||||
|
uint32 levels = stream->readUint32LE();
|
||||||
|
|
||||||
|
_texture = StarkGfx->createTexture();
|
||||||
|
_texture->setLevelCount(levels);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < levels; ++i) {
|
||||||
|
// Read the pixel data to a surface
|
||||||
|
Graphics::Surface level;
|
||||||
|
level.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
|
||||||
|
stream->read(level.getPixels(), level.w * level.h);
|
||||||
|
|
||||||
|
// Add the mipmap level to the texture
|
||||||
|
_texture->addLevel(i, &level, textureGroup->getPalette());
|
||||||
|
|
||||||
|
level.free();
|
||||||
|
|
||||||
|
w /= 2;
|
||||||
|
h /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::String _name;
|
||||||
|
Gfx::Texture *_texture;
|
||||||
|
byte _u;
|
||||||
|
};
|
||||||
|
|
||||||
|
Gfx::TextureSet *TextureSetReader::read(ArchiveReadStream *stream) {
|
||||||
|
BiffArchive archive = BiffArchive(stream, &biffObjectBuilder);
|
||||||
|
|
||||||
|
Common::Array<Texture *> textures = archive.listObjectsRecursive<Texture>();
|
||||||
|
|
||||||
|
Gfx::TextureSet *textureSet = new Gfx::TextureSet();
|
||||||
|
for (uint i = 0; i < textures.size(); i++) {
|
||||||
|
textureSet->addTexture(textures[i]->getName(), textures[i]->acquireTexturePointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return textureSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
BiffObject *TextureSetReader::biffObjectBuilder(uint32 type) {
|
||||||
|
switch (type) {
|
||||||
|
case kTextureSetGroup:
|
||||||
|
return new TextureGroup();
|
||||||
|
case kTextureSetTexture:
|
||||||
|
return new Texture();
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
60
engines/stark/formats/tm.h
Normal file
60
engines/stark/formats/tm.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_FORMATS_TM_H
|
||||||
|
#define STARK_FORMATS_TM_H
|
||||||
|
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class ArchiveReadStream;
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
class TextureSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
class BiffObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A texture set loader able to read '.tm' files
|
||||||
|
*/
|
||||||
|
class TextureSetReader {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Load a texture set from the provided stream.
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing the texture set.
|
||||||
|
*/
|
||||||
|
static Gfx::TextureSet *read(ArchiveReadStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static BiffObject *biffObjectBuilder(uint32 type);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_FORMATS_TM_H
|
218
engines/stark/formats/xarc.cpp
Normal file
218
engines/stark/formats/xarc.cpp
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Based on the Xentax Wiki documentation:
|
||||||
|
// http://wiki.xentax.com/index.php?title=The_Longest_Journey_XARC
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xarc.h"
|
||||||
|
#include "engines/stark/debug.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
#include "common/substream.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
// ARCHIVE MEMBER
|
||||||
|
|
||||||
|
class XARCMember : public Common::ArchiveMember {
|
||||||
|
public:
|
||||||
|
XARCMember(const XARCArchive *xarc, Common::ReadStream &stream, uint32 offset);
|
||||||
|
|
||||||
|
Common::SeekableReadStream *createReadStream() const;
|
||||||
|
Common::String getName() const { return _name; }
|
||||||
|
uint32 getLength() const { return _length; }
|
||||||
|
uint32 getOffset() const { return _offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const XARCArchive *_xarc;
|
||||||
|
Common::String _name;
|
||||||
|
uint32 _offset;
|
||||||
|
uint32 _length;
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
Common::String readString(Common::ReadStream &stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
XARCMember::XARCMember(const XARCArchive *xarc, Common::ReadStream &stream, uint32 offset) {
|
||||||
|
_xarc = xarc;
|
||||||
|
|
||||||
|
// Read the information about this archive member
|
||||||
|
_name = readString(stream);
|
||||||
|
_offset = offset;
|
||||||
|
_length = stream.readUint32LE();
|
||||||
|
debugC(20, kDebugArchive, "Stark::XARC Member: \"%s\" starts at offset=%d and has length=%d", _name.c_str(), _offset, _length);
|
||||||
|
|
||||||
|
// Unknown value. English: 0, others: 1
|
||||||
|
uint32 unknown = stream.readUint32LE();
|
||||||
|
debugC(kDebugUnknown, "Stark::XARC Member: \"%s\" has unknown=%d", _name.c_str(), unknown);
|
||||||
|
if (unknown != 0 && unknown != 1) {
|
||||||
|
warning("Stark::XARC Member: \"%s\" has unknown=%d with unknown meaning", _name.c_str(), unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::SeekableReadStream *XARCMember::createReadStream() const {
|
||||||
|
return _xarc->createReadStreamForMember(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String XARCMember::readString(Common::ReadStream &stream) {
|
||||||
|
Common::String str;
|
||||||
|
|
||||||
|
// Read until we find a 0
|
||||||
|
char c = 1;
|
||||||
|
while (c != 0) {
|
||||||
|
c = stream.readByte();
|
||||||
|
if (stream.eos()) {
|
||||||
|
c = 0;
|
||||||
|
} else {
|
||||||
|
str += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ARCHIVE
|
||||||
|
|
||||||
|
bool XARCArchive::open(const Common::String &filename) {
|
||||||
|
Common::File stream;
|
||||||
|
if (!stream.open(filename)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_filename = filename;
|
||||||
|
|
||||||
|
// Unknown: always 1? version?
|
||||||
|
uint32 unknown = stream.readUint32LE();
|
||||||
|
debugC(kDebugUnknown, "Stark::XARC: \"%s\" has unknown=%d", _filename.c_str(), unknown);
|
||||||
|
if (unknown != 1) {
|
||||||
|
warning("Stark::XARC: \"%s\" has unknown=%d with unknown meaning", _filename.c_str(), unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the number of contained files
|
||||||
|
uint32 numFiles = stream.readUint32LE();
|
||||||
|
debugC(20, kDebugArchive, "Stark::XARC: \"%s\" contains %d files", _filename.c_str(), numFiles);
|
||||||
|
|
||||||
|
// Read the offset to the contents of the first file
|
||||||
|
uint32 offset = stream.readUint32LE();
|
||||||
|
debugC(20, kDebugArchive, "Stark::XARC: \"%s\"'s first file has offset=%d", _filename.c_str(), offset);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < numFiles; i++) {
|
||||||
|
XARCMember *member = new XARCMember(this, stream, offset);
|
||||||
|
_members.push_back(Common::ArchiveMemberPtr(member));
|
||||||
|
|
||||||
|
// Set the offset to the next member
|
||||||
|
offset += member->getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String XARCArchive::getFilename() const {
|
||||||
|
return _filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XARCArchive::hasFile(const Common::String &name) const {
|
||||||
|
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||||
|
if ((*it)->getName() == name) {
|
||||||
|
// Found it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XARCArchive::listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern) const {
|
||||||
|
int matches = 0;
|
||||||
|
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||||
|
if ((*it)->getName().matchString(pattern)) {
|
||||||
|
// This file matches, add it
|
||||||
|
list.push_back(*it);
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XARCArchive::listMembers(Common::ArchiveMemberList &list) const {
|
||||||
|
int files = 0;
|
||||||
|
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||||
|
// Add all the members to the list
|
||||||
|
list.push_back(*it);
|
||||||
|
files++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::ArchiveMemberPtr XARCArchive::getMember(const Common::String &name) const {
|
||||||
|
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||||
|
if ((*it)->getName() == name) {
|
||||||
|
// Found it
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, return an empty ptr
|
||||||
|
return Common::ArchiveMemberPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::SeekableReadStream *XARCArchive::createReadStreamForMember(const Common::String &name) const {
|
||||||
|
for (Common::ArchiveMemberList::const_iterator it = _members.begin(); it != _members.end(); ++it) {
|
||||||
|
if ((*it)->getName() == name) {
|
||||||
|
// Found it
|
||||||
|
return createReadStreamForMember((const XARCMember *)it->get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::SeekableReadStream *XARCArchive::createReadStreamForMember(const XARCMember *member) const {
|
||||||
|
// Open the xarc file
|
||||||
|
Common::File *f = new Common::File;
|
||||||
|
if (!f)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!f->open(_filename)) {
|
||||||
|
delete f;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the substream that contains the archive member
|
||||||
|
uint32 offset = member->getOffset();
|
||||||
|
uint32 length = member->getLength();
|
||||||
|
return new Common::SeekableSubReadStream(f, offset, offset + length, DisposeAfterUse::YES);
|
||||||
|
|
||||||
|
// Different approach: keep the archive open and read full resources to memory
|
||||||
|
//f.seek(member->getOffset());
|
||||||
|
//return f.readStream(member->getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
56
engines/stark/formats/xarc.h
Normal file
56
engines/stark/formats/xarc.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_ARCHIVE_H
|
||||||
|
#define STARK_ARCHIVE_H
|
||||||
|
|
||||||
|
#include "common/archive.h"
|
||||||
|
#include "common/stream.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
class XARCMember;
|
||||||
|
|
||||||
|
class XARCArchive : public Common::Archive {
|
||||||
|
public:
|
||||||
|
bool open(const Common::String &filename);
|
||||||
|
Common::String getFilename() const;
|
||||||
|
|
||||||
|
// Archive API
|
||||||
|
bool hasFile(const Common::String &name) const;
|
||||||
|
int listMatchingMembers(Common::ArchiveMemberList &list, const Common::String &pattern) const;
|
||||||
|
int listMembers(Common::ArchiveMemberList &list) const;
|
||||||
|
const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
|
||||||
|
Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
|
||||||
|
|
||||||
|
Common::SeekableReadStream *createReadStreamForMember(const XARCMember *member) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::String _filename;
|
||||||
|
Common::ArchiveMemberList _members;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_ARCHIVE_H
|
223
engines/stark/formats/xmg.cpp
Normal file
223
engines/stark/formats/xmg.cpp
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xmg.h"
|
||||||
|
#include "engines/stark/debug.h"
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
|
||||||
|
#include "graphics/conversion.h"
|
||||||
|
#include "graphics/pixelformat.h"
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
#include "common/stream.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
Graphics::Surface *XMGDecoder::decode(Common::ReadStream *stream) {
|
||||||
|
XMGDecoder dec;
|
||||||
|
return dec.decodeImage(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fix color handling in BE machines?
|
||||||
|
Graphics::Surface *XMGDecoder::decodeImage(Common::ReadStream *stream) {
|
||||||
|
_stream = stream;
|
||||||
|
|
||||||
|
// Read the file version
|
||||||
|
uint32 version = stream->readUint32LE();
|
||||||
|
if (version != 3) {
|
||||||
|
error("Stark::XMG: File version unknown: %d", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the transparency color (RGBA)
|
||||||
|
_transColor = stream->readUint32LE();
|
||||||
|
|
||||||
|
// Read the image size
|
||||||
|
_width = stream->readUint32LE();
|
||||||
|
_height = stream->readUint32LE();
|
||||||
|
debugC(10, kDebugXMG, "Stark::XMG: Version=%d, TransparencyColor=0x%08x, size=%dx%d", version, _transColor, _width, _height);
|
||||||
|
|
||||||
|
// Read the scan length
|
||||||
|
uint32 scanLen = stream->readUint32LE();
|
||||||
|
if (scanLen != 3 * _width) {
|
||||||
|
error("Stark::XMG: The scan length (%d) doesn't match the width bytes (%d)", scanLen, 3 * _width);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown
|
||||||
|
uint32 unknown2 = stream->readUint32LE();
|
||||||
|
debugC(kDebugUnknown, "Stark::XMG: unknown2 = %08x = %d", unknown2, unknown2);
|
||||||
|
uint32 unknown3 = stream->readUint32LE();
|
||||||
|
debugC(kDebugUnknown, "Stark::XMG: unknown3 = %08x = %d", unknown3, unknown3);
|
||||||
|
|
||||||
|
// Create the destination surface
|
||||||
|
Graphics::Surface *surface = new Graphics::Surface();
|
||||||
|
surface->create(_width, _height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
|
||||||
|
|
||||||
|
_currX = 0, _currY = 0;
|
||||||
|
while (!stream->eos()) {
|
||||||
|
if (_currX >= _width) {
|
||||||
|
assert(_currX == _width);
|
||||||
|
_currX = 0;
|
||||||
|
_currY += 2;
|
||||||
|
if (_currY >= _height)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the number and mode of the tiles
|
||||||
|
byte op = stream->readByte();
|
||||||
|
uint16 count;
|
||||||
|
if ((op & 0xC0) != 0xC0) {
|
||||||
|
count = op & 0x3F;
|
||||||
|
} else {
|
||||||
|
count = ((op & 0xF) << 8) + stream->readByte();
|
||||||
|
op <<= 2;
|
||||||
|
}
|
||||||
|
op &= 0xC0;
|
||||||
|
|
||||||
|
// Process the current serie
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
Block block = decodeBlock(op);
|
||||||
|
drawBlock(block, surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMGDecoder::Block XMGDecoder::decodeBlock(byte op) {
|
||||||
|
Block block;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case 0x00:
|
||||||
|
// YCrCb
|
||||||
|
block = processYCrCb();
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
// Trans
|
||||||
|
block = processTrans();
|
||||||
|
break;
|
||||||
|
case 0x80:
|
||||||
|
// RGB
|
||||||
|
block = processRGB();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unsupported color mode '%d'", op);
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XMGDecoder::drawBlock(const Block &block, Graphics::Surface *surface) {
|
||||||
|
uint32 *pixels = (uint32 *)surface->getBasePtr(_currX, _currY);
|
||||||
|
|
||||||
|
bool drawTwoColumns = _currX + 1 < _width;
|
||||||
|
bool drawTwoLines = _currY + 1 < _height;
|
||||||
|
|
||||||
|
pixels[0] = block.a1;
|
||||||
|
|
||||||
|
if (drawTwoColumns) {
|
||||||
|
pixels[1] = block.a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawTwoLines) {
|
||||||
|
pixels[_width + 0] = block.b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawTwoColumns && drawTwoLines) {
|
||||||
|
pixels[_width + 1] = block.b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currX += drawTwoColumns ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMGDecoder::Block XMGDecoder::processYCrCb() {
|
||||||
|
byte y0, y1, y2, y3;
|
||||||
|
byte cr, cb;
|
||||||
|
|
||||||
|
y0 = _stream->readByte();
|
||||||
|
y1 = _stream->readByte();
|
||||||
|
y2 = _stream->readByte();
|
||||||
|
y3 = _stream->readByte();
|
||||||
|
cr = _stream->readByte();
|
||||||
|
cb = _stream->readByte();
|
||||||
|
|
||||||
|
byte r, g, b;
|
||||||
|
Block block;
|
||||||
|
|
||||||
|
Graphics::YUV2RGB(y0, cb, cr, r, g, b);
|
||||||
|
block.a1 = (255u << 24) + (b << 16) + (g << 8) + r;
|
||||||
|
|
||||||
|
Graphics::YUV2RGB(y1, cb, cr, r, g, b);
|
||||||
|
block.a2 = (255u << 24) + (b << 16) + (g << 8) + r;
|
||||||
|
|
||||||
|
Graphics::YUV2RGB(y2, cb, cr, r, g, b);
|
||||||
|
block.b1 = (255u << 24) + (b << 16) + (g << 8) + r;
|
||||||
|
|
||||||
|
Graphics::YUV2RGB(y3, cb, cr, r, g, b);
|
||||||
|
block.b2 = (255u << 24) + (b << 16) + (g << 8) + r;
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMGDecoder::Block XMGDecoder::processTrans() {
|
||||||
|
Block block;
|
||||||
|
|
||||||
|
block.a1 = _transColor;
|
||||||
|
block.a2 = _transColor;
|
||||||
|
block.b1 = _transColor;
|
||||||
|
block.b2 = _transColor;
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMGDecoder::Block XMGDecoder::processRGB() {
|
||||||
|
Block block;
|
||||||
|
uint32 color;
|
||||||
|
|
||||||
|
color = _stream->readUint16LE();
|
||||||
|
color += _stream->readByte() << 16;
|
||||||
|
if (color != _transColor)
|
||||||
|
color += 255 << 24;
|
||||||
|
block.a1 = color;
|
||||||
|
|
||||||
|
color = _stream->readUint16LE();
|
||||||
|
color += _stream->readByte() << 16;
|
||||||
|
if (color != _transColor)
|
||||||
|
color += 255 << 24;
|
||||||
|
block.a2 = color;
|
||||||
|
|
||||||
|
color = _stream->readUint16LE();
|
||||||
|
color += _stream->readByte() << 16;
|
||||||
|
if (color != _transColor)
|
||||||
|
color += 255 << 24;
|
||||||
|
block.b1 = color;
|
||||||
|
|
||||||
|
color = _stream->readUint16LE();
|
||||||
|
color += _stream->readByte() << 16;
|
||||||
|
if (color != _transColor)
|
||||||
|
color += 255 << 24;
|
||||||
|
block.b2 = color;
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
72
engines/stark/formats/xmg.h
Normal file
72
engines/stark/formats/xmg.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_XMG_H
|
||||||
|
#define STARK_XMG_H
|
||||||
|
|
||||||
|
#include "common/stream.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
struct Surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XMG (still image) decoder
|
||||||
|
*/
|
||||||
|
class XMGDecoder {
|
||||||
|
public:
|
||||||
|
static Graphics::Surface *decode(Common::ReadStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
XMGDecoder() {}
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
uint32 a1, a2;
|
||||||
|
uint32 b1, b2;
|
||||||
|
};
|
||||||
|
|
||||||
|
Graphics::Surface *decodeImage(Common::ReadStream *stream);
|
||||||
|
Block decodeBlock(byte op);
|
||||||
|
void drawBlock(const Block &block, Graphics::Surface *surface);
|
||||||
|
|
||||||
|
Block processYCrCb();
|
||||||
|
Block processTrans();
|
||||||
|
Block processRGB();
|
||||||
|
|
||||||
|
uint32 _width;
|
||||||
|
uint32 _height;
|
||||||
|
|
||||||
|
uint32 _currX;
|
||||||
|
uint32 _currY;
|
||||||
|
|
||||||
|
Common::ReadStream *_stream;
|
||||||
|
|
||||||
|
uint32 _transColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_XMG_H
|
332
engines/stark/formats/xrc.cpp
Normal file
332
engines/stark/formats/xrc.cpp
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xarc.h"
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/animhierarchy.h"
|
||||||
|
#include "engines/stark/resources/animscript.h"
|
||||||
|
#include "engines/stark/resources/bonesmesh.h"
|
||||||
|
#include "engines/stark/resources/bookmark.h"
|
||||||
|
#include "engines/stark/resources/camera.h"
|
||||||
|
#include "engines/stark/resources/command.h"
|
||||||
|
#include "engines/stark/resources/dialog.h"
|
||||||
|
#include "engines/stark/resources/direction.h"
|
||||||
|
#include "engines/stark/resources/fmv.h"
|
||||||
|
#include "engines/stark/resources/image.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
#include "engines/stark/resources/floorface.h"
|
||||||
|
#include "engines/stark/resources/floorfield.h"
|
||||||
|
#include "engines/stark/resources/knowledge.h"
|
||||||
|
#include "engines/stark/resources/knowledgeset.h"
|
||||||
|
#include "engines/stark/resources/layer.h"
|
||||||
|
#include "engines/stark/resources/level.h"
|
||||||
|
#include "engines/stark/resources/light.h"
|
||||||
|
#include "engines/stark/resources/lipsync.h"
|
||||||
|
#include "engines/stark/resources/location.h"
|
||||||
|
#include "engines/stark/resources/path.h"
|
||||||
|
#include "engines/stark/resources/pattable.h"
|
||||||
|
#include "engines/stark/resources/root.h"
|
||||||
|
#include "engines/stark/resources/script.h"
|
||||||
|
#include "engines/stark/resources/scroll.h"
|
||||||
|
#include "engines/stark/resources/speech.h"
|
||||||
|
#include "engines/stark/resources/sound.h"
|
||||||
|
#include "engines/stark/resources/string.h"
|
||||||
|
#include "engines/stark/resources/textureset.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
XRCReadStream::XRCReadStream(const Common::String &archiveName,
|
||||||
|
Common::SeekableReadStream *parentStream, DisposeAfterUse::Flag disposeParentStream) :
|
||||||
|
SeekableSubReadStream(parentStream, 0, parentStream->size(), disposeParentStream),
|
||||||
|
_archiveName(archiveName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
XRCReadStream::~XRCReadStream() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String XRCReadStream::readString() {
|
||||||
|
// Read the string length
|
||||||
|
uint16 length = readUint16LE();
|
||||||
|
|
||||||
|
// Read the string
|
||||||
|
char *data = new char[length];
|
||||||
|
read(data, length);
|
||||||
|
Common::String string(data, length);
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Type XRCReadStream::readResourceType() {
|
||||||
|
byte rawType;
|
||||||
|
rawType = readByte();
|
||||||
|
return Resources::Type((Resources::Type::ResourceType) (rawType));
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceReference XRCReadStream::readResourceReference() {
|
||||||
|
ResourceReference reference;
|
||||||
|
reference.loadFromStream(this);
|
||||||
|
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d XRCReadStream::readVector3() {
|
||||||
|
Math::Vector3d v;
|
||||||
|
v.readFromStream(this);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Rect XRCReadStream::readRect() {
|
||||||
|
Common::Rect r;
|
||||||
|
r.left = readSint32LE();
|
||||||
|
r.top = readSint32LE();
|
||||||
|
r.right = readSint32LE();
|
||||||
|
r.bottom = readSint32LE();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Point XRCReadStream::readPoint() {
|
||||||
|
uint32 x = readUint32LE();
|
||||||
|
uint32 y = readUint32LE();
|
||||||
|
|
||||||
|
return Common::Point(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float XRCReadStream::readFloat() {
|
||||||
|
float f;
|
||||||
|
read(&f, sizeof(float));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XRCReadStream::readBool() {
|
||||||
|
uint32 b = readUint32LE();
|
||||||
|
return b != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XRCReadStream::isDataLeft() {
|
||||||
|
return pos() < size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String XRCReadStream::getArchiveName() const {
|
||||||
|
return _archiveName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Object *XRCReader::importTree(XARCArchive *archive) {
|
||||||
|
// Find the XRC file
|
||||||
|
Common::ArchiveMemberList members;
|
||||||
|
archive->listMatchingMembers(members, "*.xrc");
|
||||||
|
if (members.size() == 0) {
|
||||||
|
error("No resource tree in archive '%s'", archive->getFilename().c_str());
|
||||||
|
}
|
||||||
|
if (members.size() > 1) {
|
||||||
|
error("Too many resource scripts in archive '%s'", archive->getFilename().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the XRC file
|
||||||
|
Common::SeekableReadStream *stream = archive->createReadStreamForMember(members.front()->getName());
|
||||||
|
XRCReadStream *xrcStream = new XRCReadStream(archive->getFilename(), stream);
|
||||||
|
|
||||||
|
// Import the resource tree
|
||||||
|
Resources::Object *root = importResource(xrcStream, nullptr);
|
||||||
|
|
||||||
|
delete xrcStream;
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Object *XRCReader::importResource(XRCReadStream *stream, Resources::Object *parent) {
|
||||||
|
Resources::Object *resource = createResource(stream, parent);
|
||||||
|
importResourceData(stream, resource);
|
||||||
|
importResourceChildren(stream, resource);
|
||||||
|
|
||||||
|
// Resource lifecycle update
|
||||||
|
resource->onPostRead();
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Object *XRCReader::createResource(XRCReadStream *stream, Resources::Object *parent) {
|
||||||
|
// Read the resource type and subtype
|
||||||
|
Resources::Type type = stream->readResourceType();
|
||||||
|
byte subType = stream->readByte();
|
||||||
|
|
||||||
|
// Read the resource properties
|
||||||
|
uint16 index = stream->readUint16LE();
|
||||||
|
Common::String name = stream->readString();
|
||||||
|
|
||||||
|
// Create a new resource
|
||||||
|
Resources::Object *resource;
|
||||||
|
switch (type.get()) {
|
||||||
|
case Resources::Type::kRoot:
|
||||||
|
resource = new Resources::Root(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kLevel:
|
||||||
|
resource = new Resources::Level(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kLocation:
|
||||||
|
resource = new Resources::Location(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kLayer:
|
||||||
|
resource = Resources::Layer::construct(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kCamera:
|
||||||
|
resource = new Resources::Camera(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kFloor:
|
||||||
|
resource = new Resources::Floor(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kFloorFace:
|
||||||
|
resource = new Resources::FloorFace(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kItem:
|
||||||
|
resource = Resources::Item::construct(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kScript:
|
||||||
|
resource = new Resources::Script(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kAnimHierarchy:
|
||||||
|
resource = new Resources::AnimHierarchy(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kAnim:
|
||||||
|
resource = Resources::Anim::construct(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kDirection:
|
||||||
|
resource = new Resources::Direction(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kImage:
|
||||||
|
resource = Resources::Image::construct(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kAnimScript:
|
||||||
|
resource = new Resources::AnimScript(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kAnimScriptItem:
|
||||||
|
resource = new Resources::AnimScriptItem(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kSoundItem:
|
||||||
|
resource = new Resources::Sound(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kPath:
|
||||||
|
resource = Resources::Path::construct(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kFloorField:
|
||||||
|
resource = new Resources::FloorField(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kBookmark:
|
||||||
|
resource = new Resources::Bookmark(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kKnowledgeSet:
|
||||||
|
resource = new Resources::KnowledgeSet(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kKnowledge:
|
||||||
|
resource = new Resources::Knowledge(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kCommand:
|
||||||
|
resource = new Resources::Command(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kPATTable:
|
||||||
|
resource = new Resources::PATTable(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kDialog:
|
||||||
|
resource = new Resources::Dialog(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kSpeech:
|
||||||
|
resource = new Resources::Speech(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kLight:
|
||||||
|
resource = new Resources::Light(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kBonesMesh:
|
||||||
|
resource = new Resources::BonesMesh(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kScroll:
|
||||||
|
resource = new Resources::Scroll(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kFMV:
|
||||||
|
resource = new Resources::FMV(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kLipSync:
|
||||||
|
resource = new Resources::LipSync(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kString:
|
||||||
|
resource = new Resources::String(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
case Resources::Type::kTextureSet:
|
||||||
|
resource = new Resources::TextureSet(parent, subType, index, name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resource = new Resources::UnimplementedResource(parent, type, subType, index, name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XRCReader::importResourceData(XRCReadStream *stream, Resources::Object *resource) {
|
||||||
|
// Read the data length
|
||||||
|
uint32 dataLength = stream->readUint32LE();
|
||||||
|
|
||||||
|
// Read the resource type specific data using a memory stream
|
||||||
|
if (dataLength > 0) {
|
||||||
|
XRCReadStream *xrcDataStream = new XRCReadStream(stream->getArchiveName(), stream->readStream(dataLength));
|
||||||
|
|
||||||
|
resource->readData(xrcDataStream);
|
||||||
|
|
||||||
|
if (xrcDataStream->isDataLeft()) {
|
||||||
|
warning("Not all XRC data was read. Type %s, subtype %d, name %s",
|
||||||
|
resource->getType().getName(), resource->getSubType(), resource->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xrcDataStream->eos()) {
|
||||||
|
warning("Too much XRC data was read. Type %s, subtype %d, name %s",
|
||||||
|
resource->getType().getName(), resource->getSubType(), resource->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete xrcDataStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XRCReader::importResourceChildren(XRCReadStream *stream, Resources::Object *resource) {
|
||||||
|
// Get the number of children
|
||||||
|
uint16 numChildren = stream->readUint16LE();
|
||||||
|
|
||||||
|
// Read more unknown data
|
||||||
|
uint16 unknown3 = stream->readUint16LE();
|
||||||
|
if (unknown3 != 0) {
|
||||||
|
warning("Stark::XRCReader: \"%s\" has unknown3=0x%04X with unknown meaning", resource->getName().c_str(), unknown3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the children resources
|
||||||
|
for (int i = 0; i < numChildren; i++) {
|
||||||
|
Resources::Object *child = importResource(stream, resource);
|
||||||
|
|
||||||
|
// Add child to parent
|
||||||
|
resource->addChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
88
engines/stark/formats/xrc.h
Normal file
88
engines/stark/formats/xrc.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_XRC_READER_H
|
||||||
|
#define STARK_XRC_READER_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "common/substream.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
#include "math/vector4d.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Formats {
|
||||||
|
|
||||||
|
class XARCArchive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A read stream with helper functions to read usual XRC data types
|
||||||
|
*/
|
||||||
|
class XRCReadStream : public Common::SeekableSubReadStream {
|
||||||
|
public:
|
||||||
|
XRCReadStream(const Common::String &archiveName, Common::SeekableReadStream *parentStream, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::YES);
|
||||||
|
virtual ~XRCReadStream();
|
||||||
|
|
||||||
|
/** Obtain the file name of the archive containing the XRC tree */
|
||||||
|
Common::String getArchiveName() const;
|
||||||
|
|
||||||
|
Common::String readString();
|
||||||
|
Resources::Type readResourceType();
|
||||||
|
ResourceReference readResourceReference();
|
||||||
|
Math::Vector3d readVector3();
|
||||||
|
Common::Rect readRect();
|
||||||
|
Common::Point readPoint();
|
||||||
|
float readFloat();
|
||||||
|
bool readBool();
|
||||||
|
bool isDataLeft();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::String _archiveName;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An XRC stream parser, used to build resource trees.
|
||||||
|
*/
|
||||||
|
class XRCReader {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Build a resource tree from a stream
|
||||||
|
*/
|
||||||
|
static Resources::Object *importTree(XARCArchive *archive);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static Resources::Object *importResource(XRCReadStream *stream, Resources::Object *parent);
|
||||||
|
static Resources::Object *createResource(XRCReadStream *stream, Resources::Object *parent);
|
||||||
|
static void importResourceChildren(XRCReadStream *stream, Resources::Object *resource);
|
||||||
|
static void importResourceData(XRCReadStream* stream, Resources::Object* resource);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Formats
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_XRC_READER_H
|
101
engines/stark/gfx/driver.cpp
Normal file
101
engines/stark/gfx/driver.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
#include "engines/stark/gfx/opengls.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
Driver *Driver::create() {
|
||||||
|
Driver *driver = NULL;
|
||||||
|
|
||||||
|
#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
|
||||||
|
// OpenGL Shaders
|
||||||
|
driver = new OpenGLSDriver();
|
||||||
|
if (driver)
|
||||||
|
return driver;
|
||||||
|
#endif // defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
|
||||||
|
|
||||||
|
error("Couldn't instance any graphics driver");
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics::PixelFormat Driver::getScreenFormat() {
|
||||||
|
return Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Driver::computeScreenViewport() {
|
||||||
|
int32 screenWidth = g_system->getWidth();
|
||||||
|
int32 screenHeight = g_system->getHeight();
|
||||||
|
|
||||||
|
if (g_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
|
||||||
|
// Aspect ratio correction
|
||||||
|
int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
|
||||||
|
int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
|
||||||
|
_screenViewport = Common::Rect(viewportWidth, viewportHeight);
|
||||||
|
|
||||||
|
// Pillarboxing
|
||||||
|
_screenViewport.translate((screenWidth - viewportWidth) / 2,
|
||||||
|
(screenHeight - viewportHeight) / 2);
|
||||||
|
} else {
|
||||||
|
// Aspect ratio correction disabled, just stretch
|
||||||
|
_screenViewport = Common::Rect(screenWidth, screenHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Rect Driver::gameViewport() const {
|
||||||
|
Common::Rect game = Common::Rect(_screenViewport.width(), _screenViewport.height() * kGameViewportHeight / kOriginalHeight);
|
||||||
|
game.translate(_screenViewport.left, _screenViewport.top + _screenViewport.height() * kBottomBorderHeight / kOriginalHeight);
|
||||||
|
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Point Driver::getScreenPosBounded(const Common::Point &point) const {
|
||||||
|
Common::Point boundedPos = point;
|
||||||
|
boundedPos.x = CLIP<int16>(boundedPos.x, _screenViewport.left, _screenViewport.right);
|
||||||
|
|
||||||
|
return boundedPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Point Driver::convertCoordinateCurrentToOriginal(const Common::Point &point) const {
|
||||||
|
// Most of the engine expects 640x480 coordinates
|
||||||
|
Common::Point scaledPosition = point;
|
||||||
|
scaledPosition.x -= _screenViewport.left;
|
||||||
|
scaledPosition.y -= _screenViewport.top;
|
||||||
|
scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, _screenViewport.width());
|
||||||
|
scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, _screenViewport.height());
|
||||||
|
scaledPosition.x *= kOriginalWidth / (float)_screenViewport.width();
|
||||||
|
scaledPosition.y *= kOriginalHeight / (float)_screenViewport.height();
|
||||||
|
|
||||||
|
return scaledPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint Driver::scaleWidthOriginalToCurrent(uint width) const {
|
||||||
|
return _screenViewport.width() * width / kOriginalWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint Driver::scaleHeightOriginalToCurrent(uint height) const {
|
||||||
|
return _screenViewport.height() * height / kOriginalHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
124
engines/stark/gfx/driver.h
Normal file
124
engines/stark/gfx/driver.h
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_DRIVER_H
|
||||||
|
#define STARK_GFX_DRIVER_H
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
#include "math/matrix4.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class VisualActor;
|
||||||
|
class VisualProp;
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
class SurfaceRenderer;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
class Driver {
|
||||||
|
public:
|
||||||
|
static Driver *create();
|
||||||
|
|
||||||
|
virtual ~Driver() {}
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
|
||||||
|
virtual void setScreenViewport(bool noScaling) = 0; // deprecated
|
||||||
|
|
||||||
|
virtual void setViewport(Common::Rect rect, bool noScaling) = 0;
|
||||||
|
|
||||||
|
/** Get the screen viewport in actual resolution */
|
||||||
|
Common::Rect getScreenViewport() { return _screenViewport; }
|
||||||
|
|
||||||
|
Common::Rect gameViewport() const;
|
||||||
|
|
||||||
|
virtual void clearScreen() = 0;
|
||||||
|
virtual void flipBuffer() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new texture
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual Texture *createTexture(const Graphics::Surface *surface = nullptr, const byte *palette = nullptr) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new actor renderer
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing it.
|
||||||
|
*/
|
||||||
|
virtual VisualActor *createActorRenderer() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new prop renderer
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing it.
|
||||||
|
*/
|
||||||
|
virtual VisualProp *createPropRenderer() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new surface renderer
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing it.
|
||||||
|
*/
|
||||||
|
virtual SurfaceRenderer *createSurfaceRenderer() = 0;
|
||||||
|
|
||||||
|
/** Bound a screen coordinate coord within the actual game area */
|
||||||
|
Common::Point getScreenPosBounded(const Common::Point &point) const;
|
||||||
|
|
||||||
|
/** Convert a coordinate from current to original resolution */
|
||||||
|
Common::Point convertCoordinateCurrentToOriginal(const Common::Point &point) const;
|
||||||
|
|
||||||
|
/** Scale a width value from original resolution to current resolution */
|
||||||
|
uint scaleWidthOriginalToCurrent(uint width) const;
|
||||||
|
|
||||||
|
/** Scale a height value from original resolution to current resolution */
|
||||||
|
uint scaleHeightOriginalToCurrent(uint height) const;
|
||||||
|
|
||||||
|
virtual Graphics::PixelFormat getScreenFormat();
|
||||||
|
|
||||||
|
virtual void set3DMode() = 0;
|
||||||
|
|
||||||
|
static const int32 kOriginalWidth = 640;
|
||||||
|
static const int32 kOriginalHeight = 480;
|
||||||
|
|
||||||
|
static const int32 kTopBorderHeight = 36;
|
||||||
|
static const int32 kGameViewportHeight = 365;
|
||||||
|
static const int32 kBottomBorderHeight = 79;
|
||||||
|
|
||||||
|
static const int32 kGameViewportWidth = 640;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void computeScreenViewport();
|
||||||
|
|
||||||
|
Common::Rect _screenViewport;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_DRIVER_H
|
182
engines/stark/gfx/opengls.cpp
Normal file
182
engines/stark/gfx/opengls.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/opengls.h"
|
||||||
|
|
||||||
|
#include "common/config-manager.h"
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "math/matrix4.h"
|
||||||
|
|
||||||
|
#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/openglsactor.h"
|
||||||
|
#include "engines/stark/gfx/openglsprop.h"
|
||||||
|
#include "engines/stark/gfx/openglssurface.h"
|
||||||
|
#include "engines/stark/gfx/opengltexture.h"
|
||||||
|
|
||||||
|
#include "graphics/pixelbuffer.h"
|
||||||
|
#include "graphics/opengles2/shader.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
static const GLfloat surfaceVertices[] = {
|
||||||
|
// XS YT
|
||||||
|
0.0, 0.0,
|
||||||
|
1.0, 0.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenGLSDriver::OpenGLSDriver() :
|
||||||
|
_surfaceShader(nullptr),
|
||||||
|
_actorShader(nullptr),
|
||||||
|
_surfaceVBO(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLSDriver::~OpenGLSDriver() {
|
||||||
|
Graphics::Shader::freeBuffer(_surfaceVBO);
|
||||||
|
delete _surfaceShader;
|
||||||
|
delete _actorShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::init() {
|
||||||
|
bool fullscreen = ConfMan.getBool("fullscreen");
|
||||||
|
g_system->setupScreen(kOriginalWidth, kOriginalHeight, fullscreen, true);
|
||||||
|
|
||||||
|
computeScreenViewport();
|
||||||
|
|
||||||
|
static const char* attributes[] = { "position", "texcoord", nullptr };
|
||||||
|
_surfaceShader = Graphics::Shader::fromFiles("stark_surface", attributes);
|
||||||
|
_surfaceVBO = Graphics::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(surfaceVertices), surfaceVertices);
|
||||||
|
_surfaceShader->enableVertexAttribute("position", _surfaceVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
|
||||||
|
_surfaceShader->enableVertexAttribute("texcoord", _surfaceVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
|
||||||
|
|
||||||
|
static const char* actorAttributes[] = { "position1", "position2", "bone1", "bone2", "boneWeight", "normal", "texcoord", nullptr };
|
||||||
|
_actorShader = Graphics::Shader::fromFiles("stark_actor", actorAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::setScreenViewport(bool noScaling) {
|
||||||
|
if (noScaling) {
|
||||||
|
_viewport = Common::Rect(g_system->getWidth(), g_system->getHeight());
|
||||||
|
_unscaledViewport = _viewport;
|
||||||
|
} else {
|
||||||
|
_viewport = _screenViewport;
|
||||||
|
_unscaledViewport = Common::Rect(kOriginalWidth, kOriginalHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
glViewport(_viewport.left, _viewport.top, _viewport.width(), _viewport.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::setViewport(Common::Rect rect, bool noScaling) {
|
||||||
|
if (noScaling) {
|
||||||
|
_viewport = rect;
|
||||||
|
_unscaledViewport = rect;
|
||||||
|
} else {
|
||||||
|
_viewport = Common::Rect(
|
||||||
|
_screenViewport.width() * rect.width() / kOriginalWidth,
|
||||||
|
_screenViewport.height() * rect.height() / kOriginalHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
_viewport.translate(
|
||||||
|
_screenViewport.left + _screenViewport.width() * rect.left / kOriginalWidth,
|
||||||
|
_screenViewport.top + _screenViewport.height() * rect.top / kOriginalHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
_unscaledViewport = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
glViewport(_viewport.left, g_system->getHeight() - _viewport.bottom, _viewport.width(), _viewport.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::clearScreen() {
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::flipBuffer() {
|
||||||
|
g_system->updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture *OpenGLSDriver::createTexture(const Graphics::Surface *surface, const byte *palette) {
|
||||||
|
OpenGlTexture *texture = new OpenGlTexture();
|
||||||
|
|
||||||
|
if (surface) {
|
||||||
|
texture->update(surface, palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualActor *OpenGLSDriver::createActorRenderer() {
|
||||||
|
return new OpenGLSActorRenderer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualProp *OpenGLSDriver::createPropRenderer() {
|
||||||
|
return new OpenGLSPropRenderer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceRenderer *OpenGLSDriver::createSurfaceRenderer() {
|
||||||
|
return new OpenGLSSurfaceRenderer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::start2DMode() {
|
||||||
|
// Enable alpha blending
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
//glBlendEquation(GL_FUNC_ADD); // It's the default
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::end2DMode() {
|
||||||
|
// Disable alpha blending
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSDriver::set3DMode() {
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Rect OpenGLSDriver::getViewport() const {
|
||||||
|
return _viewport;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Rect OpenGLSDriver::getUnscaledViewport() const {
|
||||||
|
return _unscaledViewport;
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics::Shader *OpenGLSDriver::createActorShaderInstance() {
|
||||||
|
return _actorShader->clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
Graphics::Shader *OpenGLSDriver::createSurfaceShaderInstance() {
|
||||||
|
return _surfaceShader->clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
|
85
engines/stark/gfx/opengls.h
Normal file
85
engines/stark/gfx/opengls.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_OPENGLS_H
|
||||||
|
#define STARK_GFX_OPENGLS_H
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
|
||||||
|
#include "math/vector2d.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
class Shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
class OpenGLSDriver : public Driver {
|
||||||
|
public:
|
||||||
|
OpenGLSDriver();
|
||||||
|
~OpenGLSDriver();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
|
||||||
|
void setScreenViewport(bool noScaling) override;
|
||||||
|
void setViewport(Common::Rect rect, bool noScaling) override;
|
||||||
|
|
||||||
|
void clearScreen() override;
|
||||||
|
void flipBuffer() override;
|
||||||
|
|
||||||
|
Texture *createTexture(const Graphics::Surface *surface = nullptr, const byte *palette = nullptr) override;
|
||||||
|
VisualActor *createActorRenderer() override;
|
||||||
|
VisualProp *createPropRenderer() override;
|
||||||
|
SurfaceRenderer *createSurfaceRenderer() override;
|
||||||
|
|
||||||
|
Graphics::Shader *createActorShaderInstance();
|
||||||
|
Graphics::Shader *createSurfaceShaderInstance();
|
||||||
|
|
||||||
|
void start2DMode();
|
||||||
|
void end2DMode();
|
||||||
|
void set3DMode();
|
||||||
|
|
||||||
|
Common::Rect getViewport() const;
|
||||||
|
Common::Rect getUnscaledViewport() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::Rect _viewport;
|
||||||
|
Common::Rect _unscaledViewport;
|
||||||
|
|
||||||
|
Graphics::Shader *_surfaceShader;
|
||||||
|
Graphics::Shader *_actorShader;
|
||||||
|
uint32 _surfaceVBO;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
|
||||||
|
|
||||||
|
#endif // STARK_GFX_OPENGLS_H
|
293
engines/stark/gfx/openglsactor.cpp
Normal file
293
engines/stark/gfx/openglsactor.cpp
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/openglsactor.h"
|
||||||
|
|
||||||
|
#include "engines/stark/model/model.h"
|
||||||
|
#include "engines/stark/model/skeleton.h"
|
||||||
|
#include "engines/stark/scene.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/gfx/opengls.h"
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
#include "graphics/opengles2/shader.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
OpenGLSActorRenderer::OpenGLSActorRenderer(OpenGLSDriver *gfx) :
|
||||||
|
VisualActor(),
|
||||||
|
_gfx(gfx) {
|
||||||
|
_shader = _gfx->createActorShaderInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLSActorRenderer::~OpenGLSActorRenderer() {
|
||||||
|
clearVertices();
|
||||||
|
|
||||||
|
delete _shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSActorRenderer::render(const Math::Vector3d position, float direction, const LightEntryArray &lights) {
|
||||||
|
if (_meshIsDirty) {
|
||||||
|
// Update the OpenGL Buffer Objects if required
|
||||||
|
clearVertices();
|
||||||
|
uploadVertices();
|
||||||
|
_meshIsDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_model->getSkeleton()->animate(_time);
|
||||||
|
|
||||||
|
_gfx->set3DMode();
|
||||||
|
|
||||||
|
Math::Matrix4 model = getModelMatrix(position, direction);
|
||||||
|
Math::Matrix4 view = StarkScene->getViewMatrix();
|
||||||
|
Math::Matrix4 projection = StarkScene->getProjectionMatrix();
|
||||||
|
|
||||||
|
Math::Matrix4 modelViewMatrix = view * model;
|
||||||
|
modelViewMatrix.transpose(); // OpenGL expects matrices transposed when compared to ResidualVM's
|
||||||
|
|
||||||
|
Math::Matrix4 projectionMatrix = projection;
|
||||||
|
projectionMatrix.transpose(); // OpenGL expects matrices transposed when compared to ResidualVM's
|
||||||
|
|
||||||
|
Math::Matrix4 normalMatrix = modelViewMatrix;
|
||||||
|
normalMatrix.invertAffineOrthonormal();
|
||||||
|
//normalMatrix.transpose(); // OpenGL expects matrices transposed when compared to ResidualVM's
|
||||||
|
//normalMatrix.transpose(); // No need to transpose twice in a row
|
||||||
|
|
||||||
|
_shader->use(true);
|
||||||
|
_shader->setUniform("modelViewMatrix", modelViewMatrix);
|
||||||
|
_shader->setUniform("projectionMatrix", projectionMatrix);
|
||||||
|
_shader->setUniform("normalMatrix", normalMatrix.getRotation());
|
||||||
|
setBoneRotationArrayUniform("boneRotation");
|
||||||
|
setBonePositionArrayUniform("bonePosition");
|
||||||
|
setLightArrayUniform("lights", lights);
|
||||||
|
|
||||||
|
Common::Array<MeshNode *> meshes = _model->getMeshes();
|
||||||
|
Common::Array<MaterialNode *> mats = _model->getMaterials();
|
||||||
|
const Gfx::TextureSet *texture = _model->getTextureSet();
|
||||||
|
|
||||||
|
for (Common::Array<MeshNode *>::const_iterator mesh = meshes.begin(); mesh != meshes.end(); ++mesh) {
|
||||||
|
for (Common::Array<FaceNode *>::const_iterator face = (*mesh)->_faces.begin(); face != (*mesh)->_faces.end(); ++face) {
|
||||||
|
// For each face draw its vertices from the VBO, indexed by the EBO
|
||||||
|
const MaterialNode *material = mats[(*face)->_matIdx];
|
||||||
|
const Gfx::Texture *tex = texture->getTexture(material->_texName);
|
||||||
|
if (tex) {
|
||||||
|
tex->bind();
|
||||||
|
} else {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint vbo = _faceVBO[*face];
|
||||||
|
GLuint ebo = _faceEBO[*face];
|
||||||
|
|
||||||
|
_shader->enableVertexAttribute("position1", vbo, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 0);
|
||||||
|
_shader->enableVertexAttribute("position2", vbo, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 12);
|
||||||
|
_shader->enableVertexAttribute("bone1", vbo, 1, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 24);
|
||||||
|
_shader->enableVertexAttribute("bone2", vbo, 1, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 28);
|
||||||
|
_shader->enableVertexAttribute("boneWeight", vbo, 1, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 32);
|
||||||
|
_shader->enableVertexAttribute("normal", vbo, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 36);
|
||||||
|
_shader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float), 48);
|
||||||
|
_shader->use(true);
|
||||||
|
_shader->setUniform("textured", tex != nullptr);
|
||||||
|
_shader->setUniform("color", Math::Vector3d(material->_r, material->_g, material->_b));
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
glDrawElements(GL_TRIANGLES, 3 * (*face)->_tris.size(), GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSActorRenderer::clearVertices() {
|
||||||
|
for (FaceBufferMap::iterator it = _faceVBO.begin(); it != _faceVBO.end(); ++it) {
|
||||||
|
Graphics::Shader::freeBuffer(it->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
|
||||||
|
Graphics::Shader::freeBuffer(it->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_faceVBO.clear();
|
||||||
|
_faceEBO.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSActorRenderer::uploadVertices() {
|
||||||
|
Common::Array<MeshNode *> meshes = _model->getMeshes();
|
||||||
|
for (Common::Array<MeshNode *>::const_iterator mesh = meshes.begin(); mesh != meshes.end(); ++mesh) {
|
||||||
|
for (Common::Array<FaceNode *>::const_iterator face = (*mesh)->_faces.begin(); face != (*mesh)->_faces.end(); ++face) {
|
||||||
|
_faceVBO[*face] = createFaceVBO(*face);
|
||||||
|
_faceEBO[*face] = createFaceEBO(*face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 OpenGLSActorRenderer::createFaceVBO(const FaceNode *face) {
|
||||||
|
float *vertices = new float[14 * face->_verts.size()];
|
||||||
|
float *vertPtr = vertices;
|
||||||
|
|
||||||
|
// Build a vertex array
|
||||||
|
for (Common::Array<VertNode *>::const_iterator tri = face->_verts.begin(); tri != face->_verts.end(); ++tri) {
|
||||||
|
*vertPtr++ = (*tri)->_pos1.x();
|
||||||
|
*vertPtr++ = (*tri)->_pos1.y();
|
||||||
|
*vertPtr++ = (*tri)->_pos1.z();
|
||||||
|
|
||||||
|
*vertPtr++ = (*tri)->_pos2.x();
|
||||||
|
*vertPtr++ = (*tri)->_pos2.y();
|
||||||
|
*vertPtr++ = (*tri)->_pos2.z();
|
||||||
|
|
||||||
|
*vertPtr++ = (*tri)->_bone1;
|
||||||
|
*vertPtr++ = (*tri)->_bone2;
|
||||||
|
|
||||||
|
*vertPtr++ = (*tri)->_boneWeight;
|
||||||
|
|
||||||
|
*vertPtr++ = (*tri)->_normal.x();
|
||||||
|
*vertPtr++ = (*tri)->_normal.y();
|
||||||
|
*vertPtr++ = (*tri)->_normal.z();
|
||||||
|
|
||||||
|
*vertPtr++ = -(*tri)->_texS;
|
||||||
|
*vertPtr++ = (*tri)->_texT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 vbo = Graphics::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 14 * face->_verts.size(), vertices);
|
||||||
|
delete[] vertices;
|
||||||
|
|
||||||
|
return vbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 OpenGLSActorRenderer::createFaceEBO(const FaceNode *face) {
|
||||||
|
uint32 *indices = new uint32[3 * face->_tris.size()];
|
||||||
|
uint32 *idxPtr = indices;
|
||||||
|
|
||||||
|
// Build a vertex indices array
|
||||||
|
for (Common::Array<TriNode *>::const_iterator tri = face->_tris.begin(); tri != face->_tris.end(); ++tri) {
|
||||||
|
for (int vert = 0; vert < 3; ++vert) {
|
||||||
|
if (vert == 0)
|
||||||
|
*idxPtr++ = (*tri)->_vert1;
|
||||||
|
else if (vert == 1)
|
||||||
|
*idxPtr++ = (*tri)->_vert2;
|
||||||
|
else
|
||||||
|
*idxPtr++ = (*tri)->_vert3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ebo = Graphics::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * 3 * face->_tris.size(), indices);
|
||||||
|
delete[] indices;
|
||||||
|
|
||||||
|
return ebo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSActorRenderer::setBonePositionArrayUniform(const char *uniform) {
|
||||||
|
const Common::Array<BoneNode *> bones = _model->getSkeleton()->getBones();
|
||||||
|
|
||||||
|
GLint pos = _shader->getUniformLocation(uniform);
|
||||||
|
if (pos == -1) {
|
||||||
|
error("No uniform named '%s'", uniform);
|
||||||
|
}
|
||||||
|
|
||||||
|
float *positions = new float[3 * bones.size()];
|
||||||
|
float *positionsPtr = positions;
|
||||||
|
|
||||||
|
for (uint i = 0; i < bones.size(); i++) {
|
||||||
|
*positionsPtr++ = bones[i]->_animPos.x();
|
||||||
|
*positionsPtr++ = bones[i]->_animPos.y();
|
||||||
|
*positionsPtr++ = bones[i]->_animPos.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
glUniform3fv(pos, bones.size(), positions);
|
||||||
|
delete[] positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSActorRenderer::setBoneRotationArrayUniform(const char *uniform) {
|
||||||
|
const Common::Array<BoneNode *> bones = _model->getSkeleton()->getBones();
|
||||||
|
|
||||||
|
GLint rot = _shader->getUniformLocation(uniform);
|
||||||
|
if (rot == -1) {
|
||||||
|
error("No uniform named '%s'", uniform);
|
||||||
|
}
|
||||||
|
|
||||||
|
float *rotations = new float[4 * bones.size()];
|
||||||
|
float *rotationsPtr = rotations;
|
||||||
|
|
||||||
|
for (uint i = 0; i < bones.size(); i++) {
|
||||||
|
*rotationsPtr++ = bones[i]->_animRot.x();
|
||||||
|
*rotationsPtr++ = bones[i]->_animRot.y();
|
||||||
|
*rotationsPtr++ = bones[i]->_animRot.z();
|
||||||
|
*rotationsPtr++ = bones[i]->_animRot.w();
|
||||||
|
}
|
||||||
|
|
||||||
|
glUniform4fv(rot, bones.size(), rotations);
|
||||||
|
delete[] rotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSActorRenderer::setLightArrayUniform(const char *uniform, const LightEntryArray &lights) {
|
||||||
|
static const uint maxLights = 10;
|
||||||
|
|
||||||
|
assert(lights.size() >= 1);
|
||||||
|
assert(lights.size() <= maxLights);
|
||||||
|
|
||||||
|
const LightEntry *ambient = lights[0];
|
||||||
|
assert(ambient->type == LightEntry::kAmbient); // The first light must be the ambient light
|
||||||
|
_shader->setUniform("ambientColor", ambient->color);
|
||||||
|
|
||||||
|
Math::Matrix4 viewMatrix = StarkScene->getViewMatrix();
|
||||||
|
Math::Matrix3 viewMatrixRot = viewMatrix.getRotation();
|
||||||
|
|
||||||
|
for (uint i = 0; i < lights.size() - 1; i++) {
|
||||||
|
const LightEntry *l = lights[i + 1];
|
||||||
|
|
||||||
|
Math::Vector4d worldPosition;
|
||||||
|
worldPosition.x() = l->position.x();
|
||||||
|
worldPosition.y() = l->position.y();
|
||||||
|
worldPosition.z() = l->position.z();
|
||||||
|
worldPosition.w() = 1.0;
|
||||||
|
|
||||||
|
Math::Vector4d eyePosition = viewMatrix * worldPosition;
|
||||||
|
|
||||||
|
// The light type is stored in the w coordinate of the position to save an uniform slot
|
||||||
|
eyePosition.w() = l->type;
|
||||||
|
|
||||||
|
Math::Vector3d worldDirection = l->direction;
|
||||||
|
Math::Vector3d eyeDirection = viewMatrixRot * worldDirection;
|
||||||
|
eyeDirection.normalize();
|
||||||
|
|
||||||
|
_shader->setUniform(Common::String::format("lights[%d].position", i).c_str(), eyePosition);
|
||||||
|
_shader->setUniform(Common::String::format("lights[%d].direction", i).c_str(), eyeDirection);
|
||||||
|
_shader->setUniform(Common::String::format("lights[%d].color", i).c_str(), l->color);
|
||||||
|
|
||||||
|
Math::Vector4d params;
|
||||||
|
params.x() = l->falloffNear;
|
||||||
|
params.y() = l->falloffFar;
|
||||||
|
params.z() = l->innerConeAngle.getCosine();
|
||||||
|
params.w() = l->outerConeAngle.getCosine();
|
||||||
|
|
||||||
|
_shader->setUniform(Common::String::format("lights[%d].params", i).c_str(), params);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = lights.size() - 1; i < maxLights; i++) {
|
||||||
|
// Make sure unused lights are disabled
|
||||||
|
_shader->setUniform(Common::String::format("lights[%d].position", i).c_str(), Math::Vector4d());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
69
engines/stark/gfx/openglsactor.h
Normal file
69
engines/stark/gfx/openglsactor.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_OPENGL_S_ACTOR_H
|
||||||
|
#define STARK_GFX_OPENGL_S_ACTOR_H
|
||||||
|
|
||||||
|
#include "common/hashmap.h"
|
||||||
|
|
||||||
|
#include "engines/stark/hash-ptr.h"
|
||||||
|
#include "engines/stark/gfx/renderentry.h"
|
||||||
|
#include "engines/stark/visual/actor.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
class Shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
class OpenGLSDriver;
|
||||||
|
|
||||||
|
class OpenGLSActorRenderer : public VisualActor {
|
||||||
|
public:
|
||||||
|
OpenGLSActorRenderer(OpenGLSDriver *gfx);
|
||||||
|
virtual ~OpenGLSActorRenderer();
|
||||||
|
|
||||||
|
void render(const Math::Vector3d position, float direction, const LightEntryArray &lights) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef Common::HashMap<FaceNode *, uint32> FaceBufferMap;
|
||||||
|
|
||||||
|
OpenGLSDriver *_gfx;
|
||||||
|
Graphics::Shader *_shader;
|
||||||
|
|
||||||
|
FaceBufferMap _faceVBO;
|
||||||
|
FaceBufferMap _faceEBO;
|
||||||
|
|
||||||
|
void clearVertices();
|
||||||
|
void uploadVertices();
|
||||||
|
uint32 createFaceVBO(const FaceNode *face);
|
||||||
|
uint32 createFaceEBO(const FaceNode *face);
|
||||||
|
void setBonePositionArrayUniform(const char *uniform);
|
||||||
|
void setBoneRotationArrayUniform(const char *uniform);
|
||||||
|
void setLightArrayUniform(const char *uniform, const LightEntryArray &lights);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_OPENGL_S_ACTOR_H
|
129
engines/stark/gfx/openglsprop.cpp
Normal file
129
engines/stark/gfx/openglsprop.cpp
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/openglsprop.h"
|
||||||
|
|
||||||
|
#include "engines/stark/scene.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
#include "graphics/opengles2/shader.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
OpenGLSPropRenderer::OpenGLSPropRenderer(Driver *gfx) :
|
||||||
|
VisualProp(),
|
||||||
|
_gfx(gfx),
|
||||||
|
_faceVBO(-1) {
|
||||||
|
static const char* attributes[] = { "position", "normal", "texcoord", nullptr };
|
||||||
|
_shader = Graphics::Shader::fromFiles("stark_prop", attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLSPropRenderer::~OpenGLSPropRenderer() {
|
||||||
|
clearVertices();
|
||||||
|
|
||||||
|
delete _shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSPropRenderer::render(const Math::Vector3d position, float direction) {
|
||||||
|
if (_faceVBO == -1) {
|
||||||
|
// Update the OpenGL Buffer Objects if required
|
||||||
|
clearVertices();
|
||||||
|
uploadVertices();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gfx->set3DMode();
|
||||||
|
|
||||||
|
Math::Matrix4 model = getModelMatrix(position, direction);
|
||||||
|
Math::Matrix4 view = StarkScene->getViewMatrix();
|
||||||
|
Math::Matrix4 projection = StarkScene->getProjectionMatrix();
|
||||||
|
|
||||||
|
Math::Matrix4 mvp = projection * view * model;
|
||||||
|
mvp.transpose();
|
||||||
|
|
||||||
|
_shader->use(true);
|
||||||
|
_shader->setUniform("mvp", mvp);
|
||||||
|
|
||||||
|
const Common::Array<Formats::BiffMesh::Face> &faces = _model->getFaces();
|
||||||
|
const Common::Array<Formats::BiffMesh::Material> &materials = _model->getMaterials();
|
||||||
|
|
||||||
|
for (Common::Array<Formats::BiffMesh::Face>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
|
||||||
|
const Formats::BiffMesh::Material &material = materials[face->materialId];
|
||||||
|
|
||||||
|
// For each face draw its vertices from the VBO, indexed by the EBO
|
||||||
|
const Gfx::Texture *tex = _texture->getTexture(material.texture);
|
||||||
|
if (tex) {
|
||||||
|
tex->bind();
|
||||||
|
} else {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint ebo = _faceEBO[face];
|
||||||
|
|
||||||
|
_shader->enableVertexAttribute("position", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0);
|
||||||
|
_shader->enableVertexAttribute("normal", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 12);
|
||||||
|
_shader->enableVertexAttribute("texcoord", _faceVBO, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 24);
|
||||||
|
_shader->use(true);
|
||||||
|
_shader->setUniform("textured", tex != nullptr);
|
||||||
|
_shader->setUniform("color", Math::Vector3d(material.r, material.g, material.b));
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
glDrawElements(GL_TRIANGLES, face->vertexIndices.size(), GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSPropRenderer::clearVertices() {
|
||||||
|
Graphics::Shader::freeBuffer(_faceVBO);
|
||||||
|
_faceVBO = -1;
|
||||||
|
|
||||||
|
for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
|
||||||
|
Graphics::Shader::freeBuffer(it->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_faceEBO.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSPropRenderer::uploadVertices() {
|
||||||
|
_faceVBO = createFaceVBO();
|
||||||
|
|
||||||
|
const Common::Array<Formats::BiffMesh::Face> &faces = _model->getFaces();
|
||||||
|
for (Common::Array<Formats::BiffMesh::Face>::const_iterator face = faces.begin(); face != faces.end(); ++face) {
|
||||||
|
_faceEBO[face] = createFaceEBO(face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 OpenGLSPropRenderer::createFaceVBO() {
|
||||||
|
const Common::Array<Formats::BiffMesh::Vertex> &vertices = _model->getVertices();
|
||||||
|
|
||||||
|
return Graphics::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 9 * vertices.size(), &vertices.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 OpenGLSPropRenderer::createFaceEBO(const Formats::BiffMesh::Face *face) {
|
||||||
|
return Graphics::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
67
engines/stark/gfx/openglsprop.h
Normal file
67
engines/stark/gfx/openglsprop.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_OPENGL_S_RENDERED_H
|
||||||
|
#define STARK_GFX_OPENGL_S_RENDERED_H
|
||||||
|
|
||||||
|
#include "common/hashmap.h"
|
||||||
|
|
||||||
|
#include "engines/stark/hash-ptr.h"
|
||||||
|
#include "engines/stark/formats/biffmesh.h"
|
||||||
|
#include "engines/stark/visual/prop.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
class Shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
class Driver;
|
||||||
|
|
||||||
|
class OpenGLSPropRenderer : public VisualProp {
|
||||||
|
public:
|
||||||
|
OpenGLSPropRenderer(Driver *gfx);
|
||||||
|
virtual ~OpenGLSPropRenderer();
|
||||||
|
|
||||||
|
void render(const Math::Vector3d position, float direction) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef Common::HashMap<const Formats::BiffMesh::Face *, uint32> FaceBufferMap;
|
||||||
|
|
||||||
|
Driver *_gfx;
|
||||||
|
Graphics::Shader *_shader;
|
||||||
|
|
||||||
|
int32 _faceVBO;
|
||||||
|
FaceBufferMap _faceEBO;
|
||||||
|
|
||||||
|
void clearVertices();
|
||||||
|
void uploadVertices();
|
||||||
|
uint32 createFaceVBO();
|
||||||
|
uint32 createFaceEBO(const Formats::BiffMesh::Face *face);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_OPENGL_S_RENDERED_H
|
78
engines/stark/gfx/openglssurface.cpp
Normal file
78
engines/stark/gfx/openglssurface.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/openglssurface.h"
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/opengls.h"
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
#include "graphics/opengles2/shader.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
OpenGLSSurfaceRenderer::OpenGLSSurfaceRenderer(OpenGLSDriver *gfx) :
|
||||||
|
SurfaceRenderer(),
|
||||||
|
_gfx(gfx) {
|
||||||
|
_shader = _gfx->createSurfaceShaderInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLSSurfaceRenderer::~OpenGLSSurfaceRenderer() {
|
||||||
|
delete _shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSSurfaceRenderer::render(const Texture *texture, const Common::Point &dest) {
|
||||||
|
// Destination rectangle
|
||||||
|
const float sLeft = dest.x;
|
||||||
|
const float sTop = dest.y;
|
||||||
|
const float sWidth = texture->width();
|
||||||
|
const float sHeight = texture->height();
|
||||||
|
|
||||||
|
_gfx->start2DMode();
|
||||||
|
|
||||||
|
_shader->use();
|
||||||
|
_shader->setUniform1f("fadeLevel", _fadeLevel);
|
||||||
|
_shader->setUniform("verOffsetXY", normalizeOriginalCoordinates(sLeft, sTop));
|
||||||
|
if (_noScalingOverride) {
|
||||||
|
_shader->setUniform("verSizeWH", normalizeCurrentCoordinates(sWidth, sHeight));
|
||||||
|
} else {
|
||||||
|
_shader->setUniform("verSizeWH", normalizeOriginalCoordinates(sWidth, sHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
texture->bind();
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
_gfx->end2DMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector2d OpenGLSSurfaceRenderer::normalizeOriginalCoordinates(float x, float y) const {
|
||||||
|
Common::Rect viewport = _gfx->getUnscaledViewport();
|
||||||
|
return Math::Vector2d(x / (float)viewport.width(), y / (float)viewport.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector2d OpenGLSSurfaceRenderer::normalizeCurrentCoordinates(float x, float y) const {
|
||||||
|
Common::Rect viewport = _gfx->getViewport();
|
||||||
|
return Math::Vector2d(x / (float)viewport.width(), y / (float)viewport.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
62
engines/stark/gfx/openglssurface.h
Normal file
62
engines/stark/gfx/openglssurface.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_OPENGL_S_SURFACE_H
|
||||||
|
#define STARK_GFX_OPENGL_S_SURFACE_H
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/surfacerenderer.h"
|
||||||
|
|
||||||
|
#include "math/vector2d.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
class Shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
class OpenGLSDriver;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An programmable pipeline OpenGL surface renderer
|
||||||
|
*/
|
||||||
|
class OpenGLSSurfaceRenderer : public SurfaceRenderer {
|
||||||
|
public:
|
||||||
|
OpenGLSSurfaceRenderer(OpenGLSDriver *gfx);
|
||||||
|
virtual ~OpenGLSSurfaceRenderer();
|
||||||
|
|
||||||
|
// SurfaceRenderer API
|
||||||
|
void render(const Texture *texture, const Common::Point &dest);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Math::Vector2d normalizeOriginalCoordinates(float x, float y) const;
|
||||||
|
Math::Vector2d normalizeCurrentCoordinates(float x, float y) const;
|
||||||
|
|
||||||
|
OpenGLSDriver *_gfx;
|
||||||
|
Graphics::Shader *_shader;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_OPENGL_S_SURFACE_H
|
100
engines/stark/gfx/opengltexture.cpp
Normal file
100
engines/stark/gfx/opengltexture.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/opengltexture.h"
|
||||||
|
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
|
||||||
|
#include <SDL_opengl.h>
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
OpenGlTexture::OpenGlTexture() :
|
||||||
|
Texture(),
|
||||||
|
_id(0),
|
||||||
|
_levelCount(0) {
|
||||||
|
glGenTextures(1, &_id);
|
||||||
|
|
||||||
|
bind();
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGlTexture::~OpenGlTexture() {
|
||||||
|
glDeleteTextures(1, &_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGlTexture::bind() const {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGlTexture::updateLevel(uint32 level, const Graphics::Surface *surface, const byte *palette) {
|
||||||
|
if (level == 0) {
|
||||||
|
_width = surface->w;
|
||||||
|
_height = surface->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface->format.bytesPerPixel != 4) {
|
||||||
|
// Convert the surface to texture format
|
||||||
|
Graphics::Surface *convertedSurface = surface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), palette);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, convertedSurface->w, convertedSurface->h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, convertedSurface->getPixels());
|
||||||
|
|
||||||
|
convertedSurface->free();
|
||||||
|
delete convertedSurface;
|
||||||
|
} else {
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, surface->getPixels());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGlTexture::update(const Graphics::Surface *surface, const byte *palette) {
|
||||||
|
bind();
|
||||||
|
updateLevel(0, surface, palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGlTexture::setLevelCount(uint32 count) {
|
||||||
|
_levelCount = count;
|
||||||
|
|
||||||
|
if (count >= 1) {
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
|
||||||
|
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGlTexture::addLevel(uint32 level, const Graphics::Surface *surface, const byte *palette) {
|
||||||
|
assert(level < _levelCount);
|
||||||
|
|
||||||
|
updateLevel(level, surface, palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
55
engines/stark/gfx/opengltexture.h
Normal file
55
engines/stark/gfx/opengltexture.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_OPENGL_TEXTURE_H
|
||||||
|
#define STARK_GFX_OPENGL_TEXTURE_H
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An OpenGL texture wrapper
|
||||||
|
*/
|
||||||
|
class OpenGlTexture : public Texture {
|
||||||
|
public:
|
||||||
|
OpenGlTexture();
|
||||||
|
virtual ~OpenGlTexture();
|
||||||
|
|
||||||
|
// Texture API
|
||||||
|
void bind() const override;
|
||||||
|
void update(const Graphics::Surface *surface, const byte *palette = nullptr) override;
|
||||||
|
void setLevelCount(uint32 count) override;
|
||||||
|
void addLevel(uint32 level, const Graphics::Surface *surface, const byte *palette = nullptr) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateLevel(uint32 level, const Graphics::Surface *surface, const byte *palette = nullptr);
|
||||||
|
|
||||||
|
uint32 _id;
|
||||||
|
uint32 _levelCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_OPENGL_TEXTURE_H
|
183
engines/stark/gfx/renderentry.cpp
Normal file
183
engines/stark/gfx/renderentry.cpp
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/renderentry.h"
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
|
||||||
|
#include "engines/stark/visual/actor.h"
|
||||||
|
#include "engines/stark/visual/image.h"
|
||||||
|
#include "engines/stark/visual/prop.h"
|
||||||
|
#include "engines/stark/visual/smacker.h"
|
||||||
|
#include "engines/stark/visual/text.h"
|
||||||
|
#include "engines/stark/visual/visual.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
RenderEntry::RenderEntry(Resources::ItemVisual *owner, const Common::String &name) :
|
||||||
|
_visual(nullptr),
|
||||||
|
_name(name),
|
||||||
|
_owner(owner),
|
||||||
|
_direction3D(0.0),
|
||||||
|
_sortKey(0.0),
|
||||||
|
_clickable(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEntry::render(const LightEntryArray &lights) {
|
||||||
|
if (!_visual) {
|
||||||
|
// warning("No visual for render entry '%s'", _name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualImageXMG *imageXMG = _visual->get<VisualImageXMG>();
|
||||||
|
if (imageXMG) {
|
||||||
|
imageXMG->render(_position, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualActor *actor = _visual->get<VisualActor>();
|
||||||
|
if (actor) {
|
||||||
|
actor->render(_position3D, _direction3D, lights);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualProp *prop = _visual->get<VisualProp>();
|
||||||
|
if (prop) {
|
||||||
|
prop->render(_position3D, _direction3D);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualSmacker *smacker = _visual->get<VisualSmacker>();
|
||||||
|
if (smacker) {
|
||||||
|
smacker->render(_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualText *text = _visual->get<VisualText>();
|
||||||
|
if (text) {
|
||||||
|
text->render(_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEntry::setVisual(Visual *visual) {
|
||||||
|
_visual = visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEntry::setPosition(const Common::Point &position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEntry::setPosition3D(const Math::Vector3d &position, float direction) {
|
||||||
|
_position3D = position;
|
||||||
|
_direction3D = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEntry::setSortKey(float sortKey) {
|
||||||
|
_sortKey = sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEntry::setClickable(bool clickable) {
|
||||||
|
_clickable = clickable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEntry::compare(const RenderEntry *x, const RenderEntry *y) {
|
||||||
|
if (x->_sortKey != y->_sortKey) {
|
||||||
|
return x->_sortKey < y->_sortKey;
|
||||||
|
} else if (x->_owner && y->_owner) {
|
||||||
|
// The original used a stable sort. Common::sort is not.
|
||||||
|
// This should ensure the items remain in the same order if they have the same sort key
|
||||||
|
return x->_owner->getIndex() < y->_owner->getIndex();
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &relativePosition) const {
|
||||||
|
if (!_visual || !_clickable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualImageXMG *image = _visual->get<VisualImageXMG>();
|
||||||
|
if (image) {
|
||||||
|
Common::Rect imageRect = Common::Rect(image->getWidth(), image->getHeight());
|
||||||
|
imageRect.translate(_position.x, _position.y);
|
||||||
|
imageRect.translate(-image->getHotspot().x, -image->getHotspot().y);
|
||||||
|
|
||||||
|
relativePosition.x = position.x - imageRect.left - image->getHotspot().x;
|
||||||
|
relativePosition.y = position.y - imageRect.top - image->getHotspot().y;
|
||||||
|
if (imageRect.contains(position) && image->isPointSolid(relativePosition)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualSmacker *smacker = _visual->get<VisualSmacker>();
|
||||||
|
if (smacker) {
|
||||||
|
Common::Point smackerPosition = smacker->getPosition();
|
||||||
|
smackerPosition -= _position;
|
||||||
|
|
||||||
|
Common::Rect smackerRect = Common::Rect(smacker->getWidth(), smacker->getHeight());
|
||||||
|
smackerRect.translate(smackerPosition.x, smackerPosition.y);
|
||||||
|
|
||||||
|
relativePosition.x = position.x - smackerRect.left;
|
||||||
|
relativePosition.y = position.y - smackerRect.top;
|
||||||
|
if (smackerRect.contains(position) && smacker->isPointSolid(relativePosition)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualText *text = _visual->get<VisualText>();
|
||||||
|
if (text) {
|
||||||
|
Common::Rect textRect = text->getRect();
|
||||||
|
textRect.translate(_position.x, _position.y);
|
||||||
|
|
||||||
|
relativePosition.x = position.x - textRect.left;
|
||||||
|
relativePosition.y = position.y - textRect.top;
|
||||||
|
if (textRect.contains(position)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEntry::intersectRay(const Math::Ray &ray) const {
|
||||||
|
if (!_visual || !_clickable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualActor *actor = _visual->get<VisualActor>();
|
||||||
|
if (actor) {
|
||||||
|
return actor->intersectRay(ray, _position3D, _direction3D);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualProp *prop = _visual->get<VisualProp>();
|
||||||
|
if (prop) {
|
||||||
|
return prop->intersectRay(ray, _position3D, _direction3D);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualImageXMG *RenderEntry::getImage() const {
|
||||||
|
return _visual->get<VisualImageXMG>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
115
engines/stark/gfx/renderentry.h
Normal file
115
engines/stark/gfx/renderentry.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_RENDER_ENTRY_H
|
||||||
|
#define STARK_GFX_RENDER_ENTRY_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/ray.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class Visual;
|
||||||
|
class VisualImageXMG;
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
class ItemVisual;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
struct LightEntry {
|
||||||
|
enum Type {
|
||||||
|
kAmbient = 0,
|
||||||
|
kPoint = 1,
|
||||||
|
kDirectional = 2,
|
||||||
|
kSpot = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
Math::Vector3d color;
|
||||||
|
Math::Vector3d position;
|
||||||
|
Math::Vector3d direction;
|
||||||
|
Math::Angle innerConeAngle;
|
||||||
|
Math::Angle outerConeAngle;
|
||||||
|
float falloffNear;
|
||||||
|
float falloffFar;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Common::Array<LightEntry *> LightEntryArray;
|
||||||
|
|
||||||
|
class RenderEntry {
|
||||||
|
public:
|
||||||
|
RenderEntry(Resources::ItemVisual *owner, const Common::String &name);
|
||||||
|
virtual ~RenderEntry() {}
|
||||||
|
|
||||||
|
void render(const LightEntryArray &lights);
|
||||||
|
|
||||||
|
void setVisual(Visual *visual);
|
||||||
|
void setPosition(const Common::Point &position);
|
||||||
|
void setPosition3D(const Math::Vector3d &position, float direction);
|
||||||
|
void setSortKey(float sortKey);
|
||||||
|
void setClickable(bool clickable);
|
||||||
|
|
||||||
|
/** Gets the owner-object */
|
||||||
|
Resources::ItemVisual *getOwner() const { return _owner; }
|
||||||
|
|
||||||
|
/** Obtain the underlying image visual, if any */
|
||||||
|
VisualImageXMG *getImage() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mouse picking test for 2D items
|
||||||
|
*
|
||||||
|
* @param position game window coordinates to test
|
||||||
|
* @param relativePosition successful hit item relative coordinates
|
||||||
|
* @return successful hit
|
||||||
|
*/
|
||||||
|
bool containsPoint(const Common::Point &position, Common::Point &relativePosition) const;
|
||||||
|
|
||||||
|
/** Mouse picking test for 3D items */
|
||||||
|
bool intersectRay(const Math::Ray &ray) const;
|
||||||
|
|
||||||
|
/** Compare two render entries by their sort keys */
|
||||||
|
static bool compare(const RenderEntry *x, const RenderEntry *y);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Common::String _name;
|
||||||
|
Resources::ItemVisual *_owner;
|
||||||
|
|
||||||
|
Visual *_visual;
|
||||||
|
Common::Point _position;
|
||||||
|
Math::Vector3d _position3D;
|
||||||
|
float _direction3D;
|
||||||
|
float _sortKey;
|
||||||
|
bool _clickable;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Common::Array<RenderEntry *> RenderEntryArray;
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_RENDER_ENTRY_H
|
45
engines/stark/gfx/surfacerenderer.cpp
Normal file
45
engines/stark/gfx/surfacerenderer.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/surfacerenderer.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
SurfaceRenderer::SurfaceRenderer() :
|
||||||
|
_noScalingOverride(false),
|
||||||
|
_fadeLevel(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceRenderer::~SurfaceRenderer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceRenderer::setNoScalingOverride(bool noScalingOverride) {
|
||||||
|
_noScalingOverride = noScalingOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceRenderer::setFadeLevel(float fadeLevel) {
|
||||||
|
_fadeLevel = fadeLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
69
engines/stark/gfx/surfacerenderer.h
Normal file
69
engines/stark/gfx/surfacerenderer.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_SURFACE_RENDERER_H
|
||||||
|
#define STARK_GFX_SURFACE_RENDERER_H
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A renderer to draw textures as two dimensional surfaces to the current viewport
|
||||||
|
*/
|
||||||
|
class SurfaceRenderer {
|
||||||
|
public:
|
||||||
|
SurfaceRenderer();
|
||||||
|
virtual ~SurfaceRenderer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a 2D surface from the specified texture
|
||||||
|
*/
|
||||||
|
virtual void render(const Texture *texture, const Common::Point &dest) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this is set to true, the texture size is expected to be in current
|
||||||
|
* coordinates, and is to be drawn without scaling.
|
||||||
|
*
|
||||||
|
* This setting does not affect the destination point coordinates
|
||||||
|
*/
|
||||||
|
void setNoScalingOverride(bool noScalingOverride);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fade level is added to the color value of each pixel
|
||||||
|
*
|
||||||
|
* It is a value between -1 and 1
|
||||||
|
*/
|
||||||
|
void setFadeLevel(float fadeLevel);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _noScalingOverride;
|
||||||
|
float _fadeLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_SURFACE_RENDERER_H
|
64
engines/stark/gfx/texture.cpp
Normal file
64
engines/stark/gfx/texture.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
Texture::Texture() :
|
||||||
|
_width(0),
|
||||||
|
_height(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture::~Texture() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet::TextureSet() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet::~TextureSet() {
|
||||||
|
for (TextureMap::iterator it = _texMap.begin(); it != _texMap.end(); ++it) {
|
||||||
|
delete it->_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureSet::addTexture(const Common::String &name, Texture *texture) {
|
||||||
|
if (_texMap.contains(name)) {
|
||||||
|
error("A texture with the name '%s' already exists in the set.", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
_texMap.setVal(name, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Texture *TextureSet::getTexture(const Common::String &name) const {
|
||||||
|
TextureMap::const_iterator it = _texMap.find(name);
|
||||||
|
if (it != _texMap.end())
|
||||||
|
return it->_value;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
99
engines/stark/gfx/texture.h
Normal file
99
engines/stark/gfx/texture.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_GFX_TEXTURE_H
|
||||||
|
#define STARK_GFX_TEXTURE_H
|
||||||
|
|
||||||
|
#include "common/hash-str.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
struct Surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract texture
|
||||||
|
*/
|
||||||
|
class Texture {
|
||||||
|
public:
|
||||||
|
Texture();
|
||||||
|
virtual ~Texture();
|
||||||
|
|
||||||
|
/** Make the texture active */
|
||||||
|
virtual void bind() const = 0;
|
||||||
|
|
||||||
|
/** Define or update the texture pixel data */
|
||||||
|
virtual void update(const Graphics::Surface *surface, const byte *palette = nullptr) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the total number of levels of details
|
||||||
|
*
|
||||||
|
* Must be called before adding levels
|
||||||
|
*/
|
||||||
|
virtual void setLevelCount(uint32 count) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a detail level to the texture
|
||||||
|
*/
|
||||||
|
virtual void addLevel(uint32 level, const Graphics::Surface *surface, const byte *palette = nullptr) = 0;
|
||||||
|
|
||||||
|
/** Get the texture width */
|
||||||
|
uint32 width() const { return _width; }
|
||||||
|
|
||||||
|
/** Get teh texture height */
|
||||||
|
uint32 height() const { return _height; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32 _width;
|
||||||
|
uint32 _height;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of textures referenced by their names
|
||||||
|
*/
|
||||||
|
class TextureSet {
|
||||||
|
public:
|
||||||
|
TextureSet();
|
||||||
|
~TextureSet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a texture to the set
|
||||||
|
*/
|
||||||
|
void addTexture(const Common::String &name, Texture *texture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a texture from the set
|
||||||
|
*/
|
||||||
|
const Texture *getTexture(const Common::String &name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Common::HashMap<Common::String, Texture *> TextureMap;
|
||||||
|
|
||||||
|
TextureMap _texMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Gfx
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_GFX_TEXTURE_H
|
43
engines/stark/hash-ptr.h
Normal file
43
engines/stark/hash-ptr.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_HASH_PTR_H
|
||||||
|
#define STARK_HASH_PTR_H
|
||||||
|
|
||||||
|
#include "common/func.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partial specialization of the Hash functor to be able to use pointers as HashMap keys
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
struct Hash<T *> {
|
||||||
|
uint operator()(T * const &v) const {
|
||||||
|
uint x = static_cast<uint>(reinterpret_cast<size_t>(v));
|
||||||
|
return x + (x >> 3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Common
|
||||||
|
|
||||||
|
#endif
|
197
engines/stark/model/model.cpp
Normal file
197
engines/stark/model/model.cpp
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/model/model.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/model/skeleton.h"
|
||||||
|
#include "engines/stark/gfx/texture.h"
|
||||||
|
|
||||||
|
#include "math/aabb.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
Model::Model() :
|
||||||
|
_skeleton(nullptr),
|
||||||
|
_textureSet(nullptr),
|
||||||
|
_u1(0),
|
||||||
|
_u2(0.0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Model::~Model() {
|
||||||
|
for (Common::Array<MaterialNode *>::iterator it = _materials.begin(); it != _materials.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
for (Common::Array<MeshNode *>::iterator it = _meshes.begin(); it != _meshes.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
if (_skeleton)
|
||||||
|
delete _skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::readFromStream(ArchiveReadStream *stream) {
|
||||||
|
uint32 id = stream->readUint32LE();
|
||||||
|
if (id != 4) {
|
||||||
|
error("Wrong magic 1 while reading actor '%d'", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 format = stream->readUint32LE();
|
||||||
|
if (format == 256) {
|
||||||
|
_u1 = stream->readUint32LE();
|
||||||
|
} else if (format == 16) {
|
||||||
|
_u1 = 0;
|
||||||
|
} else {
|
||||||
|
error("Wrong format while reading actor '%d'", format);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 id2 = stream->readUint32LE();
|
||||||
|
if (id2 != 0xDEADBABE) {
|
||||||
|
error("Wrong magic 2 while reading actor '%d'", id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
_u2 = stream->readFloat();
|
||||||
|
|
||||||
|
uint32 numMaterials = stream->readUint32LE();
|
||||||
|
|
||||||
|
for (uint i = 0; i < numMaterials; ++i) {
|
||||||
|
MaterialNode *node = new MaterialNode();
|
||||||
|
node->_name = stream->readString();
|
||||||
|
node->_unknown1 = stream->readUint32LE();
|
||||||
|
node->_texName = stream->readString();
|
||||||
|
node->_r = stream->readFloat();
|
||||||
|
node->_g = stream->readFloat();
|
||||||
|
node->_b = stream->readFloat();
|
||||||
|
_materials.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 numUnknowns = stream->readUint32LE();
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < numUnknowns; ++i) {
|
||||||
|
UnknownNode *node = new UnknownNode();
|
||||||
|
node->_u1 = stream->readFloat();
|
||||||
|
node->_u2 = stream->readFloat();
|
||||||
|
node->_u3 = stream->readFloat();
|
||||||
|
node->_u4 = stream->readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
_skeleton = new Skeleton();
|
||||||
|
_skeleton->readFromStream(stream);
|
||||||
|
|
||||||
|
uint32 numMeshes = stream->readUint32LE();
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < numMeshes; ++i) {
|
||||||
|
MeshNode *node = new MeshNode();
|
||||||
|
|
||||||
|
node->_name = stream->readString();
|
||||||
|
|
||||||
|
uint32 len = stream->readUint32LE();
|
||||||
|
for (uint32 j = 0; j < len; ++j) {
|
||||||
|
FaceNode *face = new FaceNode();
|
||||||
|
face->_matIdx = stream->readUint32LE();
|
||||||
|
|
||||||
|
uint32 childCount = stream->readUint32LE();
|
||||||
|
for (uint32 k = 0; k < childCount; ++k) {
|
||||||
|
VertNode *vert = new VertNode();
|
||||||
|
vert->_pos1 = stream->readVector3();
|
||||||
|
vert->_pos2 = stream->readVector3();
|
||||||
|
vert->_normal = stream->readVector3();
|
||||||
|
vert->_texS = stream->readFloat();
|
||||||
|
vert->_texT = stream->readFloat();
|
||||||
|
vert->_bone1 = stream->readUint32LE();
|
||||||
|
vert->_bone2 = stream->readUint32LE();
|
||||||
|
vert->_boneWeight = stream->readFloat();
|
||||||
|
face->_verts.push_back(vert);
|
||||||
|
}
|
||||||
|
|
||||||
|
childCount = stream->readUint32LE();
|
||||||
|
for (uint32 k = 0; k < childCount; ++k) {
|
||||||
|
TriNode *tri = new TriNode();
|
||||||
|
tri->_vert1 = stream->readUint32LE();
|
||||||
|
tri->_vert2 = stream->readUint32LE();
|
||||||
|
tri->_vert3 = stream->readUint32LE();
|
||||||
|
face->_tris.push_back(tri);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->_faces.push_back(face);
|
||||||
|
}
|
||||||
|
|
||||||
|
_meshes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildBonesBoundingBoxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::setAnim(SkeletonAnim *anim) {
|
||||||
|
_skeleton->setAnim(anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::setTextureSet(Gfx::TextureSet *texture) {
|
||||||
|
_textureSet = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::buildBonesBoundingBoxes() {
|
||||||
|
const Common::Array<BoneNode *> &bones = _skeleton->getBones();
|
||||||
|
|
||||||
|
for (uint i = 0; i < bones.size(); i++) {
|
||||||
|
buildBoneBoundingBox(bones[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::buildBoneBoundingBox(BoneNode *bone) const {
|
||||||
|
bone->_boundingBox.reset();
|
||||||
|
|
||||||
|
// Add all the vertices with a non zero weight for the bone to the bone's bounding box
|
||||||
|
for (uint i = 0; i < _meshes.size(); i++) {
|
||||||
|
MeshNode *mesh = _meshes[i];
|
||||||
|
|
||||||
|
for (uint j = 0; j < mesh->_faces.size(); j++) {
|
||||||
|
FaceNode *face = mesh->_faces[j];
|
||||||
|
|
||||||
|
for (uint k = 0; k < face->_verts.size(); k++) {
|
||||||
|
VertNode *vert = face->_verts[k];
|
||||||
|
|
||||||
|
if (vert->_bone1 == bone->_idx) {
|
||||||
|
bone->_boundingBox.expand(vert->_pos1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vert->_bone2 == bone->_idx) {
|
||||||
|
bone->_boundingBox.expand(vert->_pos2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Model::intersectRay(const Math::Ray &ray) const {
|
||||||
|
const Common::Array<BoneNode *> &bones = _skeleton->getBones();
|
||||||
|
|
||||||
|
for (uint i = 0; i < bones.size(); i++) {
|
||||||
|
if (bones[i]->intersectRay(ray)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
152
engines/stark/model/model.h
Normal file
152
engines/stark/model/model.h
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MODEL_MODEL_H
|
||||||
|
#define STARK_MODEL_MODEL_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/ray.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
class TextureSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArchiveReadStream;
|
||||||
|
class Skeleton;
|
||||||
|
class SkeletonAnim;
|
||||||
|
|
||||||
|
class BoneNode;
|
||||||
|
|
||||||
|
class VertNode {
|
||||||
|
public:
|
||||||
|
Math::Vector3d _pos1, _pos2;
|
||||||
|
Math::Vector3d _normal;
|
||||||
|
float _texS, _texT;
|
||||||
|
uint32 _bone1, _bone2;
|
||||||
|
float _boneWeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TriNode {
|
||||||
|
public:
|
||||||
|
uint32 _vert1, _vert2, _vert3;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FaceNode {
|
||||||
|
public:
|
||||||
|
FaceNode() {}
|
||||||
|
|
||||||
|
~FaceNode() {
|
||||||
|
for (Common::Array<VertNode *>::iterator it = _verts.begin(); it != _verts.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
for (Common::Array<TriNode *>::iterator it = _tris.begin(); it != _tris.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 _matIdx;
|
||||||
|
Common::Array<VertNode *> _verts;
|
||||||
|
Common::Array<TriNode *> _tris;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MeshNode {
|
||||||
|
public:
|
||||||
|
MeshNode() {}
|
||||||
|
~MeshNode() {
|
||||||
|
Common::Array<FaceNode *>::iterator it = _faces.begin();
|
||||||
|
while (it != _faces.end()) {
|
||||||
|
delete *it;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Common::String _name;
|
||||||
|
Common::Array<FaceNode *> _faces;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MaterialNode {
|
||||||
|
public:
|
||||||
|
Common::String _name;
|
||||||
|
uint32 _unknown1;
|
||||||
|
Common::String _texName;
|
||||||
|
float _r, _g, _b;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnknownNode {
|
||||||
|
public:
|
||||||
|
float _u1, _u2, _u3, _u4;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 3D Model
|
||||||
|
*/
|
||||||
|
class Model {
|
||||||
|
public:
|
||||||
|
Model();
|
||||||
|
~Model();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try and initialise object from the specified stream
|
||||||
|
*/
|
||||||
|
void readFromStream(ArchiveReadStream *stream);
|
||||||
|
|
||||||
|
const Common::Array<MeshNode *> &getMeshes() const { return _meshes; }
|
||||||
|
const Common::Array<MaterialNode *> &getMaterials() const { return _materials; }
|
||||||
|
Skeleton *getSkeleton() const { return _skeleton; }
|
||||||
|
const Gfx::TextureSet *getTextureSet() const { return _textureSet; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load animation data from the specified stream
|
||||||
|
*/
|
||||||
|
void setAnim(SkeletonAnim *anim);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load texture data from the specified stream
|
||||||
|
*/
|
||||||
|
void setTextureSet(Gfx::TextureSet *textureSet);
|
||||||
|
|
||||||
|
/** Perform a collision test with a ray */
|
||||||
|
bool intersectRay(const Math::Ray &ray) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void buildBonesBoundingBoxes();
|
||||||
|
void buildBoneBoundingBox(BoneNode *bone) const;
|
||||||
|
|
||||||
|
uint32 _u1;
|
||||||
|
float _u2;
|
||||||
|
|
||||||
|
Common::Array<MaterialNode *> _materials;
|
||||||
|
Common::Array<MeshNode *> _meshes;
|
||||||
|
Skeleton *_skeleton;
|
||||||
|
Gfx::TextureSet *_textureSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MODEL_MODEL_H
|
106
engines/stark/model/skeleton.cpp
Normal file
106
engines/stark/model/skeleton.cpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/model/skeleton.h"
|
||||||
|
|
||||||
|
#include "engines/stark/model/skeleton_anim.h"
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
Skeleton::Skeleton() :
|
||||||
|
_anim(nullptr),
|
||||||
|
_lastTime(-1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Skeleton::~Skeleton() {
|
||||||
|
for (Common::Array<BoneNode *>::iterator it = _bones.begin(); it != _bones.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Common::Array<BoneNode *> Skeleton::getBones() {
|
||||||
|
return _bones;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Skeleton::readFromStream(ArchiveReadStream *stream) {
|
||||||
|
uint32 numBones = stream->readUint32LE();
|
||||||
|
for (uint32 i = 0; i < numBones; ++i) {
|
||||||
|
BoneNode *node = new BoneNode();
|
||||||
|
node->_name = stream->readString();
|
||||||
|
node->_u1 = stream->readFloat();
|
||||||
|
|
||||||
|
uint32 len = stream->readUint32LE();
|
||||||
|
for (uint32 j = 0; j < len; ++j)
|
||||||
|
node->_children.push_back(stream->readUint32LE());
|
||||||
|
|
||||||
|
node->_idx = _bones.size();
|
||||||
|
_bones.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < numBones; ++i) {
|
||||||
|
BoneNode *node = _bones[i];
|
||||||
|
for (uint j = 0; j < node->_children.size(); ++j) {
|
||||||
|
_bones[node->_children[j]]->_parent = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Skeleton::setAnim(SkeletonAnim *anim) {
|
||||||
|
_anim = anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Skeleton::setNode(uint32 time, BoneNode *bone, const BoneNode *parent) {
|
||||||
|
_anim->getCoordForBone(time, bone->_idx, bone->_animPos, bone->_animRot);
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
parent->_animRot.transform(bone->_animPos);
|
||||||
|
|
||||||
|
bone->_animPos = parent->_animPos + bone->_animPos;
|
||||||
|
bone->_animRot = parent->_animRot * bone->_animRot;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < bone->_children.size(); ++i) {
|
||||||
|
setNode(time, _bones[bone->_children[i]], bone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Skeleton::animate(uint32 time) {
|
||||||
|
// Start at root bone
|
||||||
|
// For each child
|
||||||
|
// - Set childs animation coordinate
|
||||||
|
// - Process that childs children
|
||||||
|
|
||||||
|
if (time != _lastTime) {
|
||||||
|
setNode(time, _bones[0], nullptr);
|
||||||
|
_lastTime = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BoneNode::intersectRay(const Math::Ray &ray) const {
|
||||||
|
Math::Ray localRay = ray;
|
||||||
|
localRay.translate(-_animPos);
|
||||||
|
localRay.rotate(_animRot.inverse());
|
||||||
|
|
||||||
|
return localRay.intersectAABB(_boundingBox);
|
||||||
|
}
|
||||||
|
} // End of namespace Stark
|
99
engines/stark/model/skeleton.h
Normal file
99
engines/stark/model/skeleton.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MODEL_SKELETON_H
|
||||||
|
#define STARK_MODEL_SKELETON_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/aabb.h"
|
||||||
|
#include "math/quat.h"
|
||||||
|
#include "math/ray.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class ArchiveReadStream;
|
||||||
|
class SkeletonAnim;
|
||||||
|
|
||||||
|
class BoneNode {
|
||||||
|
public:
|
||||||
|
BoneNode() : _parent(-1) {}
|
||||||
|
~BoneNode() { }
|
||||||
|
|
||||||
|
/** Perform a collision test with the ray */
|
||||||
|
bool intersectRay(const Math::Ray &ray) const;
|
||||||
|
|
||||||
|
Common::String _name;
|
||||||
|
float _u1;
|
||||||
|
Common::Array<uint32> _children;
|
||||||
|
int _parent;
|
||||||
|
uint32 _idx;
|
||||||
|
|
||||||
|
Math::Vector3d _animPos;
|
||||||
|
Math::Quaternion _animRot;
|
||||||
|
|
||||||
|
/** Bone space bounding box */
|
||||||
|
Math::AABB _boundingBox;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skeleton manager to load and store skeletal information about an actor
|
||||||
|
*/
|
||||||
|
class Skeleton {
|
||||||
|
public:
|
||||||
|
Skeleton();
|
||||||
|
~Skeleton();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the skeleton timestamp, and apply bone animations if required
|
||||||
|
*/
|
||||||
|
void animate(uint32 time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start reading animation data from the specified stream
|
||||||
|
*/
|
||||||
|
void setAnim(SkeletonAnim *anim);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create skeleton object from the specified stream
|
||||||
|
*/
|
||||||
|
void readFromStream(ArchiveReadStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the list of bones
|
||||||
|
*/
|
||||||
|
const Common::Array<BoneNode *> getBones();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setNode(uint32 time, BoneNode *bone, const BoneNode *parent);
|
||||||
|
|
||||||
|
Common::Array<BoneNode *> _bones;
|
||||||
|
SkeletonAnim *_anim;
|
||||||
|
|
||||||
|
uint32 _lastTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MODEL_SKELETON_H
|
98
engines/stark/model/skeleton_anim.cpp
Normal file
98
engines/stark/model/skeleton_anim.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/model/skeleton_anim.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/model/skeleton.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
|
||||||
|
SkeletonAnim::SkeletonAnim() {
|
||||||
|
}
|
||||||
|
|
||||||
|
SkeletonAnim::~SkeletonAnim() {
|
||||||
|
for (Common::Array<AnimNode *>::iterator it = _anims.begin(); it != _anims.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonAnim::createFromStream(ArchiveReadStream *stream) {
|
||||||
|
_id = stream->readUint32LE();
|
||||||
|
_ver = stream->readUint32LE();
|
||||||
|
if (_ver == 3) {
|
||||||
|
_u1 = 0;
|
||||||
|
_time = stream->readUint32LE();
|
||||||
|
_u2 = stream->readUint32LE();
|
||||||
|
} else {
|
||||||
|
_u1 = stream->readUint32LE();
|
||||||
|
_u2 = stream->readUint32LE();
|
||||||
|
_time = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
if (_u2 != 0xdeadbabe) {
|
||||||
|
error("Wrong magic while reading animation");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 num = stream->readUint32LE();
|
||||||
|
_anims.resize(num);
|
||||||
|
for (uint32 i = 0; i < num; ++i) {
|
||||||
|
AnimNode *node = new AnimNode();
|
||||||
|
node->_bone = stream->readUint32LE();
|
||||||
|
uint32 numKeys = stream->readUint32LE();
|
||||||
|
|
||||||
|
for (uint32 j = 0; j < numKeys; ++j) {
|
||||||
|
AnimKey *key = new AnimKey();
|
||||||
|
key->_time = stream->readUint32LE();
|
||||||
|
key->_rot = stream->readQuaternion();
|
||||||
|
key->_pos = stream->readVector3();
|
||||||
|
node->_keys.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
_anims[node->_bone] = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonAnim::getCoordForBone(uint32 time, int boneIdx, Math::Vector3d &pos, Math::Quaternion &rot) {
|
||||||
|
for (Common::Array<AnimKey *>::iterator it = _anims[boneIdx]->_keys.begin(); it < _anims[boneIdx]->_keys.end(); ++it) {
|
||||||
|
if ((*it)->_time == time) {
|
||||||
|
AnimKey *key = *it;
|
||||||
|
pos = key->_pos;
|
||||||
|
rot = key->_rot;
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if ((*it)->_time > time) {
|
||||||
|
// Between two key frames, interpolate
|
||||||
|
AnimKey *a = *it;
|
||||||
|
--it;
|
||||||
|
AnimKey *b = *it;
|
||||||
|
|
||||||
|
float t = (float)(time - b->_time) / (float)(a->_time - b->_time);
|
||||||
|
|
||||||
|
pos = b->_pos + (a->_pos - b->_pos) * t;
|
||||||
|
rot = b->_rot.slerpQuat(a->_rot, t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
80
engines/stark/model/skeleton_anim.h
Normal file
80
engines/stark/model/skeleton_anim.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MODEL_SKELETON_ANIM_H
|
||||||
|
#define STARK_MODEL_SKELETON_ANIM_H
|
||||||
|
|
||||||
|
#include "math/quat.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
#include "common/array.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class ArchiveReadStream;
|
||||||
|
|
||||||
|
class AnimKey {
|
||||||
|
public:
|
||||||
|
uint32 _time;
|
||||||
|
Math::Quaternion _rot;
|
||||||
|
Math::Vector3d _pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnimNode {
|
||||||
|
public:
|
||||||
|
~AnimNode() {
|
||||||
|
for (Common::Array<AnimKey *>::iterator it = _keys.begin(); it != _keys.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 _bone;
|
||||||
|
Common::Array<AnimKey *> _keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure responsible for skeletal animation of an actor object.
|
||||||
|
*/
|
||||||
|
class SkeletonAnim {
|
||||||
|
public:
|
||||||
|
SkeletonAnim();
|
||||||
|
~SkeletonAnim();
|
||||||
|
|
||||||
|
void createFromStream(ArchiveReadStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the interpolated bone coordinate for a given bone at a given animation timestamp
|
||||||
|
*/
|
||||||
|
void getCoordForBone(uint32 time, int boneIdx, Math::Vector3d &pos, Math::Quaternion &rot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total animation length (in ms)
|
||||||
|
*/
|
||||||
|
uint32 getLength() const { return _time; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 _id, _ver, _u1, _u2, _time;
|
||||||
|
|
||||||
|
Common::Array<AnimNode *> _anims;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MODEL_SKELETON_ANIM_H
|
93
engines/stark/module.mk
Normal file
93
engines/stark/module.mk
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
MODULE := engines/stark
|
||||||
|
|
||||||
|
MODULE_OBJS := \
|
||||||
|
console.o \
|
||||||
|
detection.o \
|
||||||
|
gfx/driver.o \
|
||||||
|
gfx/opengls.o \
|
||||||
|
gfx/openglsactor.o \
|
||||||
|
gfx/openglsprop.o \
|
||||||
|
gfx/openglssurface.o \
|
||||||
|
gfx/opengltexture.o \
|
||||||
|
gfx/renderentry.o \
|
||||||
|
gfx/surfacerenderer.o \
|
||||||
|
gfx/texture.o \
|
||||||
|
formats/biff.o \
|
||||||
|
formats/biffmesh.o \
|
||||||
|
formats/iss.o \
|
||||||
|
formats/tm.o \
|
||||||
|
formats/xarc.o \
|
||||||
|
formats/xmg.o \
|
||||||
|
formats/xrc.o \
|
||||||
|
model/model.o \
|
||||||
|
model/skeleton.o \
|
||||||
|
model/skeleton_anim.o \
|
||||||
|
movement/followpath.o \
|
||||||
|
movement/movement.o \
|
||||||
|
movement/shortestpath.o \
|
||||||
|
movement/stringpullingpath.o \
|
||||||
|
movement/turn.o \
|
||||||
|
movement/walk.o \
|
||||||
|
resources/anim.o \
|
||||||
|
resources/animhierarchy.o \
|
||||||
|
resources/animscript.o \
|
||||||
|
resources/bonesmesh.o \
|
||||||
|
resources/bookmark.o \
|
||||||
|
resources/camera.o \
|
||||||
|
resources/command.o \
|
||||||
|
resources/dialog.o \
|
||||||
|
resources/direction.o \
|
||||||
|
resources/floor.o \
|
||||||
|
resources/floorface.o \
|
||||||
|
resources/floorfield.o \
|
||||||
|
resources/fmv.o \
|
||||||
|
resources/image.o \
|
||||||
|
resources/item.o \
|
||||||
|
resources/knowledge.o \
|
||||||
|
resources/knowledgeset.o \
|
||||||
|
resources/layer.o \
|
||||||
|
resources/level.o \
|
||||||
|
resources/light.o \
|
||||||
|
resources/lipsync.o \
|
||||||
|
resources/location.o \
|
||||||
|
resources/object.o \
|
||||||
|
resources/path.o \
|
||||||
|
resources/pattable.o \
|
||||||
|
resources/root.o \
|
||||||
|
resources/script.o \
|
||||||
|
resources/scroll.o \
|
||||||
|
resources/sound.o \
|
||||||
|
resources/speech.o \
|
||||||
|
resources/string.o \
|
||||||
|
resources/textureset.o \
|
||||||
|
resourcereference.o \
|
||||||
|
scene.o \
|
||||||
|
services/archiveloader.o \
|
||||||
|
services/dialogplayer.o \
|
||||||
|
services/fontprovider.o \
|
||||||
|
services/gameinterface.o \
|
||||||
|
services/global.o \
|
||||||
|
services/resourceprovider.o \
|
||||||
|
services/services.o \
|
||||||
|
services/stateprovider.o \
|
||||||
|
services/staticprovider.o \
|
||||||
|
services/userinterface.o \
|
||||||
|
stark.o \
|
||||||
|
ui/actionmenu.o \
|
||||||
|
ui/button.o \
|
||||||
|
ui/clicktext.o \
|
||||||
|
ui/cursor.o \
|
||||||
|
ui/dialogpanel.o \
|
||||||
|
ui/fmvplayer.o \
|
||||||
|
ui/gamewindow.o \
|
||||||
|
ui/inventorywindow.o \
|
||||||
|
ui/topmenu.o \
|
||||||
|
ui/window.o \
|
||||||
|
visual/actor.o \
|
||||||
|
visual/image.o \
|
||||||
|
visual/prop.o \
|
||||||
|
visual/smacker.o \
|
||||||
|
visual/text.o
|
||||||
|
|
||||||
|
# Include common rules
|
||||||
|
include $(srcdir)/rules.mk
|
130
engines/stark/movement/followpath.cpp
Normal file
130
engines/stark/movement/followpath.cpp
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/movement/followpath.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
FollowPath::FollowPath(Resources::ItemVisual *item) :
|
||||||
|
Movement(item),
|
||||||
|
_path(nullptr),
|
||||||
|
_speed(0.0),
|
||||||
|
_position(0.0),
|
||||||
|
_previouslyEnabled(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
FollowPath::~FollowPath() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPath::start() {
|
||||||
|
Movement::start();
|
||||||
|
|
||||||
|
changeItemAnim();
|
||||||
|
|
||||||
|
_previouslyEnabled = _item->isEnabled();
|
||||||
|
_item->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPath::stop() {
|
||||||
|
Movement::stop();
|
||||||
|
|
||||||
|
_item->setEnabled(_previouslyEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPath::onGameLoop() {
|
||||||
|
// Compute the new position on the path
|
||||||
|
_position += _speed * StarkGlobal->getMillisecondsPerGameloop();
|
||||||
|
|
||||||
|
// Find the current path edge, and position on the path edge
|
||||||
|
uint currentEdge = 0;
|
||||||
|
float positionInEdge = _position;
|
||||||
|
for (uint i = 0; i < _path->getEdgeCount(); i++) {
|
||||||
|
float edgeLength = _path->getWeightedEdgeLength(i);
|
||||||
|
if (positionInEdge < edgeLength) {
|
||||||
|
break; // Found the current path edge
|
||||||
|
}
|
||||||
|
|
||||||
|
positionInEdge -= edgeLength;
|
||||||
|
currentEdge++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we went beyond the path's end
|
||||||
|
if (currentEdge >= _path->getEdgeCount()) {
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the new position for the item
|
||||||
|
Math::Vector3d newPosition = _path->getWeightedPositionInEdge(currentEdge, positionInEdge);
|
||||||
|
|
||||||
|
// Update the item's properties in the scene
|
||||||
|
if (is3D()) {
|
||||||
|
Resources::FloorPositionedItem *item3D = Resources::Object::cast<Resources::FloorPositionedItem>(_item);
|
||||||
|
Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
|
int32 floorFaceIndex = floor->findFaceContainingPoint(newPosition);
|
||||||
|
if (floorFaceIndex >= 0) {
|
||||||
|
item3D->setFloorFaceIndex(floorFaceIndex);
|
||||||
|
} else {
|
||||||
|
item3D->overrideSortKey(_path->getSortKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
item3D->setPosition3D(newPosition);
|
||||||
|
|
||||||
|
Math::Vector3d direction = _path->getEdgeDirection(currentEdge);
|
||||||
|
item3D->setDirection(computeAngleBetweenVectorsXYPlane(direction, Math::Vector3d(1.0, 0.0, 0.0)));
|
||||||
|
} else {
|
||||||
|
Common::Point position2D = Common::Point(newPosition.x(), newPosition.y());
|
||||||
|
_item->setPosition2D(position2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeItemAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPath::changeItemAnim() {
|
||||||
|
if (_ended) {
|
||||||
|
_item->setAnimKind(Resources::Anim::kActorUsageIdle);
|
||||||
|
} else {
|
||||||
|
_item->setAnimKind(Resources::Anim::kActorUsageWalk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPath::setPath(Resources::Path *path) {
|
||||||
|
_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPath::setSpeed(float speed) {
|
||||||
|
_speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FollowPath::is3D() const {
|
||||||
|
return _path->getSubType() == Resources::Path::kPath3D;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
65
engines/stark/movement/followpath.h
Normal file
65
engines/stark/movement/followpath.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MOVEMENT_FOLLOW_PATH_H
|
||||||
|
#define STARK_MOVEMENT_FOLLOW_PATH_H
|
||||||
|
|
||||||
|
#include <engines/stark/resources/path.h>
|
||||||
|
#include "engines/stark/movement/movement.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an item follow pre-computed path
|
||||||
|
*
|
||||||
|
* Works for 2D and 3D items, with respectively 2D and 3D paths
|
||||||
|
*/
|
||||||
|
class FollowPath : public Movement {
|
||||||
|
public:
|
||||||
|
FollowPath(Resources::ItemVisual *item);
|
||||||
|
virtual ~FollowPath();
|
||||||
|
|
||||||
|
// Movement API
|
||||||
|
void start() override;
|
||||||
|
void onGameLoop() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
/** Set the path to follow */
|
||||||
|
void setPath(Stark::Resources::Path *path);
|
||||||
|
|
||||||
|
/** Set the movement speed on the path */
|
||||||
|
void setSpeed(float speed);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void changeItemAnim();
|
||||||
|
bool is3D() const;
|
||||||
|
|
||||||
|
Resources::Path *_path;
|
||||||
|
float _speed;
|
||||||
|
|
||||||
|
float _position;
|
||||||
|
bool _previouslyEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MOVEMENT_FOLLOW_PATH_H
|
64
engines/stark/movement/movement.cpp
Normal file
64
engines/stark/movement/movement.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/movement/movement.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
Movement::Movement(Resources::ItemVisual *item) :
|
||||||
|
_ended(false),
|
||||||
|
_item(item),
|
||||||
|
_defaultTurnAngleSpeed(18.0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Movement::~Movement() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Movement::start() {
|
||||||
|
_ended = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Movement::stop() {
|
||||||
|
_ended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Movement::hasEnded() const {
|
||||||
|
return _ended;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Movement::computeAngleBetweenVectorsXYPlane(const Math::Vector3d &v1, const Math::Vector3d &v2) const {
|
||||||
|
Math::Vector3d v1XY = v1;
|
||||||
|
v1XY.z() = 0.0;
|
||||||
|
|
||||||
|
Math::Vector3d v2XY = v2;
|
||||||
|
v2XY.z() = 0.0;
|
||||||
|
|
||||||
|
Math::Angle angle = Math::Vector3d::angle(v1XY, v2XY);
|
||||||
|
Math::Vector3d cross = Math::Vector3d::crossProduct(v1XY, v2XY);
|
||||||
|
if (cross.z() < 0) {
|
||||||
|
angle = -angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return angle.getDegrees();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
79
engines/stark/movement/movement.h
Normal file
79
engines/stark/movement/movement.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MOVEMENT_MOVEMENT_H
|
||||||
|
#define STARK_MOVEMENT_MOVEMENT_H
|
||||||
|
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
class ItemVisual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract movement of an item on the current location's floor
|
||||||
|
*/
|
||||||
|
class Movement {
|
||||||
|
public:
|
||||||
|
Movement(Resources::ItemVisual *item);
|
||||||
|
virtual ~Movement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate the movement
|
||||||
|
*/
|
||||||
|
virtual void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop / abort the movement
|
||||||
|
*/
|
||||||
|
virtual void stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once per game loop
|
||||||
|
*/
|
||||||
|
virtual void onGameLoop() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the movement complete?
|
||||||
|
*/
|
||||||
|
bool hasEnded() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum TurnDirection {
|
||||||
|
kTurnNone,
|
||||||
|
kTurnLeft,
|
||||||
|
kTurnRight
|
||||||
|
};
|
||||||
|
|
||||||
|
const float _defaultTurnAngleSpeed; // Degrees per gameloop
|
||||||
|
|
||||||
|
float computeAngleBetweenVectorsXYPlane(const Math::Vector3d &v1, const Math::Vector3d &v2) const;
|
||||||
|
|
||||||
|
bool _ended;
|
||||||
|
Resources::ItemVisual *_item;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MOVEMENT_MOVEMENT_H
|
98
engines/stark/movement/shortestpath.cpp
Normal file
98
engines/stark/movement/shortestpath.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/movement/shortestpath.h"
|
||||||
|
|
||||||
|
#include "engines/stark/hash-ptr.h"
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
ShortestPath::NodeList ShortestPath::search(const Resources::FloorEdge *start, const Resources::FloorEdge *goal) {
|
||||||
|
NodeList frontier;
|
||||||
|
NodePrecedenceMap cameFrom;
|
||||||
|
NodeCostMap costSoFar;
|
||||||
|
|
||||||
|
frontier.push_back(start);
|
||||||
|
cameFrom[start] = nullptr;
|
||||||
|
costSoFar[start] = 0;
|
||||||
|
|
||||||
|
while (!frontier.empty()) {
|
||||||
|
const Resources::FloorEdge *current = popEdgeWithLowestCost(frontier, costSoFar);
|
||||||
|
|
||||||
|
if (current == goal)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Common::Array<Resources::FloorEdge *> neighbours = current->getNeighbours();
|
||||||
|
for (uint i = 0; i < neighbours.size(); i++) {
|
||||||
|
const Resources::FloorEdge *next = neighbours[i];
|
||||||
|
|
||||||
|
float newCost = costSoFar[current] + current->costTo(next);
|
||||||
|
if (!costSoFar.contains(next) || newCost < costSoFar[next]) {
|
||||||
|
frontier.push_back(next);
|
||||||
|
cameFrom[next] = current;
|
||||||
|
costSoFar[next] = newCost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rebuildPath(start, goal, cameFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortestPath::NodeList ShortestPath::rebuildPath(const Resources::FloorEdge *start, const Resources::FloorEdge *goal,
|
||||||
|
const NodePrecedenceMap &cameFrom) const {
|
||||||
|
NodeList path;
|
||||||
|
|
||||||
|
const Resources::FloorEdge *current = goal;
|
||||||
|
path.push_front(goal);
|
||||||
|
|
||||||
|
while (current && current != start) {
|
||||||
|
current = cameFrom[current];
|
||||||
|
path.push_front(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current != start) {
|
||||||
|
// No path has been found from start to goal
|
||||||
|
return NodeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
path.push_front(start);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Resources::FloorEdge *ShortestPath::popEdgeWithLowestCost(NodeList &frontier, const NodeCostMap &costSoFar) const {
|
||||||
|
// Poor man's priority queue using a list ...
|
||||||
|
NodeList::iterator lowestCostItem = frontier.begin();
|
||||||
|
for (NodeList::iterator it = frontier.begin(); it != frontier.end(); it++) {
|
||||||
|
if (costSoFar[*it] < costSoFar[*lowestCostItem]) {
|
||||||
|
lowestCostItem = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Resources::FloorEdge *result = *lowestCostItem;
|
||||||
|
|
||||||
|
frontier.erase(lowestCostItem);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
59
engines/stark/movement/shortestpath.h
Normal file
59
engines/stark/movement/shortestpath.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MOVEMENT_SHORTEST_PATH_H
|
||||||
|
#define STARK_MOVEMENT_SHORTEST_PATH_H
|
||||||
|
|
||||||
|
#include "common/list.h"
|
||||||
|
#include "common/hashmap.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
class FloorEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the shortest path between two nodes in a graph
|
||||||
|
*
|
||||||
|
* This is an implementation of Dijsktra's search algorithm
|
||||||
|
*/
|
||||||
|
class ShortestPath {
|
||||||
|
public:
|
||||||
|
typedef Common::List<const Resources::FloorEdge *> NodeList;
|
||||||
|
|
||||||
|
/** Computes the shortest path between the start and the goal graph nodes */
|
||||||
|
NodeList search(const Resources::FloorEdge *start, const Resources::FloorEdge *goal);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Common::HashMap<const Resources::FloorEdge *, const Resources::FloorEdge *> NodePrecedenceMap;
|
||||||
|
typedef Common::HashMap<const Resources::FloorEdge *, float> NodeCostMap;
|
||||||
|
|
||||||
|
const Resources::FloorEdge *popEdgeWithLowestCost(NodeList &frontier, const NodeCostMap &costSoFar) const;
|
||||||
|
|
||||||
|
NodeList rebuildPath(const Resources::FloorEdge *start, const Resources::FloorEdge *goal,
|
||||||
|
const NodePrecedenceMap &cameFrom) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MOVEMENT_SHORTEST_PATH_H
|
70
engines/stark/movement/stringpullingpath.cpp
Normal file
70
engines/stark/movement/stringpullingpath.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/movement/stringpullingpath.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
#include "math/line3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
void StringPullingPath::addStep(const Math::Vector3d &position) {
|
||||||
|
_steps.push_back(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringPullingPath::reset() {
|
||||||
|
_steps.clear();
|
||||||
|
_targetStep = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d StringPullingPath::computeWalkTarget(const Math::Vector3d &fromPosition) {
|
||||||
|
Current *current = StarkGlobal->getCurrent();
|
||||||
|
Resources::Floor *floor = current->getFloor();
|
||||||
|
|
||||||
|
// HACK: Sometimes the character gets stuck because of rounding errors
|
||||||
|
// If we detect the character is stuck on a step, just make it go to the next one.
|
||||||
|
// TODO: Improve the string pulling code so that the targets can also be points between two steps.
|
||||||
|
if (fromPosition.getDistanceTo(_steps[_targetStep]) < 1.0 && _targetStep < _steps.size() - 1) {
|
||||||
|
_targetStep++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = _targetStep + 1; i < _steps.size(); i++) {
|
||||||
|
Math::Line3d testSegment = Math::Line3d(fromPosition, _steps[i]);
|
||||||
|
if (!floor->isSegmentInside(testSegment)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_targetStep = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _steps[_targetStep];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringPullingPath::hasSteps() const {
|
||||||
|
return _steps.size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
59
engines/stark/movement/stringpullingpath.h
Normal file
59
engines/stark/movement/stringpullingpath.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MOVEMENT_STRING_PULLING_PATH_H
|
||||||
|
#define STARK_MOVEMENT_STRING_PULLING_PATH_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a path and allow to walk along it smoothly
|
||||||
|
*
|
||||||
|
* The base principle of the string pulling algorithm is to skip steps
|
||||||
|
* if it is possible to walk directly to a later step in straight line.
|
||||||
|
*/
|
||||||
|
class StringPullingPath {
|
||||||
|
public:
|
||||||
|
/** Append a step to the path */
|
||||||
|
void addStep(const Math::Vector3d &position);
|
||||||
|
|
||||||
|
/** Reset the steps, and the current target on the path */
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/** Move the walk target forward according to the position */
|
||||||
|
Math::Vector3d computeWalkTarget(const Math::Vector3d &fromPosition);
|
||||||
|
|
||||||
|
/** Returns true if this path is not degenerated (empty or single point) */
|
||||||
|
bool hasSteps() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::Array<Math::Vector3d> _steps;
|
||||||
|
uint32 _targetStep;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MOVEMENT_STRING_PULLING_PATH_H
|
84
engines/stark/movement/turn.cpp
Normal file
84
engines/stark/movement/turn.cpp
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/movement/turn.h"
|
||||||
|
|
||||||
|
#include "math/matrix3.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
Turn::Turn(Resources::FloorPositionedItem *item) :
|
||||||
|
Movement(item),
|
||||||
|
_item3D(item),
|
||||||
|
_turnSpeed(_defaultTurnAngleSpeed) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Turn::~Turn() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Turn::onGameLoop() {
|
||||||
|
// Compute the direction to turn towards
|
||||||
|
Math::Vector3d direction = _targetDirection;
|
||||||
|
direction.z() = 0;
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
// Compute the angle with the current character direction
|
||||||
|
Math::Vector3d currentDirection = _item3D->getDirectionVector();
|
||||||
|
float directionDeltaAngle = computeAngleBetweenVectorsXYPlane(currentDirection, direction);
|
||||||
|
|
||||||
|
// If the angle between the current direction and the new one is too high,
|
||||||
|
// make the character turn on itself until the angle is low enough
|
||||||
|
TurnDirection turnDirection;
|
||||||
|
if (ABS(directionDeltaAngle) > _turnSpeed + 0.1f) {
|
||||||
|
turnDirection = directionDeltaAngle < 0 ? kTurnLeft : kTurnRight;
|
||||||
|
} else {
|
||||||
|
turnDirection = kTurnNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (turnDirection == kTurnNone) {
|
||||||
|
direction = _targetDirection;
|
||||||
|
} else {
|
||||||
|
// Make the character turn towards the target direction
|
||||||
|
direction = currentDirection;
|
||||||
|
|
||||||
|
Math::Matrix3 rot;
|
||||||
|
rot.buildAroundZ(turnDirection == kTurnLeft ? -_turnSpeed : _turnSpeed);
|
||||||
|
rot.transformVector(&direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the item's direction
|
||||||
|
_item3D->setDirection(computeAngleBetweenVectorsXYPlane(direction, Math::Vector3d(1.0, 0.0, 0.0)));
|
||||||
|
|
||||||
|
// Check if we are close enough to the destination to stop
|
||||||
|
if (direction == _targetDirection) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Turn::setTargetDirection(const Math::Vector3d &direction) {
|
||||||
|
_targetDirection = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
56
engines/stark/movement/turn.h
Normal file
56
engines/stark/movement/turn.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MOVEMENT_TURN_H
|
||||||
|
#define STARK_MOVEMENT_TURN_H
|
||||||
|
|
||||||
|
#include "engines/stark/movement/movement.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
class FloorPositionedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an item turn on itself towards a target direction
|
||||||
|
*/
|
||||||
|
class Turn : public Movement {
|
||||||
|
public:
|
||||||
|
Turn(Resources::FloorPositionedItem *item);
|
||||||
|
virtual ~Turn();
|
||||||
|
|
||||||
|
// Movement API
|
||||||
|
void onGameLoop() override;
|
||||||
|
|
||||||
|
/** Set the direction to turn towards */
|
||||||
|
void setTargetDirection(const Math::Vector3d &direction);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Resources::FloorPositionedItem *_item3D;
|
||||||
|
Math::Vector3d _targetDirection;
|
||||||
|
float _turnSpeed;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MOVEMENT_TURN_H
|
201
engines/stark/movement/walk.cpp
Normal file
201
engines/stark/movement/walk.cpp
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/movement/walk.h"
|
||||||
|
|
||||||
|
#include "engines/stark/movement/shortestpath.h"
|
||||||
|
#include "engines/stark/movement/stringpullingpath.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
#include "engines/stark/resources/floorface.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
#include "engines/stark/resources/location.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
Walk::Walk(Resources::FloorPositionedItem *item) :
|
||||||
|
Movement(item),
|
||||||
|
_item3D(item),
|
||||||
|
_running(false),
|
||||||
|
_turnDirection(kTurnNone) {
|
||||||
|
_path = new StringPullingPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
Walk::~Walk() {
|
||||||
|
delete _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::start() {
|
||||||
|
Movement::start();
|
||||||
|
|
||||||
|
updatePath();
|
||||||
|
changeItemAnim();
|
||||||
|
|
||||||
|
Resources::Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||||
|
location->startFollowingCharacter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::stop() {
|
||||||
|
Movement::stop();
|
||||||
|
|
||||||
|
changeItemAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::updatePath() const {
|
||||||
|
Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
|
Math::Vector3d startPosition = _item3D->getPosition3D();
|
||||||
|
int32 startFloorFaceIndex = floor->findFaceContainingPoint(startPosition);
|
||||||
|
if (startFloorFaceIndex == -1) {
|
||||||
|
startFloorFaceIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::FloorFace *startFloorFace = floor->getFace(startFloorFaceIndex);
|
||||||
|
Resources::FloorEdge *startFloorEdge = startFloorFace->findNearestEdge(startPosition);
|
||||||
|
|
||||||
|
|
||||||
|
int32 destinationFloorFaceIndex = floor->findFaceContainingPoint(_destination);
|
||||||
|
Resources::FloorFace *destinationFloorFace = floor->getFace(destinationFloorFaceIndex);
|
||||||
|
Resources::FloorEdge *destinationFloorEdge = destinationFloorFace->findNearestEdge(_destination);
|
||||||
|
|
||||||
|
ShortestPath pathSearch;
|
||||||
|
ShortestPath::NodeList edgePath = pathSearch.search(startFloorEdge, destinationFloorEdge);
|
||||||
|
|
||||||
|
_path->reset();
|
||||||
|
|
||||||
|
for (ShortestPath::NodeList::const_iterator it = edgePath.begin(); it != edgePath.end(); it++) {
|
||||||
|
_path->addStep((*it)->getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
_path->addStep(_destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::onGameLoop() {
|
||||||
|
if (!_path->hasSteps()) {
|
||||||
|
// There is no path to the destination
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
|
// Get the target to walk to
|
||||||
|
Math::Vector3d currentPosition = _item3D->getPosition3D();
|
||||||
|
Math::Vector3d target = _path->computeWalkTarget(currentPosition);
|
||||||
|
|
||||||
|
// Compute the direction to walk into
|
||||||
|
Math::Vector3d direction = target - currentPosition;
|
||||||
|
direction.z() = 0;
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
// Compute the angle with the current character direction
|
||||||
|
Math::Vector3d currentDirection = _item3D->getDirectionVector();
|
||||||
|
float directionDeltaAngle = computeAngleBetweenVectorsXYPlane(currentDirection, direction);
|
||||||
|
|
||||||
|
// If the angle between the current direction and the new one is too high,
|
||||||
|
// make the character turn on itself until the angle is low enough
|
||||||
|
if (ABS(directionDeltaAngle) > _defaultTurnAngleSpeed + 0.1f) {
|
||||||
|
_turnDirection = directionDeltaAngle < 0 ? kTurnLeft : kTurnRight;
|
||||||
|
} else {
|
||||||
|
_turnDirection = kTurnNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
float distancePerGameloop = computeDistancePerGameLoop();
|
||||||
|
|
||||||
|
Math::Vector3d newPosition;
|
||||||
|
if (_turnDirection == kTurnNone) {
|
||||||
|
// Compute the new position using the distance per gameloop
|
||||||
|
if (currentPosition.getDistanceTo(target) > distancePerGameloop) {
|
||||||
|
newPosition = currentPosition + direction * distancePerGameloop;
|
||||||
|
} else {
|
||||||
|
newPosition = target;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The character does not change position when it is turning
|
||||||
|
newPosition = currentPosition;
|
||||||
|
direction = currentDirection;
|
||||||
|
|
||||||
|
Math::Matrix3 rot;
|
||||||
|
rot.buildAroundZ(_turnDirection == kTurnLeft ? -_defaultTurnAngleSpeed : _defaultTurnAngleSpeed);
|
||||||
|
rot.transformVector(&direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some scripts expect the character position to be the exact destination
|
||||||
|
if (newPosition == _destination) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the new position's height according to the floor
|
||||||
|
int32 newFloorFaceIndex = floor->findFaceContainingPoint(newPosition);
|
||||||
|
if (newFloorFaceIndex >= 0) {
|
||||||
|
floor->computePointHeightInFace(newPosition, newFloorFaceIndex);
|
||||||
|
} else {
|
||||||
|
warning("Item %s is walking off the floor", _item->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the item's properties
|
||||||
|
_item3D->setPosition3D(newPosition);
|
||||||
|
if (direction.getMagnitude() != 0.0) {
|
||||||
|
_item3D->setDirection(computeAngleBetweenVectorsXYPlane(direction, Math::Vector3d(1.0, 0.0, 0.0)));
|
||||||
|
}
|
||||||
|
_item3D->setFloorFaceIndex(newFloorFaceIndex);
|
||||||
|
|
||||||
|
changeItemAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
float Walk::computeDistancePerGameLoop() const {
|
||||||
|
Resources::Anim *anim = _item->getAnim();
|
||||||
|
float distancePerGameloop = anim->getMovementSpeed() * StarkGlobal->getMillisecondsPerGameloop() / 1000.0;
|
||||||
|
|
||||||
|
return distancePerGameloop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::setDestination(const Math::Vector3d &destination) {
|
||||||
|
_destination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::setRunning() {
|
||||||
|
_running = true;
|
||||||
|
changeItemAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::changeItemAnim() {
|
||||||
|
if (_ended) {
|
||||||
|
_item->setAnimKind(Resources::Anim::kActorUsageIdle);
|
||||||
|
} else if (_turnDirection != kTurnNone) {
|
||||||
|
_item->setAnimKind(Resources::Anim::kActorUsageIdle);
|
||||||
|
} else if (_running) {
|
||||||
|
_item->setAnimKind(Resources::Anim::kActorUsageRun);
|
||||||
|
} else {
|
||||||
|
_item->setAnimKind(Resources::Anim::kActorUsageWalk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Walk::changeDestination(const Math::Vector3d &destination) {
|
||||||
|
setDestination(destination);
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
} // End of namespace Stark
|
76
engines/stark/movement/walk.h
Normal file
76
engines/stark/movement/walk.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_MOVEMENT_WALK_H
|
||||||
|
#define STARK_MOVEMENT_WALK_H
|
||||||
|
|
||||||
|
#include "engines/stark/movement/movement.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class StringPullingPath;
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
class FloorPositionedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an item walk / run to its destination on the current
|
||||||
|
* location's floor
|
||||||
|
*/
|
||||||
|
class Walk : public Movement {
|
||||||
|
public:
|
||||||
|
Walk(Resources::FloorPositionedItem *item);
|
||||||
|
virtual ~Walk();
|
||||||
|
|
||||||
|
// Movement API
|
||||||
|
void start() override;
|
||||||
|
void stop() override;
|
||||||
|
void onGameLoop() override;
|
||||||
|
|
||||||
|
/** Set the destination */
|
||||||
|
void setDestination(const Math::Vector3d &destination);
|
||||||
|
|
||||||
|
/** Change the destination and recompute the path */
|
||||||
|
void changeDestination(const Math::Vector3d &destination);
|
||||||
|
|
||||||
|
/** Set the running flag */
|
||||||
|
void setRunning();
|
||||||
|
|
||||||
|
private:
|
||||||
|
float computeDistancePerGameLoop() const;
|
||||||
|
|
||||||
|
void changeItemAnim();
|
||||||
|
void updatePath() const;
|
||||||
|
|
||||||
|
Resources::FloorPositionedItem *_item3D;
|
||||||
|
StringPullingPath *_path;
|
||||||
|
|
||||||
|
Math::Vector3d _destination;
|
||||||
|
|
||||||
|
bool _running;
|
||||||
|
TurnDirection _turnDirection;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_MOVEMENT_WALK_H
|
136
engines/stark/resourcereference.cpp
Normal file
136
engines/stark/resourcereference.cpp
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
#include "engines/stark/debug.h"
|
||||||
|
#include "engines/stark/resources/level.h"
|
||||||
|
#include "engines/stark/resources/location.h"
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/resourceprovider.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
|
||||||
|
ResourceReference::PathElement::PathElement(Resources::Type type, uint16 index) :
|
||||||
|
_type(type), _index(index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String ResourceReference::PathElement::describe() const {
|
||||||
|
return Common::String::format("(%s idx %d)", _type.getName(), _index);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceReference::ResourceReference() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceReference::addPathElement(Resources::Type type, uint16 index) {
|
||||||
|
_path.push_back(PathElement(type, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Object *ResourceReference::resolve() const {
|
||||||
|
Resources::Object *resource = nullptr;
|
||||||
|
for (uint i = 0; i < _path.size(); i++) {
|
||||||
|
PathElement element = _path[i];
|
||||||
|
|
||||||
|
switch (element.getType().get()) {
|
||||||
|
case Resources::Type::kLevel:
|
||||||
|
if (element.getIndex()) {
|
||||||
|
resource = StarkResourceProvider->getLevel(element.getIndex());
|
||||||
|
} else {
|
||||||
|
resource = StarkGlobal->getLevel();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Resources::Type::kLocation:
|
||||||
|
resource = StarkResourceProvider->getLocation(resource->getIndex(), element.getIndex());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resource = resource->findChildWithIndex(element.getType(), element.getIndex());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceReference::empty() const {
|
||||||
|
return _path.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String ResourceReference::describe() const {
|
||||||
|
Common::String desc;
|
||||||
|
|
||||||
|
for (uint i = 0; i < _path.size(); i++) {
|
||||||
|
desc += _path[i].describe() + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceReference::buildFromResource(Resources::Object *resource) {
|
||||||
|
Common::Array<PathElement> reversePath;
|
||||||
|
while (resource && resource->getType() != Resources::Type::kRoot) {
|
||||||
|
reversePath.push_back(PathElement(resource->getType(), resource->getIndex()));
|
||||||
|
|
||||||
|
switch (resource->getType().get()) {
|
||||||
|
case Resources::Type::kLocation: {
|
||||||
|
Resources::Location *location = Resources::Object::cast<Resources::Location>(resource);
|
||||||
|
resource = StarkResourceProvider->getLevelFromLocation(location);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
resource = resource->findParent<Resources::Object>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_path.clear();
|
||||||
|
for (int i = reversePath.size() - 1; i >= 0; i--) {
|
||||||
|
_path.push_back(reversePath[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceReference::loadFromStream(Common::ReadStream *stream) {
|
||||||
|
_path.clear();
|
||||||
|
|
||||||
|
uint32 pathSize = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < pathSize; i++) {
|
||||||
|
byte rawType = stream->readByte();
|
||||||
|
Resources::Type type = Resources::Type((Resources::Type::ResourceType) (rawType));
|
||||||
|
uint16 index = stream->readUint16LE();
|
||||||
|
|
||||||
|
addPathElement(type, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceReference::saveToStream(Common::WriteStream *stream) {
|
||||||
|
stream->writeUint32LE(_path.size());
|
||||||
|
for (uint i = 0; i < _path.size(); i++) {
|
||||||
|
byte rawType = _path[i].getType().get();
|
||||||
|
uint16 index = _path[i].getIndex();
|
||||||
|
|
||||||
|
stream->writeByte(rawType);
|
||||||
|
stream->writeUint16LE(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
89
engines/stark/resourcereference.h
Normal file
89
engines/stark/resourcereference.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_RESOURCE_REFERENCE_H
|
||||||
|
#define STARK_RESOURCES_RESOURCE_REFERENCE_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/stream.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a resource.
|
||||||
|
*
|
||||||
|
* Internally, the referenced resource is designed by its path
|
||||||
|
* in the resource tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ResourceReference {
|
||||||
|
public:
|
||||||
|
ResourceReference();
|
||||||
|
|
||||||
|
Common::String describe() const;
|
||||||
|
|
||||||
|
/** Read the reference from a stream */
|
||||||
|
void loadFromStream(Common::ReadStream *stream);
|
||||||
|
|
||||||
|
/** Write the reference to a stream */
|
||||||
|
void saveToStream(Common::WriteStream *stream);
|
||||||
|
|
||||||
|
/** Make the reference point to the specified object */
|
||||||
|
void buildFromResource(Resources::Object *resource);
|
||||||
|
|
||||||
|
/** Resolve the reference to the actual resource */
|
||||||
|
template <class T>
|
||||||
|
T* resolve() const;
|
||||||
|
|
||||||
|
/** Return true if this reference is a null pointer */
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addPathElement(Resources::Type type, uint16 index);
|
||||||
|
Resources::Object *resolve() const;
|
||||||
|
|
||||||
|
class PathElement {
|
||||||
|
public:
|
||||||
|
PathElement(Resources::Type type, uint16 index);
|
||||||
|
Common::String describe() const;
|
||||||
|
|
||||||
|
Resources::Type getType() const { return _type; }
|
||||||
|
uint16 getIndex() const { return _index; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Resources::Type _type;
|
||||||
|
uint16 _index;
|
||||||
|
};
|
||||||
|
|
||||||
|
Common::Array<PathElement> _path;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T* ResourceReference::resolve() const {
|
||||||
|
return Resources::Object::cast<T>(resolve());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_RESOURCE_REFERENCE_H
|
523
engines/stark/resources/anim.cpp
Normal file
523
engines/stark/resources/anim.cpp
Normal file
|
@ -0,0 +1,523 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/biffmesh.h"
|
||||||
|
#include "engines/stark/formats/tm.h"
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/driver.h"
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/bonesmesh.h"
|
||||||
|
#include "engines/stark/resources/direction.h"
|
||||||
|
#include "engines/stark/resources/image.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
#include "engines/stark/resources/textureset.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
|
||||||
|
#include "engines/stark/model/skeleton_anim.h"
|
||||||
|
#include "engines/stark/visual/actor.h"
|
||||||
|
#include "engines/stark/visual/prop.h"
|
||||||
|
#include "engines/stark/visual/smacker.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Object *Anim::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||||
|
switch (subType) {
|
||||||
|
case kAnimImages:
|
||||||
|
return new AnimImages(parent, subType, index, name);
|
||||||
|
case kAnimProp:
|
||||||
|
return new AnimProp(parent, subType, index, name);
|
||||||
|
case kAnimVideo:
|
||||||
|
return new AnimVideo(parent, subType, index, name);
|
||||||
|
case kAnimSkeleton:
|
||||||
|
return new AnimSkeleton(parent, subType, index, name);
|
||||||
|
default:
|
||||||
|
error("Unknown anim subtype %d", subType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim::~Anim() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim::Anim(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_usage(0),
|
||||||
|
_currentFrame(0),
|
||||||
|
_numFrames(0),
|
||||||
|
_refCount(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Anim::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_usage = stream->readUint32LE();
|
||||||
|
_numFrames = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Anim::selectFrame(uint32 frameIndex) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Anim::getUsage() const {
|
||||||
|
return _usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Anim::applyToItem(Item *item) {
|
||||||
|
_refCount++;
|
||||||
|
}
|
||||||
|
void Anim::removeFromItem(Item *item) {
|
||||||
|
_refCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Anim::isInUse() {
|
||||||
|
return _refCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Anim::getPointHotspotIndex(const Common::Point &point) const {
|
||||||
|
// Most anim types only have one hotspot
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Anim::getDuration() const {
|
||||||
|
// TODO: Implement for each anim type
|
||||||
|
warning("Anim::getDuration is not implemented");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Anim::playAsAction(ItemVisual *item) {
|
||||||
|
// TODO: Implement for each anim type
|
||||||
|
warning("Anim::playAsAction is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Anim::isAtTime(uint32 time) const {
|
||||||
|
// TODO: Implement for each anim type
|
||||||
|
warning("Anim::isAtTime is not implemented");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Anim::getMovementSpeed() const {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Anim::printData() {
|
||||||
|
debug("usage: %d", _usage);
|
||||||
|
debug("numFrames: %d", _numFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimImages::~AnimImages() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimImages::AnimImages(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Anim(parent, subType, index, name),
|
||||||
|
_field_3C(0),
|
||||||
|
_currentDirection(0),
|
||||||
|
_currentFrameImage(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimImages::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Anim::readData(stream);
|
||||||
|
|
||||||
|
_field_3C = stream->readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimImages::onAllLoaded() {
|
||||||
|
Anim::onAllLoaded();
|
||||||
|
|
||||||
|
_directions = listChildren<Direction>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimImages::selectFrame(uint32 frameIndex) {
|
||||||
|
if (frameIndex > _numFrames) {
|
||||||
|
// The original silently ignores this as well
|
||||||
|
warning("Request for frame %d for anim '%s' has been ignored, it is above max frame %d", frameIndex, getName().c_str(), _numFrames);
|
||||||
|
_currentFrame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentFrame = frameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *AnimImages::getVisual() {
|
||||||
|
Direction *direction = _directions[_currentDirection];
|
||||||
|
_currentFrameImage = direction->findChildWithIndex<Image>(_currentFrame);
|
||||||
|
return _currentFrameImage->getVisual();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimImages::printData() {
|
||||||
|
Anim::printData();
|
||||||
|
|
||||||
|
debug("field_3C: %f", _field_3C);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AnimImages::getPointHotspotIndex(const Common::Point &point) const {
|
||||||
|
if (_currentFrameImage) {
|
||||||
|
return _currentFrameImage->indexForPoint(point);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimImages::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
Anim::saveLoad(serializer);
|
||||||
|
|
||||||
|
serializer->syncAsUint32LE(_currentFrame);
|
||||||
|
|
||||||
|
if (serializer->isLoading()) {
|
||||||
|
selectFrame(_currentFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimProp::~AnimProp() {
|
||||||
|
delete _visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimProp::AnimProp(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Anim(parent, subType, index, name),
|
||||||
|
_movementSpeed(100) {
|
||||||
|
_visual = StarkGfx->createPropRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *AnimProp::getVisual() {
|
||||||
|
return _visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimProp::getMovementSpeed() const {
|
||||||
|
return _movementSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimProp::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Anim::readData(stream);
|
||||||
|
|
||||||
|
_field_3C = stream->readString();
|
||||||
|
|
||||||
|
uint32 meshCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < meshCount; i++) {
|
||||||
|
_meshFilenames.push_back(stream->readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
_textureFilename = stream->readString();
|
||||||
|
_movementSpeed = stream->readUint32LE();
|
||||||
|
_archiveName = stream->getArchiveName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimProp::onPostRead() {
|
||||||
|
if (_meshFilenames.size() != 1) {
|
||||||
|
error("Unexpected mesh count in prop anim: '%d'", _meshFilenames.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_meshFilenames[0], _archiveName);
|
||||||
|
_visual->setModel(Formats::BiffMeshReader::read(stream));
|
||||||
|
delete stream;
|
||||||
|
|
||||||
|
stream = StarkArchiveLoader->getFile(_textureFilename, _archiveName);
|
||||||
|
_visual->setTexture(Formats::TextureSetReader::read(stream));
|
||||||
|
delete stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimProp::printData() {
|
||||||
|
Anim::printData();
|
||||||
|
|
||||||
|
debug("field_3C: %s", _field_3C.c_str());
|
||||||
|
|
||||||
|
Common::String description;
|
||||||
|
for (uint32 i = 0; i < _meshFilenames.size(); i++) {
|
||||||
|
debug("meshFilename[%d]: %s", i, _meshFilenames[i].c_str());
|
||||||
|
}
|
||||||
|
debug("textureFilename: %s", _textureFilename.c_str());
|
||||||
|
debug("movementSpeed: %d", _movementSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimVideo::~AnimVideo() {
|
||||||
|
delete _smacker;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimVideo::AnimVideo(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Anim(parent, subType, index, name),
|
||||||
|
_width(0),
|
||||||
|
_height(0),
|
||||||
|
_smacker(nullptr),
|
||||||
|
_field_4C(-1),
|
||||||
|
_field_50(0),
|
||||||
|
_loop(false),
|
||||||
|
_actionItem(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimVideo::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Anim::readData(stream);
|
||||||
|
_smackerFile = stream->readString();
|
||||||
|
_width = stream->readUint32LE();
|
||||||
|
_height = stream->readUint32LE();
|
||||||
|
|
||||||
|
_positions.clear();
|
||||||
|
_sizes.clear();
|
||||||
|
|
||||||
|
uint32 size = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < size; i++) {
|
||||||
|
_positions.push_back(stream->readPoint());
|
||||||
|
_sizes.push_back(stream->readRect());
|
||||||
|
}
|
||||||
|
|
||||||
|
_loop = stream->readBool();
|
||||||
|
_field_4C = stream->readSint32LE();
|
||||||
|
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_field_50 = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
_archiveName = stream->getArchiveName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimVideo::onAllLoaded() {
|
||||||
|
if (!_smacker) {
|
||||||
|
Common::SeekableReadStream *stream = StarkArchiveLoader->getExternalFile(_smackerFile, _archiveName);
|
||||||
|
|
||||||
|
_smacker = new VisualSmacker(StarkGfx);
|
||||||
|
_smacker->load(stream);
|
||||||
|
updateSmackerPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimVideo::onGameLoop() {
|
||||||
|
if (!_smacker || !isInUse()) {
|
||||||
|
return; // Animation not in use, no need to update the movie
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_smacker->isDone()) {
|
||||||
|
// The last frame has been reached
|
||||||
|
if (!_loop && _actionItem) {
|
||||||
|
// Reset our item if needed
|
||||||
|
_actionItem->resetActionAnim();
|
||||||
|
_actionItem = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_loop) {
|
||||||
|
_smacker->rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_smacker->isDone()) {
|
||||||
|
_smacker->update();
|
||||||
|
updateSmackerPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *AnimVideo::getVisual() {
|
||||||
|
return _smacker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimVideo::updateSmackerPosition() {
|
||||||
|
int frame = _smacker->getFrameNumber();
|
||||||
|
if (frame != -1 && frame < (int) _positions.size()) {
|
||||||
|
_smacker->setPosition(_positions[frame]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimVideo::getDuration() const {
|
||||||
|
return _smacker->getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimVideo::playAsAction(ItemVisual *item) {
|
||||||
|
_actionItem = item;
|
||||||
|
|
||||||
|
if (!_loop) {
|
||||||
|
_smacker->rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnimVideo::isAtTime(uint32 time) const {
|
||||||
|
uint32 currentTime = _smacker->getCurrentTime();
|
||||||
|
return currentTime >= time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimVideo::printData() {
|
||||||
|
Anim::printData();
|
||||||
|
|
||||||
|
debug("smackerFile: %s", _smackerFile.c_str());
|
||||||
|
debug("size: x %d, y %d", _width, _height);
|
||||||
|
|
||||||
|
Common::String description;
|
||||||
|
for (uint32 i = 0; i < _positions.size(); i++) {
|
||||||
|
description += Common::String::format("(x %d, y %d) ", _positions[i].x, _positions[i].y);
|
||||||
|
}
|
||||||
|
debug("positions: %s", description.c_str());
|
||||||
|
|
||||||
|
description.clear();
|
||||||
|
for (uint32 i = 0; i < _sizes.size(); i++) {
|
||||||
|
description += Common::String::format("(l %d, t %d, r %d, b %d) ",
|
||||||
|
_sizes[i].left, _sizes[i].top, _sizes[i].right, _sizes[i].bottom);
|
||||||
|
}
|
||||||
|
debug("sizes: %s", description.c_str());
|
||||||
|
|
||||||
|
debug("field_4C: %d", _field_4C);
|
||||||
|
debug("field_50: %d", _field_50);
|
||||||
|
debug("loop: %d", _loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimSkeleton::~AnimSkeleton() {
|
||||||
|
delete _visual;
|
||||||
|
delete _seletonAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimSkeleton::AnimSkeleton(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Anim(parent, subType, index, name),
|
||||||
|
_castsShadow(true),
|
||||||
|
_loop(false),
|
||||||
|
_movementSpeed(100),
|
||||||
|
_field_6C(1),
|
||||||
|
_seletonAnim(nullptr),
|
||||||
|
_currentTime(0),
|
||||||
|
_totalTime(0),
|
||||||
|
_actionItem(nullptr) {
|
||||||
|
_visual = StarkGfx->createActorRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::applyToItem(Item *item) {
|
||||||
|
Anim::applyToItem(item);
|
||||||
|
|
||||||
|
if (!_loop) {
|
||||||
|
_currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentTime > _totalTime) {
|
||||||
|
_currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelItem *modelItem = Object::cast<ModelItem>(item);
|
||||||
|
|
||||||
|
BonesMesh *mesh = modelItem->findBonesMesh();
|
||||||
|
TextureSet *texture = modelItem->findTextureSet(TextureSet::kTextureNormal);
|
||||||
|
|
||||||
|
_visual->setModel(mesh->getModel());
|
||||||
|
_visual->setTexture(texture->getTexture());
|
||||||
|
_visual->setAnim(_seletonAnim);
|
||||||
|
_visual->setTime(_currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::removeFromItem(Item *item) {
|
||||||
|
Anim::removeFromItem(item);
|
||||||
|
|
||||||
|
_actionItem = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *AnimSkeleton::getVisual() {
|
||||||
|
return _visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Anim::readData(stream);
|
||||||
|
|
||||||
|
_animFilename = stream->readString();
|
||||||
|
stream->readString(); // Skipped in the original
|
||||||
|
stream->readString(); // Skipped in the original
|
||||||
|
stream->readString(); // Skipped in the original
|
||||||
|
|
||||||
|
_loop = stream->readBool();
|
||||||
|
_movementSpeed = stream->readUint32LE();
|
||||||
|
|
||||||
|
if (_movementSpeed < 1) {
|
||||||
|
_movementSpeed = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_castsShadow = stream->readBool();
|
||||||
|
} else {
|
||||||
|
_castsShadow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_field_6C = stream->readUint32LE();
|
||||||
|
} else {
|
||||||
|
_field_6C = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_archiveName = stream->getArchiveName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::onPostRead() {
|
||||||
|
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_animFilename, _archiveName);
|
||||||
|
|
||||||
|
_seletonAnim = new SkeletonAnim();
|
||||||
|
_seletonAnim->createFromStream(stream);
|
||||||
|
|
||||||
|
delete stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::onAllLoaded() {
|
||||||
|
Anim::onAllLoaded();
|
||||||
|
|
||||||
|
_totalTime = _seletonAnim->getLength();
|
||||||
|
_currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::onGameLoop() {
|
||||||
|
Anim::onGameLoop();
|
||||||
|
|
||||||
|
if (isInUse() && _totalTime) {
|
||||||
|
uint32 newTime = _currentTime + StarkGlobal->getMillisecondsPerGameloop();
|
||||||
|
|
||||||
|
if (!_loop && newTime > _totalTime) {
|
||||||
|
if (_actionItem) {
|
||||||
|
_actionItem->resetActionAnim();
|
||||||
|
_actionItem = nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_currentTime = newTime % _totalTime;
|
||||||
|
_visual->setTime(_currentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimSkeleton::getMovementSpeed() const {
|
||||||
|
return _movementSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimSkeleton::getDuration() const {
|
||||||
|
return _totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::playAsAction(ItemVisual *item) {
|
||||||
|
_actionItem = item;
|
||||||
|
|
||||||
|
if (!_loop) {
|
||||||
|
_currentTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnimSkeleton::isAtTime(uint32 time) const {
|
||||||
|
return _currentTime >= time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimSkeleton::printData() {
|
||||||
|
Anim::printData();
|
||||||
|
|
||||||
|
debug("filename: %s", _animFilename.c_str());
|
||||||
|
debug("castsShadow: %d", _castsShadow);
|
||||||
|
debug("loop: %d", _loop);
|
||||||
|
debug("movementSpeed: %d", _movementSpeed);
|
||||||
|
debug("field_6C: %d", _field_6C);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
283
engines/stark/resources/anim.h
Normal file
283
engines/stark/resources/anim.h
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_ANIM_H
|
||||||
|
#define STARK_RESOURCES_ANIM_H
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class SkeletonAnim;
|
||||||
|
class VisualActor;
|
||||||
|
class VisualProp;
|
||||||
|
class VisualSmacker;
|
||||||
|
class Visual;
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Direction;
|
||||||
|
class Image;
|
||||||
|
class Item;
|
||||||
|
class ItemVisual;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation base class
|
||||||
|
*
|
||||||
|
* Animations provide a time dependent visual state to Items
|
||||||
|
*/
|
||||||
|
class Anim : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kAnim;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kAnimImages = 1,
|
||||||
|
kAnimProp = 2,
|
||||||
|
kAnimVideo = 3,
|
||||||
|
kAnimSkeleton = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ActionUsage {
|
||||||
|
kActionUsagePassive = 1,
|
||||||
|
kActionUsageActive = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UIUsage {
|
||||||
|
kUIUsageInventory = 1,
|
||||||
|
kUIUsageUseCursorPassive = 4,
|
||||||
|
kUIUsageUseCursorActive = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ActorUsage {
|
||||||
|
kActorUsageIdle = 1,
|
||||||
|
kActorUsageWalk = 2,
|
||||||
|
kActorUsageTalk = 3,
|
||||||
|
kActorUsageRun = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Anim factory */
|
||||||
|
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
|
||||||
|
Anim(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Anim();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
/** Sets the animation frame to be displayed */
|
||||||
|
virtual void selectFrame(uint32 frameIndex);
|
||||||
|
|
||||||
|
/** Obtain the Visual to be used to render the animation */
|
||||||
|
virtual Visual *getVisual() = 0;
|
||||||
|
|
||||||
|
/** Associate the animation to an Item */
|
||||||
|
virtual void applyToItem(Item *item);
|
||||||
|
|
||||||
|
/** Dissociate the animation from an item */
|
||||||
|
virtual void removeFromItem(Item *item);
|
||||||
|
|
||||||
|
/** Check is the animation is being used by an item */
|
||||||
|
bool isInUse();
|
||||||
|
|
||||||
|
/** Obtain the purpose of this anim */
|
||||||
|
uint32 getUsage() const;
|
||||||
|
|
||||||
|
/** Return the hotspot index for a point given in relative coordinates */
|
||||||
|
virtual int getPointHotspotIndex(const Common::Point &point) const;
|
||||||
|
|
||||||
|
/** Get the animation typical duration in milliseconds */
|
||||||
|
virtual uint32 getDuration() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play the animation as an action for an item.
|
||||||
|
*
|
||||||
|
* This sets up a callback to the item for when the animation completes.
|
||||||
|
*/
|
||||||
|
virtual void playAsAction(ItemVisual *item);
|
||||||
|
|
||||||
|
/** Checks if the elapsed time since the animation start is greater than a specified duration */
|
||||||
|
virtual bool isAtTime(uint32 time) const;
|
||||||
|
|
||||||
|
/** Get the anim movement speed in units per seconds */
|
||||||
|
virtual uint32 getMovementSpeed() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void printData() override;
|
||||||
|
|
||||||
|
uint32 _usage;
|
||||||
|
uint32 _currentFrame;
|
||||||
|
uint32 _numFrames;
|
||||||
|
int32 _refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays still images controlled by an AnimScript
|
||||||
|
*/
|
||||||
|
class AnimImages : public Anim {
|
||||||
|
public:
|
||||||
|
AnimImages(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimImages();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
// Anim API
|
||||||
|
void selectFrame(uint32 frameIndex) override;
|
||||||
|
Visual *getVisual() override;
|
||||||
|
int getPointHotspotIndex(const Common::Point &point) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
float _field_3C;
|
||||||
|
|
||||||
|
uint32 _currentDirection;
|
||||||
|
Common::Array<Direction *> _directions;
|
||||||
|
|
||||||
|
Image *_currentFrameImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnimProp : public Anim {
|
||||||
|
public:
|
||||||
|
AnimProp(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimProp();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onPostRead() override;
|
||||||
|
|
||||||
|
// Anim API
|
||||||
|
Visual *getVisual();
|
||||||
|
uint32 getMovementSpeed() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::String _field_3C;
|
||||||
|
Common::Array<Common::String> _meshFilenames;
|
||||||
|
Common::String _textureFilename;
|
||||||
|
uint32 _movementSpeed;
|
||||||
|
Common::String _archiveName;
|
||||||
|
|
||||||
|
VisualProp *_visual;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a Smacker video
|
||||||
|
*/
|
||||||
|
class AnimVideo : public Anim {
|
||||||
|
public:
|
||||||
|
AnimVideo(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimVideo();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void onGameLoop() override;
|
||||||
|
|
||||||
|
// Anim API
|
||||||
|
Visual *getVisual() override;
|
||||||
|
void playAsAction(ItemVisual *item) override;
|
||||||
|
uint32 getDuration() const override;
|
||||||
|
bool isAtTime(uint32 time) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef Common::Array<Common::Point> PointArray;
|
||||||
|
typedef Common::Array<Common::Rect> RectArray;
|
||||||
|
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
/** Update the position of the video for the current frame */
|
||||||
|
void updateSmackerPosition();
|
||||||
|
|
||||||
|
Common::String _smackerFile;
|
||||||
|
Common::String _archiveName;
|
||||||
|
|
||||||
|
VisualSmacker *_smacker;
|
||||||
|
|
||||||
|
uint32 _width;
|
||||||
|
uint32 _height;
|
||||||
|
|
||||||
|
PointArray _positions;
|
||||||
|
RectArray _sizes;
|
||||||
|
|
||||||
|
int32 _field_4C;
|
||||||
|
uint32 _field_50;
|
||||||
|
bool _loop;
|
||||||
|
|
||||||
|
ItemVisual *_actionItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates a 3D mesh skeleton
|
||||||
|
*/
|
||||||
|
class AnimSkeleton : public Anim {
|
||||||
|
public:
|
||||||
|
AnimSkeleton(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimSkeleton();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onPostRead() override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void onGameLoop() override;
|
||||||
|
|
||||||
|
// Anim API
|
||||||
|
void applyToItem(Item *item) override;
|
||||||
|
void removeFromItem(Item *item) override;
|
||||||
|
Visual *getVisual() override;
|
||||||
|
uint32 getDuration() const override;
|
||||||
|
void playAsAction(ItemVisual *item) override;
|
||||||
|
bool isAtTime(uint32 time) const override;
|
||||||
|
uint32 getMovementSpeed() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
bool _castsShadow;
|
||||||
|
Common::String _archiveName;
|
||||||
|
Common::String _animFilename;
|
||||||
|
bool _loop;
|
||||||
|
uint32 _movementSpeed;
|
||||||
|
uint32 _field_6C;
|
||||||
|
|
||||||
|
uint32 _totalTime;
|
||||||
|
uint32 _currentTime;
|
||||||
|
|
||||||
|
SkeletonAnim *_seletonAnim;
|
||||||
|
VisualActor *_visual;
|
||||||
|
|
||||||
|
ItemVisual *_actionItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_ANIM_H
|
158
engines/stark/resources/animhierarchy.cpp
Normal file
158
engines/stark/resources/animhierarchy.cpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/animhierarchy.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/bonesmesh.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
#include "engines/stark/resources/textureset.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
AnimHierarchy::~AnimHierarchy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimHierarchy::AnimHierarchy(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_animUsage(0),
|
||||||
|
_currentAnim(nullptr),
|
||||||
|
_animHierarchy(nullptr),
|
||||||
|
_field_5C(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimHierarchy::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_animationReferences.clear();
|
||||||
|
|
||||||
|
uint32 refCount = stream->readUint32LE();
|
||||||
|
for (uint32 i = 0; i < refCount; i++) {
|
||||||
|
_animationReferences.push_back(stream->readResourceReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
_animHierarchyReference = stream->readResourceReference();
|
||||||
|
_field_5C = stream->readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimHierarchy::onAllLoaded() {
|
||||||
|
Object::onAllLoaded();
|
||||||
|
|
||||||
|
_animations.clear();
|
||||||
|
|
||||||
|
// Animations can be provided directly ...
|
||||||
|
for (uint i = 0; i < _animationReferences.size(); i++) {
|
||||||
|
_animations.push_back(_animationReferences[i].resolve<Anim>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... or through another animation hierarchy
|
||||||
|
_animHierarchy = _animHierarchyReference.resolve<AnimHierarchy>();
|
||||||
|
if (_animHierarchy) {
|
||||||
|
for (uint i = 0; i < _animHierarchy->_animationReferences.size(); i++) {
|
||||||
|
_animations.push_back(_animHierarchy->_animationReferences[i].resolve<Anim>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimHierarchy::setItemAnim(ItemVisual *item, int32 usage) {
|
||||||
|
unselectItemAnim(item);
|
||||||
|
_animUsage = usage;
|
||||||
|
selectItemAnim(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimHierarchy::unselectItemAnim(ItemVisual *item) {
|
||||||
|
if (_currentAnim && _currentAnim->isInUse()) {
|
||||||
|
_currentAnim->removeFromItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentAnim = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimHierarchy::selectItemAnim(ItemVisual *item) {
|
||||||
|
// Search for an animation with the appropriate index
|
||||||
|
for (uint i = 0; i < _animations.size(); i++) {
|
||||||
|
if (_animations[i]->getUsage() == _animUsage) {
|
||||||
|
_currentAnim = _animations[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to the first animation
|
||||||
|
if (!_currentAnim && !_animations.empty()) {
|
||||||
|
_currentAnim = _animations[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_currentAnim) {
|
||||||
|
error("Failed to set an animation for item %s", item->getName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_currentAnim->isInUse()) {
|
||||||
|
_currentAnim->applyToItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim *AnimHierarchy::getCurrentAnim() {
|
||||||
|
return _currentAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
BonesMesh *AnimHierarchy::findBonesMesh() {
|
||||||
|
return findChild<BonesMesh>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *AnimHierarchy::findTextureSet(uint32 textureType) {
|
||||||
|
return findChildWithSubtype<TextureSet>(textureType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim *AnimHierarchy::getAnimForUsage(uint32 usage) {
|
||||||
|
// Search for an animation with the appropriate use
|
||||||
|
for (uint i = 0; i < _animations.size(); i++) {
|
||||||
|
if (_animations[i]->getUsage() == usage) {
|
||||||
|
return _animations[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *AnimHierarchy::getVisualForUsage(uint32 usage) {
|
||||||
|
Anim *anim = getAnimForUsage(usage);
|
||||||
|
if (anim) {
|
||||||
|
return anim->getVisual();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimHierarchy::printData() {
|
||||||
|
for (uint i = 0; i < _animationReferences.size(); i++) {
|
||||||
|
debug("anim %d: %s", i, _animationReferences[i].describe().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("animHierarchy: %s", _animHierarchyReference.describe().c_str());
|
||||||
|
debug("field_5C: %f", _field_5C);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
104
engines/stark/resources/animhierarchy.h
Normal file
104
engines/stark/resources/animhierarchy.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_ANIM_HIERARCHY_H
|
||||||
|
#define STARK_RESOURCES_ANIM_HIERARCHY_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class Visual;
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Anim;
|
||||||
|
class BonesMesh;
|
||||||
|
class ItemVisual;
|
||||||
|
class TextureSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An animation hierarchy is a container resource referencing the available
|
||||||
|
* animations for an item.
|
||||||
|
*
|
||||||
|
* This resource keeps track of the currently selected animation.
|
||||||
|
*/
|
||||||
|
class AnimHierarchy : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kAnimHierarchy;
|
||||||
|
|
||||||
|
AnimHierarchy(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimHierarchy();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
|
||||||
|
/** Set and apply the current animation kind for an item */
|
||||||
|
void setItemAnim(ItemVisual *item, int32 usage);
|
||||||
|
|
||||||
|
/** Unselect the current animation and remove it from an item */
|
||||||
|
void unselectItemAnim(ItemVisual *item);
|
||||||
|
|
||||||
|
/** Apply the current animation to an item */
|
||||||
|
void selectItemAnim(ItemVisual *item);
|
||||||
|
|
||||||
|
/** Obtain the currently selected animation */
|
||||||
|
Anim *getCurrentAnim();
|
||||||
|
|
||||||
|
/** Retrieve the first bone mesh from the anim hierarchy children, if any */
|
||||||
|
BonesMesh *findBonesMesh();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the first texture of the appropriate type from the anim
|
||||||
|
* hierarchy children, if any
|
||||||
|
*/
|
||||||
|
TextureSet *findTextureSet(uint32 textureType);
|
||||||
|
|
||||||
|
Visual *getVisualForUsage(uint32 usage);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Anim *getAnimForUsage(uint32 usage);
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::Array<ResourceReference> _animationReferences;
|
||||||
|
Common::Array<Anim *> _animations;
|
||||||
|
|
||||||
|
ResourceReference _animHierarchyReference;
|
||||||
|
AnimHierarchy * _animHierarchy;
|
||||||
|
|
||||||
|
float _field_5C;
|
||||||
|
uint32 _animUsage;
|
||||||
|
Anim *_currentAnim;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_ANIM_HIERARCHY_H
|
210
engines/stark/resources/animscript.cpp
Normal file
210
engines/stark/resources/animscript.cpp
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/animscript.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/random.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
AnimScript::~AnimScript() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimScript::AnimScript(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_anim(nullptr),
|
||||||
|
_msecsToNextUpdate(0),
|
||||||
|
_nextItemIndex(-1) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScript::onAllLoaded() {
|
||||||
|
Object::onAllLoaded();
|
||||||
|
|
||||||
|
_anim = Object::cast<Anim>(_parent);
|
||||||
|
_items = listChildren<AnimScriptItem>();
|
||||||
|
|
||||||
|
if (!_items.empty()) {
|
||||||
|
// Setup the next item to the first
|
||||||
|
_nextItemIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScript::onGameLoop() {
|
||||||
|
Object::onGameLoop();
|
||||||
|
|
||||||
|
if (!_anim || !_anim->isInUse() || _nextItemIndex == -1) {
|
||||||
|
// The script is disabled, do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_msecsToNextUpdate <= (int32)StarkGlobal->getMillisecondsPerGameloop()) {
|
||||||
|
AnimScriptItem *item = _items[_nextItemIndex];
|
||||||
|
_msecsToNextUpdate += item->getDuration();
|
||||||
|
|
||||||
|
switch (item->getOpcode()) {
|
||||||
|
case AnimScriptItem::kDisplayFrame:
|
||||||
|
_anim->selectFrame(item->getOperand());
|
||||||
|
goToNextItem();
|
||||||
|
break;
|
||||||
|
case AnimScriptItem::kPlayAnimSound:
|
||||||
|
// TODO
|
||||||
|
goToNextItem();
|
||||||
|
break;
|
||||||
|
case AnimScriptItem::kGoToItem:
|
||||||
|
_nextItemIndex = item->getOperand();
|
||||||
|
break;
|
||||||
|
case AnimScriptItem::kDisplayRandomFrame: {
|
||||||
|
uint32 startFrame = item->getOperand() >> 16;
|
||||||
|
uint32 endFrame = item->getOperand() & 0xFFFF;
|
||||||
|
|
||||||
|
uint32 frame = StarkRandomSource->getRandomNumberRng(startFrame, endFrame);
|
||||||
|
_anim->selectFrame(frame);
|
||||||
|
goToNextItem();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AnimScriptItem::kSleepRandomDuration: {
|
||||||
|
uint duration = StarkRandomSource->getRandomNumber(item->getOperand());
|
||||||
|
_msecsToNextUpdate += duration;
|
||||||
|
goToNextItem();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AnimScriptItem::kPlayStockSound:
|
||||||
|
// TODO
|
||||||
|
goToNextItem();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown anim script type %d", item->getOpcode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_msecsToNextUpdate -= StarkGlobal->getMillisecondsPerGameloop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScript::goToNextItem() {
|
||||||
|
_nextItemIndex += 1;
|
||||||
|
_nextItemIndex %= _items.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScript::goToScriptItem(AnimScriptItem *item) {
|
||||||
|
_nextItemIndex = findItemIndex(item);
|
||||||
|
_msecsToNextUpdate = 0;
|
||||||
|
|
||||||
|
if (item && item->getOpcode() == AnimScriptItem::kDisplayFrame) {
|
||||||
|
_anim->selectFrame(item->getOperand());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimScript::getDurationStartingWithItem(AnimScriptItem *startItem) {
|
||||||
|
uint32 duration = 0;
|
||||||
|
uint32 itemIndex = findItemIndex(startItem);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
bool goingBackwards = false;
|
||||||
|
AnimScriptItem *item = _items[itemIndex];
|
||||||
|
|
||||||
|
switch (item->getOpcode()) {
|
||||||
|
case AnimScriptItem::kDisplayFrame:
|
||||||
|
case AnimScriptItem::kPlayAnimSound:
|
||||||
|
case AnimScriptItem::kDisplayRandomFrame:
|
||||||
|
itemIndex += 1;
|
||||||
|
itemIndex %= _items.size();
|
||||||
|
break;
|
||||||
|
case AnimScriptItem::kGoToItem:
|
||||||
|
if (item->getOperand() <= itemIndex) {
|
||||||
|
goingBackwards = true;
|
||||||
|
}
|
||||||
|
itemIndex = item->getOperand();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemIndex == 0 || goingBackwards) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
duration += item->getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnimScript::hasReached(AnimScriptItem *item) {
|
||||||
|
int32 index = findItemIndex(item);
|
||||||
|
return _nextItemIndex >= index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 AnimScript::findItemIndex(AnimScriptItem *item) {
|
||||||
|
if (!item) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < _items.size(); i++) {
|
||||||
|
if (_items[i] == item) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScript::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
serializer->syncAsSint32LE(_nextItemIndex);
|
||||||
|
|
||||||
|
if (serializer->isLoading()) {
|
||||||
|
_msecsToNextUpdate = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimScriptItem::~AnimScriptItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimScriptItem::AnimScriptItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_opcode(0),
|
||||||
|
_duration(0),
|
||||||
|
_operand(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScriptItem::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_opcode = stream->readUint32LE();
|
||||||
|
_duration = stream->readUint32LE();
|
||||||
|
_operand = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimScriptItem::printData() {
|
||||||
|
debug("op: %d, duration: %d ms, operand: %d", _opcode, _duration, _operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
131
engines/stark/resources/animscript.h
Normal file
131
engines/stark/resources/animscript.h
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_ANIM_SCRIPT_H
|
||||||
|
#define STARK_RESOURCES_ANIM_SCRIPT_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Anim;
|
||||||
|
class AnimScriptItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation scripts control the currently displayed frame for images animation
|
||||||
|
* resources.
|
||||||
|
*
|
||||||
|
* Animation scripts contain animation script items defining which frames
|
||||||
|
* should be displayed and when.
|
||||||
|
*
|
||||||
|
* Animation scripts also allow to play sounds.
|
||||||
|
*/
|
||||||
|
class AnimScript : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kAnimScript;
|
||||||
|
|
||||||
|
AnimScript(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimScript();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void onGameLoop() override;
|
||||||
|
void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
/** Go to a script item. Cancel any delay so that it is shown immediately. */
|
||||||
|
void goToScriptItem(AnimScriptItem *item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the duration in milliseconds of an animation script portion.
|
||||||
|
*
|
||||||
|
* Said portion goes from the specified starting point to the end of the script
|
||||||
|
*/
|
||||||
|
uint32 getDurationStartingWithItem(AnimScriptItem *startItem);
|
||||||
|
|
||||||
|
/** Is the current script item later in the script when compared to the specified one? */
|
||||||
|
bool hasReached(AnimScriptItem *item);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void goToNextItem();
|
||||||
|
int32 findItemIndex(AnimScriptItem *item);
|
||||||
|
|
||||||
|
Anim *_anim;
|
||||||
|
Common::Array<AnimScriptItem *> _items;
|
||||||
|
|
||||||
|
int32 _nextItemIndex;
|
||||||
|
int32 _msecsToNextUpdate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation script element
|
||||||
|
*
|
||||||
|
* Has a type defining the operation to perform,
|
||||||
|
* an argument and a duration.
|
||||||
|
*/
|
||||||
|
class AnimScriptItem : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kAnimScriptItem;
|
||||||
|
|
||||||
|
enum Opcodes {
|
||||||
|
kDisplayFrame = 0,
|
||||||
|
kPlayAnimSound = 1,
|
||||||
|
kGoToItem = 2,
|
||||||
|
kDisplayRandomFrame = 3,
|
||||||
|
kSleepRandomDuration = 4,
|
||||||
|
kPlayStockSound = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
AnimScriptItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~AnimScriptItem();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
/** Obtain the operation code */
|
||||||
|
uint32 getOpcode() const { return _opcode; }
|
||||||
|
|
||||||
|
/** Obtain the operation parameter */
|
||||||
|
uint32 getOperand() const { return _operand; }
|
||||||
|
|
||||||
|
/** Obtain the operation duration */
|
||||||
|
uint32 getDuration() const { return _duration; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
uint32 _opcode;
|
||||||
|
uint32 _operand;
|
||||||
|
uint32 _duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_ANIM_SCRIPT_H
|
66
engines/stark/resources/bonesmesh.cpp
Normal file
66
engines/stark/resources/bonesmesh.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/bonesmesh.h"
|
||||||
|
|
||||||
|
#include "engines/stark/model/model.h"
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
BonesMesh::~BonesMesh() {
|
||||||
|
delete _model;
|
||||||
|
}
|
||||||
|
|
||||||
|
BonesMesh::BonesMesh(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_model(nullptr) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BonesMesh::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_filename = stream->readString();
|
||||||
|
_archiveName = stream->getArchiveName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BonesMesh::onPostRead() {
|
||||||
|
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||||
|
|
||||||
|
_model = new Model();
|
||||||
|
_model->readFromStream(stream);
|
||||||
|
|
||||||
|
delete stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model *BonesMesh::getModel() {
|
||||||
|
return _model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BonesMesh::printData() {
|
||||||
|
debug("filename: %s", _filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
68
engines/stark/resources/bonesmesh.h
Normal file
68
engines/stark/resources/bonesmesh.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_BONES_MESH_H
|
||||||
|
#define STARK_RESOURCES_BONES_MESH_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class Model;
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bone mesh resources reference a mesh usable by actor resources
|
||||||
|
*/
|
||||||
|
class BonesMesh : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kBonesMesh;
|
||||||
|
|
||||||
|
BonesMesh(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~BonesMesh();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onPostRead() override;
|
||||||
|
|
||||||
|
/** Obtain the mesh object */
|
||||||
|
Model *getModel();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::String _filename;
|
||||||
|
Common::String _archiveName;
|
||||||
|
|
||||||
|
Model *_model;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_BONES_MESH_H
|
66
engines/stark/resources/bookmark.cpp
Normal file
66
engines/stark/resources/bookmark.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/bookmark.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Bookmark::~Bookmark() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Bookmark::Bookmark(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d Bookmark::getPosition() const {
|
||||||
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
|
Math::Vector3d position = _position;
|
||||||
|
|
||||||
|
int32 floorFaceIndex = floor->findFaceContainingPoint(position);
|
||||||
|
floor->computePointHeightInFace(position, floorFaceIndex);
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bookmark::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_position.x() = stream->readFloat();
|
||||||
|
_position.y() = stream->readFloat();
|
||||||
|
_position.z() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bookmark::printData() {
|
||||||
|
Common::Debug debug = streamDbg();
|
||||||
|
debug << "position: " << _position << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
67
engines/stark/resources/bookmark.h
Normal file
67
engines/stark/resources/bookmark.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_BOOKMARK_H
|
||||||
|
#define STARK_RESOURCES_BOOKMARK_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bookmark resources are handles for a position on the floor field.
|
||||||
|
*
|
||||||
|
* The height value is not set, it needs to be retrieved by interpolation
|
||||||
|
* from the floor field.
|
||||||
|
*/
|
||||||
|
class Bookmark : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kBookmark;
|
||||||
|
|
||||||
|
Bookmark(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Bookmark();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
/** Obtain the position */
|
||||||
|
Math::Vector3d getPosition() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Math::Vector3d _position;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_BOOKMARK_H
|
104
engines/stark/resources/camera.cpp
Normal file
104
engines/stark/resources/camera.cpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/camera.h"
|
||||||
|
|
||||||
|
#include "engines/stark/debug.h"
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/resources/location.h"
|
||||||
|
#include "engines/stark/scene.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Camera::~Camera() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera::Camera(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_f1(0),
|
||||||
|
_fov(45),
|
||||||
|
_nearClipPlane(100.0),
|
||||||
|
_farClipPlane(64000.0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::setClipPlanes(float near, float far) {
|
||||||
|
_nearClipPlane = near;
|
||||||
|
_farClipPlane = far;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_position = stream->readVector3();
|
||||||
|
_lookDirection = stream->readVector3();
|
||||||
|
_f1 = stream->readFloat();
|
||||||
|
_fov = stream->readFloat();
|
||||||
|
_viewSize = stream->readRect();
|
||||||
|
_v4 = stream->readVector3();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::onAllLoaded() {
|
||||||
|
Object::onAllLoaded();
|
||||||
|
|
||||||
|
// Compute scroll coordinates bounds
|
||||||
|
Common::Point maxScroll;
|
||||||
|
maxScroll.x = _viewSize.width() - 640;
|
||||||
|
maxScroll.y = _viewSize.height() - 365;
|
||||||
|
|
||||||
|
Location *location = findParent<Location>();
|
||||||
|
location->initScroll(maxScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::onEnterLocation() {
|
||||||
|
Object::onEnterLocation();
|
||||||
|
|
||||||
|
// Setup the camera
|
||||||
|
StarkScene->initCamera(_position, _lookDirection, _fov, _viewSize, _nearClipPlane, _farClipPlane);
|
||||||
|
|
||||||
|
// Scroll the camera to its initial position
|
||||||
|
Location *location = findParent<Location>();
|
||||||
|
location->setScrollPosition(location->getScrollPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Angle Camera::getHorizontalAngle() const {
|
||||||
|
Math::Angle lookDirectionAngle = Math::Vector3d::angle(_lookDirection, Math::Vector3d(1.0, 0.0, 0.0));
|
||||||
|
Math::Vector3d cross = Math::Vector3d::crossProduct(_lookDirection, Math::Vector3d(1.0, 0.0, 0.0));
|
||||||
|
if (cross.z() < 0) {
|
||||||
|
return -lookDirectionAngle;
|
||||||
|
} else {
|
||||||
|
return lookDirectionAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::printData() {
|
||||||
|
Common::Debug debug = streamDbg();
|
||||||
|
debug << "position: " << _position << "\n";
|
||||||
|
debug << "lookDirection: " << _lookDirection << "\n";
|
||||||
|
debug << "f1: " << _f1 << "\n";
|
||||||
|
debug << "fov: " << _fov << "\n";
|
||||||
|
debug << "viewSize:" << _viewSize.left << _viewSize.top << _viewSize.right << _viewSize.bottom << "\n";
|
||||||
|
debug << "v4: " << _v4 << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
83
engines/stark/resources/camera.h
Normal file
83
engines/stark/resources/camera.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_CAMERA_H
|
||||||
|
#define STARK_RESOURCES_CAMERA_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/angle.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
#include "math/vector4d.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Camera resources define the camera position, perspective parameters,
|
||||||
|
* and look at direction.
|
||||||
|
*/
|
||||||
|
class Camera : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kCamera;
|
||||||
|
|
||||||
|
Camera(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Camera();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void onEnterLocation() override;
|
||||||
|
|
||||||
|
/** Define the near and far clip planes distances */
|
||||||
|
void setClipPlanes(float near, float far);
|
||||||
|
|
||||||
|
/** Compute the angle between the X vector and the look at direction in the horizontal plane */
|
||||||
|
Math::Angle getHorizontalAngle() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Math::Vector3d _position;
|
||||||
|
Math::Vector3d _lookDirection;
|
||||||
|
float _f1;
|
||||||
|
float _fov;
|
||||||
|
Common::Rect _viewSize;
|
||||||
|
Math::Vector3d _v4;
|
||||||
|
|
||||||
|
float _nearClipPlane;
|
||||||
|
float _farClipPlane;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_CAMERA_H
|
1198
engines/stark/resources/command.cpp
Normal file
1198
engines/stark/resources/command.cpp
Normal file
File diff suppressed because it is too large
Load diff
276
engines/stark/resources/command.h
Normal file
276
engines/stark/resources/command.h
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_COMMAND_H
|
||||||
|
#define STARK_RESOURCES_COMMAND_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class ResourceReference;
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Script;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command resources are script operations.
|
||||||
|
*
|
||||||
|
* The operation code is the resource subtype.
|
||||||
|
*
|
||||||
|
* The operation arguments can be integers, strings or resource references.
|
||||||
|
*/
|
||||||
|
class Command : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kCommand;
|
||||||
|
|
||||||
|
Command(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Command();
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kCommandBegin = 0,
|
||||||
|
kCommandEnd = 1,
|
||||||
|
kScriptCall = 2,
|
||||||
|
kDialogCall = 3,
|
||||||
|
kSetInteractiveMode = 4,
|
||||||
|
kLocationGoTo = 5,
|
||||||
|
|
||||||
|
kWalkTo = 7,
|
||||||
|
kGameLoop = 8,
|
||||||
|
kScriptPause = 9,
|
||||||
|
kScriptPauseRandom = 10,
|
||||||
|
|
||||||
|
kScriptAbort = 13,
|
||||||
|
|
||||||
|
kExit2DLocation = 16,
|
||||||
|
kGoto2DLocation = 17,
|
||||||
|
|
||||||
|
kRumbleScene = 19,
|
||||||
|
kFadeScene = 20,
|
||||||
|
|
||||||
|
kLocationGoToNewCD = 22,
|
||||||
|
kGameEnd = 23,
|
||||||
|
kInventoryOpen = 24,
|
||||||
|
|
||||||
|
kItem3DPlaceOn = 81,
|
||||||
|
kItem3DWalkTo = 82,
|
||||||
|
kItem3DFollowPath = 83,
|
||||||
|
kItemLookAt = 84,
|
||||||
|
|
||||||
|
kItem2DFollowPath = 86,
|
||||||
|
kItemEnable = 87,
|
||||||
|
kItemSetActivity = 88,
|
||||||
|
kItemSelectInInventory = 89,
|
||||||
|
|
||||||
|
kUseAnimHierarchy = 92,
|
||||||
|
kPlayAnimation = 93,
|
||||||
|
kScriptEnable = 94,
|
||||||
|
kShowPlay = 95,
|
||||||
|
kKnowledgeSetBoolean = 96,
|
||||||
|
|
||||||
|
kKnowledgeSetInteger = 100,
|
||||||
|
kKnowledgeAddInteger = 101,
|
||||||
|
|
||||||
|
kEnableFloorField = 103,
|
||||||
|
kPlayAnimScriptItem = 104,
|
||||||
|
|
||||||
|
kKnowledgeAssignBool = 107,
|
||||||
|
|
||||||
|
kKnowledgeAssignInteger = 110,
|
||||||
|
kLocationScrollTo = 111,
|
||||||
|
kSoundPlay = 112,
|
||||||
|
|
||||||
|
kKnowledgeSetIntRandom = 115,
|
||||||
|
|
||||||
|
kKnowledgeSubValue = 117,
|
||||||
|
kItemLookDirection = 118,
|
||||||
|
|
||||||
|
kStopPlayingSound = 119,
|
||||||
|
kLayerGoTo = 120,
|
||||||
|
kLayerEnable = 121,
|
||||||
|
kLocationScrollSet = 122,
|
||||||
|
kPlayFullMotionVideo = 123,
|
||||||
|
|
||||||
|
kAnimSetFrame = 125,
|
||||||
|
kKnowledgeAssignNegatedBool = 126,
|
||||||
|
kEnableDiaryEntry = 127,
|
||||||
|
kPATChangeTooltip = 128,
|
||||||
|
kSoundChange = 129,
|
||||||
|
kLightSetColor = 130,
|
||||||
|
|
||||||
|
kItem3DRunTo = 132,
|
||||||
|
kItemPlaceDirection = 133,
|
||||||
|
|
||||||
|
kActivateTexture = 135,
|
||||||
|
kActivateMesh = 136,
|
||||||
|
kItem3DSetWalkTarget = 137,
|
||||||
|
|
||||||
|
kSpeakWithoutTalking = 139,
|
||||||
|
|
||||||
|
kIsOnFloorField = 162,
|
||||||
|
kIsItemEnabled = 163,
|
||||||
|
|
||||||
|
kIsScriptEnabled = 165,
|
||||||
|
kIsKnowledgeBooleanSet = 166,
|
||||||
|
|
||||||
|
kIsKnowledgeIntegerInRange = 170,
|
||||||
|
kIsKnowledgeIntegerAbove = 171,
|
||||||
|
kIsKnowledgeIntegerEqual = 172,
|
||||||
|
kIsKnowledgeIntegerLower = 173,
|
||||||
|
kIsScriptActive = 174,
|
||||||
|
kIsRandom = 175,
|
||||||
|
kIsAnimScriptItemReached = 176,
|
||||||
|
kIsItemOnPlace = 177,
|
||||||
|
|
||||||
|
kIsAnimPlaying = 179,
|
||||||
|
kIsItemActivity = 180,
|
||||||
|
|
||||||
|
kIsItemNearPlace = 183,
|
||||||
|
|
||||||
|
kIsAnimAtTime = 185,
|
||||||
|
kIsLocation2D = 186,
|
||||||
|
kIsInventoryOpen = 187
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Argument {
|
||||||
|
enum Type {
|
||||||
|
kTypeInteger1 = 1,
|
||||||
|
kTypeInteger2 = 2,
|
||||||
|
kTypeResourceReference = 3,
|
||||||
|
kTypeString = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32 type;
|
||||||
|
uint32 intValue;
|
||||||
|
Common::String stringValue;
|
||||||
|
ResourceReference referenceValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Execute the command */
|
||||||
|
Command *execute(uint32 callMode, Script *script);
|
||||||
|
|
||||||
|
/** Obtain the next command to be executed */
|
||||||
|
Command *nextCommand();
|
||||||
|
|
||||||
|
/** Obtain the next command to be executed, depending on a predicate */
|
||||||
|
Command *nextCommandIf(bool predicate);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Command *resolveArgumentSiblingReference(const Argument &argument);
|
||||||
|
|
||||||
|
Math::Vector3d getObjectPosition(const ResourceReference &targetRef, int32 *floorFace = nullptr);
|
||||||
|
|
||||||
|
Command *opScriptBegin();
|
||||||
|
Command *opScriptCall(Script *script, const ResourceReference &scriptRef, int32 synchronous);
|
||||||
|
Command *opDialogCall(Script *script, const ResourceReference &dialogRef, int32 suspend);
|
||||||
|
Command *opSetInteractiveMode(bool enabled);
|
||||||
|
Command *opLocationGoTo(const Common::String &level, const Common::String &location, const ResourceReference &bookmarkRef, int32 direction);
|
||||||
|
Command *opWalkTo(Script *script, const ResourceReference &objectRef, int32 suspend);
|
||||||
|
Command *opScriptPauseGameLoop(Script *script, int32 count);
|
||||||
|
Command *opScriptPause(Script *script, const ResourceReference &durationRef);
|
||||||
|
Command *opScriptPauseRandom(Script *script, const ResourceReference &itemRef);
|
||||||
|
Command *opScriptAbort(ResourceReference scriptRef, bool disable);
|
||||||
|
Command *opExit2DLocation(Script *script);
|
||||||
|
Command *opGoto2DLocation(const Common::String &level, const Common::String &location);
|
||||||
|
Command *opRumbleScene(int32 unknown1, int32 unknown2);
|
||||||
|
Command *opFadeScene(int32 unknown1, int32 unknown2, int32 unknown3);
|
||||||
|
Command *opGameEnd();
|
||||||
|
Command *opInventoryOpen(bool open);
|
||||||
|
Command *opItem3DPlaceOn(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
||||||
|
Command *opItem3DWalkTo(Script *script, const ResourceReference &itemRef, const ResourceReference &targetRef, bool suspend);
|
||||||
|
Command *opItemFollowPath(Script *script, ResourceReference itemRef, ResourceReference pathRef, uint32 speed, uint32 suspend);
|
||||||
|
Command *opItemLookAt(Script *script, const ResourceReference &itemRef, const ResourceReference &objRef, bool suspend, int32 unknown);
|
||||||
|
Command *opItemEnable(const ResourceReference &itemRef, int32 enable);
|
||||||
|
Command *opItemSetActivity(const ResourceReference &itemRef, int32 unknown1, int32 unknown2);
|
||||||
|
Command *opItemSelectInInventory(const ResourceReference &itemRef);
|
||||||
|
Command *opUseAnimHierachy(const ResourceReference &animHierRef);
|
||||||
|
Command *opPlayAnimation(Script *script, const ResourceReference &animRef, bool suspend);
|
||||||
|
Command *opScriptEnable(const ResourceReference &scriptRef, int32 enable);
|
||||||
|
Command *opShowPlay(Script *script, const ResourceReference &ref, int32 suspend);
|
||||||
|
Command *opKnowledgeSetBoolean(const ResourceReference &knowledgeRef, int32 enable);
|
||||||
|
Command *opKnowledgeSetInteger(const ResourceReference &knowledgeRef, int32 value);
|
||||||
|
Command *opKnowledgeSetIntRandom(const ResourceReference &knowledgeRef, uint32 min, uint32 max);
|
||||||
|
Command *opKnowledgeAddInteger(const ResourceReference &knowledgeRef, int32 increment);
|
||||||
|
Command *opKnowledgeSubValue(const ResourceReference &knowledgeRef, const ResourceReference &valueRef);
|
||||||
|
Command *opEnableFloorField(const ResourceReference &floorFieldRef, int32 value);
|
||||||
|
Command *opPlayAnimScriptItem(Script *script, const ResourceReference &animScriptItemRef, int32 suspend);
|
||||||
|
Command *opKnowledgeAssignBool(const ResourceReference &knowledgeRef1, const ResourceReference &knowledgeRef2);
|
||||||
|
Command *opKnowledgeAssignNegatedBool(const ResourceReference &knowledgeRef1, const ResourceReference &knowledgeRef2);
|
||||||
|
Command *opKnowledgeAssignInteger(const ResourceReference &knowledgeRef1, const ResourceReference &knowledgeRef2);
|
||||||
|
Command *opLocationScrollTo(Script *script, const ResourceReference &scrollRef, bool suspend);
|
||||||
|
Command *opSoundPlay(Script *script, const ResourceReference &soundRef, int32 suspend);
|
||||||
|
Command *opItemLookDirection(Script *script, const ResourceReference &itemRef, int32 direction, bool suspend);
|
||||||
|
Command *opStopPlayingSound(const ResourceReference &soundRef);
|
||||||
|
Command *opLayerGoTo(const ResourceReference &layerRef);
|
||||||
|
Command *opLayerEnable(const ResourceReference &layerRef, int32 enable);
|
||||||
|
Command *opLocationScrollSet(const ResourceReference &scrollRef);
|
||||||
|
Command *opPlayFullMotionVideo(Script *script, const ResourceReference &movieRef, int32 unknown);
|
||||||
|
Command *opAnimSetFrame(const ResourceReference &animRef, const ResourceReference &knowledgeRef);
|
||||||
|
Command *opEnableDiaryEntry(const ResourceReference &knowledgeRef);
|
||||||
|
Command *opPATChangeTooltip(const ResourceReference &patRef, const ResourceReference &stringRef);
|
||||||
|
Command *opSoundChange(Script *script, const ResourceReference &soundRef, int32 volume, int32 pan, int32 duration, bool pause);
|
||||||
|
Command *opLightSetColor(const ResourceReference &lightRef, int32 red, int32 green, int32 blue);
|
||||||
|
Command *opItem3DRunTo(Script *script, const ResourceReference &itemRef, const ResourceReference &targetRef, int32 suspend);
|
||||||
|
Command *opItemPlaceDirection(const ResourceReference &itemRef, int32 direction);
|
||||||
|
Command *opActivateTexture(const ResourceReference &textureRef);
|
||||||
|
Command *opActivateMesh(const ResourceReference &meshRef);
|
||||||
|
Command *opItem3DSetWalkTarget(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
||||||
|
Command *opSpeakWithoutTalking(Script *script, const ResourceReference &speechRef, int32 unknown);
|
||||||
|
Command *opIsOnFloorField(const ResourceReference &itemRef, const ResourceReference &floorFieldRef);
|
||||||
|
Command *opIsItemEnabled(const ResourceReference &itemRef);
|
||||||
|
Command *opIsScriptEnabled(const ResourceReference &scriptRef);
|
||||||
|
Command *opIsKnowledgeBooleanSet(const ResourceReference &knowledgeRef);
|
||||||
|
Command *opIsKnowledgeIntegerInRange(const ResourceReference &knowledgeRef, int32 min, int32 max);
|
||||||
|
Command *opIsKnowledgeIntegerAbove(const ResourceReference &knowledgeRef, int32 value);
|
||||||
|
Command *opIsKnowledgeIntegerEqual(const ResourceReference &knowledgeRef, int32 value);
|
||||||
|
Command *opIsKnowledgeIntegerLower(const ResourceReference &knowledgeRef, int32 value);
|
||||||
|
Command *opIsScriptActive(const ResourceReference &scriptRef);
|
||||||
|
Command *opIsRandom(int32 chance);
|
||||||
|
Command *opIsAnimScriptItemReached(const ResourceReference &animScriptItemRef);
|
||||||
|
Command *opIsItemNearPlace(const ResourceReference &itemRef, const ResourceReference &positionRef, int32 testDistance);
|
||||||
|
Command *opIsItemOnPlace(const ResourceReference &itemRef, const ResourceReference &positionRef);
|
||||||
|
Command *opIsAnimPlaying(const ResourceReference &animRef);
|
||||||
|
Command *opIsItemActivity(const ResourceReference &itemRef, int32 value);
|
||||||
|
Command *opIsAnimAtTime(const ResourceReference &animRef, int32 time);
|
||||||
|
Command *opIsLocation2D();
|
||||||
|
Command *opIsInventoryOpen();
|
||||||
|
|
||||||
|
Common::Array<Argument> _arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_COMMAND_H
|
310
engines/stark/resources/dialog.cpp
Normal file
310
engines/stark/resources/dialog.cpp
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/dialog.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
#include "engines/stark/resources/knowledge.h"
|
||||||
|
#include "engines/stark/resources/script.h"
|
||||||
|
#include "engines/stark/resources/speech.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Dialog::~Dialog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog::Dialog(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_character(0),
|
||||||
|
_hasAskAbout(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Object::readData(stream);
|
||||||
|
|
||||||
|
_hasAskAbout = stream->readUint32LE();
|
||||||
|
_character = stream->readUint32LE();
|
||||||
|
|
||||||
|
uint32 numTopics = stream->readUint32LE();
|
||||||
|
for (uint32 i = 0; i < numTopics; i++) {
|
||||||
|
Topic topic;
|
||||||
|
topic._removeOnceDepleted = stream->readBool();
|
||||||
|
|
||||||
|
uint32 numReplies = stream->readUint32LE();
|
||||||
|
for (uint j = 0; j < numReplies; j++) {
|
||||||
|
Reply reply;
|
||||||
|
|
||||||
|
reply._conditionType = stream->readUint32LE();
|
||||||
|
reply._conditionReference = stream->readResourceReference();
|
||||||
|
reply._conditionScriptReference = stream->readResourceReference();
|
||||||
|
reply._conditionReversed = stream->readUint32LE();
|
||||||
|
reply._field_88 = stream->readUint32LE();
|
||||||
|
reply._minChapter = stream->readUint32LE();
|
||||||
|
reply._maxChapter = stream->readUint32LE();
|
||||||
|
reply._noCaption = stream->readUint32LE();
|
||||||
|
reply._nextDialogIndex = stream->readSint32LE();
|
||||||
|
reply._nextScriptReference = stream->readResourceReference();
|
||||||
|
|
||||||
|
uint32 numLines = stream->readUint32LE();
|
||||||
|
for (uint k = 0; k < numLines; k++) {
|
||||||
|
reply._lines.push_back(stream->readResourceReference());
|
||||||
|
reply._lines.push_back(stream->readResourceReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
topic._replies.push_back(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
_topics.push_back(topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
for (uint i = 0; i < _topics.size(); i++) {
|
||||||
|
serializer->syncAsSint32LE(_topics[i]._currentReplyIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::printData() {
|
||||||
|
Object::printData();
|
||||||
|
|
||||||
|
debug("character: %d", _character);
|
||||||
|
debug("hasAskAbout: %d", _hasAskAbout);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < _topics.size(); i++) {
|
||||||
|
Topic &topic = _topics[i];
|
||||||
|
debug("topic[%d].removeOnceDepleted: %d", i, topic._removeOnceDepleted);
|
||||||
|
|
||||||
|
for (uint j = 0; j < topic._replies.size(); j++) {
|
||||||
|
Reply reply = topic._replies[j];
|
||||||
|
|
||||||
|
debug("topic[%d].reply[%d].conditionType: %d", i, j, reply._conditionType);
|
||||||
|
debug("topic[%d].reply[%d].conditionReference: %s", i, j, reply._conditionReference.describe().c_str());
|
||||||
|
debug("topic[%d].reply[%d].conditionScriptReference: %s", i, j, reply._conditionScriptReference.describe().c_str());
|
||||||
|
debug("topic[%d].reply[%d].conditionReversed: %d", i, j, reply._conditionReversed);
|
||||||
|
debug("topic[%d].reply[%d].minChapter: %d", i, j, reply._minChapter);
|
||||||
|
debug("topic[%d].reply[%d].maxChapter: %d", i, j, reply._maxChapter);
|
||||||
|
debug("topic[%d].reply[%d].noCaption: %d", i, j, reply._noCaption);
|
||||||
|
debug("topic[%d].reply[%d].field_88: %d", i, j, reply._field_88);
|
||||||
|
debug("topic[%d].reply[%d].nextScriptReference: %s", i, j, reply._nextScriptReference.describe().c_str());
|
||||||
|
debug("topic[%d].reply[%d].nextDialogIndex: %d", i, j, reply._nextDialogIndex);
|
||||||
|
|
||||||
|
for (uint k = 0; k < reply._lines.size(); k++) {
|
||||||
|
debug("topic[%d].reply[%d].line[%d]: %s", i, j, k, reply._lines[k].describe().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog::TopicArray Dialog::listAvailableTopics() {
|
||||||
|
Common::Array<Dialog::Topic *> topics;
|
||||||
|
|
||||||
|
for (uint i = 0; i < _topics.size(); i++) {
|
||||||
|
Topic *topic = &_topics[i];
|
||||||
|
if (topic->getNextReplyIndex() < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
topics.push_back(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
return topics;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog::Topic::Topic() :
|
||||||
|
_removeOnceDepleted(true),
|
||||||
|
_currentReplyIndex(-1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Dialog::Topic::getNextReplyIndex() const {
|
||||||
|
uint32 nextIndex = _currentReplyIndex + 1;
|
||||||
|
|
||||||
|
if (nextIndex >= _replies.size()) {
|
||||||
|
// No more replies ...
|
||||||
|
if (_removeOnceDepleted || _replies.empty()) {
|
||||||
|
// Don't show this topic
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
// Repeat the last reply
|
||||||
|
nextIndex = _replies.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 currentChapter = StarkGlobal->getCurrentChapter();
|
||||||
|
|
||||||
|
// Skip replies from previous chapters
|
||||||
|
while (nextIndex < _replies.size() && _replies[nextIndex]._maxChapter < currentChapter) {
|
||||||
|
nextIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextIndex >= _replies.size()) {
|
||||||
|
// No more replies ...
|
||||||
|
if (_removeOnceDepleted || _replies.empty()) {
|
||||||
|
// Don't show this topic
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
// Repeat the last reply
|
||||||
|
nextIndex = _replies.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapter check
|
||||||
|
const Reply &reply = _replies[nextIndex];
|
||||||
|
if (currentChapter < reply._minChapter || currentChapter >= reply._maxChapter) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog::Reply *Dialog::Topic::startReply(uint32 index) {
|
||||||
|
_currentReplyIndex = index;
|
||||||
|
|
||||||
|
Reply *reply = &_replies[_currentReplyIndex];
|
||||||
|
reply->start();
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog::Reply *Dialog::Topic::getReply(uint32 index) {
|
||||||
|
return &_replies[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String Dialog::Topic::getCaption() const {
|
||||||
|
int32 replyIndex = getNextReplyIndex();
|
||||||
|
if (replyIndex < 0) {
|
||||||
|
error("Trying to obtain the caption of a depleted dialog topic.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Reply &reply = _replies[replyIndex];
|
||||||
|
|
||||||
|
if (reply._lines.empty()) {
|
||||||
|
error("Trying to obtain the caption of a reply with no lines.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Speech *speech = reply._lines[0].resolve<Speech>();
|
||||||
|
if (speech) {
|
||||||
|
return speech->getPhrase();
|
||||||
|
} else {
|
||||||
|
return "No Caption";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Dialog::Reply::Reply() :
|
||||||
|
_conditionReversed(0),
|
||||||
|
_field_88(0),
|
||||||
|
_minChapter(0),
|
||||||
|
_maxChapter(999),
|
||||||
|
_conditionType(0),
|
||||||
|
_noCaption(0),
|
||||||
|
_nextDialogIndex(-1),
|
||||||
|
_nextSpeechIndex(-1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::Reply::start() {
|
||||||
|
if (_noCaption) {
|
||||||
|
_nextSpeechIndex = -1;
|
||||||
|
} else {
|
||||||
|
// Skip the first line when it is a caption
|
||||||
|
_nextSpeechIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
goToNextLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::Reply::goToNextLine() {
|
||||||
|
_nextSpeechIndex++;
|
||||||
|
while ((uint32)_nextSpeechIndex < _lines.size() && _lines[_nextSpeechIndex].empty()) {
|
||||||
|
_nextSpeechIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uint32)_nextSpeechIndex >= _lines.size()) {
|
||||||
|
_nextSpeechIndex = -2; // No more lines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Speech *Dialog::Reply::getCurrentSpeech() {
|
||||||
|
if (_nextSpeechIndex < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _lines[_nextSpeechIndex].resolve<Speech>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dialog::Reply::checkCondition() const {
|
||||||
|
switch (_conditionType) {
|
||||||
|
case kConditionTypeAlways:
|
||||||
|
return true;
|
||||||
|
case kConditionTypeNoOtherOptions:
|
||||||
|
return true; // Will be removed from to the options later if some other options are available
|
||||||
|
case kConditionTypeHasItem: {
|
||||||
|
Item *item = _conditionReference.resolve<Item>();
|
||||||
|
return item->isEnabled();
|
||||||
|
}
|
||||||
|
case kConditionTypeCheckValue4:
|
||||||
|
case kConditionTypeCheckValue5: {
|
||||||
|
Knowledge *condition = _conditionReference.resolve<Knowledge>();
|
||||||
|
return condition->getBooleanValue();
|
||||||
|
}
|
||||||
|
case kConditionTypeRunScriptCheckValue: {
|
||||||
|
Script *conditionScript = _conditionScriptReference.resolve<Script>();
|
||||||
|
conditionScript->execute(Resources::Script::kCallModeDialogAnswer);
|
||||||
|
|
||||||
|
Knowledge *condition = _conditionReference.resolve<Knowledge>();
|
||||||
|
return condition->getBooleanValue();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
warning("Unimplemented dialog reply condition %d", _conditionType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dialog::Reply::isLastOnly() const {
|
||||||
|
return _conditionType == kConditionTypeNoOtherOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog *Dialog::getNextDialog(Dialog::Reply *reply) {
|
||||||
|
if (reply->_nextDialogIndex < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _parent->findChildWithIndex<Dialog>(reply->_nextDialogIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Script *Dialog::getNextScript(Dialog::Reply *reply) {
|
||||||
|
if (reply->_nextScriptReference.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply->_nextScriptReference.resolve<Script>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
164
engines/stark/resources/dialog.h
Normal file
164
engines/stark/resources/dialog.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_DIALOG_H
|
||||||
|
#define STARK_RESOURCES_DIALOG_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Speech;
|
||||||
|
class Script;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialog between two characters.
|
||||||
|
*
|
||||||
|
* Dialogs are made of a list of topics. Each topic has a list of
|
||||||
|
* possible answers, one of which is played when the player selects the topic,
|
||||||
|
* until all the possible answers have been played.
|
||||||
|
*
|
||||||
|
* Answers are made of a list of lines. All of the lines of an answer are played,
|
||||||
|
* one after the other when an answer is played. Lines reference Speech resources.
|
||||||
|
*/
|
||||||
|
class Dialog : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kDialog;
|
||||||
|
|
||||||
|
Dialog(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Dialog();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A topic reply
|
||||||
|
*/
|
||||||
|
class Reply {
|
||||||
|
public:
|
||||||
|
Reply();
|
||||||
|
|
||||||
|
enum ConditionType {
|
||||||
|
kConditionTypeAlways = 0,
|
||||||
|
kConditionTypeNoOtherOptions = 1,
|
||||||
|
kConditionTypeHasItem = 3,
|
||||||
|
kConditionTypeCheckValue4 = 4,
|
||||||
|
kConditionTypeCheckValue5 = 5,
|
||||||
|
kConditionTypeRunScriptCheckValue = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Start playing the reply. Sets the current line to the first one */
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/** Select the next line to be played */
|
||||||
|
void goToNextLine();
|
||||||
|
|
||||||
|
/** Obtain the Speech resource for the current line, or null if the reply has ended */
|
||||||
|
Speech *getCurrentSpeech();
|
||||||
|
|
||||||
|
/** Evaluates the reply's condition */
|
||||||
|
bool checkCondition() const;
|
||||||
|
|
||||||
|
/** Should this reply only be made available when there are no other options left? */
|
||||||
|
bool isLastOnly() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Static data
|
||||||
|
Common::Array<ResourceReference> _lines;
|
||||||
|
uint32 _conditionType;
|
||||||
|
ResourceReference _conditionReference;
|
||||||
|
ResourceReference _conditionScriptReference;
|
||||||
|
uint32 _conditionReversed;
|
||||||
|
uint32 _field_88;
|
||||||
|
uint32 _minChapter;
|
||||||
|
uint32 _maxChapter;
|
||||||
|
uint32 _noCaption;
|
||||||
|
int32 _nextDialogIndex;
|
||||||
|
ResourceReference _nextScriptReference;
|
||||||
|
|
||||||
|
// State
|
||||||
|
int32 _nextSpeechIndex;
|
||||||
|
|
||||||
|
friend class Dialog;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialog topic
|
||||||
|
*/
|
||||||
|
class Topic {
|
||||||
|
public:
|
||||||
|
Topic();
|
||||||
|
|
||||||
|
/** Compute the next possible reply index after the currently selected reply */
|
||||||
|
int32 getNextReplyIndex() const;
|
||||||
|
|
||||||
|
/** Obtain the caption for the topic */
|
||||||
|
Common::String getCaption() const;
|
||||||
|
|
||||||
|
/** Select a reply from its index */
|
||||||
|
Reply *startReply(uint32 index);
|
||||||
|
|
||||||
|
/** Get the reply with the specified index */
|
||||||
|
Reply *getReply(uint32 index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::Array<Reply> _replies;
|
||||||
|
|
||||||
|
bool _removeOnceDepleted;
|
||||||
|
int32 _currentReplyIndex;
|
||||||
|
|
||||||
|
friend class Dialog;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Common::Array<Topic *> TopicArray;
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
/** List the currently available topics for this Dialog */
|
||||||
|
TopicArray listAvailableTopics();
|
||||||
|
|
||||||
|
/** Obtain the Dialog which should be played at the outcome of this one, if any */
|
||||||
|
Dialog *getNextDialog(Reply *reply);
|
||||||
|
|
||||||
|
/** Obtain the Script which should be executed after this dialog, if any */
|
||||||
|
Script *getNextScript(Reply *reply);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::Array<Topic> _topics;
|
||||||
|
uint32 _character;
|
||||||
|
uint32 _hasAskAbout;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_DIALOG_H
|
54
engines/stark/resources/direction.cpp
Normal file
54
engines/stark/resources/direction.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/direction.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Direction::~Direction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction::Direction(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_field_34(0),
|
||||||
|
_field_38(0),
|
||||||
|
_field_3C(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Direction::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_field_34 = stream->readUint32LE();
|
||||||
|
_field_38 = stream->readUint32LE();
|
||||||
|
_field_3C = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Direction::printData() {
|
||||||
|
debug("field_34: %d", _field_34);
|
||||||
|
debug("field_38: %d", _field_38);
|
||||||
|
debug("field_3C: %d", _field_3C);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
58
engines/stark/resources/direction.h
Normal file
58
engines/stark/resources/direction.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_DIRECTION_H
|
||||||
|
#define STARK_RESOURCES_DIRECTION_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Direction : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kDirection;
|
||||||
|
|
||||||
|
Direction(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Direction();
|
||||||
|
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
uint32 _field_34;
|
||||||
|
uint32 _field_38;
|
||||||
|
uint32 _field_3C;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_DIRECTION_H
|
272
engines/stark/resources/floor.cpp
Normal file
272
engines/stark/resources/floor.cpp
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/resources/floorface.h"
|
||||||
|
|
||||||
|
#include "common/math.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Floor::Floor(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_facesCount(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Floor::~Floor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d Floor::getVertex(uint32 index) const {
|
||||||
|
return _vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Floor::findFaceContainingPoint(const Math::Vector3d &point) const {
|
||||||
|
for (uint32 i = 0; i < _faces.size(); i++) {
|
||||||
|
if (_faces[i]->isPointInside(point)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floor::computePointHeightInFace(Math::Vector3d &point, uint32 faceIndex) const {
|
||||||
|
_faces[faceIndex]->computePointHeight(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Floor::findFaceHitByRay(const Math::Ray &ray, Math::Vector3d &intersection) const {
|
||||||
|
for (uint32 i = 0; i < _faces.size(); i++) {
|
||||||
|
// TODO: Check the ray's intersection with an AABB first if this ends up being slow
|
||||||
|
if (_faces[i]->intersectRay(ray, intersection)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Floor::findFaceClosestToRay(const Math::Ray &ray, Math::Vector3d ¢er) const {
|
||||||
|
float minDistance = FLT_MAX;
|
||||||
|
int32 minFace = -1;
|
||||||
|
for (uint32 i = 0; i < _faces.size(); i++) {
|
||||||
|
if (_faces[i]->hasVertices()) {
|
||||||
|
float distance = _faces[i]->distanceToRay(ray);
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minFace = i;
|
||||||
|
minDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minFace >= 0) {
|
||||||
|
center = _faces[minFace]->getCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return minFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Floor::getDistanceFromCamera(uint32 faceIndex) const {
|
||||||
|
FloorFace *face = _faces[faceIndex];
|
||||||
|
return face->getDistanceFromCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorFace *Floor::getFace(uint32 index) const {
|
||||||
|
return _faces[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Floor::isSegmentInside(const Math::Line3d &segment) const {
|
||||||
|
// The segment is inside the floor if at least one of its extremities is,
|
||||||
|
// and it does not cross any floor border
|
||||||
|
|
||||||
|
int32 beginFace = findFaceContainingPoint(segment.begin());
|
||||||
|
if (beginFace < 0) {
|
||||||
|
// The segment begin point is not on the floor
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < _edges.size(); i++) {
|
||||||
|
const FloorEdge &edge = _edges[i];
|
||||||
|
if (edge.isFloorBorder() && edge.intersectsSegment(this, segment)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floor::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_facesCount = stream->readUint32LE();
|
||||||
|
uint32 vertexCount = stream->readUint32LE();
|
||||||
|
|
||||||
|
for (uint i = 0; i < vertexCount; i++) {
|
||||||
|
Math::Vector3d v = stream->readVector3();
|
||||||
|
_vertices.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floor::onAllLoaded() {
|
||||||
|
Object::onAllLoaded();
|
||||||
|
|
||||||
|
_faces = listChildren<FloorFace>();
|
||||||
|
|
||||||
|
buildEdgeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floor::buildEdgeList() {
|
||||||
|
_edges.clear();
|
||||||
|
|
||||||
|
// Add the triangle edges from all our faces
|
||||||
|
for (uint i = 0; i < _faces.size(); i++) {
|
||||||
|
if (_faces[i]->hasVertices()) {
|
||||||
|
addFaceEdgeToList(i, 2, 0);
|
||||||
|
addFaceEdgeToList(i, 0, 1);
|
||||||
|
addFaceEdgeToList(i, 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the edges to their faces
|
||||||
|
for (uint i = 0; i < _edges.size(); i++) {
|
||||||
|
int32 faceIndex1 = _edges[i].getFaceIndex1();
|
||||||
|
int32 faceIndex2 = _edges[i].getFaceIndex2();
|
||||||
|
|
||||||
|
if (faceIndex1 >= 0) {
|
||||||
|
_faces[faceIndex1]->addEdge(&_edges[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faceIndex2 >= 0) {
|
||||||
|
_faces[faceIndex2]->addEdge(&_edges[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a list of neighbours for each edge
|
||||||
|
for (uint i = 0; i < _edges.size(); i++) {
|
||||||
|
_edges[i].buildNeighbours(this);
|
||||||
|
_edges[i].computeMiddle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floor::addFaceEdgeToList(uint32 faceIndex, uint32 index1, uint32 index2) {
|
||||||
|
uint32 vertexIndex1 = _faces[faceIndex]->getVertexIndex(index1);
|
||||||
|
uint32 vertexIndex2 = _faces[faceIndex]->getVertexIndex(index2);
|
||||||
|
uint32 startIndex = MIN(vertexIndex1, vertexIndex2);
|
||||||
|
uint32 endIndex = MAX(vertexIndex1, vertexIndex2);
|
||||||
|
|
||||||
|
// Check if we already have an edge with the same vertices
|
||||||
|
for (uint i = 0; i < _edges.size(); i++) {
|
||||||
|
if (_edges[i].hasVertices(startIndex, endIndex)) {
|
||||||
|
_edges[i].setOtherFace(faceIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_edges.push_back(FloorEdge(startIndex, endIndex, faceIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floor::printData() {
|
||||||
|
debug("face count: %d", _facesCount);
|
||||||
|
|
||||||
|
Common::Debug debug = streamDbg();
|
||||||
|
for (uint i = 0; i < _vertices.size(); i++) {
|
||||||
|
debug << i << ": " << _vertices[i] << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorEdge::FloorEdge(uint16 vertexIndex1, uint16 vertexIndex2, uint32 faceIndex1) :
|
||||||
|
_vertexIndex1(vertexIndex1),
|
||||||
|
_vertexIndex2(vertexIndex2),
|
||||||
|
_faceIndex1(faceIndex1),
|
||||||
|
_faceIndex2(-1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorEdge::hasVertices(uint16 vertexIndex1, uint16 vertexIndex2) const {
|
||||||
|
return _vertexIndex1 == vertexIndex1 && _vertexIndex2 == vertexIndex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorEdge::setOtherFace(uint32 faceIndex) {
|
||||||
|
_faceIndex2 = faceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Array<FloorEdge *> FloorEdge::getNeighbours() const {
|
||||||
|
return _neighbours;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FloorEdge::costTo(const FloorEdge *other) const {
|
||||||
|
return _middle.getDistanceTo(other->_middle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d FloorEdge::getPosition() const {
|
||||||
|
return _middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorEdge::buildNeighbours(const Floor *floor) {
|
||||||
|
_neighbours.clear();
|
||||||
|
|
||||||
|
if (_faceIndex1 >= 0) {
|
||||||
|
addNeighboursFromFace(floor->getFace(_faceIndex1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_faceIndex2 >= 0) {
|
||||||
|
addNeighboursFromFace(floor->getFace(_faceIndex2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorEdge::addNeighboursFromFace(const FloorFace *face) {
|
||||||
|
Common::Array<FloorEdge *> faceEdges = face->getEdges();
|
||||||
|
for (uint i = 0; i < faceEdges.size(); i++) {
|
||||||
|
if (faceEdges[i] != this) {
|
||||||
|
_neighbours.push_back(faceEdges[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorEdge::computeMiddle(const Floor *floor) {
|
||||||
|
Math::Vector3d vertex1 = floor->getVertex(_vertexIndex1);
|
||||||
|
Math::Vector3d vertex2 = floor->getVertex(_vertexIndex2);
|
||||||
|
_middle = (vertex1 + vertex2) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 FloorEdge::getFaceIndex1() const {
|
||||||
|
return _faceIndex1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 FloorEdge::getFaceIndex2() const {
|
||||||
|
return _faceIndex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorEdge::isFloorBorder() const {
|
||||||
|
return _faceIndex2 == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorEdge::intersectsSegment(const Floor *floor, const Math::Line3d &segment) const {
|
||||||
|
Math::Vector3d vertex1 = floor->getVertex(_vertexIndex1);
|
||||||
|
Math::Vector3d vertex2 = floor->getVertex(_vertexIndex2);
|
||||||
|
Math::Line3d edgeSement = Math::Line3d(vertex1, vertex2);
|
||||||
|
|
||||||
|
return edgeSement.intersectLine2d(segment, nullptr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
178
engines/stark/resources/floor.h
Normal file
178
engines/stark/resources/floor.h
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_FLOOR_H
|
||||||
|
#define STARK_RESOURCES_FLOOR_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/line3d.h"
|
||||||
|
#include "math/ray.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Floor;
|
||||||
|
class FloorFace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A floor face (triangle) edge
|
||||||
|
*
|
||||||
|
* Used for path finding
|
||||||
|
*/
|
||||||
|
class FloorEdge {
|
||||||
|
public:
|
||||||
|
FloorEdge(uint16 vertexIndex1, uint16 vertexIndex2, uint32 faceIndex1);
|
||||||
|
|
||||||
|
/** Build a list of neighbour edges in the graph */
|
||||||
|
void buildNeighbours(const Floor *floor);
|
||||||
|
|
||||||
|
/** Set the edge middle position */
|
||||||
|
void computeMiddle(const Floor *floor);
|
||||||
|
|
||||||
|
/** Set the edge's second face */
|
||||||
|
void setOtherFace(uint32 faceIndex);
|
||||||
|
|
||||||
|
/** Check if the edge has the same vertices as the parameters */
|
||||||
|
bool hasVertices(uint16 vertexIndex1, uint16 vertexIndex2) const;
|
||||||
|
|
||||||
|
/** List the edge neighbour edges in the floor */
|
||||||
|
Common::Array<FloorEdge *> getNeighbours() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the cost for going to a neighbour edge
|
||||||
|
*
|
||||||
|
* This is used for pathfinding. The cost is equal to the distance
|
||||||
|
* between the middle of both edges
|
||||||
|
*/
|
||||||
|
float costTo(const FloorEdge *other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the edge position
|
||||||
|
*
|
||||||
|
* This is the middle of the edge
|
||||||
|
*/
|
||||||
|
Math::Vector3d getPosition() const;
|
||||||
|
|
||||||
|
/** Is this edge on the floor border? */
|
||||||
|
bool isFloorBorder() const;
|
||||||
|
|
||||||
|
/** Does the segment intersect the edge in the 2D plane? */
|
||||||
|
bool intersectsSegment(const Floor *floor, const Math::Line3d &segment) const;
|
||||||
|
|
||||||
|
int32 getFaceIndex1() const;
|
||||||
|
int32 getFaceIndex2() const;
|
||||||
|
private:
|
||||||
|
void addNeighboursFromFace(const FloorFace *face);
|
||||||
|
|
||||||
|
uint16 _vertexIndex1;
|
||||||
|
uint16 _vertexIndex2;
|
||||||
|
Math::Vector3d _middle;
|
||||||
|
int32 _faceIndex1;
|
||||||
|
int32 _faceIndex2;
|
||||||
|
|
||||||
|
Common::Array<FloorEdge *> _neighbours;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This resource represents the floor of a 3D layer.
|
||||||
|
* Characters can only walk on the floor.
|
||||||
|
*
|
||||||
|
* The floor is made of a list of faces building a mesh.
|
||||||
|
*/
|
||||||
|
class Floor : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kFloor;
|
||||||
|
|
||||||
|
Floor(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Floor();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void onAllLoaded() override;
|
||||||
|
|
||||||
|
/** Obtain the vertex for an index */
|
||||||
|
Math::Vector3d getVertex(uint32 index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the index of the face containing the point when both the floorfield
|
||||||
|
* and the point are projected on a Z=0 plane.
|
||||||
|
*
|
||||||
|
* Return -1 if no face contains the point.
|
||||||
|
*/
|
||||||
|
int32 findFaceContainingPoint(const Math::Vector3d &point) const;
|
||||||
|
|
||||||
|
/** Fill the z coordinate of the point so that it is on the plane of a face */
|
||||||
|
void computePointHeightInFace(Math::Vector3d &point, uint32 faceIndex) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a ray is intersecting the floor
|
||||||
|
*
|
||||||
|
* @param ray The ray
|
||||||
|
* @param intersection The intersection between the ray and the floor. Only valid when the return value is positive.
|
||||||
|
* @return -1 if no face contains the point, the hit face index otherwise
|
||||||
|
*/
|
||||||
|
int32 findFaceHitByRay(const Math::Ray &ray, Math::Vector3d &intersection) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the floor face center closest to the ray
|
||||||
|
*
|
||||||
|
* @param ray The ray
|
||||||
|
* @param center The closest face center to the ray. Only valid when the return value is positive.
|
||||||
|
* @return -1 if no face was found, the face index with its center closest to the ray otherwise
|
||||||
|
*/
|
||||||
|
int32 findFaceClosestToRay(const Math::Ray &ray, Math::Vector3d ¢er) const;
|
||||||
|
|
||||||
|
/** Obtain the distance to the camera for a face */
|
||||||
|
float getDistanceFromCamera(uint32 faceIndex) const;
|
||||||
|
|
||||||
|
/** Get a floor face by its index */
|
||||||
|
FloorFace *getFace(uint32 index) const;
|
||||||
|
|
||||||
|
/** Check if the segment is entirely inside the floor */
|
||||||
|
bool isSegmentInside(const Math::Line3d &segment) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
void buildEdgeList();
|
||||||
|
void addFaceEdgeToList(uint32 faceIndex, uint32 index1, uint32 index2);
|
||||||
|
|
||||||
|
uint32 _facesCount;
|
||||||
|
Common::Array<Math::Vector3d> _vertices;
|
||||||
|
Common::Array<FloorFace *> _faces;
|
||||||
|
Common::Array<FloorEdge> _edges;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_FLOOR_H
|
200
engines/stark/resources/floorface.cpp
Normal file
200
engines/stark/resources/floorface.cpp
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/floorface.h"
|
||||||
|
|
||||||
|
#include "engines/stark/debug.h"
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
FloorFace::FloorFace(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_distanceFromCamera(0),
|
||||||
|
_unk2(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
|
||||||
|
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||||
|
_indices[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorFace::~FloorFace() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorFace::isPointInside(const Math::Vector3d &point) const {
|
||||||
|
// Compute the barycentric coordinates of the point in the triangle
|
||||||
|
float area = 1.0 / 2.0
|
||||||
|
* (-_vertices[1].y() * _vertices[2].x()
|
||||||
|
+ _vertices[0].y() * (-_vertices[1].x() + _vertices[2].x())
|
||||||
|
+ _vertices[0].x() * (_vertices[1].y() - _vertices[2].y())
|
||||||
|
+ _vertices[1].x() * _vertices[2].y());
|
||||||
|
|
||||||
|
int32 sign = area < 0 ? -1 : 1;
|
||||||
|
|
||||||
|
float s = (_vertices[0].y() * _vertices[2].x() - _vertices[0].x() * _vertices[2].y()
|
||||||
|
+ (_vertices[2].y() - _vertices[0].y()) * point.x()
|
||||||
|
+ (_vertices[0].x() - _vertices[2].x()) * point.y())
|
||||||
|
* sign;
|
||||||
|
|
||||||
|
float t = (_vertices[0].x() * _vertices[1].y() - _vertices[0].y() * _vertices[1].x()
|
||||||
|
+ (_vertices[0].y() - _vertices[1].y()) * point.x()
|
||||||
|
+ (_vertices[1].x() - _vertices[0].x()) * point.y())
|
||||||
|
* sign;
|
||||||
|
|
||||||
|
// Check the coordinates are in the triangle
|
||||||
|
return s > 0 && t > 0 && (s + t) < 2.0 * area * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorFace::computePointHeight(Math::Vector3d &point) const {
|
||||||
|
// Compute the barycentric coordinates of the point in the triangle
|
||||||
|
float area = 1.0 / 2.0
|
||||||
|
* (-_vertices[1].y() * _vertices[2].x()
|
||||||
|
+ _vertices[0].y() * (-_vertices[1].x() + _vertices[2].x())
|
||||||
|
+ _vertices[0].x() * (_vertices[1].y() - _vertices[2].y())
|
||||||
|
+ _vertices[1].x() * _vertices[2].y());
|
||||||
|
|
||||||
|
float s = (_vertices[0].y() * _vertices[2].x() - _vertices[0].x() * _vertices[2].y()
|
||||||
|
+ (_vertices[2].y() - _vertices[0].y()) * point.x()
|
||||||
|
+ (_vertices[0].x() - _vertices[2].x()) * point.y())
|
||||||
|
/ (2.0 * area);
|
||||||
|
|
||||||
|
float t = (_vertices[0].x() * _vertices[1].y() - _vertices[0].y() * _vertices[1].x()
|
||||||
|
+ (_vertices[0].y() - _vertices[1].y()) * point.x()
|
||||||
|
+ (_vertices[1].x() - _vertices[0].x()) * point.y())
|
||||||
|
/ (2.0 * area);
|
||||||
|
|
||||||
|
// Compute the Z coordinate of the point
|
||||||
|
float pointZ = (1.0 - s - t) * _vertices[0].z() + s * _vertices[1].z() + t * _vertices[2].z();
|
||||||
|
|
||||||
|
point.setValue(2, pointZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorFace::intersectRay(const Math::Ray &ray, Math::Vector3d &intersection) const {
|
||||||
|
// Compute the triangle plane normal
|
||||||
|
Math::Vector3d n = Math::Vector3d::crossProduct(_vertices[1] - _vertices[0], _vertices[2] - _vertices[0]);
|
||||||
|
if (n == Math::Vector3d()) {
|
||||||
|
return false; // We don't handle degenerate triangles
|
||||||
|
}
|
||||||
|
|
||||||
|
// Point on triangle plane: dot(P - _vertices[0], n) = 0
|
||||||
|
// Point on ray: P = origin + r * direction
|
||||||
|
// Point on both => r = - dot(n, origin - _vertices[0]) / dot(n, direction)
|
||||||
|
|
||||||
|
float num = -Math::Vector3d::dotProduct(n, ray.origin() - _vertices[0]);
|
||||||
|
float denom = Math::Vector3d::dotProduct(n, ray.direction());
|
||||||
|
|
||||||
|
if (fabs(denom) < 0.00001) {
|
||||||
|
// The ray is parallel to the plane
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = num / denom;
|
||||||
|
if (r < 0.0) {
|
||||||
|
// The ray goes away from the triangle
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the intersection point between the triangle plane and the ray
|
||||||
|
intersection = ray.origin() + r * ray.direction();
|
||||||
|
|
||||||
|
// Check the intersection point is inside the triangle
|
||||||
|
return isPointInside(intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
float FloorFace::distanceToRay(const Math::Ray &ray) const {
|
||||||
|
Math::Vector3d center = getCenter();
|
||||||
|
return Math::Vector3d::crossProduct(ray.direction(), center - ray.origin()).getMagnitude();
|
||||||
|
}
|
||||||
|
|
||||||
|
float FloorFace::getDistanceFromCamera() const {
|
||||||
|
return _distanceFromCamera;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 FloorFace::getVertexIndex(int32 index) const {
|
||||||
|
assert(index < 3);
|
||||||
|
return _indices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorFace::addEdge(FloorEdge *edge) {
|
||||||
|
_edges.push_back(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::Array<FloorEdge *> FloorFace::getEdges() const {
|
||||||
|
return _edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorEdge *FloorFace::findNearestEdge(const Math::Vector3d &point) const {
|
||||||
|
float minDistance = -1;
|
||||||
|
FloorEdge *edge = nullptr;
|
||||||
|
|
||||||
|
for (uint i = 0; i < _edges.size(); i++) {
|
||||||
|
float distance = (point - _edges[i]->getPosition()).getSquareMagnitude();
|
||||||
|
|
||||||
|
if (!edge || distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
edge = _edges[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d FloorFace::getCenter() const {
|
||||||
|
return (_vertices[0] + _vertices[1] + _vertices[2]) / 3.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorFace::hasVertices() const {
|
||||||
|
return _indices[0] != 0 || _indices[1] != 0 || _indices[2] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorFace::readData(Formats::XRCReadStream *stream) {
|
||||||
|
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||||
|
_indices[i] = stream->readSint16LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
_distanceFromCamera = stream->readFloat();
|
||||||
|
|
||||||
|
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||||
|
stream->readSint16LE(); // Skipped in the original
|
||||||
|
}
|
||||||
|
|
||||||
|
_unk2 = stream->readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorFace::onAllLoaded() {
|
||||||
|
Object::onAllLoaded();
|
||||||
|
Floor *floor = Object::cast<Floor>(_parent);
|
||||||
|
|
||||||
|
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||||
|
_vertices[i] = floor->getVertex(_indices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorFace::printData() {
|
||||||
|
debug("indices: %d %d %d, distanceFromCamera %f, unk2 %f", _indices[0], _indices[1], _indices[2], _distanceFromCamera, _unk2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
119
engines/stark/resources/floorface.h
Normal file
119
engines/stark/resources/floorface.h
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_FLOOR_FACE_H
|
||||||
|
#define STARK_RESOURCES_FLOOR_FACE_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/ray.h"
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class FloorEdge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A floor face is a 3D triangle used to build the floor
|
||||||
|
*/
|
||||||
|
class FloorFace : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kFloorFace;
|
||||||
|
|
||||||
|
FloorFace(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~FloorFace();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void onAllLoaded() override;
|
||||||
|
|
||||||
|
/** Return true if the point is inside the face when both are projected on a Z=0 plane*/
|
||||||
|
bool isPointInside(const Math::Vector3d &point) const;
|
||||||
|
|
||||||
|
/** Fill the z coordinate of the point so that it is on the plane */
|
||||||
|
void computePointHeight(Math::Vector3d &point) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a ray is intersecting this face
|
||||||
|
*
|
||||||
|
* @param origin The ray's origin
|
||||||
|
* @param direction The ray's direction
|
||||||
|
* @param intersection The intersection between the ray and the face. Only valid when the return value is true.
|
||||||
|
* @return true if the ray intersects the face, false otherwise.
|
||||||
|
*/
|
||||||
|
bool intersectRay(const Math::Ray &ray, Math::Vector3d &intersection) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the distance between the face center and the ray
|
||||||
|
*/
|
||||||
|
float distanceToRay(const Math::Ray &ray) const;
|
||||||
|
|
||||||
|
/** Obtain the distance to the camera */
|
||||||
|
float getDistanceFromCamera() const;
|
||||||
|
|
||||||
|
/** Get one of the three vertex indices from the face */
|
||||||
|
int16 getVertexIndex(int32 index) const;
|
||||||
|
|
||||||
|
/** Add an edge to the triangle edge list */
|
||||||
|
void addEdge(FloorEdge *edge);
|
||||||
|
|
||||||
|
/** Get the triangle's edge list */
|
||||||
|
Common::Array<FloorEdge *> getEdges() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the edge closest to a point
|
||||||
|
*
|
||||||
|
* Distance are compared using the middle point of each edge of the face
|
||||||
|
*/
|
||||||
|
FloorEdge *findNearestEdge(const Math::Vector3d &point) const;
|
||||||
|
|
||||||
|
/** Get the point at the center of the face's triangle */
|
||||||
|
Math::Vector3d getCenter() const;
|
||||||
|
|
||||||
|
/** Checks if the face is non degenerate */
|
||||||
|
bool hasVertices() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
int16 _indices[3];
|
||||||
|
Math::Vector3d _vertices[3];
|
||||||
|
|
||||||
|
Common::Array<FloorEdge *> _edges; // Owned by Floor
|
||||||
|
|
||||||
|
float _distanceFromCamera;
|
||||||
|
float _unk2;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_FLOOR_FACE_H
|
60
engines/stark/resources/floorfield.cpp
Normal file
60
engines/stark/resources/floorfield.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/floorfield.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
FloorField::~FloorField() {
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorField::FloorField(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorField::readData(Formats::XRCReadStream *stream) {
|
||||||
|
uint32 count = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
_facesInFloorField.push_back(stream->readByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FloorField::hasFace(int32 floorFaceIndex) const {
|
||||||
|
if (floorFaceIndex < 0 || floorFaceIndex > (int32) _facesInFloorField.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _facesInFloorField[floorFaceIndex] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorField::printData() {
|
||||||
|
for (uint i = 0; i < _facesInFloorField.size(); i++) {
|
||||||
|
debug("faceInFloorField[%d]: %d", i, _facesInFloorField[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
64
engines/stark/resources/floorfield.h
Normal file
64
engines/stark/resources/floorfield.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_FLOORFIELD_H
|
||||||
|
#define STARK_RESOURCES_FLOORFIELD_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A floor field represents a portion of the floor in a 3D layer
|
||||||
|
*
|
||||||
|
* A floor field is bounded by the faces it contains
|
||||||
|
*/
|
||||||
|
class FloorField : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kFloorField;
|
||||||
|
|
||||||
|
FloorField(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~FloorField();
|
||||||
|
|
||||||
|
/** Is the specified face inside the floorfield? */
|
||||||
|
bool hasFace(int32 floorFaceIndex) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::Array<byte> _facesInFloorField;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_FLOORFIELD_H
|
53
engines/stark/resources/fmv.cpp
Normal file
53
engines/stark/resources/fmv.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/fmv.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
FMV::~FMV() {
|
||||||
|
}
|
||||||
|
|
||||||
|
FMV::FMV(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_diaryAddEntryOnPlay(true),
|
||||||
|
_gameDisc(1) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FMV::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_filename = stream->readString();
|
||||||
|
_diaryAddEntryOnPlay = stream->readBool();
|
||||||
|
_gameDisc = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FMV::printData() {
|
||||||
|
debug("filename: %s", _filename.c_str());
|
||||||
|
debug("diaryAddEntryOnPlay: %d", _diaryAddEntryOnPlay);
|
||||||
|
debug("gameDisc: %d", _gameDisc);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
62
engines/stark/resources/fmv.h
Normal file
62
engines/stark/resources/fmv.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_FMV_H
|
||||||
|
#define STARK_RESOURCES_FMV_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A full motion video
|
||||||
|
*/
|
||||||
|
class FMV : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kFMV;
|
||||||
|
|
||||||
|
FMV(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~FMV();
|
||||||
|
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
Common::String getFilename() const { return _filename; }
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::String _filename;
|
||||||
|
uint32 _diaryAddEntryOnPlay;
|
||||||
|
uint32 _gameDisc;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_FMV_H
|
241
engines/stark/resources/image.cpp
Normal file
241
engines/stark/resources/image.cpp
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/image.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/services/archiveloader.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/visual/image.h"
|
||||||
|
#include "engines/stark/visual/text.h"
|
||||||
|
|
||||||
|
#include "math/line2d.h"
|
||||||
|
#include "math/vector2d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Object *Image::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||||
|
switch (subType) {
|
||||||
|
case kImageSub2:
|
||||||
|
case kImageSub3:
|
||||||
|
return new ImageStill(parent, subType, index, name);
|
||||||
|
case kImageSub4:
|
||||||
|
return new ImageText(parent, subType, index, name);
|
||||||
|
default:
|
||||||
|
error("Unknown image subtype %d", subType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::~Image() {
|
||||||
|
delete _visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_transparent(false),
|
||||||
|
_transparency(0),
|
||||||
|
_field_44_ADF(0),
|
||||||
|
_field_48_ADF(30),
|
||||||
|
_visual(nullptr) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_filename = stream->readString();
|
||||||
|
_hotspot = stream->readPoint();
|
||||||
|
_transparent = stream->readBool();
|
||||||
|
_transparency = stream->readUint32LE();
|
||||||
|
|
||||||
|
uint32 polygonCount = stream->readUint32LE();
|
||||||
|
for (uint32 i = 0; i < polygonCount; i++) {
|
||||||
|
Polygon polygon;
|
||||||
|
|
||||||
|
uint32 pointCount = stream->readUint32LE();
|
||||||
|
for (uint32 j = 0; j < pointCount; j++) {
|
||||||
|
polygon.push_back(stream->readPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
_polygons.push_back(polygon);
|
||||||
|
}
|
||||||
|
|
||||||
|
_archiveName = stream->getArchiveName();
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *Image::getVisual() {
|
||||||
|
initVisual();
|
||||||
|
return _visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::printData() {
|
||||||
|
debug("filename: %s", _filename.c_str());
|
||||||
|
debug("hotspot: x %d, y %d", _hotspot.x, _hotspot.y);
|
||||||
|
debug("transparent: %d", _transparent);
|
||||||
|
debug("transparency: %d", _transparency);
|
||||||
|
debug("field_44: %d", _field_44_ADF);
|
||||||
|
debug("field_48: %d", _field_48_ADF);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < _polygons.size(); i++) {
|
||||||
|
Common::String description;
|
||||||
|
for (uint32 j = 0; j < _polygons[i].size(); j++) {
|
||||||
|
description += Common::String::format("(x %d, y %d) ", _polygons[i][j].x, _polygons[i][j].y);
|
||||||
|
}
|
||||||
|
debug("polygon %d: %s", i, description.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Image::indexForPoint(const Common::Point &point) const {
|
||||||
|
int index = -1;
|
||||||
|
for (uint32 i = 0; i < _polygons.size(); i++) {
|
||||||
|
if (isPointInPolygon(_polygons[i], point)) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Image::isPointInPolygon(const Polygon &polygon, const Common::Point &point) const {
|
||||||
|
if (polygon.size() <= 1) {
|
||||||
|
return false; // Empty polygon
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ray cast from the point
|
||||||
|
Math::Segment2d testLine(Math::Vector2d(point.x, point.y), Math::Vector2d(-100, -100));
|
||||||
|
|
||||||
|
// Special case the line created between the last point and the first
|
||||||
|
Math::Vector2d prevPoint = Math::Vector2d(polygon.back().x, polygon.back().y);
|
||||||
|
|
||||||
|
// Count the intersections of the ray with the polygon's edges
|
||||||
|
int intersectCount = 0;
|
||||||
|
for (uint32 j = 0; j < polygon.size(); j++) {
|
||||||
|
Math::Vector2d curPoint = Math::Vector2d(polygon[j].x, polygon[j].y);
|
||||||
|
|
||||||
|
if (Math::Segment2d(prevPoint, curPoint).intersectsSegment(testLine, nullptr)) {
|
||||||
|
intersectCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevPoint = curPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the ray crosses the polygon an odd number of times, the point is inside the polygon
|
||||||
|
return intersectCount % 2 != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageStill::~ImageStill() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageStill::ImageStill(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Image(parent, subType, index, name),
|
||||||
|
_noName(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageStill::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Image::readData(stream);
|
||||||
|
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_field_44_ADF = stream->readUint32LE();
|
||||||
|
_field_44_ADF /= 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_field_48_ADF = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
_noName = _filename == "noname" || _filename == "noname.xmg";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageStill::onPostRead() {
|
||||||
|
initVisual();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageStill::initVisual() {
|
||||||
|
if (_visual) {
|
||||||
|
return; // The visual is already there
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_noName) {
|
||||||
|
return; // No file to load
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ReadStream *stream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||||
|
|
||||||
|
VisualImageXMG *xmg = new VisualImageXMG(StarkGfx);
|
||||||
|
xmg->load(stream);
|
||||||
|
xmg->setHotSpot(_hotspot);
|
||||||
|
|
||||||
|
_visual = xmg;
|
||||||
|
|
||||||
|
delete stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageStill::printData() {
|
||||||
|
Image::printData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageText::ImageText(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Image(parent, subType, index, name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageText::~ImageText() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageText::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Image::readData(stream);
|
||||||
|
|
||||||
|
_size = stream->readPoint();
|
||||||
|
_text = stream->readString();
|
||||||
|
_color = stream->readUint32LE();
|
||||||
|
_font = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageText::initVisual() {
|
||||||
|
if (_visual) {
|
||||||
|
return; // The visual is already there
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_text.hasPrefix("GFX_")) {
|
||||||
|
warning("TODO: Implement '%s'", _text.c_str());
|
||||||
|
_visual = nullptr;
|
||||||
|
} else {
|
||||||
|
VisualText *text = new VisualText(StarkGfx);
|
||||||
|
text->setText(_text);
|
||||||
|
text->setColor(_color | 0xFF000000);
|
||||||
|
text->setTargetWidth(_size.x);
|
||||||
|
text->setFont(FontProvider::kCustomFont, _font);
|
||||||
|
_visual = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageText::printData() {
|
||||||
|
Image::printData();
|
||||||
|
|
||||||
|
debug("size: x %d, y %d", _size.x, _size.y);
|
||||||
|
debug("text: %s", _text.c_str());
|
||||||
|
debug("color: %d", _color);
|
||||||
|
debug("font: %d", _font);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
138
engines/stark/resources/image.h
Normal file
138
engines/stark/resources/image.h
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_IMAGE_H
|
||||||
|
#define STARK_RESOURCES_IMAGE_H
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class Visual;
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A still image resource
|
||||||
|
*/
|
||||||
|
class Image : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kImage;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kImageSub2 = 2,
|
||||||
|
kImageSub3 = 3,
|
||||||
|
kImageSub4 = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Image factory */
|
||||||
|
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
|
||||||
|
typedef Common::Array<Common::Point> Polygon;
|
||||||
|
|
||||||
|
Image(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Image();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
/** Initialize the renderable for the image */
|
||||||
|
virtual Visual *getVisual();
|
||||||
|
|
||||||
|
/** Get the pat-table index for a given point */
|
||||||
|
int indexForPoint(const Common::Point &point) const;
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
bool isPointInPolygon(const Polygon &polygon, const Common::Point &point) const;
|
||||||
|
|
||||||
|
virtual void initVisual() = 0;
|
||||||
|
|
||||||
|
Common::String _filename;
|
||||||
|
Common::String _archiveName;
|
||||||
|
|
||||||
|
Visual *_visual;
|
||||||
|
|
||||||
|
bool _transparent;
|
||||||
|
uint32 _transparency;
|
||||||
|
uint32 _field_44_ADF;
|
||||||
|
uint32 _field_48_ADF;
|
||||||
|
|
||||||
|
Common::Point _hotspot;
|
||||||
|
Common::Array<Polygon> _polygons;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A still image resource loading its data from an XMG file
|
||||||
|
*/
|
||||||
|
class ImageStill : public Image {
|
||||||
|
public:
|
||||||
|
ImageStill(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~ImageStill();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onPostRead() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Resource API
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
// Image API
|
||||||
|
void initVisual() override;
|
||||||
|
|
||||||
|
bool _noName;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text image rendered from a TTF font
|
||||||
|
*/
|
||||||
|
class ImageText : public Image {
|
||||||
|
public:
|
||||||
|
ImageText(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~ImageText();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Resource API
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
// Image API
|
||||||
|
void initVisual();
|
||||||
|
|
||||||
|
Common::Point _size;
|
||||||
|
Common::String _text;
|
||||||
|
uint32 _color;
|
||||||
|
uint32 _font;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_IMAGE_H
|
969
engines/stark/resources/item.cpp
Normal file
969
engines/stark/resources/item.cpp
Normal file
|
@ -0,0 +1,969 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/gfx/renderentry.h"
|
||||||
|
#include "engines/stark/movement/movement.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/anim.h"
|
||||||
|
#include "engines/stark/resources/animhierarchy.h"
|
||||||
|
#include "engines/stark/resources/bonesmesh.h"
|
||||||
|
#include "engines/stark/resources/bookmark.h"
|
||||||
|
#include "engines/stark/resources/floor.h"
|
||||||
|
#include "engines/stark/resources/floorface.h"
|
||||||
|
#include "engines/stark/resources/location.h"
|
||||||
|
#include "engines/stark/resources/pattable.h"
|
||||||
|
#include "engines/stark/resources/script.h"
|
||||||
|
#include "engines/stark/resources/textureset.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/global.h"
|
||||||
|
#include "engines/stark/services/services.h"
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
#include "engines/stark/services/userinterface.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Object *Item::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||||
|
switch (subType) {
|
||||||
|
case kItemGlobalTemplate:
|
||||||
|
return new GlobalItemTemplate(parent, subType, index, name);
|
||||||
|
case kItemInventory:
|
||||||
|
return new InventoryItem(parent, subType, index, name);
|
||||||
|
case kItemLevelTemplate:
|
||||||
|
return new LevelItemTemplate(parent, subType, index, name);
|
||||||
|
case kItemStaticProp:
|
||||||
|
case kItemAnimatedProp:
|
||||||
|
return new FloorPositionedImageItem(parent, subType, index, name);
|
||||||
|
case kItemBackgroundElement:
|
||||||
|
case kItemBackground:
|
||||||
|
return new ImageItem(parent, subType, index, name);
|
||||||
|
case kItemModel:
|
||||||
|
return new ModelItem(parent, subType, index, name);
|
||||||
|
default:
|
||||||
|
error("Unknown item subtype %d", subType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::Item(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_enabled(true),
|
||||||
|
_characterIndex(0),
|
||||||
|
_movement(nullptr),
|
||||||
|
_movementSuspendedScript(nullptr) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::~Item() {
|
||||||
|
delete _movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_enabled = stream->readBool();
|
||||||
|
_characterIndex = stream->readSint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::onGameLoop() {
|
||||||
|
Object::onGameLoop();
|
||||||
|
|
||||||
|
if (_enabled && _movement) {
|
||||||
|
_movement->onGameLoop();
|
||||||
|
|
||||||
|
if (_movement && _movement->hasEnded()) {
|
||||||
|
setMovement(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item::isEnabled() const {
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::setEnabled(bool enabled) {
|
||||||
|
if (_enabled && !enabled) {
|
||||||
|
setMovement(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Item::getCharacterIndex() const {
|
||||||
|
return _characterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *Item::getRenderEntry(const Common::Point &positionOffset) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String Item::getHotspotTitle(uint32 hotspotIndex) const {
|
||||||
|
PATTable *table = findChildWithOrder<PATTable>(hotspotIndex);
|
||||||
|
if (table) {
|
||||||
|
return table->getName();
|
||||||
|
} else {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Movement *Item::getMovement() const {
|
||||||
|
return _movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::setMovement(Movement *movement) {
|
||||||
|
if (_movementSuspendedScript) {
|
||||||
|
if (_movement && _movement->hasEnded()) {
|
||||||
|
_movementSuspendedScript->setResumeStatus(Script::kResumeComplete);
|
||||||
|
} else {
|
||||||
|
_movementSuspendedScript->setResumeStatus(Script::kResumeAbort);
|
||||||
|
}
|
||||||
|
_movementSuspendedScript = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_movement && !_movement->hasEnded()) {
|
||||||
|
_movement->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete _movement;
|
||||||
|
_movement = movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::setMovementSuspendedScript(Script *script) {
|
||||||
|
_movementSuspendedScript = script;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::printData() {
|
||||||
|
debug("enabled: %d", _enabled);
|
||||||
|
debug("character: %d", _characterIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
serializer->syncAsSint32LE(_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemVisual::~ItemVisual() {
|
||||||
|
delete _renderEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemVisual::ItemVisual(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Item(parent, subType, index, name),
|
||||||
|
_renderEntry(nullptr),
|
||||||
|
_actionAnim(nullptr),
|
||||||
|
_animHierarchy(nullptr),
|
||||||
|
_currentAnimKind(-1),
|
||||||
|
_clickable(true) {
|
||||||
|
_renderEntry = new Gfx::RenderEntry(this, getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Item::readData(stream);
|
||||||
|
|
||||||
|
_clickable = stream->readBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::onAllLoaded() {
|
||||||
|
Item::onAllLoaded();
|
||||||
|
|
||||||
|
_animHierarchy = findChild<AnimHierarchy>(false);
|
||||||
|
|
||||||
|
_renderEntry->setClickable(_clickable);
|
||||||
|
|
||||||
|
if (_subType != kItemModel) {
|
||||||
|
setAnimKind(Anim::kActionUsagePassive);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_enabled) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Location *location = findParent<Location>();
|
||||||
|
if (location) {
|
||||||
|
location->registerCharacterItem(_characterIndex, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
Item::saveLoad(serializer);
|
||||||
|
|
||||||
|
serializer->syncAsSint32LE(_currentAnimKind);
|
||||||
|
|
||||||
|
serializer->syncAsResourceReference(&_animHierarchy);
|
||||||
|
if (serializer->isLoading() && _animHierarchy) {
|
||||||
|
setAnimHierarchy(_animHierarchy);
|
||||||
|
}
|
||||||
|
|
||||||
|
serializer->syncAsResourceReference(&_actionAnim);
|
||||||
|
if (serializer->isLoading()) {
|
||||||
|
if (_actionAnim) {
|
||||||
|
_actionAnim->applyToItem(this);
|
||||||
|
} else {
|
||||||
|
setAnimKind(_currentAnimKind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::onPreDestroy() {
|
||||||
|
if (_actionAnim) {
|
||||||
|
_actionAnim->removeFromItem(this);
|
||||||
|
_actionAnim = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::onPreDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::setEnabled(bool enabled) {
|
||||||
|
Item::setEnabled(enabled);
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
_animHierarchy->selectItemAnim(this);
|
||||||
|
} else {
|
||||||
|
resetActionAnim();
|
||||||
|
_animHierarchy->unselectItemAnim(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemVisual *ItemVisual::getSceneInstance() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 ItemVisual::getAnimKind() const {
|
||||||
|
return _currentAnimKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::setAnimKind(int32 usage) {
|
||||||
|
bool animNeedsUpdate = usage != _currentAnimKind || _actionAnim != nullptr || _animHierarchy->getCurrentAnim() == nullptr;
|
||||||
|
|
||||||
|
resetActionAnim();
|
||||||
|
|
||||||
|
_currentAnimKind = usage;
|
||||||
|
if (animNeedsUpdate && _animHierarchy) {
|
||||||
|
_animHierarchy->setItemAnim(this, usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::printData() {
|
||||||
|
Item::printData();
|
||||||
|
|
||||||
|
debug("clickable: %d", _clickable);
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim *ItemVisual::getAnim() const {
|
||||||
|
if (_actionAnim) {
|
||||||
|
return _actionAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _animHierarchy->getCurrentAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::setAnimHierarchy(AnimHierarchy *animHierarchy) {
|
||||||
|
resetActionAnim();
|
||||||
|
|
||||||
|
if (_animHierarchy) {
|
||||||
|
_animHierarchy->unselectItemAnim(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_animHierarchy = animHierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *ItemVisual::getVisual() {
|
||||||
|
Anim *anim = getAnim();
|
||||||
|
|
||||||
|
if (!anim) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return anim->getVisual();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ItemVisual::getHotspotIndexForPoint(const Common::Point &point) {
|
||||||
|
Anim *anim = getAnim();
|
||||||
|
if (anim) {
|
||||||
|
return anim->getPointHotspotIndex(point);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemVisual::canPerformAction(uint32 action, uint32 hotspotIndex) {
|
||||||
|
PATTable *table = findChildWithOrder<PATTable>(hotspotIndex);
|
||||||
|
return table && table->canPerformAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemVisual::doAction(uint32 action, uint32 hotspotIndex) {
|
||||||
|
PATTable *table = findChildWithOrder<PATTable>(hotspotIndex);
|
||||||
|
if (table && table->canPerformAction(action)) {
|
||||||
|
return table->runScriptForAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::playActionAnim(Anim *anim) {
|
||||||
|
resetActionAnim();
|
||||||
|
|
||||||
|
_animHierarchy->unselectItemAnim(this);
|
||||||
|
_actionAnim = anim;
|
||||||
|
anim->applyToItem(this);
|
||||||
|
anim->playAsAction(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::resetActionAnim() {
|
||||||
|
if (_actionAnim) {
|
||||||
|
_actionAnim->removeFromItem(this);
|
||||||
|
_actionAnim = nullptr;
|
||||||
|
|
||||||
|
// TODO: Add a condition to this?
|
||||||
|
_animHierarchy->selectItemAnim(this);
|
||||||
|
if (_subType == kItemModel) {
|
||||||
|
_animHierarchy->setItemAnim(this, Anim::kActorUsageIdle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemVisual::setPosition2D(const Common::Point &position) {
|
||||||
|
warning("ItemVisual::setPosition2D is not implemented for this item type: %d (%s)", _subType, _name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemTemplate::~ItemTemplate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemTemplate::ItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Item(parent, subType, index, name),
|
||||||
|
_meshIndex(-1),
|
||||||
|
_textureNormalIndex(-1),
|
||||||
|
_textureFaceIndex(-1),
|
||||||
|
_animHierarchyIndex(-1),
|
||||||
|
_referencedItem(nullptr),
|
||||||
|
_instanciatedItem(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::onAllLoaded() {
|
||||||
|
Item::onAllLoaded();
|
||||||
|
|
||||||
|
BonesMesh *bonesMesh = findChild<BonesMesh>(false);
|
||||||
|
if (bonesMesh) {
|
||||||
|
_meshIndex = bonesMesh->getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *textureNormal = findChildWithSubtype<TextureSet>(TextureSet::kTextureNormal, false);
|
||||||
|
if (textureNormal) {
|
||||||
|
_textureNormalIndex = textureNormal->getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *textureFace = findChildWithSubtype<TextureSet>(TextureSet::kTextureFace, false);
|
||||||
|
if (textureFace) {
|
||||||
|
_textureFaceIndex = textureFace->getIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||||
|
Item::saveLoadCurrent(serializer);
|
||||||
|
|
||||||
|
serializer->syncAsSint32LE(_meshIndex);
|
||||||
|
serializer->syncAsSint32LE(_textureNormalIndex);
|
||||||
|
serializer->syncAsSint32LE(_textureFaceIndex);
|
||||||
|
serializer->syncAsSint32LE(_animHierarchyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::setInstanciatedItem(Item *instance) {
|
||||||
|
_instanciatedItem = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemVisual *ItemTemplate::getSceneInstance() {
|
||||||
|
if (_instanciatedItem) {
|
||||||
|
return _instanciatedItem->getSceneInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String ItemTemplate::getHotspotTitle(uint32 hotspotIndex) const {
|
||||||
|
if (_referencedItem) {
|
||||||
|
return _referencedItem->getHotspotTitle(hotspotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Item::getHotspotTitle(hotspotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::setStockAnimHierachy(AnimHierarchy *animHierarchy) {
|
||||||
|
Object *animHierarchyParent = animHierarchy->findParent<Object>();
|
||||||
|
|
||||||
|
if (animHierarchyParent == this) {
|
||||||
|
_animHierarchyIndex = animHierarchy->getIndex();
|
||||||
|
} else {
|
||||||
|
_animHierarchyIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::setBonesMesh(int32 index) {
|
||||||
|
_meshIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::setTexture(int32 index, uint32 textureType) {
|
||||||
|
if (textureType == TextureSet::kTextureNormal) {
|
||||||
|
_textureNormalIndex = index;
|
||||||
|
} else if (textureType == TextureSet::kTextureFace) {
|
||||||
|
_textureFaceIndex = index;
|
||||||
|
} else {
|
||||||
|
error("Unknown texture type %d", textureType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the animation to apply the changes
|
||||||
|
ModelItem *sceneInstance = Resources::Object::cast<Resources::ModelItem>(getSceneInstance());
|
||||||
|
sceneInstance->updateAnim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::setAnimHierarchy(AnimHierarchy *animHierarchy) {
|
||||||
|
setStockAnimHierachy(animHierarchy);
|
||||||
|
|
||||||
|
if (_instanciatedItem) {
|
||||||
|
_instanciatedItem->setAnimHierarchy(animHierarchy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalItemTemplate::~GlobalItemTemplate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalItemTemplate::GlobalItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
ItemTemplate(parent, subType, index, name) {
|
||||||
|
_animHierarchyIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BonesMesh *GlobalItemTemplate::findBonesMesh() {
|
||||||
|
if (_meshIndex == -1) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<BonesMesh>(_meshIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *GlobalItemTemplate::findTextureSet(uint32 textureType) {
|
||||||
|
if (textureType == TextureSet::kTextureNormal) {
|
||||||
|
if (_textureNormalIndex == -1) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<TextureSet>(_textureNormalIndex);
|
||||||
|
}
|
||||||
|
} else if (textureType == TextureSet::kTextureFace) {
|
||||||
|
if (_textureFaceIndex == -1) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<TextureSet>(_textureFaceIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Unknown texture type %d", textureType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimHierarchy *GlobalItemTemplate::findStockAnimHierarchy() {
|
||||||
|
if (_animHierarchyIndex == -1) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<AnimHierarchy>(_animHierarchyIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryItem::~InventoryItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryItem::InventoryItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
ItemVisual(parent, subType, index, name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *InventoryItem::getRenderEntry(const Common::Point &positionOffset) {
|
||||||
|
if (_enabled) {
|
||||||
|
setAnimKind(Anim::kUIUsageInventory);
|
||||||
|
|
||||||
|
Visual *visual = getVisual();
|
||||||
|
|
||||||
|
_renderEntry->setVisual(visual);
|
||||||
|
_renderEntry->setPosition(Common::Point());
|
||||||
|
} else {
|
||||||
|
_renderEntry->setVisual(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renderEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InventoryItem::setEnabled(bool enabled) {
|
||||||
|
ItemVisual::setEnabled(enabled);
|
||||||
|
|
||||||
|
// Deselect the item in the inventory when removing it
|
||||||
|
int16 selectedInventoryItem = StarkUserInterface->getSelectedInventoryItem();
|
||||||
|
if (!enabled && selectedInventoryItem == getIndex()) {
|
||||||
|
StarkUserInterface->selectInventoryItem(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *InventoryItem::getActionVisual(bool active) const {
|
||||||
|
if (active) {
|
||||||
|
return _animHierarchy->getVisualForUsage(Anim::kActionUsageActive);
|
||||||
|
} else {
|
||||||
|
return _animHierarchy->getVisualForUsage(Anim::kActionUsagePassive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Visual *InventoryItem::getCursorVisual() const {
|
||||||
|
Visual *visual = _animHierarchy->getVisualForUsage(Anim::kUIUsageUseCursorPassive);
|
||||||
|
|
||||||
|
if (!visual) {
|
||||||
|
visual = _animHierarchy->getVisualForUsage(Anim::kUIUsageUseCursorActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!visual) {
|
||||||
|
visual = _animHierarchy->getVisualForUsage(Anim::kUIUsageInventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return visual;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LevelItemTemplate::~LevelItemTemplate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelItemTemplate::LevelItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
ItemTemplate(parent, subType, index, name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelItemTemplate::readData(Formats::XRCReadStream *stream) {
|
||||||
|
ItemTemplate::readData(stream);
|
||||||
|
|
||||||
|
_reference = stream->readResourceReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelItemTemplate::onAllLoaded() {
|
||||||
|
ItemTemplate::onAllLoaded();
|
||||||
|
|
||||||
|
_referencedItem = _reference.resolve<ItemTemplate>();
|
||||||
|
if (_referencedItem) {
|
||||||
|
_referencedItem->setInstanciatedItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BonesMesh *LevelItemTemplate::findBonesMesh() {
|
||||||
|
if (_meshIndex == -1) {
|
||||||
|
return _referencedItem->findBonesMesh();
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<BonesMesh>(_meshIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *LevelItemTemplate::findTextureSet(uint32 textureType) {
|
||||||
|
if (textureType == TextureSet::kTextureNormal) {
|
||||||
|
if (_textureNormalIndex == -1) {
|
||||||
|
return _referencedItem->findTextureSet(textureType);
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<TextureSet>(_textureNormalIndex);
|
||||||
|
}
|
||||||
|
} else if (textureType == TextureSet::kTextureFace) {
|
||||||
|
if (_textureFaceIndex == -1) {
|
||||||
|
return _referencedItem->findTextureSet(textureType);
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<TextureSet>(_textureFaceIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Unknown texture type %d", textureType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimHierarchy *LevelItemTemplate::findStockAnimHierarchy() {
|
||||||
|
if (_animHierarchyIndex == -1 && !_referencedItem) {
|
||||||
|
_animHierarchyIndex = 0; // Prefer referenced anim to local
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_animHierarchyIndex == -1) {
|
||||||
|
return _referencedItem->findStockAnimHierarchy();
|
||||||
|
} else {
|
||||||
|
return findChildWithIndex<AnimHierarchy>(_animHierarchyIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemTemplate *LevelItemTemplate::getItemTemplate() const {
|
||||||
|
return _referencedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelItemTemplate::printData() {
|
||||||
|
ItemTemplate::printData();
|
||||||
|
|
||||||
|
debug("reference: %s", _reference.describe().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorPositionedItem::~FloorPositionedItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorPositionedItem::FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
ItemVisual(parent, subType, index, name),
|
||||||
|
_direction3D(0.0),
|
||||||
|
_floorFaceIndex(-1),
|
||||||
|
_sortKeyOverride(false),
|
||||||
|
_sortKeyOverridenValue(0.0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d FloorPositionedItem::getPosition3D() const {
|
||||||
|
return _position3D;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::setPosition3D(const Math::Vector3d &position) {
|
||||||
|
_position3D = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 FloorPositionedItem::getFloorFaceIndex() const {
|
||||||
|
return _floorFaceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::setFloorFaceIndex(int32 faceIndex) {
|
||||||
|
_floorFaceIndex = faceIndex;
|
||||||
|
_sortKeyOverride = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::placeOnBookmark(Bookmark *target) {
|
||||||
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
|
_position3D = target->getPosition();
|
||||||
|
|
||||||
|
// Find the floor face index the item is on
|
||||||
|
setFloorFaceIndex(floor->findFaceContainingPoint(_position3D));
|
||||||
|
|
||||||
|
// Set the z coordinate using the floor height at that position
|
||||||
|
if (_floorFaceIndex < 0) {
|
||||||
|
warning("Item '%s' has been place out of the floor field", getName().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::placeDefaultPosition() {
|
||||||
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
FloorFace *face = floor->getFace(0);
|
||||||
|
|
||||||
|
_position3D = face->getCenter();
|
||||||
|
|
||||||
|
// Find the floor face index the item is on
|
||||||
|
setFloorFaceIndex(0);
|
||||||
|
|
||||||
|
// Set the z coordinate using the floor height at that position
|
||||||
|
floor->computePointHeightInFace(_position3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Vector3d FloorPositionedItem::getDirectionVector() const {
|
||||||
|
Math::Matrix3 rot;
|
||||||
|
rot.buildAroundZ(-_direction3D);
|
||||||
|
|
||||||
|
Math::Vector3d direction(1.0, 0.0, 0.0);
|
||||||
|
rot.transformVector(&direction);
|
||||||
|
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::setDirection(const Math::Angle &direction) {
|
||||||
|
_direction3D = direction.getDegrees(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::overrideSortKey(float sortKey) {
|
||||||
|
_sortKeyOverride = true;
|
||||||
|
_sortKeyOverridenValue = sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FloorPositionedItem::getSortKey() const {
|
||||||
|
if (_sortKeyOverride) {
|
||||||
|
return _sortKeyOverridenValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
|
if (_floorFaceIndex == -1) {
|
||||||
|
// warning("Undefined floor face index for item '%s'", getName().c_str());
|
||||||
|
return floor->getDistanceFromCamera(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return floor->getDistanceFromCamera(_floorFaceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
ItemVisual::saveLoad(serializer);
|
||||||
|
serializer->syncAsVector3d(_position3D);
|
||||||
|
serializer->syncAsFloat(_direction3D);
|
||||||
|
serializer->syncAsSint32LE(_floorFaceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorPositionedImageItem::~FloorPositionedImageItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorPositionedImageItem::FloorPositionedImageItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
FloorPositionedItem(parent, subType, index, name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedImageItem::readData(Formats::XRCReadStream *stream) {
|
||||||
|
FloorPositionedItem::readData(stream);
|
||||||
|
|
||||||
|
setFloorFaceIndex(stream->readSint32LE());
|
||||||
|
_position = stream->readPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *FloorPositionedImageItem::getRenderEntry(const Common::Point &positionOffset) {
|
||||||
|
if (_enabled) {
|
||||||
|
Visual *visual = getVisual();
|
||||||
|
_renderEntry->setVisual(visual);
|
||||||
|
|
||||||
|
if (getAnim() && getAnim()->getSubType() == Anim::kAnimVideo) {
|
||||||
|
// AnimVideos override the _position, but still need to move according to scroll-offsets
|
||||||
|
_renderEntry->setPosition(positionOffset);
|
||||||
|
} else {
|
||||||
|
_renderEntry->setPosition(_position - positionOffset);
|
||||||
|
}
|
||||||
|
_renderEntry->setSortKey(getSortKey());
|
||||||
|
} else {
|
||||||
|
_renderEntry->setVisual(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renderEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedImageItem::setPosition2D(const Common::Point &position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloorPositionedImageItem::printData() {
|
||||||
|
FloorPositionedItem::printData();
|
||||||
|
|
||||||
|
debug("floorFaceIndex: %d", _floorFaceIndex);
|
||||||
|
debug("position: x %d, y %d", _position.x, _position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageItem::~ImageItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageItem::ImageItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
ItemVisual(parent, subType, index, name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageItem::readData(Formats::XRCReadStream *stream) {
|
||||||
|
ItemVisual::readData(stream);
|
||||||
|
|
||||||
|
_position = stream->readPoint();
|
||||||
|
_reference = stream->readResourceReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *ImageItem::getRenderEntry(const Common::Point &positionOffset) {
|
||||||
|
if (_enabled) {
|
||||||
|
Visual *visual = getVisual();
|
||||||
|
_renderEntry->setVisual(visual);
|
||||||
|
|
||||||
|
if (getAnim() && getAnim()->getSubType() == Anim::kAnimVideo) {
|
||||||
|
// AnimVideos override the _position, but still need to move according to scroll-offsets
|
||||||
|
_renderEntry->setPosition(positionOffset);
|
||||||
|
} else {
|
||||||
|
_renderEntry->setPosition(_position - positionOffset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_renderEntry->setVisual(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renderEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageItem::setPosition2D(const Common::Point &position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageItem::printData() {
|
||||||
|
ItemVisual::printData();
|
||||||
|
|
||||||
|
debug("reference: %s", _reference.describe().c_str());
|
||||||
|
debug("position: x %d, y %d", _position.x, _position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelItem::~ModelItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelItem::ModelItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
FloorPositionedItem(parent, subType, index, name),
|
||||||
|
_meshIndex(-1),
|
||||||
|
_textureNormalIndex(-1),
|
||||||
|
_textureFaceIndex(-1),
|
||||||
|
_referencedItem(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::readData(Formats::XRCReadStream *stream) {
|
||||||
|
FloorPositionedItem::readData(stream);
|
||||||
|
|
||||||
|
_reference = stream->readResourceReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::onAllLoaded() {
|
||||||
|
FloorPositionedItem::onAllLoaded();
|
||||||
|
|
||||||
|
BonesMesh *bonesMesh = findChild<BonesMesh>(false);
|
||||||
|
if (bonesMesh) {
|
||||||
|
_meshIndex = bonesMesh->getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *textureNormal = findChildWithSubtype<TextureSet>(TextureSet::kTextureNormal, false);
|
||||||
|
if (textureNormal) {
|
||||||
|
_textureNormalIndex = textureNormal->getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *textureFace = findChildWithSubtype<TextureSet>(TextureSet::kTextureFace, false);
|
||||||
|
if (textureFace) {
|
||||||
|
_textureFaceIndex = textureFace->getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
_referencedItem = _reference.resolve<ItemTemplate>();
|
||||||
|
if (_referencedItem) {
|
||||||
|
_referencedItem->setInstanciatedItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::onEnterLocation() {
|
||||||
|
FloorPositionedItem::onEnterLocation();
|
||||||
|
|
||||||
|
if (_referencedItem) {
|
||||||
|
_referencedItem->setInstanciatedItem(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_referencedItem) {
|
||||||
|
_animHierarchy = _referencedItem->findStockAnimHierarchy();
|
||||||
|
}
|
||||||
|
|
||||||
|
setAnimKind(Anim::kActorUsageIdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::onExitLocation() {
|
||||||
|
FloorPositionedItem::onExitLocation();
|
||||||
|
|
||||||
|
resetActionAnim();
|
||||||
|
if (_animHierarchy) {
|
||||||
|
_animHierarchy->unselectItemAnim(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::setBonesMesh(int32 index) {
|
||||||
|
_meshIndex = index;
|
||||||
|
|
||||||
|
if (_meshIndex != -1) {
|
||||||
|
updateAnim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BonesMesh *ModelItem::findBonesMesh() {
|
||||||
|
// Prefer retrieving the mesh from the anim hierarchy
|
||||||
|
BonesMesh *bonesMesh = _animHierarchy->findBonesMesh();
|
||||||
|
|
||||||
|
// Otherwise, use a children mesh, or a referenced mesh
|
||||||
|
if (!bonesMesh) {
|
||||||
|
if (_meshIndex == -1) {
|
||||||
|
bonesMesh = _referencedItem->findBonesMesh();
|
||||||
|
} else {
|
||||||
|
bonesMesh = findChildWithIndex<BonesMesh>(_meshIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bonesMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::setTexture(int32 index, uint32 textureType) {
|
||||||
|
if (textureType == TextureSet::kTextureNormal) {
|
||||||
|
_textureNormalIndex = index;
|
||||||
|
} else if (textureType == TextureSet::kTextureFace) {
|
||||||
|
_textureFaceIndex = index;
|
||||||
|
} else {
|
||||||
|
error("Unknown texture type %d", textureType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureSet *ModelItem::findTextureSet(uint32 textureType) {
|
||||||
|
// Prefer retrieving the mesh from the anim hierarchy
|
||||||
|
TextureSet *textureSet = _animHierarchy->findTextureSet(textureType);
|
||||||
|
|
||||||
|
// Otherwise, use a children mesh, or a referenced mesh
|
||||||
|
if (!textureSet) {
|
||||||
|
if (textureType == TextureSet::kTextureNormal) {
|
||||||
|
if (_textureNormalIndex == -1) {
|
||||||
|
textureSet = _referencedItem->findTextureSet(textureType);
|
||||||
|
} else {
|
||||||
|
textureSet = findChildWithIndex<TextureSet>(_textureNormalIndex);
|
||||||
|
}
|
||||||
|
} else if (textureType == TextureSet::kTextureFace) {
|
||||||
|
if (_textureFaceIndex == -1) {
|
||||||
|
textureSet = _referencedItem->findTextureSet(textureType);
|
||||||
|
} else {
|
||||||
|
textureSet = findChildWithIndex<TextureSet>(_textureFaceIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Unknown texture type %d", textureType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return textureSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::updateAnim() {
|
||||||
|
Anim *anim = getAnim();
|
||||||
|
if (anim && anim->getSubType() == Anim::kAnimSkeleton) {
|
||||||
|
anim->removeFromItem(this);
|
||||||
|
anim->applyToItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *ModelItem::getRenderEntry(const Common::Point &positionOffset) {
|
||||||
|
if (_enabled) {
|
||||||
|
Visual *visual = getVisual();
|
||||||
|
|
||||||
|
if (!visual) {
|
||||||
|
_animHierarchy->selectItemAnim(this);
|
||||||
|
visual = getVisual();
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderEntry->setVisual(visual);
|
||||||
|
_renderEntry->setPosition3D(_position3D, _direction3D);
|
||||||
|
_renderEntry->setSortKey(getSortKey());
|
||||||
|
} else {
|
||||||
|
_renderEntry->setVisual(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renderEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String ModelItem::getHotspotTitle(uint32 hotspotIndex) const {
|
||||||
|
if (_referencedItem) {
|
||||||
|
return _referencedItem->getHotspotTitle(hotspotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Item::getHotspotTitle(hotspotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemTemplate *ModelItem::getItemTemplate() const {
|
||||||
|
return _referencedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelItem::printData() {
|
||||||
|
FloorPositionedItem::printData();
|
||||||
|
|
||||||
|
debug("reference: %s", _reference.describe().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemTemplate::onEnterLocation() {
|
||||||
|
Object::onEnterLocation();
|
||||||
|
|
||||||
|
if (_referencedItem) {
|
||||||
|
_referencedItem->setInstanciatedItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
476
engines/stark/resources/item.h
Normal file
476
engines/stark/resources/item.h
Normal file
|
@ -0,0 +1,476 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_ITEM_H
|
||||||
|
#define STARK_RESOURCES_ITEM_H
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "math/vector3d.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
class Movement;
|
||||||
|
class Visual;
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
class RenderEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Anim;
|
||||||
|
class AnimHierarchy;
|
||||||
|
class BonesMesh;
|
||||||
|
class Bookmark;
|
||||||
|
class ItemVisual;
|
||||||
|
class Script;
|
||||||
|
class TextureSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A scene element
|
||||||
|
*
|
||||||
|
* Can be a character, background, animation, ...
|
||||||
|
*/
|
||||||
|
class Item : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kItem;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kItemGlobalTemplate = 1,
|
||||||
|
kItemInventory = 2,
|
||||||
|
kItemLevelTemplate = 3,
|
||||||
|
kItemStaticProp = 5,
|
||||||
|
kItemAnimatedProp = 6,
|
||||||
|
kItemBackgroundElement = 7,
|
||||||
|
kItemBackground = 8,
|
||||||
|
kItemModel = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Item factory */
|
||||||
|
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
|
||||||
|
Item(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Item();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
virtual void onGameLoop() override;
|
||||||
|
void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
/** Is the item present in the scene */
|
||||||
|
bool isEnabled() const;
|
||||||
|
|
||||||
|
/** Enable or disable the item */
|
||||||
|
virtual void setEnabled(bool enabled);
|
||||||
|
|
||||||
|
/** Get the item's character index */
|
||||||
|
int32 getCharacterIndex() const;
|
||||||
|
|
||||||
|
/** Obtain the render entry to use to display the item */
|
||||||
|
virtual Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset);
|
||||||
|
|
||||||
|
/** Obtain the concrete instance of an item template */
|
||||||
|
virtual ItemVisual *getSceneInstance() = 0;
|
||||||
|
|
||||||
|
/** Obtain the title for one of the item's hotspots */
|
||||||
|
virtual Common::String getHotspotTitle(uint32 hotspotIndex) const;
|
||||||
|
|
||||||
|
/** Replace the current movement with an other */
|
||||||
|
void setMovement(Movement *movement);
|
||||||
|
|
||||||
|
/** Get the current movement if any */
|
||||||
|
Movement *getMovement() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the script waiting for the item's movement to complete.
|
||||||
|
*
|
||||||
|
* This script will be updated with the outcome of the movement
|
||||||
|
* (completion or abortion)
|
||||||
|
*/
|
||||||
|
void setMovementSuspendedScript(Script *script);
|
||||||
|
|
||||||
|
/** Set the currently active anim hierachy */
|
||||||
|
virtual void setAnimHierarchy(AnimHierarchy *animHierarchy) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
bool _enabled;
|
||||||
|
int32 _characterIndex;
|
||||||
|
|
||||||
|
Movement *_movement;
|
||||||
|
Script *_movementSuspendedScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A renderable item
|
||||||
|
*
|
||||||
|
* Renderable items are found in location layers
|
||||||
|
*/
|
||||||
|
class ItemVisual : public Item {
|
||||||
|
public:
|
||||||
|
ItemVisual(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~ItemVisual();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
virtual void onAllLoaded() override;
|
||||||
|
virtual void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
virtual void onPreDestroy() override;
|
||||||
|
|
||||||
|
// Item API
|
||||||
|
void setEnabled(bool enabled) override;
|
||||||
|
ItemVisual *getSceneInstance() override;
|
||||||
|
void setAnimHierarchy(AnimHierarchy *animHierarchy) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the item's 2D position.
|
||||||
|
*
|
||||||
|
* Only applies to 2D items
|
||||||
|
*/
|
||||||
|
virtual void setPosition2D(const Common::Point &position);
|
||||||
|
|
||||||
|
/** Get the hotspot index for an item relative position */
|
||||||
|
int getHotspotIndexForPoint(const Common::Point &point);
|
||||||
|
|
||||||
|
/** Check whether the item has runnable scripts for the specified action */
|
||||||
|
bool canPerformAction(uint32 action, uint32 hotspotIndex);
|
||||||
|
|
||||||
|
/** Perform an action on one of the item's hotspots */
|
||||||
|
bool doAction(uint32 action, uint32 hotspotIndex);
|
||||||
|
|
||||||
|
/** Define the current animation kind for the item */
|
||||||
|
void setAnimKind(int32 usage);
|
||||||
|
|
||||||
|
/** Get the current animation kind */
|
||||||
|
int32 getAnimKind() const;
|
||||||
|
|
||||||
|
/** Get the currently playing animation */
|
||||||
|
Anim *getAnim() const;
|
||||||
|
|
||||||
|
/** Replace the current generic animation with an action specific animation */
|
||||||
|
void playActionAnim(Anim *anim);
|
||||||
|
|
||||||
|
/** Remove the current specific animation and revert to a generic one */
|
||||||
|
void resetActionAnim();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Resource API
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Visual *getVisual();
|
||||||
|
|
||||||
|
Gfx::RenderEntry *_renderEntry;
|
||||||
|
|
||||||
|
Anim *_actionAnim;
|
||||||
|
AnimHierarchy *_animHierarchy;
|
||||||
|
int32 _currentAnimKind;
|
||||||
|
bool _clickable;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item template
|
||||||
|
*
|
||||||
|
* Item templates need to be instanciated into renderable items to be displayed
|
||||||
|
*/
|
||||||
|
class ItemTemplate : public Item {
|
||||||
|
public:
|
||||||
|
ItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~ItemTemplate();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void onEnterLocation() override;
|
||||||
|
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
// Item API
|
||||||
|
ItemVisual *getSceneInstance() override;
|
||||||
|
Common::String getHotspotTitle(uint32 hotspotIndex) const override;
|
||||||
|
void setAnimHierarchy(AnimHierarchy *animHierarchy) override;
|
||||||
|
|
||||||
|
/** Obtain the bone mesh to use to render the item */
|
||||||
|
virtual BonesMesh *findBonesMesh() = 0;
|
||||||
|
|
||||||
|
/** Obtain the texture to use to render the item */
|
||||||
|
virtual TextureSet *findTextureSet(uint32 textureType) = 0;
|
||||||
|
|
||||||
|
/** Obtain the animation hierarchy to fetch animations from */
|
||||||
|
virtual AnimHierarchy *findStockAnimHierarchy() = 0;
|
||||||
|
|
||||||
|
/** Define the anim hierarchy to be persisted across locations */
|
||||||
|
void setStockAnimHierachy(AnimHierarchy *animHierarchy);
|
||||||
|
|
||||||
|
/** Change the item's mesh */
|
||||||
|
void setBonesMesh(int32 index);
|
||||||
|
|
||||||
|
/** Set the mesh main or face texture */
|
||||||
|
void setTexture(int32 index, uint32 textureType);
|
||||||
|
|
||||||
|
/** Set the scene instanciation for this template */
|
||||||
|
void setInstanciatedItem(Item *instance);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32 _meshIndex;
|
||||||
|
int32 _textureNormalIndex;
|
||||||
|
int32 _textureFaceIndex;
|
||||||
|
int32 _animHierarchyIndex;
|
||||||
|
|
||||||
|
Item *_instanciatedItem;
|
||||||
|
ItemTemplate *_referencedItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A global item template
|
||||||
|
*
|
||||||
|
* Global item templates are found in the global level
|
||||||
|
*/
|
||||||
|
class GlobalItemTemplate : public ItemTemplate {
|
||||||
|
public:
|
||||||
|
GlobalItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~GlobalItemTemplate();
|
||||||
|
|
||||||
|
// ItemTemplate API
|
||||||
|
BonesMesh *findBonesMesh() override;
|
||||||
|
TextureSet *findTextureSet(uint32 textureType) override;
|
||||||
|
AnimHierarchy *findStockAnimHierarchy() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An inventory item
|
||||||
|
*/
|
||||||
|
class InventoryItem : public ItemVisual {
|
||||||
|
public:
|
||||||
|
InventoryItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~InventoryItem();
|
||||||
|
|
||||||
|
// Item API
|
||||||
|
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||||
|
void setEnabled(bool enabled) override;
|
||||||
|
|
||||||
|
/** Obtain an action menu icon */
|
||||||
|
Visual *getActionVisual(bool active) const;
|
||||||
|
|
||||||
|
/** Obtain an inventory item cursor */
|
||||||
|
Visual *getCursorVisual() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A level item template
|
||||||
|
*
|
||||||
|
* Level item templates are found in levels so that they can be shared between
|
||||||
|
* locations.
|
||||||
|
*/
|
||||||
|
class LevelItemTemplate : public ItemTemplate {
|
||||||
|
public:
|
||||||
|
LevelItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~LevelItemTemplate();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
|
||||||
|
// ItemTemplate API
|
||||||
|
BonesMesh *findBonesMesh() override;
|
||||||
|
TextureSet *findTextureSet(uint32 textureType) override;
|
||||||
|
AnimHierarchy *findStockAnimHierarchy() override;
|
||||||
|
|
||||||
|
/** Get the item's level or global template if any */
|
||||||
|
ItemTemplate *getItemTemplate() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
ResourceReference _reference;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D positioned item
|
||||||
|
*
|
||||||
|
* Items with a 3D position, used in 3D layers. The sort key determines the order
|
||||||
|
* in which such items are drawn in.
|
||||||
|
*/
|
||||||
|
class FloorPositionedItem : public ItemVisual {
|
||||||
|
public:
|
||||||
|
FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~FloorPositionedItem();
|
||||||
|
|
||||||
|
// Object API
|
||||||
|
void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
/** Move the item to a bookmarked position */
|
||||||
|
void placeOnBookmark(Bookmark *target);
|
||||||
|
|
||||||
|
/** Place the item on the center of the first floor face */
|
||||||
|
void placeDefaultPosition();
|
||||||
|
|
||||||
|
/** Get the item position */
|
||||||
|
Math::Vector3d getPosition3D() const;
|
||||||
|
/** Move the item */
|
||||||
|
void setPosition3D(const Math::Vector3d &position);
|
||||||
|
|
||||||
|
/** Get the floor face index the item is standing on */
|
||||||
|
int32 getFloorFaceIndex() const;
|
||||||
|
/** Change the face the item is standing on */
|
||||||
|
void setFloorFaceIndex(int32 faceIndex);
|
||||||
|
|
||||||
|
/** Get a vector pointing in the same direction as the item */
|
||||||
|
Math::Vector3d getDirectionVector() const;
|
||||||
|
|
||||||
|
/** Set the direction the item faces */
|
||||||
|
void setDirection(const Math::Angle &direction);
|
||||||
|
|
||||||
|
/** Obtain the sort value for the item, used to compute the draw order */
|
||||||
|
float getSortKey() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't rely on the floor face to compute the sort key, use the provided value instead.
|
||||||
|
*
|
||||||
|
* This can be used to handle cases where the item is not over the floor.
|
||||||
|
*/
|
||||||
|
void overrideSortKey(float sortKey);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32 _floorFaceIndex;
|
||||||
|
Math::Vector3d _position3D;
|
||||||
|
float _direction3D;
|
||||||
|
|
||||||
|
bool _sortKeyOverride;
|
||||||
|
float _sortKeyOverridenValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D positioned image item
|
||||||
|
*
|
||||||
|
* Used to display still images or animated images in 3D layers
|
||||||
|
*/
|
||||||
|
class FloorPositionedImageItem : public FloorPositionedItem {
|
||||||
|
public:
|
||||||
|
FloorPositionedImageItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~FloorPositionedImageItem();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
// Item API
|
||||||
|
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||||
|
|
||||||
|
// ItemVisual API
|
||||||
|
void setPosition2D(const Common::Point &position) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::Point _position;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model item
|
||||||
|
*
|
||||||
|
* Used to draw characters
|
||||||
|
*/
|
||||||
|
class ModelItem : public FloorPositionedItem {
|
||||||
|
public:
|
||||||
|
ModelItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~ModelItem();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
void onEnterLocation() override;
|
||||||
|
void onExitLocation() override;
|
||||||
|
|
||||||
|
// Item API
|
||||||
|
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||||
|
Common::String getHotspotTitle(uint32 hotspotIndex) const override;
|
||||||
|
|
||||||
|
/** Set the mesh main or face texture */
|
||||||
|
void setTexture(int32 index, uint32 textureType);
|
||||||
|
|
||||||
|
/** Change the item's mesh */
|
||||||
|
void setBonesMesh(int32 index);
|
||||||
|
|
||||||
|
/** Obtain the bone mesh to use to render the item */
|
||||||
|
BonesMesh *findBonesMesh();
|
||||||
|
|
||||||
|
/** Obtain the texture to use to render the item */
|
||||||
|
TextureSet *findTextureSet(uint32 textureType);
|
||||||
|
|
||||||
|
/** Get the item's level or global template if any */
|
||||||
|
ItemTemplate *getItemTemplate() const;
|
||||||
|
|
||||||
|
/** Update the item's animation after a texture / mesh change */
|
||||||
|
void updateAnim();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
int32 _meshIndex;
|
||||||
|
int32 _textureNormalIndex;
|
||||||
|
int32 _textureFaceIndex;
|
||||||
|
|
||||||
|
ResourceReference _reference;
|
||||||
|
ItemTemplate *_referencedItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2D positioned image item
|
||||||
|
*
|
||||||
|
* Used to display background elements in 2D layers
|
||||||
|
*/
|
||||||
|
class ImageItem : public ItemVisual {
|
||||||
|
public:
|
||||||
|
ImageItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~ImageItem();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
// Item API
|
||||||
|
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||||
|
|
||||||
|
// ItemVisual API
|
||||||
|
void setPosition2D(const Common::Point &position) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
ResourceReference _reference;
|
||||||
|
Common::Point _position;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_ITEM_H
|
103
engines/stark/resources/knowledge.cpp
Normal file
103
engines/stark/resources/knowledge.cpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/knowledge.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Knowledge::~Knowledge() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Knowledge::Knowledge(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_booleanValue(false),
|
||||||
|
_integerValue(0) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Knowledge::setBooleanValue(bool value) {
|
||||||
|
_booleanValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Knowledge::getBooleanValue() {
|
||||||
|
return _booleanValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Knowledge::setIntegerValue(int32 value) {
|
||||||
|
_integerValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Knowledge::getIntegerValue() {
|
||||||
|
return _integerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Knowledge::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
serializer->syncAsSint32LE(_integerValue);
|
||||||
|
serializer->syncAsSint32LE(_booleanValue);
|
||||||
|
serializer->syncAsResourceReference(_referenceValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Knowledge::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Object::readData(stream);
|
||||||
|
|
||||||
|
switch (_subType) {
|
||||||
|
case kBoolean:
|
||||||
|
case kBooleanWithChild:
|
||||||
|
_booleanValue = stream->readBool();
|
||||||
|
break;
|
||||||
|
case kInteger:
|
||||||
|
case kInteger2:
|
||||||
|
_integerValue = stream->readSint32LE();
|
||||||
|
break;
|
||||||
|
case kReference:
|
||||||
|
_referenceValue = stream->readResourceReference();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown knowledge subtype %d", _subType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Knowledge::printData() {
|
||||||
|
switch (_subType) {
|
||||||
|
case kBoolean:
|
||||||
|
case kBooleanWithChild:
|
||||||
|
debug("value: %d", _booleanValue);
|
||||||
|
break;
|
||||||
|
case kInteger:
|
||||||
|
case kInteger2:
|
||||||
|
debug("value: %d", _integerValue);
|
||||||
|
break;
|
||||||
|
case kReference:
|
||||||
|
debug("value: %s", _referenceValue.describe().c_str());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown knowledge subtype %d", _subType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
84
engines/stark/resources/knowledge.h
Normal file
84
engines/stark/resources/knowledge.h
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_KNOWLEDGE_H
|
||||||
|
#define STARK_RESOURCES_KNOWLEDGE_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
#include "engines/stark/resourcereference.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A game logic state value holder
|
||||||
|
*/
|
||||||
|
class Knowledge : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kKnowledge;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kBoolean = 0,
|
||||||
|
kInteger = 2,
|
||||||
|
kInteger2 = 3,
|
||||||
|
kReference = 4,
|
||||||
|
kBooleanWithChild = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
Knowledge(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Knowledge();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void saveLoad(ResourceSerializer *serializer) override;
|
||||||
|
|
||||||
|
/** Define the value for boolean Knowledge elements */
|
||||||
|
void setBooleanValue(bool value);
|
||||||
|
|
||||||
|
/** Obtain the value for boolean Knowledge elements */
|
||||||
|
bool getBooleanValue();
|
||||||
|
|
||||||
|
/** Define the value for integer Knowledge elements */
|
||||||
|
void setIntegerValue(int32 value);
|
||||||
|
|
||||||
|
/** Obtain the value for integer Knowledge elements */
|
||||||
|
int32 getIntegerValue();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
bool _booleanValue;
|
||||||
|
int32 _integerValue;
|
||||||
|
ResourceReference _referenceValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_KNOWLEDGE_H
|
60
engines/stark/resources/knowledgeset.cpp
Normal file
60
engines/stark/resources/knowledgeset.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/knowledgeset.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
KnowledgeSet::~KnowledgeSet() {
|
||||||
|
}
|
||||||
|
|
||||||
|
KnowledgeSet::KnowledgeSet(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KnowledgeSet::printData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntryArray KnowledgeSet::getInventoryRenderEntries() {
|
||||||
|
// TODO: Keep and persist inventory items order
|
||||||
|
Common::Array<Resources::Item *> inventoryItems = listChildren<Resources::Item>(Resources::Item::kItemInventory);
|
||||||
|
Common::Array<Resources::Item *>::iterator it = inventoryItems.begin();
|
||||||
|
Gfx::RenderEntryArray result;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; it != inventoryItems.end(); ++it, ++i) {
|
||||||
|
if (i < 4) continue; // HACK: The first 4 elements are UI elements, so skip them for now.
|
||||||
|
if ((*it)->isEnabled()) {
|
||||||
|
result.push_back((*it)->getRenderEntry(Common::Point(0, 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
68
engines/stark/resources/knowledgeset.h
Normal file
68
engines/stark/resources/knowledgeset.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_KNOWLEDGE_SET_H
|
||||||
|
#define STARK_RESOURCES_KNOWLEDGE_SET_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/renderentry.h"
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A typed collection of Knowledge resources
|
||||||
|
*/
|
||||||
|
class KnowledgeSet : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kKnowledgeSet;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kInventory = 1,
|
||||||
|
kState = 2,
|
||||||
|
kPersons = 3,
|
||||||
|
kLocations = 4,
|
||||||
|
kDiary = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
KnowledgeSet(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~KnowledgeSet();
|
||||||
|
|
||||||
|
Gfx::RenderEntryArray getInventoryRenderEntries();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_KNOWLEDGE_SET_H
|
246
engines/stark/resources/layer.cpp
Normal file
246
engines/stark/resources/layer.cpp
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/layer.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/camera.h"
|
||||||
|
#include "engines/stark/resources/item.h"
|
||||||
|
#include "engines/stark/resources/light.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Object *Layer::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||||
|
switch (subType) {
|
||||||
|
case kLayer2D:
|
||||||
|
return new Layer2D(parent, subType, index, name);
|
||||||
|
case kLayer3D:
|
||||||
|
return new Layer3D(parent, subType, index, name);
|
||||||
|
default:
|
||||||
|
error("Unknown layer subtype %d", subType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer::~Layer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer::Layer(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_scrollScale(1.0),
|
||||||
|
_enabled(true) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_scrollScale = stream->readFloat();
|
||||||
|
if (_scrollScale > 10.0 || _scrollScale < -1.0)
|
||||||
|
_scrollScale = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::printData() {
|
||||||
|
debug("scrollScale: %f", _scrollScale);
|
||||||
|
debug("enabled: %d", _enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::setScrollPosition(const Common::Point &position) {
|
||||||
|
// The location scroll position is scaled to create a parallax effect
|
||||||
|
_scroll.x = (_scrollScale + 1.0) * (float) position.x;
|
||||||
|
_scroll.y = (_scrollScale + 1.0) * (float) position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Layer::isEnabled() const {
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::enable(bool enabled) {
|
||||||
|
_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::LightEntryArray Layer::listLightEntries() {
|
||||||
|
Common::Array<Light *> lights = listChildren<Light>();
|
||||||
|
|
||||||
|
Gfx::LightEntryArray lightEntries;
|
||||||
|
for (uint i = 0; i < lights.size(); i++) {
|
||||||
|
lightEntries.push_back(lights[i]->getLightEntry());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lightEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer2D::~Layer2D() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer2D::Layer2D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Layer(parent, subType, index, name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer2D::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Layer::readData(stream);
|
||||||
|
|
||||||
|
uint32 itemsCount = stream->readUint32LE();
|
||||||
|
for (uint i = 0; i < itemsCount; i++) {
|
||||||
|
uint32 itemIndex = stream->readUint32LE();
|
||||||
|
_itemIndices.push_back(itemIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_enabled = stream->readBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer2D::onEnterLocation() {
|
||||||
|
Layer::onEnterLocation();
|
||||||
|
|
||||||
|
Common::Array<Item *> items = listChildren<Item>();
|
||||||
|
|
||||||
|
// Build the item list in the appropriate order
|
||||||
|
_items.clear();
|
||||||
|
for (uint i = 0; i < _itemIndices.size(); i++) {
|
||||||
|
for (uint j = 0; j < items.size(); j++) {
|
||||||
|
if (items[j]->getIndex() == _itemIndices[i]) {
|
||||||
|
_items.push_back(items[j]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer2D::onExitLocation() {
|
||||||
|
Layer::onExitLocation();
|
||||||
|
|
||||||
|
_items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *Layer2D::getBackgroundRenderEntry() {
|
||||||
|
// TODO
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntryArray Layer2D::listRenderEntries() {
|
||||||
|
Gfx::RenderEntryArray renderEntries;
|
||||||
|
for (uint i = 0; i < _items.size(); i++) {
|
||||||
|
Item *item = _items[i];
|
||||||
|
|
||||||
|
Gfx::RenderEntry *renderEntry = item->getRenderEntry(_scroll);
|
||||||
|
|
||||||
|
if (!renderEntry) {
|
||||||
|
// warning("No render entry for item '%s'", item->getName().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEntries.push_back(renderEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer2D::printData() {
|
||||||
|
Layer::printData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer3D::~Layer3D() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer3D::Layer3D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Layer(parent, subType, index, name),
|
||||||
|
_field_54(1),
|
||||||
|
_maxShadowLength(75),
|
||||||
|
_nearClipPlane(100.0),
|
||||||
|
_farClipPlane(64000.0),
|
||||||
|
_backgroundItem(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer3D::readData(Formats::XRCReadStream *stream) {
|
||||||
|
Layer::readData(stream);
|
||||||
|
|
||||||
|
_field_54 = stream->readUint32LE();
|
||||||
|
_nearClipPlane = stream->readFloat();
|
||||||
|
_farClipPlane = stream->readFloat();
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_maxShadowLength = stream->readUint32LE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer3D::onAllLoaded() {
|
||||||
|
Layer::onAllLoaded();
|
||||||
|
|
||||||
|
_items = listChildren<Item>();
|
||||||
|
_backgroundItem = findChildWithSubtype<Item>(Item::kItemBackground);
|
||||||
|
|
||||||
|
Camera *camera = findChild<Camera>();
|
||||||
|
camera->setClipPlanes(_nearClipPlane, _farClipPlane);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntry *Layer3D::getBackgroundRenderEntry() {
|
||||||
|
if (!_backgroundItem) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _backgroundItem->getRenderEntry(_scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::RenderEntryArray Layer3D::listRenderEntries() {
|
||||||
|
// Sort the items by distance to the camera
|
||||||
|
Gfx::RenderEntryArray itemEntries;
|
||||||
|
for (uint i = 0; i < _items.size(); i++) {
|
||||||
|
Item *item = _items[i];
|
||||||
|
|
||||||
|
if (item->getSubType() != Item::kItemBackground) {
|
||||||
|
Gfx::RenderEntry *renderEntry = item->getRenderEntry(_scroll);
|
||||||
|
|
||||||
|
if (!renderEntry) {
|
||||||
|
// warning("No render entry for item '%s'", item->getName().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemEntries.push_back(renderEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Common::sort(itemEntries.begin(), itemEntries.end(), Gfx::RenderEntry::compare);
|
||||||
|
|
||||||
|
Gfx::RenderEntryArray renderEntries;
|
||||||
|
|
||||||
|
// Add the background render entry to the list first
|
||||||
|
Gfx::RenderEntry *backgroundRenderEntry = getBackgroundRenderEntry();
|
||||||
|
if (backgroundRenderEntry) {
|
||||||
|
renderEntries.push_back(backgroundRenderEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the other items
|
||||||
|
renderEntries.push_back(itemEntries);
|
||||||
|
|
||||||
|
return renderEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer3D::printData() {
|
||||||
|
Layer::printData();
|
||||||
|
|
||||||
|
debug("field_54: %d", _field_54);
|
||||||
|
debug("maxShadowLength: %d", _maxShadowLength);
|
||||||
|
debug("nearClipPlane: %f", _nearClipPlane);
|
||||||
|
debug("farClipPlane: %f", _farClipPlane);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
150
engines/stark/resources/layer.h
Normal file
150
engines/stark/resources/layer.h
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_LAYER_H
|
||||||
|
#define STARK_RESOURCES_LAYER_H
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/gfx/renderentry.h"
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
class Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A location layer
|
||||||
|
*
|
||||||
|
* Layers own the scene items
|
||||||
|
*/
|
||||||
|
class Layer : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kLayer;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kLayer2D = 1,
|
||||||
|
kLayer3D = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Layer factory */
|
||||||
|
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
|
||||||
|
Layer(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Layer();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
|
||||||
|
/** Obtain the render entry for the background item */
|
||||||
|
virtual Gfx::RenderEntry *getBackgroundRenderEntry() = 0;
|
||||||
|
|
||||||
|
/** Obtain the render entries for all items, including the background */
|
||||||
|
virtual Gfx::RenderEntryArray listRenderEntries() = 0;
|
||||||
|
|
||||||
|
/** Obtain a list of render entries for all the lights in the layer */
|
||||||
|
Gfx::LightEntryArray listLightEntries();
|
||||||
|
|
||||||
|
/** Scroll the layer to the specified position */
|
||||||
|
void setScrollPosition(const Common::Point &position);
|
||||||
|
|
||||||
|
/** Enable the layer */
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
|
/** Is the layer enabled? Disabled layers are not drawn. */
|
||||||
|
bool isEnabled() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::Point _scroll;
|
||||||
|
float _scrollScale; // Used for the parallax effect
|
||||||
|
bool _enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 2D layer
|
||||||
|
*
|
||||||
|
* 2D layers contain 2D positioned items
|
||||||
|
*/
|
||||||
|
class Layer2D : public Layer {
|
||||||
|
public:
|
||||||
|
Layer2D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Layer2D();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onEnterLocation() override;
|
||||||
|
void onExitLocation() override;
|
||||||
|
|
||||||
|
// Layer API
|
||||||
|
Gfx::RenderEntry *getBackgroundRenderEntry() override;
|
||||||
|
Gfx::RenderEntryArray listRenderEntries() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
Common::Array<uint32> _itemIndices;
|
||||||
|
Common::Array<Item *> _items;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 3D layer
|
||||||
|
*
|
||||||
|
* 3D layers contain 3D positioned items, a camera and a floorfield
|
||||||
|
*/
|
||||||
|
class Layer3D : public Layer {
|
||||||
|
public:
|
||||||
|
Layer3D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Layer3D();
|
||||||
|
|
||||||
|
// Resource API
|
||||||
|
void readData(Formats::XRCReadStream *stream) override;
|
||||||
|
void onAllLoaded() override;
|
||||||
|
|
||||||
|
// Layer API
|
||||||
|
Gfx::RenderEntry *getBackgroundRenderEntry() override;
|
||||||
|
Gfx::RenderEntryArray listRenderEntries() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
|
||||||
|
uint32 _field_54;
|
||||||
|
uint32 _maxShadowLength;
|
||||||
|
float _nearClipPlane;
|
||||||
|
float _farClipPlane;
|
||||||
|
|
||||||
|
Item *_backgroundItem;
|
||||||
|
Common::Array<Item *> _items;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_LAYER_H
|
42
engines/stark/resources/level.cpp
Normal file
42
engines/stark/resources/level.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/level.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Level::~Level() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Level::Level(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Level::printData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
64
engines/stark/resources/level.h
Normal file
64
engines/stark/resources/level.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARK_RESOURCES_LEVEL_H
|
||||||
|
#define STARK_RESOURCES_LEVEL_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/object.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
|
||||||
|
namespace Formats {
|
||||||
|
class XRCReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Levels are holder resources for the locations
|
||||||
|
*
|
||||||
|
* Levels are used to share resources between related locations.
|
||||||
|
* Resources in a level are kept when switching to another location of the same level.
|
||||||
|
*/
|
||||||
|
class Level : public Object {
|
||||||
|
public:
|
||||||
|
static const Type::ResourceType TYPE = Type::kLevel;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kGlobal = 1,
|
||||||
|
kGame = 2,
|
||||||
|
kStatic = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
Level(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
virtual ~Level();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void printData() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
||||||
|
|
||||||
|
#endif // STARK_RESOURCES_LEVEL_H
|
105
engines/stark/resources/light.cpp
Normal file
105
engines/stark/resources/light.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/light.h"
|
||||||
|
|
||||||
|
#include "engines/stark/formats/xrc.h"
|
||||||
|
#include "engines/stark/gfx/renderentry.h"
|
||||||
|
#include "engines/stark/services/stateprovider.h"
|
||||||
|
|
||||||
|
namespace Stark {
|
||||||
|
namespace Resources {
|
||||||
|
|
||||||
|
Light::~Light() {
|
||||||
|
delete _lightEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
Light::Light(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
|
Object(parent, subType, index, name),
|
||||||
|
_outerConeAngle(0),
|
||||||
|
_innerConeAngle(0),
|
||||||
|
_falloffNear(100.0),
|
||||||
|
_falloffFar(500.0),
|
||||||
|
_lightEntry(nullptr) {
|
||||||
|
_type = TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::readData(Formats::XRCReadStream *stream) {
|
||||||
|
_color = stream->readVector3();
|
||||||
|
_position = stream->readVector3();
|
||||||
|
_direction = stream->readVector3();
|
||||||
|
_outerConeAngle = stream->readFloat();
|
||||||
|
_innerConeAngle = stream->readFloat();
|
||||||
|
|
||||||
|
if (stream->isDataLeft()) {
|
||||||
|
_falloffNear = stream->readFloat();
|
||||||
|
_falloffFar = stream->readFloat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::onPostRead() {
|
||||||
|
Object::onPostRead();
|
||||||
|
|
||||||
|
_lightEntry = new Gfx::LightEntry();
|
||||||
|
_lightEntry->type = (Gfx::LightEntry::Type) _subType;
|
||||||
|
_lightEntry->direction = _direction;
|
||||||
|
_lightEntry->innerConeAngle = _innerConeAngle / 2.0;
|
||||||
|
_lightEntry->outerConeAngle = _outerConeAngle / 2.0;
|
||||||
|
_lightEntry->falloffNear = _falloffNear;
|
||||||
|
_lightEntry->falloffFar = _falloffFar;
|
||||||
|
|
||||||
|
// TODO: Add support for negative lights
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::saveLoad(ResourceSerializer *serializer) {
|
||||||
|
Object::saveLoad(serializer);
|
||||||
|
|
||||||
|
serializer->syncAsVector3d(_color);
|
||||||
|
serializer->syncAsVector3d(_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::setColor(int32 red, int32 green, int32 blue) {
|
||||||
|
_color.x() = (float) red / 255.0;
|
||||||
|
_color.y() = (float) green / 255.0;
|
||||||
|
_color.z() = (float) blue / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx::LightEntry *Light::getLightEntry() {
|
||||||
|
_lightEntry->color = _color;
|
||||||
|
_lightEntry->position = _position;
|
||||||
|
|
||||||
|
return _lightEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::printData() {
|
||||||
|
Common::Debug debug = streamDbg();
|
||||||
|
debug << "color: " << _color << "\n";
|
||||||
|
debug << "position: " << _position << "\n";
|
||||||
|
debug << "direction: " << _direction << "\n";
|
||||||
|
debug << "innerConeAngle: " << _innerConeAngle << "\n";
|
||||||
|
debug << "outerConeAngle: " << _outerConeAngle << "\n";
|
||||||
|
debug << "falloffNear: " << _falloffNear << "\n";
|
||||||
|
debug << "falloffFar: " << _falloffFar << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Resources
|
||||||
|
} // End of namespace Stark
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue