diff --git a/rwengine/include/data/Loader.hpp b/rwengine/include/data/Loader.hpp new file mode 100644 index 00000000..167de2f7 --- /dev/null +++ b/rwengine/include/data/Loader.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +/** + * Generic base class for loader implementations + */ +template class Loader +{ +public: + /** + * Type of the resource produced by the loader + */ + typedef T ResultType; + + /** + * Method that should be used to export the loaded data + */ + ResultType get(); +}; diff --git a/rwengine/include/data/ResourceHandle.hpp b/rwengine/include/data/ResourceHandle.hpp new file mode 100644 index 00000000..df740958 --- /dev/null +++ b/rwengine/include/data/ResourceHandle.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +namespace RW +{ + /** + * Possible states for ResourceHandle + */ + enum ResourceState + { + /// Resource has been declared but not loaded + Loading = 0, + /// Resource has been loaded and is available + Loaded = 1, + /// Loading the resource failed + Failed = 2 + }; +}; + + +template class ResourceHandle +{ +public: + T* resource; + RW::ResourceState state; + std::string name; + + typedef std::shared_ptr> Ref; + + ResourceHandle(const std::string& name) + : resource(nullptr), state(RW::Loading), name(name) { } +}; diff --git a/rwengine/include/engine/GameData.hpp b/rwengine/include/engine/GameData.hpp index c246a3c7..ed01e663 100644 --- a/rwengine/include/engine/GameData.hpp +++ b/rwengine/include/engine/GameData.hpp @@ -209,7 +209,7 @@ public: /** * Loaded models */ - std::map models; + std::map::Ref> models; /** * Loaded textures (Textures are ID by name and alpha pairs) diff --git a/rwengine/include/engine/GameObject.hpp b/rwengine/include/engine/GameObject.hpp index 85aba2af..08ca4237 100644 --- a/rwengine/include/engine/GameObject.hpp +++ b/rwengine/include/engine/GameObject.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,8 @@ public: glm::vec3 position; glm::quat rotation; - ModelHandle* model; /// Cached pointer to Object's Model. + /// Reference to Model data + ModelRef model; GameWorld* engine; @@ -55,7 +57,7 @@ public: */ bool visible; - GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model) + GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelRef model) : _lastPosition(pos), _lastRotation(rot), position(pos), rotation(rot), model(model), engine(engine), animator(nullptr), skeleton(nullptr), mHealth(0.f), _inWater(false), _lastHeight(std::numeric_limits::max()), visible(true), diff --git a/rwengine/include/engine/RWTypes.hpp b/rwengine/include/engine/RWTypes.hpp index 56af1a11..14a9d9df 100644 --- a/rwengine/include/engine/RWTypes.hpp +++ b/rwengine/include/engine/RWTypes.hpp @@ -22,16 +22,6 @@ struct Animation; typedef std::map AnimationSet; -class Model; - -// TODO: Make generic. -struct ModelHandle { - Model* model; - std::string name; - - ModelHandle(const std::string& name) : model( nullptr ), name(name) {} -}; - namespace RWTypes { diff --git a/rwengine/include/loaders/BackgroundLoader.hpp b/rwengine/include/loaders/BackgroundLoader.hpp new file mode 100644 index 00000000..03bd2245 --- /dev/null +++ b/rwengine/include/loaders/BackgroundLoader.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +/** + * Implementation of a worker that loads a resource in the background. + */ +template class BackgroundLoaderJob : public WorkJob +{ +public: + typedef typename ResourceHandle::Ref TypeRef; + + BackgroundLoaderJob(WorkContext* context, FileIndex* index, const std::string& file, const TypeRef& ref) + :WorkJob(context), index(index), filename(file), resourceRef(ref) + { } + + void work() + { + data = index->openFile(filename); + } + + + void complete() + { + if( data ) + { + L loader; + + resourceRef->resource = loader.loadFromMemory(data); + resourceRef->state = RW::Loaded; + } + } +private: + FileIndex* index; + std::string filename; + FileHandle data; + TypeRef resourceRef; +}; diff --git a/rwengine/include/loaders/LoaderDFF.hpp b/rwengine/include/loaders/LoaderDFF.hpp index 99c3cd58..a955a6e6 100644 --- a/rwengine/include/loaders/LoaderDFF.hpp +++ b/rwengine/include/loaders/LoaderDFF.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include class Model; class GameData; @@ -54,28 +56,7 @@ class LoaderDFF void readAtomic(Model* model, const RWBStream& stream); public: - Model* loadFromMemory(FileHandle file, GameData* gameData); -}; - -#include - -class LoadModelJob : public WorkJob -{ -public: - typedef std::function ModelCallback; - -private: - GameData* _gameData; - std::string _file; - ModelCallback _callback; - FileHandle data; -public: - - LoadModelJob(WorkContext* context, GameData* gd, const std::string& file, ModelCallback cb); - - void work(); - - void complete(); + Model* loadFromMemory(FileHandle file); }; #endif diff --git a/rwengine/include/objects/CharacterObject.hpp b/rwengine/include/objects/CharacterObject.hpp index 5c7d3bbd..42236323 100644 --- a/rwengine/include/objects/CharacterObject.hpp +++ b/rwengine/include/objects/CharacterObject.hpp @@ -87,7 +87,7 @@ public: * @param model * @param ped PEDS_t struct to use. */ - CharacterObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle *model, std::shared_ptr data); + CharacterObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, std::shared_ptr< CharacterData > data); ~CharacterObject(); diff --git a/rwengine/include/objects/CutsceneObject.hpp b/rwengine/include/objects/CutsceneObject.hpp index 78b98075..853cca4c 100644 --- a/rwengine/include/objects/CutsceneObject.hpp +++ b/rwengine/include/objects/CutsceneObject.hpp @@ -13,9 +13,7 @@ class CutsceneObject : public GameObject public: - CutsceneObject(GameWorld* engine, - const glm::vec3& pos, - ModelHandle* model); + CutsceneObject(GameWorld* engine, const glm::vec3& pos, const ModelRef& model); ~CutsceneObject(); Type type() { return Cutscene; } diff --git a/rwengine/include/objects/InstanceObject.hpp b/rwengine/include/objects/InstanceObject.hpp index 26389a60..acc5caed 100644 --- a/rwengine/include/objects/InstanceObject.hpp +++ b/rwengine/include/objects/InstanceObject.hpp @@ -20,14 +20,7 @@ public: std::shared_ptr dynamics; bool _enablePhysics; - InstanceObject(GameWorld* engine, - const glm::vec3& pos, - const glm::quat& rot, - ModelHandle* model, - const glm::vec3& scale, - std::shared_ptr obj, - InstanceObject *lod, - std::shared_ptr dyn + InstanceObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, const glm::vec3& scale, std::shared_ptr< ObjectData > obj, InstanceObject* lod, std::shared_ptr< DynamicObjectData > dyn ); ~InstanceObject(); diff --git a/rwengine/include/objects/VehicleObject.hpp b/rwengine/include/objects/VehicleObject.hpp index d30558c1..b3a07cfa 100644 --- a/rwengine/include/objects/VehicleObject.hpp +++ b/rwengine/include/objects/VehicleObject.hpp @@ -46,14 +46,7 @@ public: std::map dynamicParts; - VehicleObject(GameWorld* engine, - const glm::vec3& pos, - const glm::quat& rot, - ModelHandle* model, - VehicleDataHandle data, - VehicleInfoHandle info, - const glm::u8vec3& prim, - const glm::u8vec3& sec); + VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, VehicleDataHandle data, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec); virtual ~VehicleObject(); diff --git a/rwengine/include/render/Model.hpp b/rwengine/include/render/Model.hpp index 81c8a4cc..46ca992a 100644 --- a/rwengine/include/render/Model.hpp +++ b/rwengine/include/render/Model.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "DrawBuffer.hpp" #include "GeometryBuffer.hpp" @@ -166,4 +167,6 @@ public: ~Model(); }; +typedef ResourceHandle::Ref ModelRef; + #endif diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 3703f24d..98b07403 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -87,10 +88,9 @@ GameData::GameData(const std::string& path) GameData::~GameData() { for(auto& m : models) { - if(m.second->model) { - delete m.second->model; + if(m.second->resource) { + delete m.second->resource; } - delete m.second; } } @@ -408,22 +408,18 @@ void GameData::loadDFF(const std::string& name, bool async) // Before starting the job make sure the file isn't loaded again. loadedFiles.insert({name, true}); - models[realname] = new ModelHandle(realname); - - auto j = new LoadModelJob(this->engine->_work, this, name, - [&, realname]( Model* model ) { - models[realname]->model = model; - } - ); - + models[realname] = ModelRef( new ResourceHandle(realname) ); + + auto job = new BackgroundLoaderJob + { this->engine->_work, &this->index, name, models[realname] }; if( async ) { - this->engine->_work->queueJob( j ); + this->engine->_work->queueJob( job ); } else { - j->work(); - j->complete(); - delete j; + job->work(); + job->complete(); + delete job; } } diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index e5c115ad..7cd9b763 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -228,7 +228,7 @@ InstanceObject *GameWorld::createInstance(const uint16_t id, const glm::vec3& po gameData.loadTXD(texturename + ".txd", true); } - ModelHandle* m = gameData.models[modelname]; + ModelRef m = gameData.models[modelname]; // Check for dynamic data. auto dyit = gameData.dynamicObjectData.find(oi->modelName); @@ -364,7 +364,7 @@ CutsceneObject *GameWorld::createCutsceneObject(const uint16_t id, const glm::ve } - ModelHandle* m = gameData.models[modelname]; + ModelRef m = gameData.models[modelname]; auto instance = new CutsceneObject( this, @@ -410,8 +410,8 @@ VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, } } - ModelHandle* m = gameData.models[vti->modelName]; - auto model = m->model; + ModelRef& m = gameData.models[vti->modelName]; + auto model = m->resource; auto info = gameData.vehicleInfo.find(vti->handlingID); if(model && info != gameData.vehicleInfo.end()) { if( info->second->wheels.size() == 0 && info->second->seats.size() == 0 ) { @@ -470,9 +470,9 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3 gameData.loadTXD(texturename + ".txd"); } - ModelHandle* m = gameData.models[modelname]; + ModelRef m = gameData.models[modelname]; - if(m && m->model) { + if(m && m->resource) { auto ped = new CharacterObject( this, pos, rot, m, pt ); objects.insert(ped); new DefaultAIController(ped); diff --git a/rwengine/src/items/WeaponItem.cpp b/rwengine/src/items/WeaponItem.cpp index 4995600b..f1233fb7 100644 --- a/rwengine/src/items/WeaponItem.cpp +++ b/rwengine/src/items/WeaponItem.cpp @@ -9,7 +9,7 @@ void WeaponItem::fireHitscan() { - auto handFrame = _character->model->model->findFrame("srhand"); + auto handFrame = _character->model->resource->findFrame("srhand"); glm::mat4 handMatrix; if( handFrame ) { while( handFrame->getParent() ) { diff --git a/rwengine/src/loaders/LoaderDFF.cpp b/rwengine/src/loaders/LoaderDFF.cpp index e10f4a92..5a02cacd 100644 --- a/rwengine/src/loaders/LoaderDFF.cpp +++ b/rwengine/src/loaders/LoaderDFF.cpp @@ -414,7 +414,7 @@ void LoaderDFF::readAtomic(Model *model, const RWBStream &stream) /// @todo are any atomic extensions important? } -Model* LoaderDFF::loadFromMemory(FileHandle file, GameData *gameData) +Model* LoaderDFF::loadFromMemory(FileHandle file) { auto model = new Model; @@ -454,29 +454,3 @@ Model* LoaderDFF::loadFromMemory(FileHandle file, GameData *gameData) return model; } - -LoadModelJob::LoadModelJob(WorkContext *context, GameData* gd, const std::string &file, ModelCallback cb) - : WorkJob(context), _gameData(gd), _file(file), _callback(cb) -{ - -} - -void LoadModelJob::work() -{ - data = _gameData->openFile(_file); -} - -void LoadModelJob::complete() -{ - Model* m = nullptr; - // TODO error status - if( data ) { - - // TODO allow some of the loading to process in a seperate thread. - LoaderDFF loader; - - m = loader.loadFromMemory(data, _gameData); - } - - _callback(m); -} diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index 88edc56f..3e9c4ef7 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -9,7 +9,7 @@ // TODO: make this not hardcoded static glm::vec3 enter_offset(0.81756252f, 0.34800607f, -0.486281008f); -CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, std::shared_ptr data) +CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, std::shared_ptr data) : GameObject(engine, pos, rot, model), currentVehicle(nullptr), currentSeat(0), _hasTargetPosition(false), _activeInventoryItem(0), @@ -49,7 +49,7 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, const if(model) { skeleton = new Skeleton; - animator = new Animator(model->model, skeleton); + animator = new Animator(model->resource, skeleton); createActor(); } diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index 6ba0fb28..7890f419 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -2,11 +2,11 @@ #include #include -CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, ModelHandle *model) +CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, const ModelRef& model) : GameObject(engine, pos, {}, model), _parent(nullptr), _bone(nullptr) { skeleton = new Skeleton; - animator = new Animator(model->model, skeleton); + animator = new Animator(model->resource, skeleton); } CutsceneObject::~CutsceneObject() diff --git a/rwengine/src/objects/InstanceObject.cpp b/rwengine/src/objects/InstanceObject.cpp index b5302334..13e2ba4f 100644 --- a/rwengine/src/objects/InstanceObject.cpp +++ b/rwengine/src/objects/InstanceObject.cpp @@ -7,7 +7,7 @@ InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - ModelHandle *model, + const ModelRef& model, const glm::vec3& scale, std::shared_ptr obj, InstanceObject* lod, diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 508dbae0..d49ce251 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -10,7 +10,7 @@ #define PART_CLOSE_VELOCITY 0.25f -VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec) +VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const ModelRef& model, VehicleDataHandle data, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec) : GameObject(engine, pos, rot, model), steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(true), vehicle(data), info(info), colourPrimary(prim), @@ -64,7 +64,7 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm: // Hide all LOD and damage frames. skeleton = new Skeleton; - for(ModelFrame* frame : model->model->frames) + for(ModelFrame* frame : model->resource->frames) { auto& name = frame->getName(); bool isDam = name.find("_dam") != name.npos; @@ -477,7 +477,7 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) if( skeleton->getData(p->normal->getIndex()).enabled ) { - auto& geom = model->model->geometries[p->normal->getGeometries()[0]]; + auto& geom = model->resource->geometries[p->normal->getGeometries()[0]]; auto pp = p->normal->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f); float td = glm::distance(glm::vec3(pp)+geom->geometryBounds.center , dpoint); @@ -627,7 +627,7 @@ void VehicleObject::createObjectHinge(btTransform& local, Part *part) if( okframe->getGeometries().size() == 0 ) return; - auto& geom = model->model->geometries[okframe->getGeometries()[0]]; + auto& geom = model->resource->geometries[okframe->getGeometries()[0]]; auto gbounds = geom->geometryBounds; if( fn.find("door") != fn.npos ) { diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index 0d28ca15..0d368c7d 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -351,11 +351,11 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha) transparentDrawQueue.clear(); // Render arrows above anything that isn't radar only (or hidden) - ModelHandle* arrowModel = engine->gameData.models["arrow"]; - if( arrowModel && arrowModel->model ) + ModelRef& arrowModel = engine->gameData.models["arrow"]; + if( arrowModel && arrowModel->resource ) { auto arrowTex = engine->gameData.textures[{"copblue",""}]; - auto arrowFrame = arrowModel->model->findFrame( "arrow" ); + auto arrowFrame = arrowModel->resource->findFrame( "arrow" ); for( auto& blip : engine->state.radarBlips ) { if( blip.second.display == BlipData::Show ) @@ -381,7 +381,7 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha) dp.ambient = 1.f; dp.colour = glm::u8vec4(255, 255, 255, 255); - auto geom = arrowModel->model->geometries[arrowFrame->getGeometries()[0]]; + auto geom = arrowModel->resource->geometries[arrowFrame->getGeometries()[0]]; Model::SubGeometry& sg = geom->subgeom[0]; dp.start = sg.start; @@ -550,7 +550,7 @@ void GameRenderer::renderPedestrian(CharacterObject *pedestrian) { glm::mat4 matrixModel = pedestrian->getTimeAdjustedTransform( _renderAlpha ); - if(!pedestrian->model->model) return; + if(!pedestrian->model->resource) return; if( pedestrian->isAnimationFixed() ) { @@ -559,12 +559,12 @@ void GameRenderer::renderPedestrian(CharacterObject *pedestrian) matrixModel = glm::translate(matrixModel, -rtranslate); } - auto root = pedestrian->model->model->frames[0]; + auto root = pedestrian->model->resource->frames[0]; - renderFrame(pedestrian->model->model, root->getChildren()[0], matrixModel, pedestrian, 1.f, pedestrian->animator); + renderFrame(pedestrian->model->resource, root->getChildren()[0], matrixModel, pedestrian, 1.f, pedestrian->animator); if(pedestrian->getActiveItem()) { - auto handFrame = pedestrian->model->model->findFrame("srhand"); + auto handFrame = pedestrian->model->resource->findFrame("srhand"); glm::mat4 localMatrix; if( handFrame ) { while( handFrame->getParent() ) { @@ -585,13 +585,13 @@ void GameRenderer::renderVehicle(VehicleObject *vehicle) glm::mat4 matrixModel = vehicle->getTimeAdjustedTransform( _renderAlpha ); - renderModel(vehicle->model->model, matrixModel, vehicle); + renderModel(vehicle->model->resource, matrixModel, vehicle); // Draw wheels n' stuff for( size_t w = 0; w < vehicle->info->wheels.size(); ++w) { auto woi = engine->findObjectType(vehicle->vehicle->wheelModelID); if( woi ) { - Model* wheelModel = engine->gameData.models["wheels"]->model; + Model* wheelModel = engine->gameData.models["wheels"]->resource; auto& wi = vehicle->physVehicle->getWheelInfo(w); if( wheelModel ) { // Construct our own matrix so we can use the local transform @@ -641,7 +641,7 @@ void GameRenderer::renderInstance(InstanceObject *instance) } } - if(!instance->model->model) + if(!instance->model->resource) { return; } @@ -657,9 +657,9 @@ void GameRenderer::renderInstance(InstanceObject *instance) } float mindist = 100000.f; - for (size_t g = 0; g < instance->model->model->geometries.size(); g++) + for (size_t g = 0; g < instance->model->resource->geometries.size(); g++) { - RW::BSGeometryBounds& bounds = instance->model->model->geometries[g]->geometryBounds; + RW::BSGeometryBounds& bounds = instance->model->resource->geometries[g]->geometryBounds; mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - _camera.position) - bounds.radius); } @@ -680,20 +680,20 @@ void GameRenderer::renderInstance(InstanceObject *instance) culled++; return; } - else if (instance->LODinstance->model->model) { - model = instance->LODinstance->model->model; + else if (instance->LODinstance->model->resource) { + model = instance->LODinstance->model->resource; - fadingModel = instance->model->model; + fadingModel = instance->model->resource; opacity = (mindist) / instance->object->drawDistance[0]; } } else { - fadingModel = instance->model->model; + fadingModel = instance->model->resource; opacity = (mindist) / instance->object->drawDistance[0]; } } else if (! instance->object->LOD ) { - model = instance->model->model; + model = instance->model->resource; opacity = (mindist) / instance->object->drawDistance[0]; } } @@ -703,14 +703,14 @@ void GameRenderer::renderInstance(InstanceObject *instance) return; } - auto root = instance->model->model->frames[0]; + auto root = instance->model->resource->frames[0]; int lodInd = 1; if( mindist > instance->object->drawDistance[0] ) { lodInd = 2; } auto LODindex = root->getChildren().size() - lodInd; auto f = root->getChildren()[LODindex]; - model = instance->model->model; + model = instance->model->resource; frame = f; if( lodInd == 2 ) { @@ -750,9 +750,9 @@ void GameRenderer::renderPickup(PickupObject *pickup) if( odata->ID >= 170 && odata->ID <= 184 ) { auto weapons = engine->gameData.models["weapons"]; - if( weapons && weapons->model && odata ) { - model = weapons->model; - itemModel = weapons->model->findFrame(odata->modelName + "_l0"); + if( weapons && weapons->resource && odata ) { + model = weapons->resource; + itemModel = weapons->resource->findFrame(odata->modelName + "_l0"); if ( ! itemModel ) { engine->logger.error("Renderer", "Weapon frame " + odata->modelName + " not in model"); @@ -762,9 +762,9 @@ void GameRenderer::renderPickup(PickupObject *pickup) else { auto handle = engine->gameData.models[odata->modelName]; - if ( handle && handle->model ) + if ( handle && handle->resource ) { - model = handle->model; + model = handle->resource; itemModel = model->frames[model->rootFrameIdx]; } else @@ -784,7 +784,7 @@ void GameRenderer::renderCutsceneObject(CutsceneObject *cutscene) { if(!engine->state.currentCutscene) return; - if(!cutscene->model->model) + if(!cutscene->model->resource) { return; } @@ -808,9 +808,9 @@ void GameRenderer::renderCutsceneObject(CutsceneObject *cutscene) } float mindist = 100000.f; - for (size_t g = 0; g < cutscene->model->model->geometries.size(); g++) + for (size_t g = 0; g < cutscene->model->resource->geometries.size(); g++) { - RW::BSGeometryBounds& bounds = cutscene->model->model->geometries[g]->geometryBounds; + RW::BSGeometryBounds& bounds = cutscene->model->resource->geometries[g]->geometryBounds; mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - _camera.position) - bounds.radius); } @@ -818,10 +818,10 @@ void GameRenderer::renderCutsceneObject(CutsceneObject *cutscene) glm::mat4 align; /// @todo figure out where this 90 degree offset is coming from. align = glm::rotate(align, glm::half_pi(), {0.f, 1.f, 0.f}); - renderModel(cutscene->model->model, matrixModel * align, cutscene); + renderModel(cutscene->model->resource, matrixModel * align, cutscene); } else { - renderModel(cutscene->model->model, matrixModel, cutscene); + renderModel(cutscene->model->resource, matrixModel, cutscene); } } @@ -831,11 +831,11 @@ void GameRenderer::renderProjectile(ProjectileObject *projectile) auto odata = engine->findObjectType(projectile->getProjectileInfo().weapon->modelID); auto weapons = engine->gameData.models["weapons"]; - if( weapons && weapons->model ) { - auto itemModel = weapons->model->findFrame(odata->modelName + "_l0"); + if( weapons && weapons->resource ) { + auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0"); auto matrix = glm::inverse(itemModel->getTransform()); if(itemModel) { - renderFrame(weapons->model, itemModel, modelMatrix * matrix, nullptr, 1.f); + renderFrame(weapons->resource, itemModel, modelMatrix * matrix, nullptr, 1.f); } else { engine->logger.error("Renderer", "Weapon frame " + odata->modelName + " not in model"); @@ -875,11 +875,11 @@ void GameRenderer::renderItem(InventoryItem *item, const glm::mat4 &modelMatrix) // srhand std::shared_ptr odata = engine->findObjectType(item->getModelID()); auto weapons = engine->gameData.models["weapons"]; - if( weapons && weapons->model ) { - auto itemModel = weapons->model->findFrame(odata->modelName + "_l0"); + if( weapons && weapons->resource ) { + auto itemModel = weapons->resource->findFrame(odata->modelName + "_l0"); auto matrix = glm::inverse(itemModel->getTransform()); if(itemModel) { - renderFrame(weapons->model, itemModel, modelMatrix * matrix, nullptr, 1.f); + renderFrame(weapons->resource, itemModel, modelMatrix * matrix, nullptr, 1.f); } else { engine->logger.error("Renderer", "Weapon frame " + odata->modelName + " not in model"); diff --git a/rwengine/src/script/modules/GameModule.cpp b/rwengine/src/script/modules/GameModule.cpp index 67ab24ec..db03fcea 100644 --- a/rwengine/src/script/modules/GameModule.cpp +++ b/rwengine/src/script/modules/GameModule.cpp @@ -408,7 +408,7 @@ bool game_special_char_loaded(const ScriptArguments& args) auto chartype = args.getVM()->getWorld()->findObjectType(args[0].integer); if( chartype ) { auto modelfind = args.getVM()->getWorld()->gameData.models.find(chartype->modelName); - if( modelfind != args.getVM()->getWorld()->gameData.models.end() && modelfind->second->model != nullptr ) { + if( modelfind != args.getVM()->getWorld()->gameData.models.end() && modelfind->second->resource != nullptr ) { return true; } } @@ -616,7 +616,7 @@ void game_create_cutscene_head(const ScriptArguments& args) auto actor = static_cast(*args[0].handle); CutsceneObject* object = args.getVM()->getWorld()->createCutsceneObject(id, args.getVM()->getWorld()->state.currentCutscene->meta.sceneOffset ); - auto headframe = actor->model->model->findFrame("shead"); + auto headframe = actor->model->resource->findFrame("shead"); actor->skeleton->setEnabled(headframe, false); object->setParentActor(actor, headframe); diff --git a/rwengine/tests/test_Loader.cpp b/rwengine/tests/test_Loader.cpp new file mode 100644 index 00000000..c258eeb2 --- /dev/null +++ b/rwengine/tests/test_Loader.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +class IntLoader : public Loader +{ + int data; +public: + IntLoader( int value ) : data( value ) { } + + ResultType get() { return data; } +}; + +BOOST_AUTO_TEST_SUITE(LoaderTests) + +BOOST_AUTO_TEST_CASE(test_product) +{ + BOOST_CHECK( typeid(IntLoader::ResultType) == typeid(int) ); + IntLoader loader( 42 ); + BOOST_CHECK_EQUAL( loader.get(), 42 ); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/rwengine/tests/test_Resource.cpp b/rwengine/tests/test_Resource.cpp new file mode 100644 index 00000000..b2708e47 --- /dev/null +++ b/rwengine/tests/test_Resource.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +typedef ResourceHandle::Ref IntRef; + +BOOST_AUTO_TEST_SUITE(ResourceTests) + +BOOST_AUTO_TEST_CASE(test_ResourceHandle) +{ + int resource = 42; + IntRef ref { new ResourceHandle("") }; + + BOOST_CHECK_EQUAL( ref->resource, nullptr ); + BOOST_CHECK_EQUAL( ref->state, RW::Loading ); + + ref->state = RW::Loaded; + ref->resource = &resource; + + BOOST_CHECK_EQUAL( ref->resource, &resource ); + BOOST_CHECK_EQUAL( ref->state, RW::Loaded ); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/rwgame/ingamestate.cpp b/rwgame/ingamestate.cpp index eed8f1bb..b1bcf60c 100644 --- a/rwgame/ingamestate.cpp +++ b/rwgame/ingamestate.cpp @@ -141,7 +141,7 @@ void IngameState::tick(float dt) auto vehicle = ( target->type() == GameObject::Character ) ? static_cast(target)->getCurrentVehicle() : nullptr; if( vehicle ) { auto model = vehicle->model; - for(auto& g : model->model->geometries) { + for(auto& g : model->resource->geometries) { viewDistance = std::max( (glm::length(g->geometryBounds.center) + g->geometryBounds.radius) * 4.0f, viewDistance); diff --git a/tests/test_animation.cpp b/tests/test_animation.cpp index 4c23758e..10e8f75d 100644 --- a/tests/test_animation.cpp +++ b/tests/test_animation.cpp @@ -15,9 +15,9 @@ BOOST_AUTO_TEST_CASE(test_matrix) /** Models are currently needed to relate animation bones <=> model frame #s. */ Global::get().e->gameData.loadDFF("player.dff"); - ModelHandle* test_model = Global::get().e->gameData.models["player"]; + ModelRef& test_model = Global::get().e->gameData.models["player"]; - Animator animator(test_model->model, &skeleton); + Animator animator(test_model->resource, &skeleton); animation.duration = 1.f; animation.bones["player"] = new AnimationBone{ diff --git a/tests/test_cutscene.cpp b/tests/test_cutscene.cpp index 1584067e..2fd50035 100644 --- a/tests/test_cutscene.cpp +++ b/tests/test_cutscene.cpp @@ -8,7 +8,7 @@ BOOST_AUTO_TEST_SUITE(CutsceneTests) BOOST_AUTO_TEST_CASE(test_load) { { - auto d = Global::get().e->gameData.openFile2("intro.dat"); + auto d = Global::get().e->gameData.openFile("intro.dat"); CutsceneTracks tracks; diff --git a/tests/test_loaderdff.cpp b/tests/test_loaderdff.cpp index a791fe64..92e608b9 100644 --- a/tests/test_loaderdff.cpp +++ b/tests/test_loaderdff.cpp @@ -2,17 +2,18 @@ #include "test_globals.hpp" #include #include +#include BOOST_AUTO_TEST_SUITE(LoaderDFFTests) BOOST_AUTO_TEST_CASE(test_load_dff) { { - auto d = Global::get().e->gameData.openFile2("landstal.dff"); + auto d = Global::get().e->gameData.openFile("landstal.dff"); LoaderDFF loader; - Model* m = loader.loadFromMemory(d, &Global::get().e->gameData); + Model* m = loader.loadFromMemory(d); BOOST_REQUIRE( m != nullptr ); @@ -38,28 +39,28 @@ BOOST_AUTO_TEST_CASE(test_load_dff) } -BOOST_AUTO_TEST_CASE(test_modeljob) +BOOST_AUTO_TEST_CASE(test_loader_job) { { WorkContext ctx; - Model* m = nullptr; - bool done = false; - LoadModelJob* lmj = new LoadModelJob(&ctx, &Global::get().e->gameData, "landstal.dff", - [&](Model* model) { m = model; done = true; }); + ResourceHandle::Ref modelRef { new ResourceHandle("landstal.dff") }; + + auto index = &Global::get().e->gameData.index; + auto job = new BackgroundLoaderJob{ &ctx, index, "landstal.dff", modelRef }; - ctx.queueJob(lmj); + ctx.queueJob(job); - while( ! done ) { + while( modelRef->state == RW::Loading ) { ctx.update(); std::this_thread::yield(); } - BOOST_REQUIRE( m != nullptr ); + BOOST_REQUIRE( modelRef->resource != nullptr ); - BOOST_CHECK( m->frames.size() > 0 ); - - delete m; + BOOST_CHECK( modelRef->resource->frames.size() > 0 ); + + delete modelRef->resource; } } diff --git a/tests/test_rwbstream.cpp b/tests/test_rwbstream.cpp index 8a983267..3be49551 100644 --- a/tests/test_rwbstream.cpp +++ b/tests/test_rwbstream.cpp @@ -7,7 +7,7 @@ BOOST_AUTO_TEST_SUITE(RWBStreamTests) BOOST_AUTO_TEST_CASE(iterate_stream_test) { { - auto d = Global::get().e->gameData.openFile2("landstal.dff"); + auto d = Global::get().e->gameData.openFile("landstal.dff"); RWBStream stream(d->data, d->length); diff --git a/tests/test_text.cpp b/tests/test_text.cpp index 17d56bc0..a3a587cb 100644 --- a/tests/test_text.cpp +++ b/tests/test_text.cpp @@ -8,7 +8,7 @@ BOOST_AUTO_TEST_SUITE(TextTests) BOOST_AUTO_TEST_CASE(load_test) { { - auto d = Global::get().e->gameData.openFile2("english.gxt"); + auto d = Global::get().e->gameData.openFile("english.gxt"); GameTexts texts;