From 707ee4b32afa33a06f5946438fad0e7c2e340d19 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 3 Sep 2016 04:11:55 +0100 Subject: [PATCH 01/14] Rename ObjectData.hpp -> ModelData.hpp --- rwengine/CMakeLists.txt | 4 ++-- rwengine/src/data/{ObjectData.cpp => ModelData.cpp} | 0 rwengine/src/data/{ObjectData.hpp => ModelData.hpp} | 0 rwengine/src/engine/GameData.cpp | 2 +- rwengine/src/engine/GameWorld.hpp | 2 +- rwengine/src/loaders/GenericDATLoader.cpp | 2 +- rwengine/src/loaders/LoaderIDE.hpp | 2 +- rwengine/src/render/GameRenderer.cpp | 2 +- tests/test_object_data.cpp | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename rwengine/src/data/{ObjectData.cpp => ModelData.cpp} (100%) rename rwengine/src/data/{ObjectData.hpp => ModelData.hpp} (100%) diff --git a/rwengine/CMakeLists.txt b/rwengine/CMakeLists.txt index 557347fe..616d96f4 100644 --- a/rwengine/CMakeLists.txt +++ b/rwengine/CMakeLists.txt @@ -36,8 +36,8 @@ set(RWENGINE_SOURCES src/data/GameTexts.cpp src/data/GameTexts.hpp src/data/InstanceData.hpp - src/data/ObjectData.cpp - src/data/ObjectData.hpp + src/data/ModelData.cpp + src/data/ModelData.hpp src/data/PathData.hpp src/data/Skeleton.cpp src/data/Skeleton.hpp diff --git a/rwengine/src/data/ObjectData.cpp b/rwengine/src/data/ModelData.cpp similarity index 100% rename from rwengine/src/data/ObjectData.cpp rename to rwengine/src/data/ModelData.cpp diff --git a/rwengine/src/data/ObjectData.hpp b/rwengine/src/data/ModelData.hpp similarity index 100% rename from rwengine/src/data/ObjectData.hpp rename to rwengine/src/data/ModelData.hpp diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 9cf4b886..98bd12e2 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/rwengine/src/engine/GameWorld.hpp b/rwengine/src/engine/GameWorld.hpp index 144ab020..808a1892 100644 --- a/rwengine/src/engine/GameWorld.hpp +++ b/rwengine/src/engine/GameWorld.hpp @@ -23,7 +23,7 @@ class VehicleObject; class PickupObject; class ViewCamera; -#include +#include #include struct BlipData; diff --git a/rwengine/src/loaders/GenericDATLoader.cpp b/rwengine/src/loaders/GenericDATLoader.cpp index 42de70aa..72f0dbdb 100644 --- a/rwengine/src/loaders/GenericDATLoader.cpp +++ b/rwengine/src/loaders/GenericDATLoader.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/rwengine/src/loaders/LoaderIDE.hpp b/rwengine/src/loaders/LoaderIDE.hpp index 4313913b..eda1d4af 100644 --- a/rwengine/src/loaders/LoaderIDE.hpp +++ b/rwengine/src/loaders/LoaderIDE.hpp @@ -2,7 +2,7 @@ #ifndef _LOADERIDE_HPP_ #define _LOADERIDE_HPP_ -#include +#include #include #include #include diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index b0e1bf15..5ea5813f 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include diff --git a/tests/test_object_data.cpp b/tests/test_object_data.cpp index 2d77c7b1..a70b2584 100644 --- a/tests/test_object_data.cpp +++ b/tests/test_object_data.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "test_globals.hpp" BOOST_AUTO_TEST_SUITE(ObjectDataTests) From 46a68de4061c35240e9a15bf8b6f4dd678a7a29f Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 3 Sep 2016 04:13:05 +0100 Subject: [PATCH 02/14] Fix header guard in ModelData.hpp --- rwengine/src/data/ModelData.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index 2c669c8b..632053d7 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -1,6 +1,5 @@ -#pragma once -#ifndef __GLT_OBJECTDATA_HPP__ -#define __GLT_OBJECTDATA_HPP__ +#ifndef RWENGINE_MODELDATA_HPP +#define RWENGINE_MODELDATA_HPP #include #include #include From 479aaab6660f6537d6c3492f1c28be07308b5272 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 3 Sep 2016 04:28:30 +0100 Subject: [PATCH 03/14] Fix header guard in LoaderIDE.hpp --- rwengine/src/loaders/LoaderIDE.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rwengine/src/loaders/LoaderIDE.hpp b/rwengine/src/loaders/LoaderIDE.hpp index eda1d4af..c0a814ce 100644 --- a/rwengine/src/loaders/LoaderIDE.hpp +++ b/rwengine/src/loaders/LoaderIDE.hpp @@ -1,6 +1,5 @@ -#pragma once -#ifndef _LOADERIDE_HPP_ -#define _LOADERIDE_HPP_ +#ifndef RWENGINE_LOADERIDE_HPP +#define RWENGINE_LOADERIDE_HPP #include #include From 996a82c4bf375266130ed0423cde5275018a1248 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 11 Sep 2016 02:58:00 +0100 Subject: [PATCH 04/14] Overhaul Model data handling to improve accuracy --- rwengine/src/ai/CharacterController.cpp | 4 +- rwengine/src/data/ModelData.cpp | 11 +- rwengine/src/data/ModelData.hpp | 390 ++++++++++++++---- rwengine/src/engine/GameData.cpp | 18 +- rwengine/src/engine/GameData.hpp | 15 +- rwengine/src/engine/GameWorld.cpp | 102 +++-- rwengine/src/loaders/LoaderIDE.cpp | 182 ++++---- rwengine/src/loaders/LoaderIDE.hpp | 8 +- rwengine/src/objects/CharacterObject.cpp | 5 +- rwengine/src/objects/CharacterObject.hpp | 5 +- rwengine/src/objects/CutsceneObject.cpp | 7 +- rwengine/src/objects/CutsceneObject.hpp | 2 +- rwengine/src/objects/GameObject.cpp | 4 + rwengine/src/objects/GameObject.hpp | 13 +- rwengine/src/objects/InstanceObject.cpp | 23 +- rwengine/src/objects/InstanceObject.hpp | 5 +- rwengine/src/objects/ItemPickup.cpp | 5 +- rwengine/src/objects/ItemPickup.hpp | 2 +- rwengine/src/objects/PickupObject.cpp | 5 +- rwengine/src/objects/PickupObject.hpp | 7 +- rwengine/src/objects/ProjectileObject.cpp | 2 +- rwengine/src/objects/VehicleInfo.hpp | 2 - rwengine/src/objects/VehicleObject.cpp | 22 +- rwengine/src/objects/VehicleObject.hpp | 7 +- rwengine/src/render/ObjectRenderer.cpp | 64 +-- rwengine/src/script/ScriptFunctions.hpp | 4 +- .../src/script/modules/GTA3ModuleImpl.inl | 19 +- rwgame/DrawUI.cpp | 6 +- rwgame/states/IngameState.cpp | 5 +- rwviewer/ItemListModel.cpp | 4 +- rwviewer/ViewerWidget.cpp | 19 +- rwviewer/models/ObjectListModel.cpp | 33 +- rwviewer/views/ObjectViewer.cpp | 26 +- tests/test_GameData.cpp | 12 +- tests/test_buoyancy.cpp | 2 +- tests/test_object_data.cpp | 38 +- tests/test_pickup.cpp | 2 +- tests/test_vehicle.cpp | 7 +- 38 files changed, 614 insertions(+), 473 deletions(-) diff --git a/rwengine/src/ai/CharacterController.cpp b/rwengine/src/ai/CharacterController.cpp index aa9b5afb..9e243395 100644 --- a/rwengine/src/ai/CharacterController.cpp +++ b/rwengine/src/ai/CharacterController.cpp @@ -179,7 +179,7 @@ bool Activities::EnterVehicle::update(CharacterObject *character, RW_UNUSED(controller); // Boats don't have any kind of entry animation unless you're onboard. - if (vehicle->vehicle->type == VehicleData::BOAT) { + if (vehicle->getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) { character->enterVehicle(vehicle, seat); return true; } @@ -344,7 +344,7 @@ bool Activities::ExitVehicle::update(CharacterObject *character, anm_exit = character->animations.car_getout_rhs; } - if (vehicle->vehicle->type == VehicleData::BOAT) { + if (vehicle->getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) { auto ppos = character->getPosition(); character->enterVehicle(nullptr, seat); character->setPosition(ppos); diff --git a/rwengine/src/data/ModelData.cpp b/rwengine/src/data/ModelData.cpp index 77dc3d8a..278d0001 100644 --- a/rwengine/src/data/ModelData.cpp +++ b/rwengine/src/data/ModelData.cpp @@ -1,10 +1 @@ -#include "data/ObjectData.hpp" - -const ObjectInformation::ObjectClass ObjectData::class_id = - ObjectInformation::_class("OBJS"); -const ObjectInformation::ObjectClass VehicleData::class_id = - ObjectInformation::_class("CARS"); -const ObjectInformation::ObjectClass CharacterData::class_id = - ObjectInformation::_class("PEDS"); -const ObjectInformation::ObjectClass CutsceneObjectData::class_id = - ObjectInformation::_class("HIER"); +#include "data/ModelData.hpp" diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index 632053d7..d3a60363 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -4,109 +4,227 @@ #include #include #include +#include #include +#include #include +#include #ifdef RW_WINDOWS #include #endif -typedef uint16_t ObjectID; - /** - * Stores basic information about an Object and it's real type. + * 16-bit model ID identifier (from .ide) */ -struct ObjectInformation { - typedef size_t ObjectClass; - static ObjectClass _class(const std::string& name) { - return std::hash()(name); - } +using ModelID = uint16_t; - ObjectID ID; - const ObjectClass class_type; - - ObjectInformation(const ObjectClass type) : class_type(type) { - } - - virtual ~ObjectInformation() { - } +enum class ModelDataType { + SimpleInfo = 1, + /** Unknown */ + MLoModelInfo = 2, + /** Currently unused; data in SimpleInfo instead */ + TimeModelInfo = 3, + ClumpInfo = 4, + VehicleInfo = 5, + PedInfo = 6 }; -typedef std::shared_ptr ObjectInformationPtr; - /** - * Data used by Normal Objects + * Base type for all model information + * + * @todo reference counting + * @todo store collision model */ -struct ObjectData : public ObjectInformation { - static const ObjectClass class_id; +class BaseModelInfo { +public: + std::string name; + std::string textureslot; - ObjectData() : ObjectInformation(_class("OBJS")) { + BaseModelInfo(ModelDataType type) : type_(type) { } - std::string modelName; - std::string textureName; - uint8_t numClumps; - float drawDistance[3]; - int32_t flags; - bool LOD; + virtual ~BaseModelInfo() { + } - short timeOn; - short timeOff; + ModelID id() const { + return modelid_; + } + + void setModelID(ModelID id) { + modelid_ = id; + } + + ModelDataType type() const { + return type_; + } + + void addReference() { + refcount_++; + } + + void removeReference() { + refcount_--; + } + + int getReferenceCount() const { + return refcount_; + } + + /// @todo replace with proper streaming implementation + virtual bool isLoaded() const = 0; + + static std::string getTypeName(ModelDataType type) { + switch (type) { + case ModelDataType::SimpleInfo: + return "Simple"; + case ModelDataType::VehicleInfo: + return "Vehicle"; + case ModelDataType::PedInfo: + return "Pedestrian"; + case ModelDataType::ClumpInfo: + return "Cutscene"; + default: + break; + } + return "Unknown"; + } + +private: + ModelID modelid_ = 0; + ModelDataType type_; + int refcount_ = 0; +}; + +/** + * Model data for simple types + * + * @todo replace Model* with librw types + */ +class SimpleModelInfo : public BaseModelInfo { +public: + static constexpr ModelDataType kType = ModelDataType::SimpleInfo; + + /// @todo Use TimeModelInfo instead of hacking this in here + int timeOn = 0; + int timeOff = 24; + int flags; + /// @todo Remove this? + bool LOD = false; + /// Information loaded from PATH sections + /// @todo remove this from here too :) + std::vector paths; + + SimpleModelInfo() : BaseModelInfo(kType) { + } + SimpleModelInfo(ModelDataType type) : BaseModelInfo(type) { + } + + /// @todo change with librw + void setAtomic(Model* model, int n, ModelFrame* atomic) { + model_ = model; + atomics_[n] = atomic; + } + + ModelFrame* getAtomic(int n) const { + return atomics_[n]; + } + + void setLodDistance(int n, float d) { + RW_CHECK(n < 3, "Lod Index out of range"); + loddistances_[n] = d; + } + + float getLodDistance(int n) { + RW_CHECK(n < 3, "Lod Index out of range"); + return loddistances_[n]; + } + + void setNumAtomics(int num) { + numatomics_ = num; + } + + int getNumAtomics() const { + return numatomics_; + } enum { - NORMAL_CULL = - 1, /// Cull model if player doesn't look at it. Ignored in GTA 3. - DO_NOT_FADE = 1 << 1, /// Do not fade the object when it is being - /// loaded into or out of view. - DRAW_LAST = 1 << 2, /// Model is transparent. Render this object after - /// all opaque objects, allowing transparencies of - /// other objects to be visible through this - /// object. - ADDITIVE = 1 << 3, /// Render with additive blending. Previous flag - /// must be enabled too. - IS_SUBWAY = 1 << 4, /// Model is a tunnel, i.e. set the object as - /// invisible unless the player enters cull zone - /// flag 128. This flag works only with static - /// models. - IGNORE_LIGHTING = 1 << 5, /// Don't use static lighting, we want - /// dynamic if it's possible. - NO_ZBUFFER_WRITE = - 1 << 6, /// Model is a shadow. Disable writing to z-buffer when - /// rendering it, allowing transparencies of other objects, - /// shadows, and lights to be visible through this object. - /// (Not implemented in the PS2 version) + /// Cull model if player doesn't look at it. Ignored in GTA 3. + NORMAL_CULL = 1, + /// Do not fade the object when it is being + /// loaded into or out of view. + DO_NOT_FADE = 1 << 1, + /// Model is transparent. Render this object after + /// all opaque objects, allowing transparencies of + /// other objects to be visible through this + /// object. + DRAW_LAST = 1 << 2, + /// Render with additive blending. Previous flag + /// must be enabled too. + ADDITIVE = 1 << 3, + /// Model is a tunnel, i.e. set the object as + /// invisible unless the player enters cull zone + /// flag 128. This flag works only with static + /// models. + IS_SUBWAY = 1 << 4, + /// Don't use static lighting, we want + /// dynamic if it's possible. + IGNORE_LIGHTING = 1 << 5, + /// Model is a shadow. Disable writing to z-buffer when + /// rendering it, allowing transparencies of other objects, + /// shadows, and lights to be visible through this object. + /// (Not implemented in the PS2 version) + NO_ZBUFFER_WRITE = 1 << 6, }; - // Information loaded from PATH sections - std::vector paths; +private: + Model* model_ = nullptr; + ModelFrame* atomics_[3] = {}; + float loddistances_[3] = {}; + uint8_t numatomics_ = 0; + uint8_t alpha_ = 0; /// @todo ask aap why }; -typedef std::shared_ptr ObjectDataPtr; +/** + * @todo this + */ +class TimeModelInfo : public SimpleModelInfo { + TimeModelInfo() : SimpleModelInfo(ModelDataType::TimeModelInfo) { + } +}; /** - * Data used by peds + * @todo document me */ -struct CharacterData : public ObjectInformation { - static const ObjectClass class_id; +class ClumpModelInfo : public BaseModelInfo { +public: + static constexpr ModelDataType kType = ModelDataType::ClumpInfo; - CharacterData() : ObjectInformation(_class("PEDS")) { + ClumpModelInfo() : BaseModelInfo(kType) { + } + ClumpModelInfo(ModelDataType type) : BaseModelInfo(type) { } - std::string modelName; - std::string textureName; - std::string type; - std::string behaviour; - std::string animGroup; - uint8_t driveMask; + void setModel(Model* model) { + model_ = model; + } + + Model* getModel() const { + return model_; + } + +private: + Model* model_ = nullptr; }; /** - * @brief Stores vehicle data loaded from item definition files. + * Data for a vehicle model type */ -struct VehicleData : public ObjectInformation { - static const ObjectClass class_id; +class VehicleModelInfo : public ClumpModelInfo { +public: + static constexpr ModelDataType kType = ModelDataType::VehicleInfo; - VehicleData() : ObjectInformation(_class("CARS")) { + VehicleModelInfo() : ClumpModelInfo(kType) { } enum VehicleClass { @@ -124,6 +242,8 @@ struct VehicleData : public ObjectInformation { WORKERBOAT = 1 << 10, BICYCLE = 1 << 11, ONFOOT = 1 << 12, + /// @todo verify that this is the correct bit + SPECIAL = 1 << 13, }; enum VehicleType { @@ -134,32 +254,120 @@ struct VehicleData : public ObjectInformation { HELI, }; - std::string modelName; - std::string textureName; - VehicleType type; - std::string handlingID; - std::string gameName; - VehicleClass classType; - uint8_t frequency; // big enough int type? - uint8_t lvl; // big enough int type? - uint16_t comprules; - union { // big enough int types? - uint16_t wheelModelID; // used only when type == CAR - int16_t modelLOD; // used only when type == PLANE - }; - float wheelScale; // used only when type == CAR -}; + VehicleType vehicletype_; + ModelID wheelmodel_; + float wheelscale_; + int numdoors_; + std::string handling_; + VehicleClass vehicleclass_; + int frequency_; + int level_; + int componentrules_; + std::string vehiclename_; -typedef std::shared_ptr VehicleDataHandle; - -struct CutsceneObjectData : public ObjectInformation { - static const ObjectClass class_id; - - CutsceneObjectData() : ObjectInformation(_class("HIER")) { + static VehicleType findVehicleType(const std::string& name) { + static const std::unordered_map vehicleTypes{ + {"car", CAR}, + {"boat", BOAT}, + {"train", TRAIN}, + {"plane", PLANE}, + {"heli", HELI}}; + return vehicleTypes.at(name); } - std::string modelName; - std::string textureName; + static VehicleClass findVehicleClass(const std::string& name) { + static const std::unordered_map classTypes{ + // III, VC, SA + {"ignore", IGNORE}, + {"normal", NORMAL}, + {"poorfamily", POORFAMILY}, + {"richfamily", RICHFAMILY}, + {"executive", EXECUTIVE}, + {"worker", WORKER}, + {"big", BIG}, + {"taxi", TAXI}, + {"special", SPECIAL}, + // VC, SA + {"moped", MOPED}, + {"motorbike", MOTORBIKE}, + {"leisureboat", LEISUREBOAT}, + {"workerboat", WORKERBOAT}, + {"bicycle", BICYCLE}, + {"onfoot", ONFOOT}, + }; + return classTypes.at(name); + } +}; + +class PedModelInfo : public ClumpModelInfo { +public: + static constexpr ModelDataType kType = ModelDataType::PedInfo; + + PedModelInfo() : ClumpModelInfo(kType) { + } + + enum PedType { + // III + PLAYER1 = 0, + PLAYER2, + PLAYER3, + PLAYER_4, + CIVMALE, + CIVFEMALE, + COP, + GANG1, + GANG2, + GANG3, + GANG4, + GANG5, + GANG6, + GANG7, + GANG8, + GANG9, + EMERGENCY, + FIREMAN, + CRIMINAL, + _UNNAMED, + PROSTITUTE, + SPECIAL, + }; + + PedType pedtype_ = PLAYER1; + /// @todo this should be an index + std::string behaviour_; + /// @todo this should be an index + std::string animgroup_; + /// The mask of vehicle classes this ped can drive + int carsmask_ = 0; + + static PedType findPedType(const std::string& name) { + static const std::unordered_map pedTypes{ + // III + {"PLAYER1", PLAYER1}, + {"PLAYER2", PLAYER2}, + {"PLAYER3", PLAYER3}, + {"PLAYER_4", PLAYER_4}, + {"CIVMALE", CIVMALE}, + {"CIVFEMALE", CIVFEMALE}, + {"COP", COP}, + {"GANG1", GANG1}, + {"GANG2", GANG2}, + {"GANG3", GANG3}, + {"GANG4", GANG4}, + {"GANG5", GANG5}, + {"GANG6", GANG6}, + {"GANG7", GANG7}, + {"GANG8", GANG8}, + {"GANG9", GANG9}, + {"EMERGENCY", EMERGENCY}, + {"FIREMAN", FIREMAN}, + {"CRIMINAL", CRIMINAL}, + {"_UNNAMED", _UNNAMED}, + {"PROSTITUTE", PROSTITUTE}, + {"SPECIAL", SPECIAL}, + }; + return pedTypes.at(name); + } }; /** diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 98bd12e2..1396c3d1 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -109,23 +109,19 @@ void GameData::loadIDE(const std::string& path) { LoaderIDE idel; if (idel.load(systempath)) { - objectTypes.insert(idel.objects.begin(), idel.objects.end()); + std::move(idel.objects.begin(), idel.objects.end(), + std::inserter(modelinfo, modelinfo.end())); } else { logger->error("Data", "Failed to load IDE " + path); } } uint16_t GameData::findModelObject(const std::string model) { - auto defit = std::find_if( - objectTypes.begin(), objectTypes.end(), - [&](const decltype(objectTypes)::value_type& d) { - if (d.second->class_type == ObjectInformation::_class("OBJS")) { - auto dat = static_cast(d.second.get()); - return boost::iequals(dat->modelName, model); - } - return false; - }); - if (defit != objectTypes.end()) return defit->first; + auto defit = std::find_if(modelinfo.begin(), modelinfo.end(), + [&](const decltype(modelinfo)::value_type& d) { + return boost::iequals(d.second->name, model); + }); + if (defit != modelinfo.end()) return defit->first; return -1; } diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index b33508d5..e692ec55 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -170,20 +170,15 @@ public: */ std::map zones; - /** - * Object Definitions - */ - std::map objectTypes; + std::unordered_map> modelinfo; uint16_t findModelObject(const std::string model); template - std::shared_ptr findObjectType(ObjectID id) { - auto f = objectTypes.find(id); - /// @TODO don't instanciate an object here just to read .type - T tmp; - if (f != objectTypes.end() && f->second->class_type == tmp.class_type) { - return std::static_pointer_cast(f->second); + T* findModelInfo(ModelID id) { + auto f = modelinfo.find(id); + if (f != modelinfo.end() && f->second->type() == T::kType) { + return static_cast(f->second.get()); } return nullptr; } diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 256b9e20..f03bcec5 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -140,10 +140,10 @@ bool GameWorld::placeItems(const std::string& name) { for (auto& p : instancePool.objects) { auto object = p.second; InstanceObject* instance = static_cast(object); - if (!instance->object->LOD && - instance->object->modelName.length() > 3) { - auto lodInstit = modelInstances.find( - "LOD" + instance->object->modelName.substr(3)); + auto modelinfo = instance->getModelInfo(); + if (!modelinfo->LOD && modelinfo->name.length() > 3) { + auto lodInstit = + modelInstances.find("LOD" + modelinfo->name.substr(3)); if (lodInstit != modelInstances.end()) { instance->LODinstance = lodInstit->second; } @@ -162,10 +162,10 @@ bool GameWorld::placeItems(const std::string& name) { InstanceObject* GameWorld::createInstance(const uint16_t id, const glm::vec3& pos, const glm::quat& rot) { - auto oi = data->findObjectType(id); + auto oi = data->findModelInfo(id); if (oi) { - std::string modelname = oi->modelName; - std::string texturename = oi->textureName; + std::string modelname = oi->name; + std::string texturename = oi->textureslot; std::transform(std::begin(modelname), std::end(modelname), std::begin(modelname), tolower); @@ -173,7 +173,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, std::begin(texturename), tolower); // Ensure the relevant data is loaded. - if (!oi->modelName.empty()) { + if (!modelname.empty()) { if (modelname != "null") { data->loadDFF(modelname + ".dff", false); } @@ -185,7 +185,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, ModelRef m = data->models[modelname]; // Check for dynamic data. - auto dyit = data->dynamicObjectData.find(oi->modelName); + auto dyit = data->dynamicObjectData.find(oi->name); std::shared_ptr dydata; if (dyit != data->dynamicObjectData.end()) { dydata = dyit->second; @@ -202,7 +202,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, instancePool.insert(instance); allObjects.push_back(instance); - modelInstances.insert({oi->modelName, instance}); + modelInstances.insert({oi->name, instance}); return instance; } @@ -250,34 +250,33 @@ void GameWorld::cleanupTraffic(const ViewCamera& focus) { CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id, const glm::vec3& pos, const glm::quat& rot) { + auto modelinfo = data->modelinfo[id].get(); std::string modelname; std::string texturename; - auto type = data->objectTypes.find(id); - if (type != data->objectTypes.end()) { - if (type->second->class_type == ObjectInformation::_class("HIER")) { - modelname = state->specialModels[id]; - texturename = state->specialModels[id]; - } else { - if (type->second->class_type == ObjectInformation::_class("OBJS")) { - auto v = static_cast(type->second.get()); - modelname = v->modelName; - texturename = v->textureName; - } else if (type->second->class_type == - ObjectInformation::_class("PEDS")) { - auto v = static_cast(type->second.get()); - modelname = v->modelName; - texturename = v->textureName; + if (modelinfo) { + modelname = modelinfo->name; + texturename = modelinfo->textureslot; - static std::string specialPrefix("special"); + /// @todo Store loaded models directly + switch (modelinfo->type()) { + case ModelDataType::ClumpInfo: + // Re-direct the hier objects to the special object ids + modelname = state->specialModels[id]; + texturename = state->specialModels[id]; + break; + case ModelDataType::PedInfo: + static const std::string specialPrefix("special"); if (!modelname.compare(0, specialPrefix.size(), specialPrefix)) { auto sid = modelname.substr(specialPrefix.size()); unsigned short specialID = std::atoi(sid.c_str()); modelname = state->specialCharacters[specialID]; texturename = state->specialCharacters[specialID]; + break; } - } + default: + break; } } @@ -305,7 +304,7 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id, ModelRef m = data->models[modelname]; - auto instance = new CutsceneObject(this, pos, rot, m); + auto instance = new CutsceneObject(this, pos, rot, m, modelinfo); cutscenePool.insert(instance); allObjects.push_back(instance); @@ -316,21 +315,21 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id, VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot, GameObjectID gid) { - auto vti = data->findObjectType(id); + auto vti = data->findModelInfo(id); if (vti) { logger->info("World", "Creating Vehicle ID " + std::to_string(id) + - " (" + vti->gameName + ")"); + " (" + vti->vehiclename_ + ")"); - if (!vti->modelName.empty()) { - data->loadDFF(vti->modelName + ".dff"); + if (!vti->name.empty()) { + data->loadDFF(vti->name + ".dff"); } - if (!vti->textureName.empty()) { - data->loadTXD(vti->textureName + ".txd"); + if (!vti->textureslot.empty()) { + data->loadTXD(vti->textureslot + ".txd"); } glm::u8vec3 prim(255), sec(128); auto palit = data->vehiclePalettes.find( - vti->modelName); // modelname is conveniently lowercase (usually) + vti->name); // modelname is conveniently lowercase (usually) if (palit != data->vehiclePalettes.end() && palit->second.size() > 0) { std::uniform_int_distribution uniform( 0, palit->second.size() - 1); @@ -339,19 +338,12 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, sec = data->vehicleColours[palit->second[set].second]; } else { logger->warning("World", - "No colour palette for vehicle " + vti->modelName); + "No colour palette for vehicle " + vti->name); } - auto wi = data->findObjectType(vti->wheelModelID); - if (wi) { - if (!wi->textureName.empty()) { - data->loadTXD(wi->textureName + ".txd"); - } - } - - ModelRef& m = data->models[vti->modelName]; + ModelRef& m = data->models[vti->name]; auto model = m->resource; - auto info = data->vehicleInfo.find(vti->handlingID); + auto info = data->vehicleInfo.find(vti->handling_); if (model && info != data->vehicleInfo.end()) { if (info->second->wheels.size() == 0 && info->second->seats.size() == 0) { @@ -403,13 +395,13 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3& pos, const glm::quat& rot, GameObjectID gid) { - auto pt = data->findObjectType(id); + auto pt = data->findModelInfo(id); if (pt) { - std::string modelname = pt->modelName; - std::string texturename = pt->textureName; + std::string modelname = pt->name; + std::string texturename = pt->textureslot; // Ensure the relevant data is loaded. - if (!pt->modelName.empty()) { + if (!modelname.empty()) { // Some model names have special meanings. /// @todo Should CharacterObjects handle this? static std::string specialPrefix("special"); @@ -446,7 +438,7 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, const glm::quat& rot, GameObjectID gid) { // Player object ID is hardcoded to 0. - auto pt = data->findObjectType(0); + auto pt = data->findModelInfo(0); if (pt) { // Model name is also hardcoded. std::string modelname = "player"; @@ -472,15 +464,15 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, } PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { - auto modelInfo = data->findObjectType(id); + auto modelInfo = data->modelinfo[id].get(); RW_CHECK(modelInfo != nullptr, "Pickup Object Data is not found"); if (modelInfo == nullptr) { return nullptr; } - data->loadDFF(modelInfo->modelName + ".dff"); - data->loadTXD(modelInfo->textureName + ".txd"); + data->loadDFF(modelInfo->name + ".dff"); + data->loadTXD(modelInfo->textureslot + ".txd"); PickupObject* pickup = nullptr; auto pickuptype = (PickupObject::PickupType)type; @@ -492,10 +484,10 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { // If nothing, create a generic pickup instead of an item pickup if (it != inventoryItems.end()) { - pickup = new ItemPickup(this, pos, pickuptype, *it); + pickup = new ItemPickup(this, pos, modelInfo, pickuptype, *it); } else { RW_UNIMPLEMENTED("Non-weapon pickups"); - pickup = new PickupObject(this, pos, id, pickuptype); + pickup = new PickupObject(this, pos, modelInfo, pickuptype); } pickupPool.insert(pickup); diff --git a/rwengine/src/loaders/LoaderIDE.cpp b/rwengine/src/loaders/LoaderIDE.cpp index 9a83fa11..26b00e8f 100644 --- a/rwengine/src/loaders/LoaderIDE.cpp +++ b/rwengine/src/loaders/LoaderIDE.cpp @@ -48,34 +48,35 @@ bool LoaderIDE::load(const std::string &filename) { line.end()); std::stringstream strstream(line); + std::string buff; switch (section) { default: break; case OBJS: case TOBJ: { // Supports Type 1, 2 and 3 - std::shared_ptr objs(new ObjectData); + auto objs = + std::unique_ptr(new SimpleModelInfo); - std::string id, numClumps, flags, modelName, textureName; + getline(strstream, buff, ','); + objs->setModelID(atoi(buff.c_str())); - // Read the content of the line - getline(strstream, id, ','); - getline(strstream, modelName, ','); - getline(strstream, textureName, ','); - getline(strstream, numClumps, ','); + getline(strstream, objs->name, ','); + getline(strstream, objs->textureslot, ','); - objs->numClumps = atoi(numClumps.c_str()); - for (size_t i = 0; i < objs->numClumps; i++) { - std::string drawDistance; - getline(strstream, drawDistance, ','); - objs->drawDistance[i] = atoi(drawDistance.c_str()); + getline(strstream, buff, ','); + objs->setNumAtomics(atoi(buff.c_str())); + + for (int i = 0; i < objs->getNumAtomics(); i++) { + getline(strstream, buff, ','); + objs->setLodDistance(i, atof(buff.c_str())); } - getline(strstream, flags, ','); + getline(strstream, buff, ','); + objs->flags = atoi(buff.c_str()); // Keep reading TOBJ data if (section == LoaderIDE::TOBJ) { - std::string buff; getline(strstream, buff, ','); objs->timeOn = atoi(buff.c_str()); getline(strstream, buff, ','); @@ -85,104 +86,82 @@ bool LoaderIDE::load(const std::string &filename) { objs->timeOff = 24; } - // Put stuff in our struct - objs->ID = atoi(id.c_str()); - objs->flags = atoi(flags.c_str()); - objs->modelName = modelName; - objs->textureName = textureName; - objs->LOD = false; - - if (modelName.find("LOD", 0, 3) != modelName.npos && - modelName != "LODistancoast01") { + /// @todo Figure out how LOD stuff is intended to work + if (objs->name.find("LOD", 0, 3) != std::string::npos && + objs->name != "LODistancoast01") { objs->LOD = true; } - objects.insert({objs->ID, objs}); + objects.emplace(objs->id(), std::move(objs)); break; } case CARS: { - std::shared_ptr cars(new VehicleData); + auto cars = + std::unique_ptr(new VehicleModelInfo); - std::string id, type, classType, frequency, lvl, comprules, - wheelModelID, wheelScale; + getline(strstream, buff, ','); + cars->setModelID(std::atoi(buff.c_str())); - getline(strstream, id, ','); - getline(strstream, cars->modelName, ','); - getline(strstream, cars->textureName, ','); - getline(strstream, type, ','); - getline(strstream, cars->handlingID, ','); - getline(strstream, cars->gameName, ','); - getline(strstream, classType, ','); - getline(strstream, frequency, ','); - getline(strstream, lvl, ','); - getline(strstream, comprules, ','); - getline(strstream, wheelModelID, ','); - getline(strstream, wheelScale, ','); + getline(strstream, cars->name, ','); + getline(strstream, cars->textureslot, ','); - cars->ID = atoi(id.c_str()); - cars->frequency = atoi(frequency.c_str()); - cars->lvl = atoi(lvl.c_str()); - cars->comprules = atoi(comprules.c_str()); + getline(strstream, buff, ','); + cars->vehicletype_ = + VehicleModelInfo::findVehicleType(buff); - if (type == "car") { - cars->type = VehicleData::CAR; - cars->wheelModelID = atoi(wheelModelID.c_str()); - cars->wheelScale = atof(wheelScale.c_str()); - } else if (type == "boat") { - cars->type = VehicleData::BOAT; - } else if (type == "train") { - cars->type = VehicleData::TRAIN; - cars->modelLOD = atoi(wheelModelID.c_str()); - } else if (type == "plane") { - cars->type = VehicleData::PLANE; - } else if (type == "heli") { - cars->type = VehicleData::HELI; - } + getline(strstream, cars->handling_, ','); + getline(strstream, cars->vehiclename_, ','); + getline(strstream, buff, ','); + cars->vehicleclass_ = + VehicleModelInfo::findVehicleClass(buff); - const std::map - classTypes{ - {VehicleData::IGNORE, "ignore"}, - {VehicleData::NORMAL, "normal"}, - {VehicleData::POORFAMILY, "poorfamily"}, - {VehicleData::RICHFAMILY, "richfamily"}, - {VehicleData::EXECUTIVE, "executive"}, - {VehicleData::WORKER, "worker"}, - {VehicleData::BIG, "big"}, - {VehicleData::TAXI, "taxi"}, - {VehicleData::MOPED, "moped"}, - {VehicleData::MOTORBIKE, "motorbike"}, - {VehicleData::LEISUREBOAT, "leisureboat"}, - {VehicleData::WORKERBOAT, "workerboat"}, - {VehicleData::BICYCLE, "bicycle"}, - {VehicleData::ONFOOT, "onfoot"}, - }; - for (auto &a : classTypes) { - if (classType == a.second) { - cars->classType = a.first; + getline(strstream, buff, ','); + cars->frequency_ = std::atoi(buff.c_str()); + + getline(strstream, buff, ','); + cars->level_ = std::atoi(buff.c_str()); + + getline(strstream, buff, ','); + cars->componentrules_ = std::atoi(buff.c_str()); + + switch (cars->vehicletype_) { + case VehicleModelInfo::CAR: + getline(strstream, buff, ','); + cars->wheelmodel_ = std::atoi(buff.c_str()); + getline(strstream, buff, ','); + cars->wheelscale_ = std::atof(buff.c_str()); + break; + case VehicleModelInfo::PLANE: + /// @todo load LOD + getline(strstream, buff, ','); + // cars->planeLOD_ = std::atoi(buff.c_str()); + break; + default: break; - } } - objects.insert({cars->ID, cars}); + objects.emplace(cars->id(), std::move(cars)); break; } case PEDS: { - std::shared_ptr peds(new CharacterData); + auto peds = std::unique_ptr(new PedModelInfo); - std::string id, driveMask; + getline(strstream, buff, ','); + peds->setModelID(std::atoi(buff.c_str())); - getline(strstream, id, ','); - getline(strstream, peds->modelName, ','); - getline(strstream, peds->textureName, ','); - getline(strstream, peds->type, ','); - getline(strstream, peds->behaviour, ','); - getline(strstream, peds->animGroup, ','); - getline(strstream, driveMask, ','); + getline(strstream, peds->name, ','); + getline(strstream, peds->textureslot, ','); - peds->ID = atoi(id.c_str()); - peds->driveMask = atoi(driveMask.c_str()); + getline(strstream, buff, ','); + peds->pedtype_ = PedModelInfo::findPedType(buff); - objects.insert({peds->ID, peds}); + getline(strstream, peds->behaviour_, ','); + getline(strstream, peds->animgroup_, ','); + + getline(strstream, buff, ','); + peds->carsmask_ = std::atoi(buff.c_str()); + + objects.emplace(peds->id(), std::move(peds)); break; } case PATH: { @@ -253,25 +232,22 @@ bool LoaderIDE::load(const std::string &filename) { } auto &object = objects[path.ID]; - auto instance = - std::dynamic_pointer_cast(object); - instance->paths.push_back(path); + auto simple = dynamic_cast(object.get()); + simple->paths.push_back(path); break; } case HIER: { - std::shared_ptr cut( - new CutsceneObjectData); + auto hier = + std::unique_ptr(new ClumpModelInfo); - std::string id; + getline(strstream, buff, ','); + hier->setModelID(std::atoi(buff.c_str())); - getline(strstream, id, ','); - getline(strstream, cut->modelName, ','); - getline(strstream, cut->textureName, ','); + getline(strstream, hier->name, ','); + getline(strstream, hier->textureslot, ','); - cut->ID = atoi(id.c_str()); - - objects.insert({cut->ID, cut}); + objects.emplace(hier->id(), std::move(hier)); break; } } diff --git a/rwengine/src/loaders/LoaderIDE.hpp b/rwengine/src/loaders/LoaderIDE.hpp index c0a814ce..f6a44195 100644 --- a/rwengine/src/loaders/LoaderIDE.hpp +++ b/rwengine/src/loaders/LoaderIDE.hpp @@ -27,13 +27,7 @@ public: /** * @brief objects loaded during the call to load() */ - std::map objects; - - /*std::vector> OBJSs; - std::vector> CARSs; - std::vector> PEDSs; - std::vector> HIERs; - std::vector> PATHs;*/ + std::map> objects; }; #endif diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index ef27ddf9..16845627 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -15,8 +15,8 @@ const float CharacterObject::DefaultJumpSpeed = 2.f; CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, - std::shared_ptr data) - : GameObject(engine, pos, rot, model) + BaseModelInfo *modelinfo) + : GameObject(engine, pos, rot, modelinfo, model) , currentState({}) , currentVehicle(nullptr) , currentSeat(0) @@ -24,7 +24,6 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, , jumped(false) , jumpSpeed(DefaultJumpSpeed) , motionBlockedByActivity(false) - , ped(data) , physCharacter(nullptr) , physObject(nullptr) , physShape(nullptr) diff --git a/rwengine/src/objects/CharacterObject.hpp b/rwengine/src/objects/CharacterObject.hpp index 29fb6ba0..e26da4a8 100644 --- a/rwengine/src/objects/CharacterObject.hpp +++ b/rwengine/src/objects/CharacterObject.hpp @@ -125,8 +125,6 @@ private: public: static const float DefaultJumpSpeed; - std::shared_ptr ped; - btKinematicCharacterController* physCharacter; btPairCachingGhostObject* physObject; btCapsuleShapeZ* physShape; @@ -143,7 +141,7 @@ public: */ CharacterObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, - std::shared_ptr data); + BaseModelInfo* modelinfo); ~CharacterObject(); @@ -151,6 +149,7 @@ public: return Character; } + void tick(float dt); const CharacterState& getCurrentState() const { diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index 9e317094..3d2e0a2a 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -3,8 +3,11 @@ #include CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, - const glm::quat &rot, const ModelRef &model) - : GameObject(engine, pos, rot, model), _parent(nullptr), _bone(nullptr) { + const glm::quat &rot, + const ModelRef &model, BaseModelInfo *modelinfo) + : GameObject(engine, pos, rot, modelinfo, model) + , _parent(nullptr) + , _bone(nullptr) { skeleton = new Skeleton; animator = new Animator(model->resource, skeleton); } diff --git a/rwengine/src/objects/CutsceneObject.hpp b/rwengine/src/objects/CutsceneObject.hpp index 181f50e7..fda619d6 100644 --- a/rwengine/src/objects/CutsceneObject.hpp +++ b/rwengine/src/objects/CutsceneObject.hpp @@ -12,7 +12,7 @@ class CutsceneObject : public GameObject { public: CutsceneObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model); + const glm::quat& rot, const ModelRef& model, BaseModelInfo *modelinfo); ~CutsceneObject(); Type type() { diff --git a/rwengine/src/objects/GameObject.cpp b/rwengine/src/objects/GameObject.cpp index 81c37962..08f6741a 100644 --- a/rwengine/src/objects/GameObject.cpp +++ b/rwengine/src/objects/GameObject.cpp @@ -12,6 +12,10 @@ GameObject::~GameObject() { if (skeleton) { delete skeleton; } + + if (modelinfo_) { + modelinfo_->removeReference(); + } } void GameObject::setPosition(const glm::vec3& pos) { diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index a606ddbd..78a80e2d 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -28,6 +28,8 @@ class GameObject { glm::quat _lastRotation; GameObjectID objectID; + BaseModelInfo* modelinfo_; + public: glm::vec3 position; glm::quat rotation; @@ -53,10 +55,11 @@ public: bool visible; GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - ModelRef model) + BaseModelInfo* modelinfo, ModelRef model) : _lastPosition(pos) , _lastRotation(rot) , objectID(0) + , modelinfo_(modelinfo) , position(pos) , rotation(rot) , model(model) @@ -67,6 +70,9 @@ public: , _lastHeight(std::numeric_limits::max()) , visible(true) , lifetime(GameObject::UnknownLifetime) { + if (modelinfo_) { + modelinfo_->addReference(); + } } virtual ~GameObject(); @@ -85,6 +91,11 @@ public: return getGameObjectID(); } + template + T* getModelInfo() const { + return static_cast(modelinfo_); + } + /** * @brief Enumeration of possible object types. */ diff --git a/rwengine/src/objects/InstanceObject.cpp b/rwengine/src/objects/InstanceObject.cpp index edaa209d..2a0ce5ff 100644 --- a/rwengine/src/objects/InstanceObject.cpp +++ b/rwengine/src/objects/InstanceObject.cpp @@ -8,22 +8,25 @@ InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, const glm::vec3& scale, - std::shared_ptr obj, + BaseModelInfo *modelinfo, InstanceObject* lod, std::shared_ptr dyn) - : GameObject(engine, pos, rot, model) + : GameObject(engine, pos, rot, modelinfo, model) , health(100.f) , scale(scale) , body(nullptr) - , object(obj) , LODinstance(lod) , dynamics(dyn) , _enablePhysics(false) { - if (obj) { - changeModel(obj); + if (modelinfo) { + changeModel(modelinfo); - for (auto& path : obj->paths) { - engine->aigraph.createPathNodes(position, rot, path); + /// @todo store path information properly + if (modelinfo->type() == ModelDataType::SimpleInfo) { + auto simpledata = static_cast(modelinfo); + for (auto& path : simpledata->paths) { + engine->aigraph.createPathNodes(position, rot, path); + } } } } @@ -120,18 +123,18 @@ void InstanceObject::tick(float dt) { if (animator) animator->tick(dt); } -void InstanceObject::changeModel(std::shared_ptr incoming) { +void InstanceObject::changeModel(BaseModelInfo *incoming) { if (body) { delete body; body = nullptr; } - object = incoming; + /// @todo store the new object if (incoming) { auto bod = new CollisionInstance; - if (bod->createPhysicsBody(this, object->modelName, dynamics.get())) { + if (bod->createPhysicsBody(this, incoming->name, dynamics.get())) { bod->getBulletBody()->setActivationState(ISLAND_SLEEPING); body = bod; } diff --git a/rwengine/src/objects/InstanceObject.hpp b/rwengine/src/objects/InstanceObject.hpp index fa50fbd3..e7c92838 100644 --- a/rwengine/src/objects/InstanceObject.hpp +++ b/rwengine/src/objects/InstanceObject.hpp @@ -17,14 +17,13 @@ class InstanceObject : public GameObject { public: glm::vec3 scale; CollisionInstance* body; - std::shared_ptr object; InstanceObject* LODinstance; std::shared_ptr dynamics; bool _enablePhysics; InstanceObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, - const glm::vec3& scale, std::shared_ptr obj, + const glm::vec3& scale, BaseModelInfo* modelinfo, InstanceObject* lod, std::shared_ptr dyn); ~InstanceObject(); @@ -34,7 +33,7 @@ public: void tick(float dt); - void changeModel(std::shared_ptr incoming); + void changeModel(BaseModelInfo* incoming); virtual void setRotation(const glm::quat& r); diff --git a/rwengine/src/objects/ItemPickup.cpp b/rwengine/src/objects/ItemPickup.cpp index cedea85a..4f64dcb2 100644 --- a/rwengine/src/objects/ItemPickup.cpp +++ b/rwengine/src/objects/ItemPickup.cpp @@ -5,8 +5,9 @@ #include ItemPickup::ItemPickup(GameWorld *world, const glm::vec3 &position, - PickupType type, InventoryItem *item) - : PickupObject(world, position, item->getModelID(), type), item(item) { + BaseModelInfo *modelinfo, PickupType type, + InventoryItem *item) + : PickupObject(world, position, modelinfo, type), item(item) { RW_CHECK(item != nullptr, "Pickup created with null item"); } diff --git a/rwengine/src/objects/ItemPickup.hpp b/rwengine/src/objects/ItemPickup.hpp index 9181f42c..90dccb69 100644 --- a/rwengine/src/objects/ItemPickup.hpp +++ b/rwengine/src/objects/ItemPickup.hpp @@ -14,7 +14,7 @@ class ItemPickup : public PickupObject { InventoryItem* item; public: - ItemPickup(GameWorld* world, const glm::vec3& position, PickupType type, + ItemPickup(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo, PickupType type, InventoryItem* item); bool onCharacterTouch(CharacterObject* character); diff --git a/rwengine/src/objects/PickupObject.cpp b/rwengine/src/objects/PickupObject.cpp index 34b4a618..3015ef67 100644 --- a/rwengine/src/objects/PickupObject.cpp +++ b/rwengine/src/objects/PickupObject.cpp @@ -59,13 +59,12 @@ uint32_t PickupObject::behaviourFlags(PickupType type) { } PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, - int modelID, PickupType type) - : GameObject(world, position, glm::quat(), nullptr) + BaseModelInfo* modelinfo, PickupType type) + : GameObject(world, position, glm::quat(), modelinfo, nullptr) , m_ghost(nullptr) , m_shape(nullptr) , m_enabled(false) , m_collected(false) - , m_model(modelID) , m_type(type) { btTransform tf; tf.setIdentity(); diff --git a/rwengine/src/objects/PickupObject.hpp b/rwengine/src/objects/PickupObject.hpp index 2e2f6c22..ddf346eb 100644 --- a/rwengine/src/objects/PickupObject.hpp +++ b/rwengine/src/objects/PickupObject.hpp @@ -37,15 +37,11 @@ public: static float respawnTime(PickupType type); static uint32_t behaviourFlags(PickupType type); - PickupObject(GameWorld* world, const glm::vec3& position, int modelID, + PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo *modelinfo, PickupType type); ~PickupObject(); - int getModelID() const { - return m_model; - } - Type type() { return Pickup; } @@ -76,7 +72,6 @@ private: bool m_enabled; float m_enableTimer; bool m_collected; - int m_model; VisualFX* m_corona; PickupType m_type; diff --git a/rwengine/src/objects/ProjectileObject.cpp b/rwengine/src/objects/ProjectileObject.cpp index 2150c9c3..c99960cc 100644 --- a/rwengine/src/objects/ProjectileObject.cpp +++ b/rwengine/src/objects/ProjectileObject.cpp @@ -107,7 +107,7 @@ void ProjectileObject::cleanup() { ProjectileObject::ProjectileObject(GameWorld* world, const glm::vec3& position, const ProjectileObject::ProjectileInfo& info) - : GameObject(world, position, glm::quat(), nullptr) + : GameObject(world, position, glm::quat(), nullptr, nullptr) , _info(info) , _body(nullptr) , _ghostBody(nullptr) diff --git a/rwengine/src/objects/VehicleInfo.hpp b/rwengine/src/objects/VehicleInfo.hpp index a47b3437..adead690 100644 --- a/rwengine/src/objects/VehicleInfo.hpp +++ b/rwengine/src/objects/VehicleInfo.hpp @@ -6,8 +6,6 @@ #include #include -struct VehicleData; - /** * @brief Stores data loaded from handling.cfg */ diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 19cfd2d5..d43403a4 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -84,14 +84,13 @@ private: VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, - VehicleDataHandle data, VehicleInfoHandle info, + BaseModelInfo *modelinfo, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec) - : GameObject(engine, pos, rot, model) + : GameObject(engine, pos, rot, modelinfo, model) , steerAngle(0.f) , throttle(0.f) , brake(0.f) , handbrake(true) - , vehicle(data) , info(info) , colourPrimary(prim) , colourSecondary(sec) @@ -99,7 +98,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, , physRaycaster(nullptr) , physVehicle(nullptr) { collision = new CollisionInstance; - if (collision->createPhysicsBody(this, data->modelName, nullptr, + if (collision->createPhysicsBody(this, modelinfo->name, nullptr, &info->handling)) { physRaycaster = new VehicleRaycaster(this, engine->dynamicsWorld); btRaycastVehicle::btVehicleTuning tuning; @@ -127,7 +126,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, bool front = connection.y() > 0; btWheelInfo& wi = physVehicle->addWheel( connection, btVector3(0.f, 0.f, -1.f), btVector3(1.f, 0.f, 0.f), - restLength, data->wheelScale / 2.f, tuning, front); + restLength, getVehicle()->wheelscale_ / 2.f, tuning, front); wi.m_suspensionRestLength1 = restLength; wi.m_raycastInfo.m_suspensionLength = 0.f; @@ -282,7 +281,7 @@ void VehicleObject::tickPhysics(float dt) { seat.second->updateTransform(passPosition, getRotation()); } - if (vehicle->type == VehicleData::BOAT) { + if (getVehicle()->vehicletype_ == VehicleModelInfo::BOAT) { if (isInWater()) { float sign = std::signbit(steerAngle) ? -1.f : 1.f; float steer = @@ -356,6 +355,7 @@ void VehicleObject::tickPhysics(float dt) { } } + auto isBoat = getVehicle()->vehicletype_ == VehicleModelInfo::BOAT; if (inWater) { // Ensure that vehicles don't fall asleep at the top of a wave. if (!collision->getBulletBody()->isActive()) { @@ -367,15 +367,13 @@ void VehicleObject::tickPhysics(float dt) { float oZ = 0.f; oZ = -bbZ / 2.f + (bbZ * (info->handling.percentSubmerged / 120.f)); - if (vehicle->type != VehicleData::BOAT) { + if (isBoat) { + oZ = 0.f; + } else { // Damper motion collision->getBulletBody()->setDamping(0.95f, 0.9f); } - if (vehicle->type == VehicleData::BOAT) { - oZ = 0.f; - } - // Boats, Buoyancy offset is affected by the orientation of the // chassis. // Vehicles, it isn't. @@ -399,7 +397,7 @@ void VehicleObject::tickPhysics(float dt) { applyWaterFloat(vRt); applyWaterFloat(vLeft); } else { - if (vehicle->type == VehicleData::BOAT) { + if (isBoat) { collision->getBulletBody()->setDamping(0.1f, 0.8f); } else { collision->getBulletBody()->setDamping(0.05f, 0.0f); diff --git a/rwengine/src/objects/VehicleObject.hpp b/rwengine/src/objects/VehicleObject.hpp index 34b2be8c..46edb696 100644 --- a/rwengine/src/objects/VehicleObject.hpp +++ b/rwengine/src/objects/VehicleObject.hpp @@ -24,7 +24,6 @@ private: bool handbrake; public: - VehicleDataHandle vehicle; VehicleInfoHandle info; glm::u8vec3 colourPrimary; glm::u8vec3 colourSecondary; @@ -50,7 +49,7 @@ public: std::map dynamicParts; VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - const ModelRef& model, VehicleDataHandle data, + const ModelRef& model, BaseModelInfo* modelinfo, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec); @@ -60,6 +59,10 @@ public: void setRotation(const glm::quat& orientation); + VehicleModelInfo* getVehicle() const { + return getModelInfo(); + } + Type type() { return Vehicle; } diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index e9e7d6b6..3b672287 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -51,9 +51,9 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g, dp.visibility = 1.f; if (object && object->type() == GameObject::Instance) { - auto instance = static_cast(object); + auto modelinfo = object->getModelInfo(); dp.depthWrite = - !(instance->object->flags & ObjectData::NO_ZBUFFER_WRITE); + !(modelinfo->flags & SimpleModelInfo::NO_ZBUFFER_WRITE); } if (model->geometries[g]->materials.size() > subgeom.material) { @@ -163,11 +163,10 @@ void ObjectRenderer::renderItem(InventoryItem* item, return; // No model for this item } - std::shared_ptr odata = - m_world->data->findObjectType(item->getModelID()); + auto odata = m_world->data->modelinfo[item->getModelID()].get(); auto weapons = m_world->data->models["weapons"]; if (weapons && weapons->resource) { - auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0"); + auto itemModel = weapons->resource->findFrame(odata->name + "_l0"); auto matrix = glm::inverse(itemModel->getTransform()); if (itemModel) { renderFrame(weapons->resource, itemModel, modelMatrix * matrix, @@ -187,15 +186,17 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, return; } + auto modelinfo = instance->getModelInfo(); + // Handles times provided by TOBJ data const auto currentHour = m_world->getHour(); - if (instance->object->timeOff < instance->object->timeOn) { - if (currentHour >= instance->object->timeOff && - currentHour < instance->object->timeOn) + if (modelinfo->timeOff < modelinfo->timeOn) { + if (currentHour >= modelinfo->timeOff && + currentHour < modelinfo->timeOn) return; } else { - if (currentHour >= instance->object->timeOff || - currentHour < instance->object->timeOn) + if (currentHour >= modelinfo->timeOff || + currentHour < modelinfo->timeOn) return; } @@ -216,17 +217,20 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, float opacity = 0.f; constexpr float fadeRange = 50.f; - if (instance->object->numClumps == 1) { + /// @todo replace this block with the correct logic + if (modelinfo->getNumAtomics() == 1) { // Is closest point greater than the *object* draw distance - float objectRange = instance->object->drawDistance[0]; + float objectRange = modelinfo->getLodDistance(0); float overlap = (mindist - objectRange); if (mindist > objectRange) { // Check for LOD instances if (instance->LODinstance) { // Is the closest point greater than the *LOD* draw distance - float LODrange = instance->LODinstance->object->drawDistance[0]; - if (mindist > LODrange) { - } else if (instance->LODinstance->model->resource) { + auto lodmodelinfo = + instance->LODinstance->getModelInfo(); + float LODrange = lodmodelinfo->getLodDistance(0); + if (mindist <= LODrange && + instance->LODinstance->model->resource) { // The model matrix needs to be for the LOD instead matrixModel = instance->LODinstance->getTimeAdjustedTransform( @@ -249,7 +253,7 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, } } // Otherwise, if we aren't marked as a LOD model, we can render - else if (!instance->object->LOD) { + else if (!modelinfo->LOD) { model = instance->model->resource; } } else { @@ -260,9 +264,9 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, matrixModel *= root->getTransform(); - for (int i = 0; i < instance->object->numClumps - 1; ++i) { - auto ind = (instance->object->numClumps - 1) - i; - float lodDistance = instance->object->drawDistance[i]; + for (int i = 0; i < modelinfo->getNumAtomics() - 1; ++i) { + auto ind = (modelinfo->getNumAtomics() - 1) - i; + float lodDistance = modelinfo->getLodDistance(i); if (mindist > lodDistance) { fadingFrame = root->getChildren()[ind]; fadingModel = objectModel; @@ -372,10 +376,11 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, renderFrame(vehicle->model->resource, vehicle->model->resource->frames[0], matrixModel, vehicle, 1.f, outList); + auto modelinfo = vehicle->getVehicle(); // Draw wheels n' stuff for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) { - auto woi = m_world->data->findObjectType( - vehicle->vehicle->wheelModelID); + auto woi = m_world->data->findModelInfo( + modelinfo->wheelmodel_); if (woi) { Model* wheelModel = m_world->data->models["wheels"]->resource; auto& wi = vehicle->physVehicle->getWheelInfo(w); @@ -406,12 +411,12 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, wheelM = matrixModel * wheelM; wheelM = - glm::scale(wheelM, glm::vec3(vehicle->vehicle->wheelScale)); + glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_)); if (wi.m_chassisConnectionPointCS.x() < 0.f) { wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f)); } - renderWheel(vehicle, wheelModel, wheelM, woi->modelName, + renderWheel(vehicle, wheelModel, wheelM, woi->name, outList); } } @@ -425,25 +430,24 @@ void ObjectRenderer::renderPickup(PickupObject* pickup, RenderList& outList) { modelMatrix = glm::rotate(modelMatrix, m_world->getGameTime(), glm::vec3(0.f, 0.f, 1.f)); - auto odata = - m_world->data->findObjectType(pickup->getModelID()); + auto odata = pickup->getModelInfo(); Model* model = nullptr; ModelFrame* itemModel = nullptr; /// @todo Better determination of is this object a weapon. - if (odata->ID >= 170 && odata->ID <= 184) { + if (odata->id() >= 170 && odata->id() <= 184) { auto weapons = m_world->data->models["weapons"]; if (weapons && weapons->resource && odata) { model = weapons->resource; - itemModel = weapons->resource->findFrame(odata->modelName + "_l0"); + itemModel = weapons->resource->findFrame(odata->name + "_l0"); RW_CHECK(itemModel, "Weapon Frame not present int weapon model"); if (!itemModel) { return; } } } else { - auto handle = m_world->data->models[odata->modelName]; + auto handle = m_world->data->models[odata->name]; RW_CHECK(handle && handle->resource, "Pickup has no model"); if (handle && handle->resource) { model = handle->resource; @@ -505,14 +509,14 @@ void ObjectRenderer::renderProjectile(ProjectileObject* projectile, RenderList& outList) { glm::mat4 modelMatrix = projectile->getTimeAdjustedTransform(m_renderAlpha); - auto odata = m_world->data->findObjectType( + auto odata = m_world->data->findModelInfo( projectile->getProjectileInfo().weapon->modelID); auto weapons = m_world->data->models["weapons"]; RW_CHECK(weapons, "Weapons model not loaded"); if (weapons && weapons->resource) { - auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0"); + auto itemModel = weapons->resource->findFrame(odata->name + "_l0"); auto matrix = glm::inverse(itemModel->getTransform()); RW_CHECK(itemModel, "Weapon frame not in model"); if (itemModel) { diff --git a/rwengine/src/script/ScriptFunctions.hpp b/rwengine/src/script/ScriptFunctions.hpp index 1b1c0ca7..b20226d9 100644 --- a/rwengine/src/script/ScriptFunctions.hpp +++ b/rwengine/src/script/ScriptFunctions.hpp @@ -31,11 +31,11 @@ inline VehicleObject* getCharacterVehicle(CharacterObject* character) { } inline bool isInModel(const ScriptArguments& args, CharacterObject* character, int model) { - auto data = args.getWorld()->data->findObjectType(model); + auto data = args.getWorld()->data->findModelInfo(model); if (data) { auto vehicle = getCharacterVehicle(character); if (vehicle) { - return vehicle->model ? vehicle->model->name == data->modelName + return vehicle->model ? vehicle->model->name == data->name : false; } } diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index 7f1b92ab..d5eeb808 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -3546,12 +3546,8 @@ void opcode_0136(const ScriptArguments& args, const ScriptInt arg1, const Script @arg model Model ID */ bool opcode_0137(const ScriptArguments& args, const ScriptVehicle vehicle, const ScriptModelID model) { - auto data = args.getWorld()->data->findObjectType(model); - RW_CHECK(data, "non-vehicle model ID"); - if (data) { - return vehicle->model->name == data->modelName; - } - return false; + RW_UNUSED(args); + return vehicle->getVehicle()->id() == model; } /** @@ -8156,7 +8152,11 @@ void opcode_02dd(const ScriptArguments& args, const ScriptString areaName, Scrip bool opcode_02de(const ScriptArguments& args, const ScriptPlayer player) { RW_UNUSED(args); auto vehicle = player->getCharacter()->getCurrentVehicle(); - return (vehicle && (vehicle->vehicle->classType & VehicleData::TAXI) == VehicleData::TAXI); + if (!vehicle) { + return false; + } + auto type = vehicle->getVehicle()->vehicleclass_; + return (type & VehicleModelInfo::TAXI) == VehicleModelInfo::TAXI; } /** @@ -10063,7 +10063,8 @@ void opcode_0363(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa InstanceObject* object = static_cast(i.second); // Check if this instance has the correct model id, early out if it isn't - if (!boost::iequals(object->object->modelName, modelName)) { + auto modelinfo = object->getModelInfo(); + if (!boost::iequals(modelinfo->name, modelName)) { continue; } @@ -11343,7 +11344,7 @@ void opcode_03b6(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa std::transform(oldmodel.begin(), oldmodel.end(), oldmodel.begin(), ::tolower); auto newobjectid = args.getWorld()->data->findModelObject(newmodel); - auto nobj = args.getWorld()->data->findObjectType(newobjectid); + auto nobj = args.getWorld()->data->findModelInfo(newobjectid); /// @todo Objects need to adopt the new object ID, not just the model. for(auto p : args.getWorld()->instancePool.objects) { diff --git a/rwgame/DrawUI.cpp b/rwgame/DrawUI.cpp index 7994bd39..ede27471 100644 --- a/rwgame/DrawUI.cpp +++ b/rwgame/DrawUI.cpp @@ -157,10 +157,10 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world, if (current) { uint16_t model = current->getModelID(); if (model > 0) { - ObjectDataPtr weaponData = - world->data->findObjectType(model); + auto weaponData = + world->data->findModelInfo(model); if (weaponData != nullptr) { - itemTextureName = weaponData->modelName; + itemTextureName = weaponData->name; } } } diff --git a/rwgame/states/IngameState.cpp b/rwgame/states/IngameState.cpp index 88c22b1d..cd4cf76a 100644 --- a/rwgame/states/IngameState.cpp +++ b/rwgame/states/IngameState.cpp @@ -116,16 +116,15 @@ void IngameState::startTest() { auto carRot = glm::angleAxis(glm::radians(90.f), glm::vec3(0.f, 0.f, 1.f)); // auto boatPos = glm::vec3( -1000.f, -1040.f, 5.f ); int i = 0; - for (auto& vi : getWorld()->data->objectTypes) { + for (auto& vi : getWorld()->data->modelinfo) { switch (vi.first) { case 140: continue; case 141: continue; } - if (vi.second->class_type == ObjectInformation::_class("CARS")) { + if (vi.second->type() == ModelDataType::VehicleInfo) { if (i++ > 20) break; - auto vehicle = std::static_pointer_cast(vi.second); auto& sp = carPos; auto& sr = carRot; diff --git a/rwviewer/ItemListModel.cpp b/rwviewer/ItemListModel.cpp index bff04e88..0aab0530 100644 --- a/rwviewer/ItemListModel.cpp +++ b/rwviewer/ItemListModel.cpp @@ -2,7 +2,7 @@ #include qint16 ItemListModel::getIDOf(unsigned int row) const { - if (row < world()->data->objectTypes.size()) { + if (row < world()->data->modelinfo.size()) { return row; } @@ -14,7 +14,7 @@ ItemListModel::ItemListModel(GameWorld *world, QObject *parent) } int ItemListModel::rowCount(const QModelIndex &parent) const { - return _world->data->objectTypes.size(); + return _world->data->modelinfo.size(); } int ItemListModel::columnCount(const QModelIndex &parent) const { diff --git a/rwviewer/ViewerWidget.cpp b/rwviewer/ViewerWidget.cpp index a2d9d8f6..57b3a69d 100644 --- a/rwviewer/ViewerWidget.cpp +++ b/rwviewer/ViewerWidget.cpp @@ -177,16 +177,21 @@ void ViewerWidget::showObject(qint16 item) { if (dummyObject) gworld->destroyObject(dummyObject); - auto def = world()->data->objectTypes[item]; + auto def = world()->data->modelinfo[item].get(); if (def) { - if (def->class_type == ObjectData::class_id) { - dummyObject = gworld->createInstance(item, {}); - } else if (def->class_type == CharacterData::class_id) { - dummyObject = gworld->createPedestrian(item, {}); - } else if (def->class_type == VehicleData::class_id) { - dummyObject = gworld->createVehicle(item, {}); + switch (def->type()) { + default: + dummyObject = gworld->createInstance(item, {}); + break; + case ModelDataType::PedInfo: + dummyObject = gworld->createPedestrian(item, {}); + break; + case ModelDataType::VehicleInfo: + dummyObject = gworld->createVehicle(item, {}); + break; } + RW_CHECK(dummyObject != nullptr, "Dummy Object is null"); if (dummyObject != nullptr) { activeModel = dummyObject->model->resource; diff --git a/rwviewer/models/ObjectListModel.cpp b/rwviewer/models/ObjectListModel.cpp index f8bb4749..6c14d36b 100644 --- a/rwviewer/models/ObjectListModel.cpp +++ b/rwviewer/models/ObjectListModel.cpp @@ -5,19 +5,13 @@ ObjectListModel::ObjectListModel(GameData *dat, QObject *parent) } int ObjectListModel::rowCount(const QModelIndex &parent) const { - return _gameData->objectTypes.size(); + return _gameData->modelinfo.size(); } int ObjectListModel::columnCount(const QModelIndex &parent) const { return 3; } -static std::map gDataType = { - {ObjectInformation::_class("OBJS"), "Object"}, - {ObjectInformation::_class("CARS"), "Vehicle"}, - {ObjectInformation::_class("PEDS"), "Pedestrian"}, - {ObjectInformation::_class("HIER"), "Cutscene"}}; - QVariant ObjectListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { auto id = index.internalId(); @@ -25,23 +19,12 @@ QVariant ObjectListModel::data(const QModelIndex &index, int role) const { if (index.column() == 0) { return id; } else if (index.column() == 1) { - auto object = _gameData->objectTypes[id]; - if (gDataType[object->class_type].isEmpty()) { - return QString("Unknown"); - } - return gDataType[object->class_type]; + auto object = _gameData->modelinfo[id].get(); + return QString::fromStdString( + BaseModelInfo::getTypeName(object->type())); } else if (index.column() == 2) { - auto object = _gameData->objectTypes[id]; - if (object->class_type == ObjectData::class_id) { - auto v = std::static_pointer_cast(object); - return QString::fromStdString(v->modelName); - } else if (object->class_type == VehicleData::class_id) { - auto v = std::static_pointer_cast(object); - return QString::fromStdString(v->modelName); - } else if (object->class_type == CharacterData::class_id) { - auto v = std::static_pointer_cast(object); - return QString::fromStdString(v->modelName); - } + auto object = _gameData->modelinfo[id].get(); + return QString::fromStdString(object->name); } } return QVariant::Invalid; @@ -64,9 +47,9 @@ QVariant ObjectListModel::headerData(int section, Qt::Orientation orientation, QModelIndex ObjectListModel::index(int row, int column, const QModelIndex &parent) const { - auto it = _gameData->objectTypes.begin(); + auto it = _gameData->modelinfo.begin(); for (int i = 0; i < row; i++) it++; - auto id = it->second->ID; + auto id = it->second->id(); return hasIndex(row, column, parent) ? createIndex(row, column, id) : QModelIndex(); diff --git a/rwviewer/views/ObjectViewer.cpp b/rwviewer/views/ObjectViewer.cpp index 8d2fe912..0e81dae3 100644 --- a/rwviewer/views/ObjectViewer.cpp +++ b/rwviewer/views/ObjectViewer.cpp @@ -60,30 +60,14 @@ void ObjectViewer::worldChanged() { SLOT(showItem(QModelIndex))); } -static std::map gDataType = { - {ObjectInformation::_class("OBJS"), "Object"}, - {ObjectInformation::_class("CARS"), "Vehicle"}, - {ObjectInformation::_class("PEDS"), "Pedestrian"}, - {ObjectInformation::_class("HIER"), "Cutscene"}}; - void ObjectViewer::showItem(qint16 item) { - auto def = world()->data->objectTypes[item]; + auto def = world()->data->modelinfo[item].get(); if (def) { - previewID->setText(QString::number(def->ID)); - previewClass->setText(gDataType[def->class_type]); - - if (def->class_type == ObjectData::class_id) { - auto v = std::static_pointer_cast(def); - previewModel->setText(QString::fromStdString(v->modelName)); - } else if (def->class_type == VehicleData::class_id) { - auto v = std::static_pointer_cast(def); - previewModel->setText(QString::fromStdString(v->modelName)); - } else if (def->class_type == CharacterData::class_id) { - auto v = std::static_pointer_cast(def); - previewModel->setText(QString::fromStdString(v->modelName)); - } - + previewID->setText(QString::number(def->id())); + previewClass->setText( + QString::fromStdString(BaseModelInfo::getTypeName(def->type()))); + previewModel->setText(QString::fromStdString(def->name)); previewWidget->showObject(item); } } diff --git a/tests/test_GameData.cpp b/tests/test_GameData.cpp index ba7a56b5..0d02edb7 100644 --- a/tests/test_GameData.cpp +++ b/tests/test_GameData.cpp @@ -12,16 +12,16 @@ BOOST_AUTO_TEST_CASE(test_object_data) { gd.load(); { - auto def = gd.findObjectType(1100); + auto def = gd.findModelInfo(1100); BOOST_REQUIRE(def); - BOOST_ASSERT(def->class_type == ObjectInformation::_class("OBJS")); + BOOST_ASSERT(def->type() == ModelDataType::SimpleInfo); - BOOST_CHECK_EQUAL(def->modelName, "rd_Corner1"); - BOOST_CHECK_EQUAL(def->textureName, "generic"); - BOOST_CHECK_EQUAL(def->numClumps, 1); - BOOST_CHECK_EQUAL(def->drawDistance[0], 220); + BOOST_CHECK_EQUAL(def->name, "rd_Corner1"); + BOOST_CHECK_EQUAL(def->textureslot, "generic"); + BOOST_CHECK_EQUAL(def->getNumAtomics(), 1); + BOOST_CHECK_EQUAL(def->getLodDistance(0), 220); BOOST_CHECK_EQUAL(def->flags, 0); } } diff --git a/tests/test_buoyancy.cpp b/tests/test_buoyancy.cpp index 180b82d7..0839f7e3 100644 --- a/tests/test_buoyancy.cpp +++ b/tests/test_buoyancy.cpp @@ -14,7 +14,7 @@ BOOST_AUTO_TEST_CASE(test_vehicle_buoyancy) { BOOST_REQUIRE(vehicle != nullptr); BOOST_REQUIRE(vehicle->info != nullptr); - BOOST_REQUIRE(vehicle->vehicle != nullptr); + BOOST_REQUIRE(vehicle->getVehicle() != nullptr); // Relies on tile 0,0 being watered... diff --git a/tests/test_object_data.cpp b/tests/test_object_data.cpp index a70b2584..91c6a448 100644 --- a/tests/test_object_data.cpp +++ b/tests/test_object_data.cpp @@ -13,16 +13,16 @@ BOOST_AUTO_TEST_CASE(test_object_data) { BOOST_ASSERT(l.objects.find(1100) != l.objects.end()); - auto obj = l.objects[1100]; + auto obj = l.objects[1100].get(); - auto def = std::dynamic_pointer_cast(obj); + auto def = dynamic_cast(obj); - BOOST_ASSERT(def->class_type == ObjectInformation::_class("OBJS")); + BOOST_ASSERT(def->type() == ModelDataType::SimpleInfo); - BOOST_CHECK_EQUAL(def->modelName, "rd_Corner1"); - BOOST_CHECK_EQUAL(def->textureName, "generic"); - BOOST_CHECK_EQUAL(def->numClumps, 1); - BOOST_CHECK_EQUAL(def->drawDistance[0], 220); + BOOST_CHECK_EQUAL(def->name, "rd_Corner1"); + BOOST_CHECK_EQUAL(def->textureslot, "generic"); + BOOST_CHECK_EQUAL(def->getNumAtomics(), 1); + BOOST_CHECK_EQUAL(def->getLodDistance(0), 220); BOOST_CHECK_EQUAL(def->flags, 0); } { @@ -32,21 +32,21 @@ BOOST_AUTO_TEST_CASE(test_object_data) { BOOST_ASSERT(l.objects.find(90) != l.objects.end()); - auto obj = l.objects[90]; + auto obj = l.objects[90].get(); - auto def = std::dynamic_pointer_cast(obj); + auto def = dynamic_cast(obj); - BOOST_ASSERT(def->class_type == ObjectInformation::_class("CARS")); + BOOST_ASSERT(def->type() == ModelDataType::VehicleInfo); - BOOST_CHECK_EQUAL(def->modelName, "landstal"); - BOOST_CHECK_EQUAL(def->textureName, "landstal"); - BOOST_CHECK_EQUAL(def->type, VehicleData::CAR); - BOOST_CHECK_EQUAL(def->handlingID, "LANDSTAL"); - BOOST_CHECK_EQUAL(def->gameName, "LANDSTK"); - BOOST_CHECK_EQUAL(def->classType, VehicleData::RICHFAMILY); - BOOST_CHECK_EQUAL(def->frequency, 10); - BOOST_CHECK_EQUAL(def->wheelModelID, 164); - BOOST_CHECK_CLOSE(def->wheelScale, 0.8f, 0.01f); + BOOST_CHECK_EQUAL(def->name, "landstal"); + BOOST_CHECK_EQUAL(def->textureslot, "landstal"); + BOOST_CHECK_EQUAL(def->vehicletype_, VehicleModelInfo::CAR); + BOOST_CHECK_EQUAL(def->handling_, "LANDSTAL"); + BOOST_CHECK_EQUAL(def->vehiclename_, "LANDSTK"); + BOOST_CHECK_EQUAL(def->vehicleclass_, VehicleModelInfo::RICHFAMILY); + BOOST_CHECK_EQUAL(def->frequency_, 10); + BOOST_CHECK_EQUAL(def->wheelmodel_, 164); + BOOST_CHECK_CLOSE(def->wheelscale_, 0.8f, 0.01f); } } diff --git a/tests/test_pickup.cpp b/tests/test_pickup.cpp index 88202a51..aeca2253 100644 --- a/tests/test_pickup.cpp +++ b/tests/test_pickup.cpp @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(test_item_pickup) { BOOST_REQUIRE(item != nullptr); ItemPickup* p = new ItemPickup(Global::get().e, {30.f, 0.f, 0.f}, - PickupObject::OnStreet, item); + nullptr, PickupObject::OnStreet, item); Global::get().e->allObjects.push_back(p); diff --git a/tests/test_vehicle.cpp b/tests/test_vehicle.cpp index 503826da..b5cb8dfa 100644 --- a/tests/test_vehicle.cpp +++ b/tests/test_vehicle.cpp @@ -14,10 +14,11 @@ BOOST_AUTO_TEST_CASE(test_create_vehicle) { BOOST_REQUIRE(vehicle != nullptr); BOOST_REQUIRE(vehicle->info != nullptr); - BOOST_REQUIRE(vehicle->vehicle != nullptr); + BOOST_REQUIRE(vehicle->getVehicle() != nullptr); // Hardcoded values for the moment - BOOST_CHECK_EQUAL(vehicle->vehicle->type, VehicleData::CAR); + BOOST_CHECK_EQUAL(vehicle->getVehicle()->vehicletype_, + VehicleModelInfo::CAR); BOOST_CHECK_EQUAL(vehicle->info->wheels.size(), 4); @@ -76,7 +77,7 @@ BOOST_AUTO_TEST_CASE(test_door_position) { BOOST_REQUIRE(vehicle != nullptr); BOOST_REQUIRE(vehicle->info != nullptr); - BOOST_REQUIRE(vehicle->vehicle != nullptr); + BOOST_REQUIRE(vehicle->getVehicle() != nullptr); BOOST_CHECK(vehicle->getSeatEntryPositionWorld(0).x > 5.f); From 6888fa355890f33fc49a190cd4c72ebca9a33094 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 11 Sep 2016 14:46:23 +0100 Subject: [PATCH 05/14] Load and associate MODELFILE entries --- rwengine/src/engine/GameData.cpp | 39 ++++++++++++++++++++++++++++++++ rwengine/src/engine/GameData.hpp | 5 ++++ tests/test_data.cpp | 10 ++++++++ 3 files changed, 54 insertions(+) diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 1396c3d1..79eab78e 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -99,6 +99,9 @@ void GameData::loadLevelFile(const std::string& path) { std::transform(name.begin(), name.end(), name.begin(), ::tolower); loadTXD(name); + } else if (cmd == "MODELFILE") { + auto path = line.substr(space + 1); + loadModelFile(path); } } } @@ -333,6 +336,42 @@ void GameData::loadDFF(const std::string& name, bool async) { } } +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; + } + auto m = l.loadFromMemory(file); + if (!m) { + logger->log("Data", Logger::Error, "Error loading model file " + name); + return; + } + + // Associate the frames with models. + 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); + } + for (auto& model : modelinfo) { + auto info = model.second.get(); + if (info->type() != ModelDataType::SimpleInfo) { + continue; + } + if (boost::iequals(info->name, name)) { + auto simple = static_cast(info); + simple->setAtomic(m, lod, frame); + } + } + } +} + void GameData::loadIFP(const std::string& name) { auto f = index.openFile(name); diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index e692ec55..1dad126f 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -123,6 +123,11 @@ public: */ void loadDFF(const std::string& name, bool async = false); + /** + * Loads a DFF and associates its atomics with models. + */ + void loadModelFile(const std::string& name); + /** * Loads an IFP file containing animations */ diff --git a/tests/test_data.cpp b/tests/test_data.cpp index a6493878..54481fec 100644 --- a/tests/test_data.cpp +++ b/tests/test_data.cpp @@ -83,6 +83,16 @@ BOOST_AUTO_TEST_CASE(test_handling_data_loader) { BOOST_CHECK_EQUAL(handling.driveType, VehicleHandlingInfo::All); BOOST_CHECK_EQUAL(handling.engineType, VehicleHandlingInfo::Petrol); } + +BOOST_AUTO_TEST_CASE(test_model_files_loaded) { + auto& d = Global::get().d; + + // The weapon models should be associated by the MODELFILE entries + auto ak47 = d->findModelInfo(171); + + BOOST_CHECK_EQUAL(ak47->name, "ak47"); + BOOST_CHECK_NE(ak47->getAtomic(0), nullptr); +} #endif BOOST_AUTO_TEST_SUITE_END() From 218ffdf66c909008cd5a8f1a98c50656cf584a63 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 11 Sep 2016 17:09:54 +0100 Subject: [PATCH 06/14] Load and associate model data when creating objects --- rwengine/src/data/ModelData.hpp | 8 ++++ rwengine/src/engine/GameData.cpp | 72 ++++++++++++++++++++++++++++--- rwengine/src/engine/GameData.hpp | 10 +++++ rwengine/src/engine/GameWorld.cpp | 23 ++++++++++ tests/test_data.cpp | 28 ++++++++++++ 5 files changed, 135 insertions(+), 6 deletions(-) diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index d3a60363..4097e206 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -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; }; diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 79eab78e..1148d479 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -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(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(info); + clump->setModel(m); + /// @todo how is LOD handled for clump objects? + } +} + void GameData::loadIFP(const std::string& name) { auto f = index.openFile(name); diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index 1dad126f..db73b40b 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -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 */ diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index f03bcec5..df02e00f 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -164,6 +164,12 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, const glm::quat& rot) { auto oi = data->findModelInfo(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(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"); diff --git a/tests/test_data.cpp b/tests/test_data.cpp index 54481fec..3b9d674e 100644 --- a/tests/test_data.cpp +++ b/tests/test_data.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #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(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(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() From 6951434be8ecd01851c964d2f948c7c89303a366 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 11 Sep 2016 20:04:07 +0100 Subject: [PATCH 07/14] Load objects directly --- rwengine/src/data/ModelData.hpp | 5 + rwengine/src/engine/GameData.cpp | 19 ++ rwengine/src/engine/GameData.hpp | 5 + rwengine/src/engine/GameWorld.cpp | 302 +++++++----------- rwengine/src/items/WeaponItem.cpp | 2 +- rwengine/src/objects/CharacterObject.cpp | 30 +- rwengine/src/objects/CharacterObject.hpp | 4 +- rwengine/src/objects/CutsceneObject.cpp | 14 +- rwengine/src/objects/CutsceneObject.hpp | 3 +- rwengine/src/objects/GameObject.hpp | 31 +- rwengine/src/objects/InstanceObject.cpp | 20 +- rwengine/src/objects/InstanceObject.hpp | 6 +- rwengine/src/objects/PickupObject.cpp | 2 +- rwengine/src/objects/ProjectileObject.cpp | 2 +- rwengine/src/objects/VehicleObject.cpp | 16 +- rwengine/src/objects/VehicleObject.hpp | 5 +- rwengine/src/render/ObjectRenderer.cpp | 38 +-- rwengine/src/script/ScriptFunctions.hpp | 3 +- .../src/script/modules/GTA3ModuleImpl.inl | 15 +- rwgame/states/DebugState.cpp | 3 +- rwgame/states/IngameState.cpp | 4 +- rwviewer/ViewerWidget.cpp | 2 +- tests/test_character.cpp | 2 +- tests/test_vehicle.cpp | 4 +- tests/test_weapon.cpp | 2 +- 25 files changed, 267 insertions(+), 272 deletions(-) diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index 4097e206..3fb70ef5 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -126,6 +126,11 @@ public: atomics_[n] = atomic; } + /// @todo remove this + Model* getModel() const { + return model_; + } + ModelFrame* getAtomic(int n) const { return atomics_[n]; } diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 1148d479..fdaa3dbb 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -344,6 +344,21 @@ void GameData::getNameAndLod(std::string& name, int& lod) { } } +Model* GameData::loadClump(const std::string& name) { + auto file = index.openFile(name); + if (!file) { + logger->error("Data", "Failed to load model " + name); + return nullptr; + } + LoaderDFF l; + auto m = l.loadFromMemory(file); + if (!m) { + logger->error("Data", "Error loading model file " + name); + return nullptr; + } + return m; +} + void GameData::loadModelFile(const std::string& name) { auto file = index.openFilePath(name); if (!file) { @@ -386,6 +401,8 @@ void GameData::loadModel(ModelID model) { case ModelDataType::ClumpInfo: // Re-direct the hier objects to the special object ids name = engine->state->specialModels[info->id()]; + /// @todo remove this from here + loadTXD(name + ".txd"); break; case ModelDataType::PedInfo: static const std::string specialPrefix("special"); @@ -393,6 +410,8 @@ void GameData::loadModel(ModelID model) { auto sid = name.substr(specialPrefix.size()); unsigned short specialID = std::atoi(sid.c_str()); name = engine->state->specialCharacters[specialID]; + /// @todo remove this from here + loadTXD(name + ".txd"); break; } default: diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index db73b40b..6486cb3a 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -128,6 +128,11 @@ public: */ static void getNameAndLod(std::string& name, int& lod); + /** + * Loads an archived model and returns it directly + */ + Model* loadClump(const std::string& name); + /** * Loads a DFF and associates its atomics with models. */ diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index df02e00f..7e4a7bf4 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -178,18 +178,10 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, std::transform(std::begin(texturename), std::end(texturename), std::begin(texturename), tolower); - // Ensure the relevant data is loaded. - if (!modelname.empty()) { - if (modelname != "null") { - data->loadDFF(modelname + ".dff", false); - } - } if (!texturename.empty()) { data->loadTXD(texturename + ".txd", true); } - ModelRef m = data->models[modelname]; - // Check for dynamic data. auto dyit = data->dynamicObjectData.find(oi->name); std::shared_ptr dydata; @@ -203,7 +195,7 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, } auto instance = new InstanceObject( - this, pos, rot, m, glm::vec3(1.f, 1.f, 1.f), oi, nullptr, dydata); + this, pos, rot, glm::vec3(1.f, 1.f, 1.f), oi, nullptr, dydata); instancePool.insert(instance); allObjects.push_back(instance); @@ -257,65 +249,34 @@ CutsceneObject* GameWorld::createCutsceneObject(const uint16_t id, const glm::vec3& pos, const glm::quat& rot) { auto modelinfo = data->modelinfo[id].get(); - std::string modelname; + + if (!modelinfo) { + return nullptr; + } + + auto clumpmodel = static_cast(modelinfo); 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; - - /// @todo Store loaded models directly - switch (modelinfo->type()) { - case ModelDataType::ClumpInfo: - // Re-direct the hier objects to the special object ids - modelname = state->specialModels[id]; - texturename = state->specialModels[id]; - break; - case ModelDataType::PedInfo: - static const std::string specialPrefix("special"); - if (!modelname.compare(0, specialPrefix.size(), - specialPrefix)) { - auto sid = modelname.substr(specialPrefix.size()); - unsigned short specialID = std::atoi(sid.c_str()); - modelname = state->specialCharacters[specialID]; - texturename = state->specialCharacters[specialID]; - break; - } - default: - break; - } + /// @todo track if the current cutscene model is loaded + if (true || !modelinfo->isLoaded()) { + data->loadModel(id); } + auto model = clumpmodel->getModel(); + + texturename = modelinfo->textureslot; if (id == 0) { auto playerobj = pedestrianPool.find(state->playerObject); if (playerobj) { - modelname = playerobj->model->name; + model = playerobj->getModel(); } } - // Ensure the relevant data is loaded. - if (modelname.empty()) { - logger->error( - "World", "Cutscene object " + std::to_string(id) + " has no model"); - return nullptr; - } - - if (modelname != "null") { - data->loadDFF(modelname + ".dff", false); - } - if (!texturename.empty()) { data->loadTXD(texturename + ".txd", true); } - ModelRef m = data->models[modelname]; - - auto instance = new CutsceneObject(this, pos, rot, m, modelinfo); + auto instance = new CutsceneObject(this, pos, rot, model, modelinfo); cutscenePool.insert(instance); allObjects.push_back(instance); @@ -327,83 +288,76 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot, GameObjectID gid) { auto vti = data->findModelInfo(id); - if (vti) { - logger->info("World", "Creating Vehicle ID " + std::to_string(id) + - " (" + vti->vehiclename_ + ")"); + if (!vti) { + return nullptr; + } + logger->info("World", "Creating Vehicle ID " + std::to_string(id) + " (" + + vti->vehiclename_ + ")"); - if (!vti->isLoaded()) { - data->loadModel(id); - } + if (!vti->isLoaded()) { + data->loadModel(id); + } - if (!vti->name.empty()) { - data->loadDFF(vti->name + ".dff"); - } - if (!vti->textureslot.empty()) { - data->loadTXD(vti->textureslot + ".txd"); - } + if (!vti->textureslot.empty()) { + data->loadTXD(vti->textureslot + ".txd"); + } - glm::u8vec3 prim(255), sec(128); - auto palit = data->vehiclePalettes.find( - vti->name); // modelname is conveniently lowercase (usually) - if (palit != data->vehiclePalettes.end() && palit->second.size() > 0) { - std::uniform_int_distribution uniform( - 0, palit->second.size() - 1); - int set = uniform(randomEngine); - prim = data->vehicleColours[palit->second[set].first]; - sec = data->vehicleColours[palit->second[set].second]; - } else { - logger->warning("World", - "No colour palette for vehicle " + vti->name); - } + glm::u8vec3 prim(255), sec(128); + auto palit = data->vehiclePalettes.find( + vti->name); // modelname is conveniently lowercase (usually) + if (palit != data->vehiclePalettes.end() && palit->second.size() > 0) { + std::uniform_int_distribution uniform(0, palit->second.size() - 1); + int set = uniform(randomEngine); + prim = data->vehicleColours[palit->second[set].first]; + sec = data->vehicleColours[palit->second[set].second]; + } else { + logger->warning("World", "No colour palette for vehicle " + vti->name); + } - ModelRef& m = data->models[vti->name]; - auto model = m->resource; - auto info = data->vehicleInfo.find(vti->handling_); - if (model && info != data->vehicleInfo.end()) { - if (info->second->wheels.size() == 0 && - info->second->seats.size() == 0) { - for (const ModelFrame* f : model->frames) { - const std::string& name = f->getName(); + auto model = vti->getModel(); + auto info = data->vehicleInfo.find(vti->handling_); + if (model && info != data->vehicleInfo.end()) { + if (info->second->wheels.size() == 0 && + info->second->seats.size() == 0) { + for (const ModelFrame* f : model->frames) { + const std::string& name = f->getName(); - if (name.size() > 5 && name.substr(0, 5) == "wheel") { - auto frameTrans = f->getMatrix(); - info->second->wheels.push_back( - {glm::vec3(frameTrans[3])}); - } - if (name == "ped_frontseat") { - auto p = f->getDefaultTranslation(); - // Left seat - p.x = -p.x; - info->second->seats.front.push_back({p}); - // Right seat - p.x = -p.x; - info->second->seats.front.push_back({p}); - } - if (name == "ped_backseat") { - // @todo how does this work for the barracks, ambulance - // or coach? - auto p = f->getDefaultTranslation(); - // Left seat - p.x = -p.x; - info->second->seats.back.push_back({p}); - // Right seat - p.x = -p.x; - info->second->seats.back.push_back({p}); - } + if (name.size() > 5 && name.substr(0, 5) == "wheel") { + auto frameTrans = f->getMatrix(); + info->second->wheels.push_back({glm::vec3(frameTrans[3])}); + } + if (name == "ped_frontseat") { + auto p = f->getDefaultTranslation(); + // Left seat + p.x = -p.x; + info->second->seats.front.push_back({p}); + // Right seat + p.x = -p.x; + info->second->seats.front.push_back({p}); + } + if (name == "ped_backseat") { + // @todo how does this work for the barracks, ambulance + // or coach? + auto p = f->getDefaultTranslation(); + // Left seat + p.x = -p.x; + info->second->seats.back.push_back({p}); + // Right seat + p.x = -p.x; + info->second->seats.back.push_back({p}); } } } - - auto vehicle = - new VehicleObject{this, pos, rot, m, vti, info->second, prim, sec}; - vehicle->setGameObjectID(gid); - - vehiclePool.insert(vehicle); - allObjects.push_back(vehicle); - - return vehicle; } - return nullptr; + + auto vehicle = + new VehicleObject{this, pos, rot, vti, info->second, prim, sec}; + vehicle->setGameObjectID(gid); + + vehiclePool.insert(vehicle); + allObjects.push_back(vehicle); + + return vehicle; } CharacterObject* GameWorld::createPedestrian(const uint16_t id, @@ -411,46 +365,26 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::quat& rot, GameObjectID gid) { auto pt = data->findModelInfo(id); - if (pt) { - if (!pt->isLoaded()) { - data->loadModel(id); - } - - std::string modelname = pt->name; - std::string texturename = pt->textureslot; - - // Ensure the relevant data is loaded. - if (!modelname.empty()) { - // Some model names have special meanings. - /// @todo Should CharacterObjects handle this? - static std::string specialPrefix("special"); - if (!modelname.compare(0, specialPrefix.size(), specialPrefix)) { - auto sid = modelname.substr(specialPrefix.size()); - unsigned short specialID = std::atoi(sid.c_str()); - modelname = state->specialCharacters[specialID]; - texturename = state->specialCharacters[specialID]; - } - - if (modelname != "null") { - data->loadDFF(modelname + ".dff"); - } - } - if (!texturename.empty()) { - data->loadTXD(texturename + ".txd"); - } - - ModelRef m = data->models[modelname]; - - if (m && m->resource) { - auto ped = new CharacterObject(this, pos, rot, m, pt); - ped->setGameObjectID(gid); - new DefaultAIController(ped); - pedestrianPool.insert(ped); - allObjects.push_back(ped); - return ped; - } + if (!pt) { + return nullptr; } - return nullptr; + + if (!pt->isLoaded()) { + data->loadModel(id); + } + + std::string texturename = pt->textureslot; + + if (!texturename.empty()) { + data->loadTXD(texturename + ".txd"); + } + + auto ped = new CharacterObject(this, pos, rot, pt); + ped->setGameObjectID(gid); + new DefaultAIController(ped); + pedestrianPool.insert(ped); + allObjects.push_back(ped); + return ped; } CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, @@ -458,28 +392,28 @@ CharacterObject* GameWorld::createPlayer(const glm::vec3& pos, GameObjectID gid) { // Player object ID is hardcoded to 0. auto pt = data->findModelInfo(0); - if (pt) { - // Model name is also hardcoded. - std::string modelname = "player"; - std::string texturename = "player"; - - // Ensure the relevant data is loaded. - data->loadDFF(modelname + ".dff"); - data->loadTXD(texturename + ".txd"); - - ModelRef m = data->models[modelname]; - - if (m && m->resource) { - auto ped = new CharacterObject(this, pos, rot, m, nullptr); - ped->setGameObjectID(gid); - ped->setLifetime(GameObject::PlayerLifetime); - players.push_back(new PlayerController(ped)); - pedestrianPool.insert(ped); - allObjects.push_back(ped); - return ped; - } + if (!pt) { + return nullptr; } - return nullptr; + + // Model name is also hardcoded. + std::string modelname = "player"; + std::string texturename = "player"; + + if (!pt->isLoaded()) { + auto model = data->loadClump(modelname + ".dff"); + pt->setModel(model); + } + + data->loadTXD(texturename + ".txd"); + + auto ped = new CharacterObject(this, pos, rot, pt); + ped->setGameObjectID(gid); + ped->setLifetime(GameObject::PlayerLifetime); + players.push_back(new PlayerController(ped)); + pedestrianPool.insert(ped); + allObjects.push_back(ped); + return ped; } PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { @@ -490,11 +424,10 @@ PickupObject* GameWorld::createPickup(const glm::vec3& pos, int id, int type) { return nullptr; } - if (! modelInfo->isLoaded()) { + if (!modelInfo->isLoaded()) { data->loadModel(id); } - data->loadDFF(modelInfo->name + ".dff"); data->loadTXD(modelInfo->textureslot + ".txd"); PickupObject* pickup = nullptr; @@ -881,7 +814,6 @@ void GameWorld::loadSpecialCharacter(const unsigned short index, ::tolower); /// @todo a bit more smarter than this state->specialCharacters[index] = lowerName; - data->loadDFF(lowerName + ".dff"); } void GameWorld::loadSpecialModel(const unsigned short index, diff --git a/rwengine/src/items/WeaponItem.cpp b/rwengine/src/items/WeaponItem.cpp index c408d71f..1e901e38 100644 --- a/rwengine/src/items/WeaponItem.cpp +++ b/rwengine/src/items/WeaponItem.cpp @@ -9,7 +9,7 @@ #include void WeaponItem::fireHitscan(CharacterObject* owner) { - auto handFrame = owner->model->resource->findFrame("srhand"); + auto handFrame = owner->getModel()->findFrame("srhand"); glm::mat4 handMatrix; if (handFrame) { while (handFrame->getParent()) { diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index 16845627..e61ce2ef 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -14,9 +14,9 @@ static glm::vec3 enter_offset(0.81756252f, 0.34800607f, -0.486281008f); const float CharacterObject::DefaultJumpSpeed = 2.f; CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model, + const glm::quat& rot, BaseModelInfo *modelinfo) - : GameObject(engine, pos, rot, modelinfo, model) + : GameObject(engine, pos, rot, modelinfo) , currentState({}) , currentVehicle(nullptr) , currentSeat(0) @@ -65,9 +65,11 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, animations.kd_front = engine->data->animations["kd_front"]; animations.ko_shot_front = engine->data->animations["ko_shot_front"]; - if (model) { + auto info = getModelInfo(); + if (info->getModel()) { + setModel(info->getModel()); skeleton = new Skeleton; - animator = new Animator(model->resource, skeleton); + animator = new Animator(getModel(), skeleton); createActor(); } @@ -86,7 +88,7 @@ void CharacterObject::createActor(const glm::vec2& size) { } // Don't create anything without a valid model. - if (model) { + if (getModel()) { btTransform tf; tf.setIdentity(); tf.setOrigin(btVector3(position.x, position.y, position.z)); @@ -204,8 +206,8 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) { // If we have to, interrogate the movement animation if (movementAnimation != animations.idle) { - if (!model->resource->frames[0]->getChildren().empty()) { - ModelFrame* root = model->resource->frames[0]->getChildren()[0]; + if (!getModel()->frames[0]->getChildren().empty()) { + ModelFrame* root = getModel()->frames[0]->getChildren()[0]; auto it = movementAnimation->bones.find(root->getName()); if (it != movementAnimation->bones.end()) { AnimationBone* rootBone = it->second; @@ -265,22 +267,20 @@ void CharacterObject::changeCharacterModel(const std::string& name) { std::transform(modelName.begin(), modelName.end(), modelName.begin(), ::tolower); - engine->data->loadDFF(modelName + ".dff"); - engine->data->loadTXD(modelName + ".txd"); + /// @todo don't model leak here - auto& models = engine->data->models; - auto mfind = models.find(modelName); - if (mfind != models.end()) { - model = mfind->second; - } + engine->data->loadTXD(modelName + ".txd"); + auto newmodel = engine->data->loadClump(modelName + ".dff"); if (skeleton) { delete animator; delete skeleton; } + setModel(newmodel); + skeleton = new Skeleton; - animator = new Animator(model->resource, skeleton); + animator = new Animator(getModel(), skeleton); } void CharacterObject::updateCharacter(float dt) { diff --git a/rwengine/src/objects/CharacterObject.hpp b/rwengine/src/objects/CharacterObject.hpp index e26da4a8..e081cd67 100644 --- a/rwengine/src/objects/CharacterObject.hpp +++ b/rwengine/src/objects/CharacterObject.hpp @@ -140,8 +140,7 @@ public: * @param ped PEDS_t struct to use. */ CharacterObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model, - BaseModelInfo* modelinfo); + const glm::quat& rot, BaseModelInfo* modelinfo); ~CharacterObject(); @@ -149,7 +148,6 @@ public: return Character; } - void tick(float dt); const CharacterState& getCurrentState() const { diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index 3d2e0a2a..6d1b55b3 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -3,13 +3,19 @@ #include CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, - const glm::quat &rot, - const ModelRef &model, BaseModelInfo *modelinfo) - : GameObject(engine, pos, rot, modelinfo, model) + const glm::quat &rot, Model *model, + BaseModelInfo *modelinfo) + : GameObject(engine, pos, rot, modelinfo) , _parent(nullptr) , _bone(nullptr) { + if (model) { + setModel(model); + } + else { + setModel(getModelInfo()->getModel()); + } skeleton = new Skeleton; - animator = new Animator(model->resource, skeleton); + animator = new Animator(getModel(), skeleton); } CutsceneObject::~CutsceneObject() { diff --git a/rwengine/src/objects/CutsceneObject.hpp b/rwengine/src/objects/CutsceneObject.hpp index fda619d6..280db419 100644 --- a/rwengine/src/objects/CutsceneObject.hpp +++ b/rwengine/src/objects/CutsceneObject.hpp @@ -12,7 +12,8 @@ class CutsceneObject : public GameObject { public: CutsceneObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model, BaseModelInfo *modelinfo); + const glm::quat& rot, Model* model, + BaseModelInfo* modelinfo); ~CutsceneObject(); Type type() { diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index 78a80e2d..917b21f3 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -30,13 +30,20 @@ class GameObject { BaseModelInfo* modelinfo_; + /** + * Model used for rendering + */ + Model* model_; + +protected: + void changeModelInfo(BaseModelInfo* next) { + modelinfo_ = next; + } + public: glm::vec3 position; glm::quat rotation; - /// Reference to Model data - ModelRef model; - GameWorld* engine; Animator* animator; /// Object's animator. @@ -55,14 +62,14 @@ public: bool visible; GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - BaseModelInfo* modelinfo, ModelRef model) + BaseModelInfo* modelinfo) : _lastPosition(pos) , _lastRotation(rot) , objectID(0) , modelinfo_(modelinfo) + , model_(nullptr) , position(pos) , rotation(rot) - , model(model) , engine(engine) , animator(nullptr) , skeleton(nullptr) @@ -96,6 +103,20 @@ public: return static_cast(modelinfo_); } + /** + * @return The model used in rendering + */ + Model* getModel() const { + return model_; + } + + /** + * Changes the current model, used for re-dressing chars + */ + void setModel(Model* model) { + model_ = model; + } + /** * @brief Enumeration of possible object types. */ diff --git a/rwengine/src/objects/InstanceObject.cpp b/rwengine/src/objects/InstanceObject.cpp index 2a0ce5ff..c6bdb93e 100644 --- a/rwengine/src/objects/InstanceObject.cpp +++ b/rwengine/src/objects/InstanceObject.cpp @@ -6,12 +6,10 @@ #include InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model, - const glm::vec3& scale, - BaseModelInfo *modelinfo, - InstanceObject* lod, + const glm::quat& rot, const glm::vec3& scale, + BaseModelInfo* modelinfo, InstanceObject* lod, std::shared_ptr dyn) - : GameObject(engine, pos, rot, modelinfo, model) + : GameObject(engine, pos, rot, modelinfo) , health(100.f) , scale(scale) , body(nullptr) @@ -123,15 +121,21 @@ void InstanceObject::tick(float dt) { if (animator) animator->tick(dt); } -void InstanceObject::changeModel(BaseModelInfo *incoming) { +void InstanceObject::changeModel(BaseModelInfo* incoming) { if (body) { delete body; body = nullptr; } - /// @todo store the new object - if (incoming) { + if (!incoming->isLoaded()) { + engine->data->loadModel(incoming->id()); + } + + changeModelInfo(incoming); + /// @todo this should only be temporary + setModel(getModelInfo()->getModel()); + auto bod = new CollisionInstance; if (bod->createPhysicsBody(this, incoming->name, dynamics.get())) { diff --git a/rwengine/src/objects/InstanceObject.hpp b/rwengine/src/objects/InstanceObject.hpp index e7c92838..1d582f90 100644 --- a/rwengine/src/objects/InstanceObject.hpp +++ b/rwengine/src/objects/InstanceObject.hpp @@ -22,9 +22,9 @@ public: bool _enablePhysics; InstanceObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model, - const glm::vec3& scale, BaseModelInfo* modelinfo, - InstanceObject* lod, std::shared_ptr dyn); + const glm::quat& rot, const glm::vec3& scale, + BaseModelInfo* modelinfo, InstanceObject* lod, + std::shared_ptr dyn); ~InstanceObject(); Type type() { diff --git a/rwengine/src/objects/PickupObject.cpp b/rwengine/src/objects/PickupObject.cpp index 3015ef67..89158451 100644 --- a/rwengine/src/objects/PickupObject.cpp +++ b/rwengine/src/objects/PickupObject.cpp @@ -60,7 +60,7 @@ uint32_t PickupObject::behaviourFlags(PickupType type) { PickupObject::PickupObject(GameWorld* world, const glm::vec3& position, BaseModelInfo* modelinfo, PickupType type) - : GameObject(world, position, glm::quat(), modelinfo, nullptr) + : GameObject(world, position, glm::quat(), modelinfo) , m_ghost(nullptr) , m_shape(nullptr) , m_enabled(false) diff --git a/rwengine/src/objects/ProjectileObject.cpp b/rwengine/src/objects/ProjectileObject.cpp index c99960cc..2150c9c3 100644 --- a/rwengine/src/objects/ProjectileObject.cpp +++ b/rwengine/src/objects/ProjectileObject.cpp @@ -107,7 +107,7 @@ void ProjectileObject::cleanup() { ProjectileObject::ProjectileObject(GameWorld* world, const glm::vec3& position, const ProjectileObject::ProjectileInfo& info) - : GameObject(world, position, glm::quat(), nullptr, nullptr) + : GameObject(world, position, glm::quat(), nullptr) , _info(info) , _body(nullptr) , _ghostBody(nullptr) diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index d43403a4..03a75b29 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -83,10 +83,10 @@ private: }; VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, const ModelRef& model, - BaseModelInfo *modelinfo, VehicleInfoHandle info, - const glm::u8vec3& prim, const glm::u8vec3& sec) - : GameObject(engine, pos, rot, modelinfo, model) + const glm::quat& rot, BaseModelInfo* modelinfo, + VehicleInfoHandle info, const glm::u8vec3& prim, + const glm::u8vec3& sec) + : GameObject(engine, pos, rot, modelinfo) , steerAngle(0.f) , throttle(0.f) , brake(0.f) @@ -152,7 +152,9 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, // Hide all LOD and damage frames. skeleton = new Skeleton; - for (ModelFrame* frame : model->resource->frames) { + setModel(getVehicle()->getModel()); + + for (ModelFrame* frame : getModel()->frames) { auto& name = frame->getName(); bool isDam = name.find("_dam") != name.npos; bool isLod = name.find("lo") != name.npos; @@ -554,7 +556,7 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) { if (skeleton->getData(p->normal->getIndex()).enabled) { auto& geom = - model->resource->geometries[p->normal->getGeometries()[0]]; + getModel()->geometries[p->normal->getGeometries()[0]]; auto pp = p->normal->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f); float td = glm::distance( @@ -678,7 +680,7 @@ void VehicleObject::createObjectHinge(Part* part) { if (okframe->getGeometries().size() == 0) return; - auto& geom = model->resource->geometries[okframe->getGeometries()[0]]; + auto& geom = getModel()->geometries[okframe->getGeometries()[0]]; auto gbounds = geom->geometryBounds; if (fn.find("door") != fn.npos) { diff --git a/rwengine/src/objects/VehicleObject.hpp b/rwengine/src/objects/VehicleObject.hpp index 46edb696..8d7c4c3f 100644 --- a/rwengine/src/objects/VehicleObject.hpp +++ b/rwengine/src/objects/VehicleObject.hpp @@ -49,9 +49,8 @@ public: std::map dynamicParts; VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - const ModelRef& model, BaseModelInfo* modelinfo, - VehicleInfoHandle info, const glm::u8vec3& prim, - const glm::u8vec3& sec); + BaseModelInfo* modelinfo, VehicleInfoHandle info, + const glm::u8vec3& prim, const glm::u8vec3& sec); virtual ~VehicleObject(); diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 3b672287..2e956baa 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -177,7 +177,7 @@ void ObjectRenderer::renderItem(InventoryItem* item, void ObjectRenderer::renderInstance(InstanceObject* instance, RenderList& outList) { - if (!instance->model->resource) { + if (!instance->getModel()) { return; } @@ -203,7 +203,7 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, auto matrixModel = instance->getTimeAdjustedTransform(m_renderAlpha); float mindist = glm::length(instance->getPosition() - m_camera.position) - - instance->model->resource->getBoundingRadius(); + instance->getModel()->getBoundingRadius(); mindist *= 1.f / kDrawDistanceFactor; Model* model = nullptr; @@ -230,7 +230,7 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, instance->LODinstance->getModelInfo(); float LODrange = lodmodelinfo->getLodDistance(0); if (mindist <= LODrange && - instance->LODinstance->model->resource) { + instance->LODinstance->getModel()) { // The model matrix needs to be for the LOD instead matrixModel = instance->LODinstance->getTimeAdjustedTransform( @@ -238,27 +238,27 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, // If the object is only just out of range, keep // rendering it and screen-door the LOD. if (overlap < fadeRange) { - model = instance->LODinstance->model->resource; - fadingModel = instance->model->resource; + model = instance->LODinstance->getModel(); + fadingModel = instance->getModel(); opacity = 1.f - (overlap / fadeRange); } else { - model = instance->LODinstance->model->resource; + model = instance->LODinstance->getModel(); } } } // We don't have a LOD object, so fade out gracefully. else if (overlap < fadeRange) { - fadingModel = instance->model->resource; + fadingModel = instance->getModel(); opacity = 1.f - (overlap / fadeRange); } } // Otherwise, if we aren't marked as a LOD model, we can render else if (!modelinfo->LOD) { - model = instance->model->resource; + model = instance->getModel(); } } else { - auto root = instance->model->resource->frames[0]; - auto objectModel = instance->model->resource; + auto root = instance->getModel()->frames[0]; + auto objectModel = instance->getModel(); fadingFrame = nullptr; fadingModel = nullptr; @@ -316,15 +316,15 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, matrixModel = pedestrian->getTimeAdjustedTransform(m_renderAlpha); } - if (!pedestrian->model->resource) return; + if (!pedestrian->getModel()) return; - auto root = pedestrian->model->resource->frames[0]; + auto root = pedestrian->getModel()->frames[0]; - renderFrame(pedestrian->model->resource, root->getChildren()[0], + renderFrame(pedestrian->getModel(), root->getChildren()[0], matrixModel, pedestrian, 1.f, outList); if (pedestrian->getActiveItem()) { - auto handFrame = pedestrian->model->resource->findFrame("srhand"); + auto handFrame = pedestrian->getModel()->findFrame("srhand"); glm::mat4 localMatrix; if (handFrame) { while (handFrame->getParent()) { @@ -365,15 +365,15 @@ void ObjectRenderer::renderWheel(VehicleObject* vehicle, Model* model, void ObjectRenderer::renderVehicle(VehicleObject* vehicle, RenderList& outList) { - RW_CHECK(vehicle->model, "Vehicle model is null"); + RW_CHECK(vehicle->getModel(), "Vehicle model is null"); - if (!vehicle->model) { + if (!vehicle->getModel()) { return; } glm::mat4 matrixModel = vehicle->getTimeAdjustedTransform(m_renderAlpha); - renderFrame(vehicle->model->resource, vehicle->model->resource->frames[0], + renderFrame(vehicle->getModel(), vehicle->getModel()->frames[0], matrixModel, vehicle, 1.f, outList); auto modelinfo = vehicle->getVehicle(); @@ -466,7 +466,7 @@ void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, RenderList& outList) { if (!m_world->state->currentCutscene) return; - if (!cutscene->model->resource) { + if (!cutscene->getModel()) { return; } @@ -492,7 +492,7 @@ void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, matrixModel = glm::translate(matrixModel, cutsceneOffset); } - auto model = cutscene->model->resource; + auto model = cutscene->getModel(); if (cutscene->getParentActor()) { glm::mat4 align; /// @todo figure out where this 90 degree offset is coming from. diff --git a/rwengine/src/script/ScriptFunctions.hpp b/rwengine/src/script/ScriptFunctions.hpp index b20226d9..536fac40 100644 --- a/rwengine/src/script/ScriptFunctions.hpp +++ b/rwengine/src/script/ScriptFunctions.hpp @@ -35,8 +35,7 @@ inline bool isInModel(const ScriptArguments& args, CharacterObject* character, if (data) { auto vehicle = getCharacterVehicle(character); if (vehicle) { - return vehicle->model ? vehicle->model->name == data->name - : false; + return vehicle->getVehicle()->id() == model; } } return false; diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index d5eeb808..36db098c 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -6836,12 +6836,18 @@ void opcode_023c(const ScriptArguments& args, const ScriptInt arg1, const Script @arg arg1 */ bool opcode_023d(const ScriptArguments& args, const ScriptInt arg1) { + /// @todo re-implement this when streaming is added + return true; + RW_UNUSED(args); + RW_UNUSED(arg1); +#if 0 auto model = args.getState()->specialCharacters[arg1]; auto modelfind = args.getWorld()->data->models.find(model); if( modelfind != args.getWorld()->data->models.end() && modelfind->second->resource != nullptr ) { return true; } return false; +#endif } /** @@ -8455,7 +8461,7 @@ void opcode_02f4(const ScriptArguments& args, const ScriptObject object0, const auto actor = args.getObject(0); CutsceneObject* object = args.getWorld()->createCutsceneObject(id, args.getWorld()->state->currentCutscene->meta.sceneOffset ); - auto headframe = actor->model->resource->findFrame("shead"); + auto headframe = actor->getModel()->findFrame("shead"); actor->skeleton->setEnabled(headframe, false); object->setParentActor(actor, headframe); @@ -11346,17 +11352,14 @@ void opcode_03b6(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa auto newobjectid = args.getWorld()->data->findModelObject(newmodel); auto nobj = args.getWorld()->data->findModelInfo(newobjectid); - /// @todo Objects need to adopt the new object ID, not just the model. for(auto p : args.getWorld()->instancePool.objects) { auto o = p.second; - if( !o->model ) continue; - if( o->model->name != oldmodel ) continue; + if( !o->getModel() ) continue; + if( o->getModelInfo()->name != oldmodel ) continue; float d = glm::distance(coord, o->getPosition()); if( d < radius ) { - args.getWorld()->data->loadDFF(newmodel + ".dff", false); InstanceObject* inst = static_cast(o); inst->changeModel(nobj); - inst->model = args.getWorld()->data->models[newmodel]; } } } diff --git a/rwgame/states/DebugState.cpp b/rwgame/states/DebugState.cpp index 89c55ee0..aa1aab06 100644 --- a/rwgame/states/DebugState.cpp +++ b/rwgame/states/DebugState.cpp @@ -201,7 +201,8 @@ Menu* DebugState::createMapMenu() { for (auto& i : gw->instancePool.objects) { auto obj = static_cast(i.second); if (std::find(garageDoorModels.begin(), garageDoorModels.end(), - obj->model->name) != garageDoorModels.end()) { + obj->getModelInfo()->name) != + garageDoorModels.end()) { obj->setSolid(false); } } diff --git a/rwgame/states/IngameState.cpp b/rwgame/states/IngameState.cpp index cd4cf76a..2db6bbb6 100644 --- a/rwgame/states/IngameState.cpp +++ b/rwgame/states/IngameState.cpp @@ -238,9 +238,9 @@ void IngameState::tick(float dt) { ? static_cast(target)->getCurrentVehicle() : nullptr; if (vehicle) { - auto model = vehicle->model; + auto model = vehicle->getModel(); float maxDist = 0.f; - for (auto& g : model->resource->geometries) { + for (auto& g : model->geometries) { float partSize = glm::length(g->geometryBounds.center) + g->geometryBounds.radius; maxDist = std::max(partSize, maxDist); diff --git a/rwviewer/ViewerWidget.cpp b/rwviewer/ViewerWidget.cpp index 57b3a69d..7f222dc1 100644 --- a/rwviewer/ViewerWidget.cpp +++ b/rwviewer/ViewerWidget.cpp @@ -194,7 +194,7 @@ void ViewerWidget::showObject(qint16 item) { RW_CHECK(dummyObject != nullptr, "Dummy Object is null"); if (dummyObject != nullptr) { - activeModel = dummyObject->model->resource; + activeModel = dummyObject->getModel(); } } } diff --git a/tests/test_character.cpp b/tests/test_character.cpp index bca78f16..a3a556bc 100644 --- a/tests/test_character.cpp +++ b/tests/test_character.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(test_activities) { VehicleObject* vehicle = Global::get().e->createVehicle( 90u, glm::vec3(10.f, 0.f, 0.f), glm::quat()); BOOST_REQUIRE(vehicle != nullptr); - BOOST_REQUIRE(vehicle->model != nullptr); + BOOST_REQUIRE(vehicle->getModel() != nullptr); auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f}); diff --git a/tests/test_vehicle.cpp b/tests/test_vehicle.cpp index b5cb8dfa..1fb1a9ad 100644 --- a/tests/test_vehicle.cpp +++ b/tests/test_vehicle.cpp @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(vehicle_parts) { Global::get().e->createVehicle(90u, glm::vec3(), glm::quat()); BOOST_REQUIRE(vehicle != nullptr); - BOOST_REQUIRE(vehicle->model != nullptr); + BOOST_REQUIRE(vehicle->getModel() != nullptr); VehicleObject::Part* part = vehicle->getPart("bonnet_dummy"); @@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(vehicle_part_vis) { Global::get().e->createVehicle(90u, glm::vec3(), glm::quat()); BOOST_REQUIRE(vehicle != nullptr); - BOOST_REQUIRE(vehicle->model != nullptr); + BOOST_REQUIRE(vehicle->getModel() != nullptr); VehicleObject::Part* bonnetpart = vehicle->getPart("bonnet_dummy"); auto skel = vehicle->skeleton; diff --git a/tests/test_weapon.cpp b/tests/test_weapon.cpp index cc92c154..03e05702 100644 --- a/tests/test_weapon.cpp +++ b/tests/test_weapon.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(TestWeaponScan) { // Test RADIUS scan auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f}); BOOST_REQUIRE(character != nullptr); - BOOST_REQUIRE(character->model != nullptr); + BOOST_REQUIRE(character->getModel() != nullptr); BOOST_REQUIRE(character->physObject != nullptr); WeaponScan scan(10.f, {0.f, 0.f, 10.f}, {0.f, 0.f, -10.f}); From 62ad6b862814868c8e912ec9a26a1eac739aa9e2 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 11 Sep 2016 21:57:55 +0100 Subject: [PATCH 08/14] Remove monolithic model list --- rwengine/src/engine/GameData.cpp | 32 +---- rwengine/src/engine/GameData.hpp | 10 -- rwengine/src/engine/GameWorld.cpp | 4 +- rwengine/src/render/GameRenderer.cpp | 10 +- rwengine/src/render/ObjectRenderer.cpp | 180 +++++++++---------------- rwengine/src/render/ObjectRenderer.hpp | 6 - tests/test_animation.cpp | 5 +- 7 files changed, 71 insertions(+), 176 deletions(-) diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index fdaa3dbb..2ab30759 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -27,11 +27,7 @@ GameData::GameData(Logger* log, WorkContext* work, const std::string& path) } GameData::~GameData() { - for (auto& m : models) { - if (m.second->resource) { - delete m.second->resource; - } - } + /// @todo don't leak models } void GameData::load() { @@ -45,9 +41,6 @@ void GameData::load() { loadLevelFile("data/default.dat"); loadLevelFile("data/gta3.dat"); - loadDFF("wheels.dff"); - loadDFF("weapons.dff"); - loadDFF("arrow.dff"); loadTXD("particle.txd"); loadTXD("icons.txd"); loadTXD("hud.txd"); @@ -313,29 +306,6 @@ void GameData::loadTXD(const std::string& name, bool async) { } } -void GameData::loadDFF(const std::string& name, bool async) { - auto realname = name.substr(0, name.size() - 4); - if (models.find(realname) != models.end()) { - return; - } - - // Before starting the job make sure the file isn't loaded again. - loadedFiles.insert({name, true}); - - models[realname] = ModelRef(new ResourceHandle(realname)); - - auto job = new BackgroundLoaderJob{ - workContext, &this->index, name, models[realname]}; - - if (async) { - workContext->queueJob(job); - } else { - job->work(); - job->complete(); - delete job; - } -} - void GameData::getNameAndLod(std::string& name, int& lod) { auto lodpos = name.rfind("_l"); if (lodpos != std::string::npos) { diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index 6486cb3a..35b85da6 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -118,11 +118,6 @@ public: */ void loadTXD(const std::string& name, bool async = false); - /** - * Attempts to load a DFF or does nothing if is already loaded - */ - void loadDFF(const std::string& name, bool async = false); - /** * Converts combined {name}_l{LOD} into name and lod. */ @@ -229,11 +224,6 @@ public: */ WeatherLoader weatherLoader; - /** - * Loaded models - */ - std::map::Ref> models; - /** * Loaded textures (Textures are ID by name and alpha pairs) */ diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 7e4a7bf4..733711ad 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -369,7 +369,8 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, return nullptr; } - if (!pt->isLoaded()) { + auto isSpecial = pt->name.compare(0, 7, "special") == 0; + if (!pt->isLoaded() || isSpecial) { data->loadModel(id); } @@ -812,6 +813,7 @@ void GameWorld::loadSpecialCharacter(const unsigned short index, std::string lowerName(name); std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); + // Need to replace any existing loaded model /// @todo a bit more smarter than this state->specialCharacters[index] = lowerName; } diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index 5ea5813f..7974e91b 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -366,11 +366,12 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera, RW_PROFILE_END(); + /// @todo this shouldn't be static here + static auto arrowModel = world->data->loadClump("arrow.dff"); // Render arrows above anything that isn't radar only (or hidden) - ModelRef& arrowModel = world->data->models["arrow"]; - if (arrowModel && arrowModel->resource) { + if (arrowModel) { auto arrowTex = world->data->textures[{"copblue", ""}]; - auto arrowFrame = arrowModel->resource->findFrame("arrow"); + auto arrowFrame = arrowModel->findFrame("arrow"); for (auto& blip : world->state->radarBlips) { auto dm = blip.second.display; if (dm == BlipData::Hide || dm == BlipData::RadarOnly) { @@ -399,8 +400,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera, dp.ambient = 1.f; dp.colour = glm::u8vec4(255, 255, 255, 255); - auto geom = arrowModel->resource - ->geometries[arrowFrame->getGeometries()[0]]; + auto geom = arrowModel->geometries[arrowFrame->getGeometries()[0]]; Model::SubGeometry& sg = geom->subgeom[0]; dp.start = sg.start; diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 2e956baa..b5257630 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -155,26 +155,6 @@ bool ObjectRenderer::renderFrame(Model* m, ModelFrame* f, return true; } -void ObjectRenderer::renderItem(InventoryItem* item, - const glm::mat4& modelMatrix, - RenderList& outList) { - // srhand - if (item->getModelID() == -1) { - return; // No model for this item - } - - auto odata = m_world->data->modelinfo[item->getModelID()].get(); - auto weapons = m_world->data->models["weapons"]; - if (weapons && weapons->resource) { - auto itemModel = weapons->resource->findFrame(odata->name + "_l0"); - auto matrix = glm::inverse(itemModel->getTransform()); - if (itemModel) { - renderFrame(weapons->resource, itemModel, modelMatrix * matrix, - nullptr, 1.f, outList); - } - } -} - void ObjectRenderer::renderInstance(InstanceObject* instance, RenderList& outList) { if (!instance->getModel()) { @@ -229,8 +209,7 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, auto lodmodelinfo = instance->LODinstance->getModelInfo(); float LODrange = lodmodelinfo->getLodDistance(0); - if (mindist <= LODrange && - instance->LODinstance->getModel()) { + if (mindist <= LODrange && instance->LODinstance->getModel()) { // The model matrix needs to be for the LOD instead matrixModel = instance->LODinstance->getTimeAdjustedTransform( @@ -320,10 +299,16 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, auto root = pedestrian->getModel()->frames[0]; - renderFrame(pedestrian->getModel(), root->getChildren()[0], - matrixModel, pedestrian, 1.f, outList); + renderFrame(pedestrian->getModel(), root->getChildren()[0], matrixModel, + pedestrian, 1.f, outList); if (pedestrian->getActiveItem()) { + auto item = pedestrian->getActiveItem(); + + if (item->getModelID() == -1) { + return; // No model for this item + } + auto handFrame = pedestrian->getModel()->findFrame("srhand"); glm::mat4 localMatrix; if (handFrame) { @@ -334,32 +319,13 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, handFrame = handFrame->getParent(); } } - renderItem(pedestrian->getActiveItem(), matrixModel * localMatrix, - outList); - } -} -void ObjectRenderer::renderWheel(VehicleObject* vehicle, Model* model, - const glm::mat4& matrix, - const std::string& name, RenderList& outList) { - for (const ModelFrame* f : model->frames) { - const std::string& fname = f->getName(); - if (fname != name) { - continue; - } - - auto firstLod = f->getChildren()[0]; - - for (auto& g : firstLod->getGeometries()) { - RW::BSGeometryBounds& bounds = model->geometries[g]->geometryBounds; - if (!m_camera.frustum.intersects( - bounds.center + glm::vec3(matrix[3]), bounds.radius)) { - continue; - } - - renderGeometry(model, g, matrix, 1.f, vehicle, outList); - } - break; + // Assume items are all simple + auto simple = + m_world->data->findModelInfo(item->getModelID()); + auto geometry = simple->getAtomic(0)->getGeometries().at(0); + renderGeometry(simple->getModel(), geometry, matrixModel * localMatrix, + 1.f, nullptr, outList); } } @@ -377,49 +343,48 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, matrixModel, vehicle, 1.f, outList); auto modelinfo = vehicle->getVehicle(); + // Draw wheels n' stuff + auto woi = + m_world->data->findModelInfo(modelinfo->wheelmodel_); + if (!woi || !woi->isLoaded()) { + return; + } + auto wheelgeom = woi->getAtomic(0)->getGeometries().at(0); for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) { - auto woi = m_world->data->findModelInfo( - modelinfo->wheelmodel_); - if (woi) { - Model* wheelModel = m_world->data->models["wheels"]->resource; - auto& wi = vehicle->physVehicle->getWheelInfo(w); - if (wheelModel) { - // Construct our own matrix so we can use the local transform - vehicle->physVehicle->updateWheelTransform(w, false); - /// @todo migrate this into Vehicle physics tick so we can - /// interpolate old -> new + auto& wi = vehicle->physVehicle->getWheelInfo(w); + // Construct our own matrix so we can use the local transform + vehicle->physVehicle->updateWheelTransform(w, false); + /// @todo migrate this into Vehicle physics tick so we can + /// interpolate old -> new - glm::mat4 wheelM(matrixModel); + glm::mat4 wheelM(matrixModel); - auto up = -wi.m_wheelDirectionCS; - auto right = wi.m_wheelAxleCS; - auto fwd = up.cross(right); - btQuaternion steerQ(up, wi.m_steering); - btQuaternion rollQ(right, -wi.m_rotation); + auto up = -wi.m_wheelDirectionCS; + auto right = wi.m_wheelAxleCS; + auto fwd = up.cross(right); + btQuaternion steerQ(up, wi.m_steering); + btQuaternion rollQ(right, -wi.m_rotation); - btMatrix3x3 basis(right[0], fwd[0], up[0], right[1], fwd[1], - up[1], right[2], fwd[2], up[2]); + btMatrix3x3 basis(right[0], fwd[0], up[0], right[1], fwd[1], up[1], + right[2], fwd[2], up[2]); - btTransform t; - t.setBasis(btMatrix3x3(steerQ) * btMatrix3x3(rollQ) * basis); - t.setOrigin(wi.m_chassisConnectionPointCS + - wi.m_wheelDirectionCS * - wi.m_raycastInfo.m_suspensionLength); + btTransform t; + t.setBasis(btMatrix3x3(steerQ) * btMatrix3x3(rollQ) * basis); + t.setOrigin(wi.m_chassisConnectionPointCS + + wi.m_wheelDirectionCS * + wi.m_raycastInfo.m_suspensionLength); - t.getOpenGLMatrix(glm::value_ptr(wheelM)); - wheelM = matrixModel * wheelM; + t.getOpenGLMatrix(glm::value_ptr(wheelM)); + wheelM = matrixModel * wheelM; - wheelM = - glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_)); - if (wi.m_chassisConnectionPointCS.x() < 0.f) { - wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f)); - } - - renderWheel(vehicle, wheelModel, wheelM, woi->name, - outList); - } + wheelM = glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_)); + if (wi.m_chassisConnectionPointCS.x() < 0.f) { + wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f)); } + + renderGeometry(woi->getModel(), wheelgeom, wheelM, 1.f, nullptr, + outList); } } @@ -432,34 +397,16 @@ void ObjectRenderer::renderPickup(PickupObject* pickup, RenderList& outList) { auto odata = pickup->getModelInfo(); - Model* model = nullptr; - ModelFrame* itemModel = nullptr; - - /// @todo Better determination of is this object a weapon. - if (odata->id() >= 170 && odata->id() <= 184) { - auto weapons = m_world->data->models["weapons"]; - if (weapons && weapons->resource && odata) { - model = weapons->resource; - itemModel = weapons->resource->findFrame(odata->name + "_l0"); - RW_CHECK(itemModel, "Weapon Frame not present int weapon model"); - if (!itemModel) { - return; - } - } - } else { - auto handle = m_world->data->models[odata->name]; - RW_CHECK(handle && handle->resource, "Pickup has no model"); - if (handle && handle->resource) { - model = handle->resource; - itemModel = model->frames[model->rootFrameIdx]; - } + auto model = odata->getModel(); + auto itemModel = odata->getAtomic(0); + auto geom = 0; + if (!itemModel->getGeometries().empty()) { + geom = itemModel->getGeometries()[0]; + } else if (!itemModel->getChildren().empty()) { + geom = itemModel->getChildren()[0]->getGeometries()[0]; } - if (itemModel) { - auto matrix = glm::inverse(itemModel->getTransform()); - renderFrame(model, itemModel, modelMatrix * matrix, pickup, 1.f, - outList); - } + renderGeometry(model, geom, modelMatrix, 1.f, pickup, outList); } void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, @@ -511,19 +458,12 @@ void ObjectRenderer::renderProjectile(ProjectileObject* projectile, auto odata = m_world->data->findModelInfo( projectile->getProjectileInfo().weapon->modelID); - auto weapons = m_world->data->models["weapons"]; - RW_CHECK(weapons, "Weapons model not loaded"); + auto model = odata->getModel(); + auto modelframe = odata->getAtomic(0); + auto geom = modelframe->getGeometries().at(0); - if (weapons && weapons->resource) { - auto itemModel = weapons->resource->findFrame(odata->name + "_l0"); - auto matrix = glm::inverse(itemModel->getTransform()); - RW_CHECK(itemModel, "Weapon frame not in model"); - if (itemModel) { - renderFrame(weapons->resource, itemModel, modelMatrix * matrix, - projectile, 1.f, outList); - } - } + renderGeometry(model, geom, modelMatrix, 1.f, projectile, outList); } void ObjectRenderer::buildRenderList(GameObject* object, RenderList& outList) { diff --git a/rwengine/src/render/ObjectRenderer.hpp b/rwengine/src/render/ObjectRenderer.hpp index f6b8ff6e..8857322a 100644 --- a/rwengine/src/render/ObjectRenderer.hpp +++ b/rwengine/src/render/ObjectRenderer.hpp @@ -48,12 +48,6 @@ private: void renderCutsceneObject(CutsceneObject* cutscene, RenderList& outList); void renderProjectile(ProjectileObject* projectile, RenderList& outList); - void renderItem(InventoryItem* item, const glm::mat4& modelMatrix, - RenderList& outList); - void renderWheel(VehicleObject* vehicle, Model* model, - const glm::mat4& matrix, const std::string& name, - RenderList& outList); - bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, RenderList& outList); diff --git a/tests/test_animation.cpp b/tests/test_animation.cpp index 2cb3155b..b4d2654d 100644 --- a/tests/test_animation.cpp +++ b/tests/test_animation.cpp @@ -15,10 +15,9 @@ BOOST_AUTO_TEST_CASE(test_matrix) { /** Models are currently needed to relate animation bones <=> model * frame #s. */ - Global::get().e->data->loadDFF("player.dff"); - ModelRef& test_model = Global::get().e->data->models["player"]; + auto test_model = Global::get().d->loadClump("player.dff"); - Animator animator(test_model->resource, &skeleton); + Animator animator(test_model, &skeleton); animation.duration = 1.f; animation.bones["player"] = new AnimationBone{ From 9b45a3183478009664f826aa45589a76be917f4d Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 11 Sep 2016 22:19:38 +0100 Subject: [PATCH 09/14] Remove BackgroundLoader.hpp --- rwengine/CMakeLists.txt | 1 - rwengine/src/engine/GameData.cpp | 1 - rwengine/src/loaders/BackgroundLoader.hpp | 38 ----------------------- tests/test_loaderdff.cpp | 26 ---------------- 4 files changed, 66 deletions(-) delete mode 100644 rwengine/src/loaders/BackgroundLoader.hpp diff --git a/rwengine/CMakeLists.txt b/rwengine/CMakeLists.txt index 616d96f4..0672e92d 100644 --- a/rwengine/CMakeLists.txt +++ b/rwengine/CMakeLists.txt @@ -61,7 +61,6 @@ set(RWENGINE_SOURCES src/items/InventoryItem.hpp src/items/WeaponItem.cpp src/items/WeaponItem.hpp - src/loaders/BackgroundLoader.hpp src/loaders/DataLoader.cpp src/loaders/DataLoader.hpp src/loaders/GenericDATLoader.cpp diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 2ab30759..507e76b9 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -11,7 +11,6 @@ #include