ALL: Merge branch 'tlj'

This commit is contained in:
Bastien Bouclet 2016-01-01 07:33:20 +01:00
commit 5c73d0083d
192 changed files with 25561 additions and 4 deletions

View file

@ -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
View file

@ -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

View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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)

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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
View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load diff

View 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

View 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

View 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

View 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

View 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

View 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 &center) 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

View 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 &center) 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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