1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-18 16:32:32 +02:00

Load and associate model data when creating objects

This commit is contained in:
Daniel Evans 2016-09-11 17:09:54 +01:00
parent 6888fa3558
commit 218ffdf66c
5 changed files with 135 additions and 6 deletions

View File

@ -148,6 +148,10 @@ public:
return numatomics_;
}
bool isLoaded() const override {
return model_ != nullptr;
}
enum {
/// Cull model if player doesn't look at it. Ignored in GTA 3.
NORMAL_CULL = 1,
@ -213,6 +217,10 @@ public:
return model_;
}
bool isLoaded() const override {
return model_ != nullptr;
}
private:
Model* model_ = nullptr;
};

View File

@ -336,13 +336,21 @@ void GameData::loadDFF(const std::string& name, bool async) {
}
}
void GameData::getNameAndLod(std::string& name, int& lod) {
auto lodpos = name.rfind("_l");
if (lodpos != std::string::npos) {
lod = std::atoi(name.substr(lodpos + 1).c_str());
name = name.substr(0, lodpos);
}
}
void GameData::loadModelFile(const std::string& name) {
LoaderDFF l;
auto file = index.openFilePath(name);
if (!file) {
logger->log("Data", Logger::Error, "Failed to load model file " + name);
return;
}
LoaderDFF l;
auto m = l.loadFromMemory(file);
if (!m) {
logger->log("Data", Logger::Error, "Error loading model file " + name);
@ -353,12 +361,8 @@ void GameData::loadModelFile(const std::string& name) {
for (auto& frame : m->frames) {
/// @todo this is useful elsewhere, please move elsewhere
std::string name = frame->getName();
auto lodpos = name.rfind("_l");
int lod = 0;
if (lodpos != std::string::npos) {
lod = std::atoi(name.substr(lodpos + 1).c_str());
name = name.substr(0, lodpos);
}
getNameAndLod(name, lod);
for (auto& model : modelinfo) {
auto info = model.second.get();
if (info->type() != ModelDataType::SimpleInfo) {
@ -372,6 +376,62 @@ void GameData::loadModelFile(const std::string& name) {
}
}
void GameData::loadModel(ModelID model) {
auto info = modelinfo[model].get();
/// @todo replace openFile with API for loading from CDIMAGE archives
auto name = info->name;
// Re-direct special models
switch (info->type()) {
case ModelDataType::ClumpInfo:
// Re-direct the hier objects to the special object ids
name = engine->state->specialModels[info->id()];
break;
case ModelDataType::PedInfo:
static const std::string specialPrefix("special");
if (!name.compare(0, specialPrefix.size(), specialPrefix)) {
auto sid = name.substr(specialPrefix.size());
unsigned short specialID = std::atoi(sid.c_str());
name = engine->state->specialCharacters[specialID];
break;
}
default:
break;
}
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
auto file = index.openFile(name + ".dff");
if (!file) {
logger->error("Data", "Failed to load model for " +
std::to_string(model) + " [" + name + "]");
return;
}
LoaderDFF l;
auto m = l.loadFromMemory(file);
if (!m) {
logger->error("Data",
"Error loading model file for " + std::to_string(model));
return;
}
/// @todo handle timeinfo models correctly.
auto isSimple = info->type() == ModelDataType::SimpleInfo;
if (isSimple) {
auto simple = static_cast<SimpleModelInfo*>(info);
// Associate atomics
for (auto& frame : m->frames) {
auto name = frame->getName();
int lod = 0;
getNameAndLod(name, lod);
simple->setAtomic(m, lod, frame);
}
} else {
// Associate clumps
auto clump = static_cast<ClumpModelInfo*>(info);
clump->setModel(m);
/// @todo how is LOD handled for clump objects?
}
}
void GameData::loadIFP(const std::string& name) {
auto f = index.openFile(name);

View File

@ -123,11 +123,21 @@ public:
*/
void loadDFF(const std::string& name, bool async = false);
/**
* Converts combined {name}_l{LOD} into name and lod.
*/
static void getNameAndLod(std::string& name, int& lod);
/**
* Loads a DFF and associates its atomics with models.
*/
void loadModelFile(const std::string& name);
/**
* Loads and associates a model's data
*/
void loadModel(ModelID model);
/**
* Loads an IFP file containing animations
*/

View File

@ -164,6 +164,12 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
const glm::quat& rot) {
auto oi = data->findModelInfo<SimpleModelInfo>(id);
if (oi) {
// Request loading of the model if it isn't loaded already.
/// @todo implment streaming properly
if (!oi->isLoaded()) {
data->loadModel(oi->id());
}
std::string modelname = oi->name;
std::string texturename = oi->textureslot;
@ -255,6 +261,11 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
std::string texturename;
if (modelinfo) {
/// @todo track if the current cutscene model is loaded
if (true || !modelinfo->isLoaded()) {
data->loadModel(id);
}
modelname = modelinfo->name;
texturename = modelinfo->textureslot;
@ -320,6 +331,10 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
logger->info("World", "Creating Vehicle ID " + std::to_string(id) +
" (" + vti->vehiclename_ + ")");
if (!vti->isLoaded()) {
data->loadModel(id);
}
if (!vti->name.empty()) {
data->loadDFF(vti->name + ".dff");
}
@ -397,6 +412,10 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id,
GameObjectID gid) {
auto pt = data->findModelInfo<PedModelInfo>(id);
if (pt) {
if (!pt->isLoaded()) {
data->loadModel(id);
}
std::string modelname = pt->name;
std::string texturename = pt->textureslot;
@ -471,6 +490,10 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
return nullptr;
}
if (! modelInfo->isLoaded()) {
data->loadModel(id);
}
data->loadDFF(modelInfo->name + ".dff");
data->loadTXD(modelInfo->textureslot + ".txd");

View File

@ -1,6 +1,8 @@
#include <boost/test/unit_test.hpp>
#include <data/WeaponData.hpp>
#include <loaders/GenericDATLoader.hpp>
#include <objects/PickupObject.hpp>
#include <objects/InstanceObject.hpp>
#include "test_globals.hpp"
// Tests against loading various data files
@ -93,6 +95,32 @@ BOOST_AUTO_TEST_CASE(test_model_files_loaded) {
BOOST_CHECK_EQUAL(ak47->name, "ak47");
BOOST_CHECK_NE(ak47->getAtomic(0), nullptr);
}
BOOST_AUTO_TEST_CASE(test_model_archive_loaded) {
auto& d = Global::get().d;
auto& e = Global::get().e;
/// @todo Implement streaming
// Currently, instanciating an entity will load the model
{
auto crim = d->findModelInfo<PedModelInfo>(24);
auto pickup = e->createPickup({}, 24, PickupObject::InShop);
BOOST_REQUIRE(crim->type() == ModelDataType::PedInfo);
BOOST_CHECK_NE(crim->getModel(), nullptr);
e->destroyObject(pickup);
}
{
auto info = d->findModelInfo<SimpleModelInfo>(2202);
auto inst = e->createInstance(2202, {});
BOOST_REQUIRE(info->type() == ModelDataType::SimpleInfo);
BOOST_CHECK_NE(info->getAtomic(0), nullptr);
e->destroyObject(inst);
}
}
#endif
BOOST_AUTO_TEST_SUITE_END()