mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 18:32:44 +01:00
Load and associate model data when creating objects
This commit is contained in:
parent
6888fa3558
commit
218ffdf66c
@ -148,6 +148,10 @@ public:
|
|||||||
return numatomics_;
|
return numatomics_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLoaded() const override {
|
||||||
|
return model_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/// Cull model if player doesn't look at it. Ignored in GTA 3.
|
/// Cull model if player doesn't look at it. Ignored in GTA 3.
|
||||||
NORMAL_CULL = 1,
|
NORMAL_CULL = 1,
|
||||||
@ -213,6 +217,10 @@ public:
|
|||||||
return model_;
|
return model_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLoaded() const override {
|
||||||
|
return model_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Model* model_ = nullptr;
|
Model* model_ = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
void GameData::loadModelFile(const std::string& name) {
|
||||||
LoaderDFF l;
|
|
||||||
auto file = index.openFilePath(name);
|
auto file = index.openFilePath(name);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
logger->log("Data", Logger::Error, "Failed to load model file " + name);
|
logger->log("Data", Logger::Error, "Failed to load model file " + name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
LoaderDFF l;
|
||||||
auto m = l.loadFromMemory(file);
|
auto m = l.loadFromMemory(file);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
logger->log("Data", Logger::Error, "Error loading model file " + name);
|
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) {
|
for (auto& frame : m->frames) {
|
||||||
/// @todo this is useful elsewhere, please move elsewhere
|
/// @todo this is useful elsewhere, please move elsewhere
|
||||||
std::string name = frame->getName();
|
std::string name = frame->getName();
|
||||||
auto lodpos = name.rfind("_l");
|
|
||||||
int lod = 0;
|
int lod = 0;
|
||||||
if (lodpos != std::string::npos) {
|
getNameAndLod(name, lod);
|
||||||
lod = std::atoi(name.substr(lodpos + 1).c_str());
|
|
||||||
name = name.substr(0, lodpos);
|
|
||||||
}
|
|
||||||
for (auto& model : modelinfo) {
|
for (auto& model : modelinfo) {
|
||||||
auto info = model.second.get();
|
auto info = model.second.get();
|
||||||
if (info->type() != ModelDataType::SimpleInfo) {
|
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) {
|
void GameData::loadIFP(const std::string& name) {
|
||||||
auto f = index.openFile(name);
|
auto f = index.openFile(name);
|
||||||
|
|
||||||
|
@ -123,11 +123,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
void loadDFF(const std::string& name, bool async = false);
|
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.
|
* Loads a DFF and associates its atomics with models.
|
||||||
*/
|
*/
|
||||||
void loadModelFile(const std::string& name);
|
void loadModelFile(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and associates a model's data
|
||||||
|
*/
|
||||||
|
void loadModel(ModelID model);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads an IFP file containing animations
|
* Loads an IFP file containing animations
|
||||||
*/
|
*/
|
||||||
|
@ -164,6 +164,12 @@ InstanceObject* GameWorld::createInstance(const uint16_t id,
|
|||||||
const glm::quat& rot) {
|
const glm::quat& rot) {
|
||||||
auto oi = data->findModelInfo<SimpleModelInfo>(id);
|
auto oi = data->findModelInfo<SimpleModelInfo>(id);
|
||||||
if (oi) {
|
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 modelname = oi->name;
|
||||||
std::string texturename = oi->textureslot;
|
std::string texturename = oi->textureslot;
|
||||||
|
|
||||||
@ -255,6 +261,11 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id,
|
|||||||
std::string texturename;
|
std::string texturename;
|
||||||
|
|
||||||
if (modelinfo) {
|
if (modelinfo) {
|
||||||
|
/// @todo track if the current cutscene model is loaded
|
||||||
|
if (true || !modelinfo->isLoaded()) {
|
||||||
|
data->loadModel(id);
|
||||||
|
}
|
||||||
|
|
||||||
modelname = modelinfo->name;
|
modelname = modelinfo->name;
|
||||||
texturename = modelinfo->textureslot;
|
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) +
|
logger->info("World", "Creating Vehicle ID " + std::to_string(id) +
|
||||||
" (" + vti->vehiclename_ + ")");
|
" (" + vti->vehiclename_ + ")");
|
||||||
|
|
||||||
|
if (!vti->isLoaded()) {
|
||||||
|
data->loadModel(id);
|
||||||
|
}
|
||||||
|
|
||||||
if (!vti->name.empty()) {
|
if (!vti->name.empty()) {
|
||||||
data->loadDFF(vti->name + ".dff");
|
data->loadDFF(vti->name + ".dff");
|
||||||
}
|
}
|
||||||
@ -397,6 +412,10 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id,
|
|||||||
GameObjectID gid) {
|
GameObjectID gid) {
|
||||||
auto pt = data->findModelInfo<PedModelInfo>(id);
|
auto pt = data->findModelInfo<PedModelInfo>(id);
|
||||||
if (pt) {
|
if (pt) {
|
||||||
|
if (!pt->isLoaded()) {
|
||||||
|
data->loadModel(id);
|
||||||
|
}
|
||||||
|
|
||||||
std::string modelname = pt->name;
|
std::string modelname = pt->name;
|
||||||
std::string texturename = pt->textureslot;
|
std::string texturename = pt->textureslot;
|
||||||
|
|
||||||
@ -471,6 +490,10 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! modelInfo->isLoaded()) {
|
||||||
|
data->loadModel(id);
|
||||||
|
}
|
||||||
|
|
||||||
data->loadDFF(modelInfo->name + ".dff");
|
data->loadDFF(modelInfo->name + ".dff");
|
||||||
data->loadTXD(modelInfo->textureslot + ".txd");
|
data->loadTXD(modelInfo->textureslot + ".txd");
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <loaders/GenericDATLoader.hpp>
|
#include <loaders/GenericDATLoader.hpp>
|
||||||
|
#include <objects/PickupObject.hpp>
|
||||||
|
#include <objects/InstanceObject.hpp>
|
||||||
#include "test_globals.hpp"
|
#include "test_globals.hpp"
|
||||||
|
|
||||||
// Tests against loading various data files
|
// 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_EQUAL(ak47->name, "ak47");
|
||||||
BOOST_CHECK_NE(ak47->getAtomic(0), nullptr);
|
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
|
#endif
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user