diff --git a/rwengine/include/WorkContext.hpp b/rwengine/include/WorkContext.hpp index 657e533d..5555b39e 100644 --- a/rwengine/include/WorkContext.hpp +++ b/rwengine/include/WorkContext.hpp @@ -52,6 +52,9 @@ public: virtual void complete() {} }; +// TODO: refactor everything to remove this. +class GameWorld; + class WorkContext { std::queue _workQueue; @@ -62,10 +65,12 @@ class WorkContext std::mutex _inMutex; std::mutex _outMutex; + GameWorld* _world; + public: - WorkContext() - : _worker(this) { } + WorkContext(GameWorld* world = nullptr) + : _worker(this), _world(world) { } void queueJob( WorkJob* job ) { @@ -79,6 +84,15 @@ public: const std::queue getWorkQueue() const { return _workQueue; } const std::queue getCompleteQueue() const { return _completeQueue; } + bool isEmpty() { + std::lock_guard guardIn( _inMutex ); + std::lock_guard guardOu( _outMutex ); + + return (getWorkQueue().size() + getCompleteQueue().size()) == 0; + } + + GameWorld* getWorld() const { return _world; } + void update(); }; diff --git a/rwengine/include/engine/GTATypes.hpp b/rwengine/include/engine/GTATypes.hpp index a024317b..14aefb13 100644 --- a/rwengine/include/engine/GTATypes.hpp +++ b/rwengine/include/engine/GTATypes.hpp @@ -11,6 +11,16 @@ class 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 GTATypes { @@ -46,7 +56,6 @@ struct WaterRect float xLeft, yBottom; float xRight, yTop; }; - } #endif diff --git a/rwengine/include/engine/GameData.hpp b/rwengine/include/engine/GameData.hpp index ebb805fd..adae4bf3 100644 --- a/rwengine/include/engine/GameData.hpp +++ b/rwengine/include/engine/GameData.hpp @@ -55,7 +55,7 @@ public: struct GTAFile { bool archived; /// Is the file inside an IMG or on the filesystem? - std::string path; /// Path to the file containing the file + std::string path; /// Path to the file containing the file. }; /** @@ -113,12 +113,12 @@ public: /** * Attempts to load a TXD, or does nothing if it has already been loaded */ - void loadTXD(const std::string& name); - + 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); + void loadDFF(const std::string& name, bool async = false); /** * Loads an IFP file containing animations @@ -129,11 +129,19 @@ public: * Loads data from an object definition dat. */ void loadDynamicObjects(const std::string& name); - + /** - * Returns a pointer to the named file if it is available, the memory must be freed. + * Returns a pointer to the named file if it is available, + * the memory must be freed by the caller. * @param name the filename in the archive - * @return pointer to the data, NULL if it is not available + * @return pointer to the data, NULL if it is not available + */ + char* openFile(const std::string& name); + + /** + * @brief loadFile Marks a file as open, and opens it. + * @param name + * @return */ char* loadFile(const std::string& name); @@ -157,9 +165,9 @@ public: std::map ideLocations; /** - * Maps file names to their locations + * Maps file names to data about the file. */ - std::map fileLocations; + std::map _knownFiles; /** * Map of loaded archives @@ -190,11 +198,11 @@ public: * Weather Loader */ WeatherLoader weatherLoader; - + /** * Loaded models */ - std::map models; + std::map models; /** * Loaded Textures and their atlas entries. diff --git a/rwengine/include/engine/GameObject.hpp b/rwengine/include/engine/GameObject.hpp index 4537d0f0..fd0b531a 100644 --- a/rwengine/include/engine/GameObject.hpp +++ b/rwengine/include/engine/GameObject.hpp @@ -9,7 +9,6 @@ #include class GTAAIController; -class Model; class ModelFrame; class Animator; @@ -23,7 +22,7 @@ struct GameObject glm::vec3 position; glm::quat rotation; - Model* model; /// Cached pointer to Object's Model. + ModelHandle* model; /// Cached pointer to Object's Model. GameWorld* engine; @@ -34,7 +33,7 @@ struct GameObject */ float mHealth; - GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, Model* model) + GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model) : position(pos), rotation(rot), model(model), engine(engine), animator(nullptr), mHealth(0.f) {} diff --git a/rwengine/include/engine/GameWorld.hpp b/rwengine/include/engine/GameWorld.hpp index c6478947..f9bd3afd 100644 --- a/rwengine/include/engine/GameWorld.hpp +++ b/rwengine/include/engine/GameWorld.hpp @@ -8,6 +8,8 @@ #include #include +class WorkContext; + class GameObject; class GTACharacter; class GTAInstance; @@ -31,6 +33,8 @@ class GameWorld public: GameWorld(const std::string& gamepath); + + ~GameWorld(); /** * Loads the game data @@ -191,7 +195,11 @@ public: btBroadphaseInterface* broadphase; btSequentialImpulseConstraintSolver* solver; btDiscreteDynamicsWorld* dynamicsWorld; - + + /** + * Work related + */ + WorkContext* _work; }; #endif diff --git a/rwengine/include/loaders/LoaderDFF.hpp b/rwengine/include/loaders/LoaderDFF.hpp index f4267f2a..b09f8883 100644 --- a/rwengine/include/loaders/LoaderDFF.hpp +++ b/rwengine/include/loaders/LoaderDFF.hpp @@ -27,8 +27,6 @@ public: #include -class LoaderIMG; - class LoadModelJob : public WorkJob { public: @@ -36,13 +34,12 @@ public: private: GameData* _gameData; - LoaderIMG* _archive; std::string _file; ModelCallback _callback; char* _data; public: - LoadModelJob(WorkContext* context, GameData* gd, LoaderIMG& archive, const std::string& file, ModelCallback cb); + LoadModelJob(WorkContext* context, GameData* gd, const std::string& file, ModelCallback cb); void work(); diff --git a/rwengine/include/loaders/TextureLoader.hpp b/rwengine/include/loaders/TextureLoader.hpp index c5d9c262..02cccc28 100644 --- a/rwengine/include/loaders/TextureLoader.hpp +++ b/rwengine/include/loaders/TextureLoader.hpp @@ -19,4 +19,23 @@ public: bool loadFromMemory(char *data, GameData* gameData); }; +#include +#include + +// TODO: refactor this interface to be more like ModelLoader so they can be rolled into one. +class LoadTextureArchiveJob : public WorkJob +{ +private: + GameData* _gameData; + std::string _file; + char* _data; +public: + + LoadTextureArchiveJob(WorkContext* context, GameData* gd, const std::string& file); + + void work(); + + void complete(); +}; + #endif diff --git a/rwengine/include/objects/GTACharacter.hpp b/rwengine/include/objects/GTACharacter.hpp index a2cfbfb1..2334b135 100644 --- a/rwengine/include/objects/GTACharacter.hpp +++ b/rwengine/include/objects/GTACharacter.hpp @@ -90,7 +90,7 @@ public: * @param model * @param ped PEDS_t struct to use. */ - GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, Model* model, std::shared_ptr data); + GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle *model, std::shared_ptr data); ~GTACharacter(); diff --git a/rwengine/include/objects/GTAInstance.hpp b/rwengine/include/objects/GTAInstance.hpp index 0f993c6d..e8c15f8b 100644 --- a/rwengine/include/objects/GTAInstance.hpp +++ b/rwengine/include/objects/GTAInstance.hpp @@ -17,7 +17,7 @@ struct GTAInstance : public GameObject GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - Model* model, + ModelHandle* model, const glm::vec3& scale, std::shared_ptr obj, std::shared_ptr lod diff --git a/rwengine/include/objects/GTAVehicle.hpp b/rwengine/include/objects/GTAVehicle.hpp index 6fb2233c..6c59e3e8 100644 --- a/rwengine/include/objects/GTAVehicle.hpp +++ b/rwengine/include/objects/GTAVehicle.hpp @@ -52,7 +52,7 @@ public: GTAVehicle(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - Model* model, + ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::vec3& prim, diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index d8f6fb27..1a82704a 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -82,9 +82,9 @@ void GameData::load() parseDAT(datpath+"/data/default.dat"); parseDAT(datpath+"/data/gta3.dat"); - fileLocations.insert({"wheels.DFF", {false, datpath+"/models/Generic/wheels.DFF"}}); - fileLocations.insert({"loplyguy.dff", {false, datpath+"/models/Generic/loplyguy.dff"}}); - fileLocations.insert({"particle.txd", {false, datpath+"/models/particle.txd"}}); + _knownFiles.insert({"wheels.DFF", {false, datpath+"/models/Generic/wheels.DFF"}}); + _knownFiles.insert({"loplyguy.dff", {false, datpath+"/models/Generic/loplyguy.dff"}}); + _knownFiles.insert({"particle.txd", {false, datpath+"/models/particle.txd"}}); loadDFF("wheels.DFF"); loadTXD("particle.txd"); @@ -147,7 +147,7 @@ void GameData::parseDAT(const std::string& path) } texpath = findPathRealCase(datpath, texpath); std::string texname = texpath.substr(texpath.find_last_of("/")+1); - fileLocations.insert({ texname, { false, texpath }}); + _knownFiles.insert({ texname, { false, texpath }}); loadTXD(texname); } } @@ -201,12 +201,12 @@ void GameData::loadIMG(const std::string& name) else { // Enter the asset twice.. - fileLocations.insert({ filename, { true, archivePath }}); + _knownFiles.insert({ filename, { true, archivePath }}); for(size_t t = 0; t < filename.size(); ++t) { filename[t] = tolower(filename[t]); } - fileLocations.insert({ filename, { true, archivePath }}); + _knownFiles.insert({ filename, { true, archivePath }}); } } archives.insert({archivePath, imgLoader}); @@ -388,32 +388,54 @@ void GameData::loadWater(const std::string& path) } } -void GameData::loadTXD(const std::string& name) +void GameData::loadTXD(const std::string& name, bool async) { - if( loadedFiles.find(name) != loadedFiles.end()) { + if( loadedFiles.find(name) != loadedFiles.end() ) { return; } - - char* file = loadFile(name); - if(file) { - textureLoader.loadFromMemory(file, this); - delete[] file; + + loadedFiles[name] = true; + + auto j = new LoadTextureArchiveJob(this->engine->_work, this, name); + + if( async ) { + this->engine->_work->queueJob( j ); + } + else { + j->work(); + j->complete(); + delete j; } } -void GameData::loadDFF(const std::string& name) +void GameData::loadDFF(const std::string& name, bool async) { - if( loadedFiles.find(name) != loadedFiles.end()) { + auto realname = name.substr(0, name.size() - 4); + if( models.find(realname) != models.end() ) { return; } - - char *file = loadFile(name); - if(file) - { - LoaderDFF dffLoader; - models[name.substr(0, name.size() - 4)] = dffLoader.loadFromMemory(file, this); - delete[] file; + + // 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; + } + ); + + + if( async ) { + this->engine->_work->queueJob( j ); } + else { + j->work(); + j->complete(); + delete j; + } + } void GameData::loadIFP(const std::string &name) @@ -471,15 +493,10 @@ void GameData::loadDynamicObjects(const std::string& name) } } -char* GameData::loadFile(const std::string& name) +char* GameData::openFile(const std::string& name) { - if( loadedFiles.find(name) != loadedFiles.end()) { - std::cerr << "File " << name << " already loaded!" << std::endl; - return nullptr; - } - - auto i = fileLocations.find(name); - if(i != fileLocations.end()) + auto i = _knownFiles.find(name); + if(i != _knownFiles.end()) { if(i->second.archived) { @@ -487,7 +504,6 @@ char* GameData::loadFile(const std::string& name) auto ai = archives.find(i->second.path); if(ai != archives.end()) { - loadedFiles[name] = true; return ai->second.loadToMemory(name); } else @@ -509,8 +525,6 @@ char* GameData::loadFile(const std::string& name) char *data = new char[length]; dfile.read(data, length); - loadedFiles[name] = true; - return data; } } @@ -525,6 +539,18 @@ char* GameData::loadFile(const std::string& name) return nullptr; } +char* GameData::loadFile(const std::string &name) +{ + auto it = loadedFiles.find(name); + if( it != loadedFiles.end() ) { + std::cerr << "File " << name << " already loaded?" << std::endl; + } + + loadedFiles[name] = true; + + return openFile(name); +} + TextureAtlas* GameData::getAtlas(size_t i) { if( i < atlases.size() ) { diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index e50a4082..f857bfe3 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -4,6 +4,7 @@ #include #include #include +#include // 3 isn't enough to cause a factory. #include @@ -11,11 +12,18 @@ #include GameWorld::GameWorld(const std::string& path) - : gameTime(0.f), gameData(path), renderer(this), randomEngine(rand()) + : gameTime(0.f), gameData(path), renderer(this), randomEngine(rand()), + _work( new WorkContext( this ) ) { gameData.engine = this; } +GameWorld::~GameWorld() +{ + delete _work; + // TODO: delete other things. +} + bool GameWorld::load() { collisionConfig = new btDefaultCollisionConfiguration; @@ -174,10 +182,10 @@ GTAInstance *GameWorld::createInstance(const uint16_t id, const glm::vec3& pos, if( oi != objectTypes.end()) { // Make sure the DFF and TXD are loaded if(! oi->second->modelName.empty()) { - gameData.loadDFF(oi->second->modelName + ".dff"); + gameData.loadDFF(oi->second->modelName + ".dff", true); } if(! oi->second->textureName.empty()) { - gameData.loadTXD(oi->second->textureName + ".txd"); + gameData.loadTXD(oi->second->textureName + ".txd", true); } auto instance = std::shared_ptr(new GTAInstance( @@ -236,7 +244,8 @@ GTAVehicle *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, co } } - Model* model = gameData.models[vti->second->modelName]; + ModelHandle* m = gameData.models[vti->second->modelName]; + auto model = m->model; auto info = gameData.vehicleInfo.find(vti->second->handlingID); if(model && info != gameData.vehicleInfo.end()) { if( info->second->wheels.size() == 0 && info->second->seats.size() == 0 ) { @@ -258,7 +267,7 @@ GTAVehicle *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, co } } - vehicleInstances.push_back(new GTAVehicle{ this, pos, rot, model, vti->second, info->second, prim, sec }); + vehicleInstances.push_back(new GTAVehicle{ this, pos, rot, m, vti->second, info->second, prim, sec }); return vehicleInstances.back(); } return nullptr; @@ -280,10 +289,10 @@ GTACharacter* GameWorld::createPedestrian(const uint16_t id, const glm::vec3 &po gameData.loadTXD(pt->textureName + ".txd"); } - Model* model = gameData.models[pt->modelName]; + ModelHandle* m = gameData.models[pt->modelName]; - if(model != nullptr) { - auto ped = new GTACharacter( this, pos, rot, model, pt ); + if(m != nullptr) { + auto ped = new GTACharacter( this, pos, rot, m, pt ); pedestrians.push_back(ped); new GTADefaultAIController(ped); return ped; diff --git a/rwengine/src/loaders/LoaderDFF.cpp b/rwengine/src/loaders/LoaderDFF.cpp index 45b70301..70c55927 100644 --- a/rwengine/src/loaders/LoaderDFF.cpp +++ b/rwengine/src/loaders/LoaderDFF.cpp @@ -312,25 +312,28 @@ RW::BSSectionHeader LoaderDFF::readHeader(char *data, size_t &dataI) return readStructure(data, dataI); } -#include - -LoadModelJob::LoadModelJob(WorkContext *context, GameData* gd, LoaderIMG &archive, const std::string &file, ModelCallback cb) - : WorkJob(context), _gameData(gd), _archive(&archive), _file(file), _callback(cb), _data(nullptr) +LoadModelJob::LoadModelJob(WorkContext *context, GameData* gd, const std::string &file, ModelCallback cb) + : WorkJob(context), _gameData(gd), _file(file), _callback(cb), _data(nullptr) { } void LoadModelJob::work() { - _data = _archive->loadToMemory(_file); + _data = _gameData->openFile(_file); } void LoadModelJob::complete() { - // TODO allow some of the loading to process in a seperate thread. - LoaderDFF loader; + Model* m = nullptr; + // TODO error status + if( _data ) { - Model* m = loader.loadFromMemory(_data, _gameData); + // 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/loaders/TextureLoader.cpp b/rwengine/src/loaders/TextureLoader.cpp index e5b0d960..bdb9d9ee 100644 --- a/rwengine/src/loaders/TextureLoader.cpp +++ b/rwengine/src/loaders/TextureLoader.cpp @@ -217,3 +217,26 @@ bool TextureLoader::loadFromMemory(char *data, GameData *gameData) return true; } + + +LoadTextureArchiveJob::LoadTextureArchiveJob(WorkContext *context, GameData *gd, const std::string &file) + : WorkJob(context), _gameData(gd), _file(file), _data(nullptr) +{ + +} + +void LoadTextureArchiveJob::work() +{ + _data = _gameData->openFile(_file); +} + +void LoadTextureArchiveJob::complete() +{ + // TODO error status + if(_data) { + TextureLoader loader; + loader.loadFromMemory(_data, _gameData); + } + + delete[] _data; +} diff --git a/rwengine/src/objects/GTACharacter.cpp b/rwengine/src/objects/GTACharacter.cpp index d4da48a9..d73ee26b 100644 --- a/rwengine/src/objects/GTACharacter.cpp +++ b/rwengine/src/objects/GTACharacter.cpp @@ -7,7 +7,7 @@ // TODO: make this not hardcoded static glm::vec3 enter_offset(0.81756252f, 0.34800607f, -0.486281008f); -GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, Model* model, std::shared_ptr data) +GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, std::shared_ptr data) : GameObject(engine, pos, rot, model), currentVehicle(nullptr), currentSeat(0), _hasTargetPosition(false), @@ -35,7 +35,7 @@ GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::q if(model) { animator = new Animator(); - animator->setModel(model); + animator->setModel(model->model); createActor(); enterAction(Idle); diff --git a/rwengine/src/objects/GTAInstance.cpp b/rwengine/src/objects/GTAInstance.cpp index b26f008b..776d187c 100644 --- a/rwengine/src/objects/GTAInstance.cpp +++ b/rwengine/src/objects/GTAInstance.cpp @@ -2,11 +2,10 @@ #include #include -GTAInstance::GTAInstance( - GameWorld* engine, +GTAInstance::GTAInstance(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, - Model* model, + ModelHandle *model, const glm::vec3& scale, std::shared_ptr obj, std::shared_ptr lod diff --git a/rwengine/src/objects/GTAVehicle.cpp b/rwengine/src/objects/GTAVehicle.cpp index a5d2d54b..ef319f67 100644 --- a/rwengine/src/objects/GTAVehicle.cpp +++ b/rwengine/src/objects/GTAVehicle.cpp @@ -6,7 +6,7 @@ #include #include -GTAVehicle::GTAVehicle(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, Model* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::vec3& prim, const glm::vec3& sec) +GTAVehicle::GTAVehicle(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::vec3& prim, const glm::vec3& sec) : GameObject(engine, pos, rot, model), steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false), damageFlags(0), vehicle(data), info(info), colourPrimary(prim), diff --git a/rwengine/src/render/GTARenderer.cpp b/rwengine/src/render/GTARenderer.cpp index 4c320283..548366a7 100644 --- a/rwengine/src/render/GTARenderer.cpp +++ b/rwengine/src/render/GTARenderer.cpp @@ -268,9 +268,9 @@ void GTARenderer::renderWorld(float alpha) matrixModel = glm::translate(matrixModel, charac->getPosition()); matrixModel = matrixModel * glm::mat4_cast(charac->getRotation()); - if(!charac->model) continue; + if(!charac->model->model) continue; - renderModel(charac->model, matrixModel, charac, charac->animator); + renderModel(charac->model->model, matrixModel, charac, charac->animator); } for(size_t i = 0; i < engine->objectInstances.size(); ++i) { @@ -284,24 +284,24 @@ void GTARenderer::renderWorld(float alpha) } } - if(!inst.model) - { - std::cout << "model " << inst.model << " not loaded (" << engine->gameData.models.size() << " models loaded)" << std::endl; - } - - glm::mat4 matrixModel; - matrixModel = glm::translate(matrixModel, inst.position); - matrixModel = glm::scale(matrixModel, inst.scale); - matrixModel = matrixModel * glm::mat4_cast(inst.rotation); + if(!inst.model->model) + { + continue; + } - float mindist = 100000.f; - for (size_t g = 0; g < inst.model->geometries.size(); g++) - { - RW::BSGeometryBounds& bounds = inst.model->geometries[g]->geometryBounds; - mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - camera.worldPos) - bounds.radius); - } - - if ( mindist > inst.object->drawDistance[0] ) { + glm::mat4 matrixModel; + matrixModel = glm::translate(matrixModel, inst.position); + matrixModel = glm::scale(matrixModel, inst.scale); + matrixModel = matrixModel * glm::mat4_cast(inst.rotation); + + float mindist = 100000.f; + for (size_t g = 0; g < inst.model->model->geometries.size(); g++) + { + RW::BSGeometryBounds& bounds = inst.model->model->geometries[g]->geometryBounds; + mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - camera.worldPos) - bounds.radius); + } + + if ( mindist > inst.object->drawDistance[0] ) { if ( !inst.LODinstance ) { culled++; continue; @@ -311,13 +311,13 @@ void GTARenderer::renderWorld(float alpha) culled++; continue; } - else { - renderModel(inst.LODinstance->model, matrixModel); + else if (inst.LODinstance->model->model) { + renderModel(inst.LODinstance->model->model, matrixModel); } } - } + } else if (! inst.object->LOD ) { - renderModel(inst.model, matrixModel); + renderModel(inst.model->model, matrixModel); } } @@ -333,13 +333,13 @@ void GTARenderer::renderWorld(float alpha) matrixModel = glm::translate(matrixModel, inst->getPosition()); matrixModel = matrixModel * glm::mat4_cast(inst->getRotation()); - renderModel(inst->model, matrixModel, inst); + renderModel(inst->model->model, matrixModel, inst); // Draw wheels n' stuff for( size_t w = 0; w < inst->info->wheels.size(); ++w) { auto woi = engine->objectTypes.find(inst->vehicle->wheelModelID); if(woi != engine->objectTypes.end()) { - Model* wheelModel = engine->gameData.models["wheels"]; + Model* wheelModel = engine->gameData.models["wheels"]->model; if( wheelModel) { // Tell bullet to update the matrix for this wheel. inst->physVehicle->updateWheelTransform(w, false); diff --git a/rwgame/CMakeLists.txt b/rwgame/CMakeLists.txt index 2fb04908..c5e0430b 100644 --- a/rwgame/CMakeLists.txt +++ b/rwgame/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(rwgame main.cpp + loadingstate.cpp ingamestate.cpp pausestate.cpp menustate.cpp diff --git a/rwgame/State.hpp b/rwgame/State.hpp index 010a062f..b897897d 100644 --- a/rwgame/State.hpp +++ b/rwgame/State.hpp @@ -119,6 +119,12 @@ struct StateManager states.push_back(state); state->enter(); } + + void exec(State* state) + { + exit(); + enter(state); + } void tick(float dt) { diff --git a/rwgame/ingamestate.cpp b/rwgame/ingamestate.cpp index 0925efe2..74996937 100644 --- a/rwgame/ingamestate.cpp +++ b/rwgame/ingamestate.cpp @@ -67,7 +67,7 @@ void IngameState::tick(float dt) float viewDistance = 2.f; if( _playerCharacter->getCurrentVehicle() ) { auto model = _playerCharacter->getCurrentVehicle()->model; - for(auto& g : model->geometries) { + for(auto& g : model->model->geometries) { viewDistance = std::max( (glm::length(g->geometryBounds.center) + g->geometryBounds.radius) * 1.5f, viewDistance); diff --git a/rwgame/loadingstate.cpp b/rwgame/loadingstate.cpp new file mode 100644 index 00000000..6ae8cda8 --- /dev/null +++ b/rwgame/loadingstate.cpp @@ -0,0 +1,55 @@ +#include "loadingstate.hpp" +#include "menustate.hpp" +#include "game.hpp" + +LoadingState::LoadingState() +{ +} + +void LoadingState::enter() +{ + // Load all of the files waiting to be loaded. + auto world = getWorld(); + + // Loade all of the IDEs. + for(std::map::iterator it = world->gameData.ideLocations.begin(); + it != world->gameData.ideLocations.end(); + ++it) { + world->defineItems(it->second); + } + + // Load IPLs + for(std::map::iterator it = world->gameData.iplLocations.begin(); + it != world->gameData.iplLocations.end(); + ++it) { + world->loadZone(it->second); + world->placeItems(it->second); + } +} + +void LoadingState::exit() +{ + +} + +void LoadingState::tick(float dt) +{ + // Check to see if the GameWorld has run out of jobs + // (i.e. it's time to open the main menu) + if( getWorld()->_work->isEmpty() ) { + StateManager::get().exec(new MenuState); + } +} + +void LoadingState::handleEvent(const sf::Event &e) +{ + State::handleEvent(e); +} + +void LoadingState::draw(sf::RenderWindow &w) +{ + // Display some manner of loading screen. + sf::Text loadingText("Loading...", getFont(), 28); + loadingText.setPosition({30.f, 20.f}); + w.draw(loadingText); +} diff --git a/rwgame/loadingstate.hpp b/rwgame/loadingstate.hpp new file mode 100644 index 00000000..ea7ece0b --- /dev/null +++ b/rwgame/loadingstate.hpp @@ -0,0 +1,21 @@ +#ifndef LOADINGSTATE_HHP +#define LOADINGSTATE_HPP + +#include "State.hpp" + +class LoadingState : public State +{ +public: + LoadingState(); + + virtual void enter(); + virtual void exit(); + + virtual void tick(float dt); + + virtual void draw(sf::RenderWindow &w); + + virtual void handleEvent(const sf::Event& event); +}; + +#endif // MENUSTATE_HPP diff --git a/rwgame/main.cpp b/rwgame/main.cpp index 9628d0cc..0c6feb58 100644 --- a/rwgame/main.cpp +++ b/rwgame/main.cpp @@ -13,7 +13,7 @@ #include #include -#include "menustate.hpp" +#include "loadingstate.hpp" #include #include @@ -39,8 +39,8 @@ int debugMode = 0; sf::Font font; -glm::vec3 viewPosition; -glm::vec2 viewAngles; +glm::vec3 viewPosition { -200.f, -100.f, 45.f }; +glm::vec2 viewAngles { -0.90f, 0.2f }; void setViewParameters(const glm::vec3 ¢er, const glm::vec2 &angles) { @@ -293,23 +293,6 @@ void init(std::string gtapath, bool loadWorld) // Set time to noon. gta->gameTime = 12.f * 60.f; - // Loade all of the IDEs. - for(std::map::iterator it = gta->gameData.ideLocations.begin(); - it != gta->gameData.ideLocations.end(); - ++it) { - gta->defineItems(it->second); - } - - if(loadWorld) { - // Load IPLs - for(std::map::iterator it = gta->gameData.iplLocations.begin(); - it != gta->gameData.iplLocations.end(); - ++it) { - gta->loadZone(it->second); - gta->placeItems(it->second); - } - } - debugDrawer = new DebugDraw; debugDrawer->setShaderProgram(gta->renderer.worldProgram); debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe); @@ -361,6 +344,8 @@ void update(float dt) void render(float alpha) { + gta->_work->update(); + // Update aspect ratio.. gta->renderer.camera.frustum.aspectRatio = window.getSize().x / (float) window.getSize().y; @@ -491,9 +476,7 @@ int main(int argc, char *argv[]) sf::Clock clock; - MenuState* menuState = new MenuState(); - - StateManager::get().enter(menuState); + StateManager::get().enter(new LoadingState); float accum = 0.f; float ts = 1.f / 60.f; diff --git a/rwviewer/DFFFramesTreeModel.cpp b/rwviewer/DFFFramesTreeModel.cpp index 69b8ab58..91f63c2a 100644 --- a/rwviewer/DFFFramesTreeModel.cpp +++ b/rwviewer/DFFFramesTreeModel.cpp @@ -1,7 +1,7 @@ #include "DFFFramesTreeModel.hpp" #include -DFFFramesTreeModel::DFFFramesTreeModel(Model* m, QObject* parent) +DFFFramesTreeModel::DFFFramesTreeModel(ModelHandle *m, QObject* parent) : QAbstractItemModel(parent), model(m) { @@ -29,7 +29,7 @@ int DFFFramesTreeModel::rowCount(const QModelIndex& parent) const QModelIndex DFFFramesTreeModel::index(int row, int column, const QModelIndex& parent) const { if(parent.row() == -1 && parent.column() == -1) { - return createIndex(row, column, model->frames[model->rootFrameIdx]); + return createIndex(row, column, model->model->frames[model->model->rootFrameIdx]); } ModelFrame* f = static_cast(parent.internalPointer()); ModelFrame* p = f->getChildren()[row]; diff --git a/rwviewer/DFFFramesTreeModel.hpp b/rwviewer/DFFFramesTreeModel.hpp index 0d746e18..6c398ac7 100644 --- a/rwviewer/DFFFramesTreeModel.hpp +++ b/rwviewer/DFFFramesTreeModel.hpp @@ -2,14 +2,14 @@ #ifndef _DFFFRAMESTREEMODEL_HPP_ #define _DFFFRAMESTREEMODEL_HPP_ #include +#include -class Model; class DFFFramesTreeModel : public QAbstractItemModel { - Model* model; + ModelHandle* model; public: - explicit DFFFramesTreeModel(Model* m, QObject* parent = 0); + explicit DFFFramesTreeModel(ModelHandle* m, QObject* parent = 0); virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; @@ -24,4 +24,4 @@ public: virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; }; -#endif \ No newline at end of file +#endif diff --git a/rwviewer/ModelFramesWidget.cpp b/rwviewer/ModelFramesWidget.cpp index 03baf764..d89fdde3 100644 --- a/rwviewer/ModelFramesWidget.cpp +++ b/rwviewer/ModelFramesWidget.cpp @@ -8,7 +8,7 @@ ModelFramesWidget::ModelFramesWidget(QWidget* parent, Qt::WindowFlags flags) setWidget(tree); } -void ModelFramesWidget::setModel(Model* model) +void ModelFramesWidget::setModel(ModelHandle *model) { if(framemodel) { delete framemodel; diff --git a/rwviewer/ModelFramesWidget.hpp b/rwviewer/ModelFramesWidget.hpp index 6a50f24b..13c70a5b 100644 --- a/rwviewer/ModelFramesWidget.hpp +++ b/rwviewer/ModelFramesWidget.hpp @@ -4,20 +4,20 @@ #include #include #include "DFFFramesTreeModel.hpp" +#include -class Model; class ModelFramesWidget : public QDockWidget { Q_OBJECT - Model* gmodel; + ModelHandle* gmodel; DFFFramesTreeModel* framemodel; QTreeView* tree; public: ModelFramesWidget(QWidget* parent = 0, Qt::WindowFlags flags = 0); - void setModel(Model* model); + void setModel(ModelHandle* model); }; -#endif \ No newline at end of file +#endif diff --git a/rwviewer/ViewerWidget.cpp b/rwviewer/ViewerWidget.cpp index 6b3668ee..5d854d21 100644 --- a/rwviewer/ViewerWidget.cpp +++ b/rwviewer/ViewerWidget.cpp @@ -71,7 +71,7 @@ void ViewerWidget::paintGL() glUniformMatrix4fv(r.uniView, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(r.uniProj, 1, GL_FALSE, glm::value_ptr(proj)); - gworld->renderer.renderModel(cmodel, m, dummyObject); + gworld->renderer.renderModel(cmodel->model, m, dummyObject); } } @@ -108,7 +108,7 @@ void ViewerWidget::showDFF(const QString& file) dummyObject = new GameObject(gworld, glm::vec3(), glm::quat(), cmodel); float radius = 0.f; for(auto& g - : cmodel->geometries) { + : cmodel->model->geometries) { radius = std::max( radius, glm::length(g->geometryBounds.center)+g->geometryBounds.radius); @@ -130,13 +130,13 @@ void ViewerWidget::showAnimation(Animation *anim) if(dummyObject) { if(dummyObject->animator == nullptr) { dummyObject->animator = new Animator; - dummyObject->animator->setModel(dummyObject->model); + dummyObject->animator->setModel(dummyObject->model->model); } dummyObject->animator->setAnimation(canimation); } } -Model* ViewerWidget::currentModel() const +ModelHandle* ViewerWidget::currentModel() const { return cmodel; } diff --git a/rwviewer/ViewerWidget.hpp b/rwviewer/ViewerWidget.hpp index 4de3e624..19504638 100644 --- a/rwviewer/ViewerWidget.hpp +++ b/rwviewer/ViewerWidget.hpp @@ -19,7 +19,7 @@ class ViewerWidget : public QGLWidget GameObject* dummyObject; - Model* cmodel; + ModelHandle* cmodel; Animation* canimation; float viewDistance; @@ -44,7 +44,7 @@ public: FileMode fileMode() const; - Model* currentModel() const; + ModelHandle *currentModel() const; GameWorld* world(); diff --git a/tests/test_animation.cpp b/tests/test_animation.cpp index cd6c2a8f..06c4e67b 100644 --- a/tests/test_animation.cpp +++ b/tests/test_animation.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(test_matrix) Animator animator; Global::get().e->gameData.loadDFF("player.dff"); - Model* test_model = Global::get().e->gameData.models["player"]; + ModelHandle* test_model = Global::get().e->gameData.models["player"]; BOOST_REQUIRE( test_model ); @@ -34,16 +34,16 @@ BOOST_AUTO_TEST_CASE(test_matrix) }; animator.setAnimation(&animation); - animator.setModel( test_model ); + animator.setModel( test_model->model ); { - auto intp_matrix = animator.getFrameMatrixAt( test_model->frames[0], 0.0f ); + auto intp_matrix = animator.getFrameMatrixAt( test_model->model->frames[0], 0.0f ); auto intp_col = intp_matrix[3]; BOOST_CHECK_EQUAL( glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 0.f, 0.f)), 0.0f ); } { - auto intp_matrix = animator.getFrameMatrixAt( test_model->frames[0], 0.5f ); + auto intp_matrix = animator.getFrameMatrixAt( test_model->model->frames[0], 0.5f ); auto intp_col = intp_matrix[3]; BOOST_CHECK_EQUAL( 0.0f, glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 0.5f, 0.0f)) ); } @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(test_interpolate) Animator animator; Global::get().e->gameData.loadDFF("player.dff"); - Model* test_model = Global::get().e->gameData.models["player"]; + ModelHandle* test_model = Global::get().e->gameData.models["player"]; BOOST_REQUIRE( test_model ); @@ -82,10 +82,10 @@ BOOST_AUTO_TEST_CASE(test_interpolate) }; animator.setAnimation(&animation); - animator.setModel( test_model ); + animator.setModel( test_model->model ); { - auto intp_matrix = animator.getFrameMatrix( test_model->frames[0] ); + auto intp_matrix = animator.getFrameMatrix( test_model->model->frames[0] ); auto intp_col = intp_matrix[3]; BOOST_CHECK_EQUAL( glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 0.f, 0.f)), 0.0f ); } @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(test_interpolate) animator.tick( 1.f ); { - auto intp_matrix = animator.getFrameMatrix( test_model->frames[0], 0.5f ); + auto intp_matrix = animator.getFrameMatrix( test_model->model->frames[0], 0.5f ); auto intp_col = intp_matrix[3]; BOOST_CHECK_EQUAL( 0.0f, glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 0.5f, 0.0f)) ); } @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(test_interpolate) animator.tick( 1.f ); { - auto intp_matrix = animator.getFrameMatrix( test_model->frames[0], 0.5f ); + auto intp_matrix = animator.getFrameMatrix( test_model->model->frames[0], 0.5f ); auto intp_col = intp_matrix[3]; BOOST_CHECK_EQUAL( 0.0f, glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 1.5f, 0.0f)) ); } @@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(test_interpolate) animator.tick( 1.f ); { - auto intp_matrix = animator.getFrameMatrix( test_model->frames[0], 0.5f ); + auto intp_matrix = animator.getFrameMatrix( test_model->model->frames[0], 0.5f ); auto intp_col = intp_matrix[3]; BOOST_CHECK_EQUAL( 0.0f, glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 0.5f, 0.0f)) ); } diff --git a/tests/test_character.cpp b/tests/test_character.cpp index 1c6a2756..49c97bc1 100644 --- a/tests/test_character.cpp +++ b/tests/test_character.cpp @@ -58,6 +58,7 @@ BOOST_AUTO_TEST_CASE(test_activities) { GTAVehicle* 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); auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f}); diff --git a/tests/test_globals.hpp b/tests/test_globals.hpp index c63ff490..7e1790a6 100644 --- a/tests/test_globals.hpp +++ b/tests/test_globals.hpp @@ -50,6 +50,10 @@ public: } e->dynamicsWorld->setGravity(btVector3(0.f, 0.f, 0.f)); + + while( ! e->_work->isEmpty() ) { + std::this_thread::yield(); + } } ~Global() { diff --git a/tests/test_loaderdff.cpp b/tests/test_loaderdff.cpp index 8f2652ed..4be73b18 100644 --- a/tests/test_loaderdff.cpp +++ b/tests/test_loaderdff.cpp @@ -7,12 +7,8 @@ BOOST_AUTO_TEST_SUITE(LoaderDFFTests) BOOST_AUTO_TEST_CASE(test_open_dff) { - LoaderIMG archive; - - BOOST_REQUIRE( archive.load(Global::getGamePath() + "/models/gta3") ); - { - auto d = archive.loadToMemory("landstal.dff"); + auto d = Global::get().e->gameData.openFile("landstal.dff"); LoaderDFF loader; @@ -29,16 +25,12 @@ BOOST_AUTO_TEST_CASE(test_open_dff) BOOST_AUTO_TEST_CASE(test_modeljob) { - LoaderIMG archive; - - BOOST_REQUIRE( archive.load(Global::getGamePath() + "/models/gta3") ); - { WorkContext ctx; Model* m = nullptr; bool done = false; - LoadModelJob* lmj = new LoadModelJob(&ctx, &Global::get().e->gameData, archive, "landstal.dff", + LoadModelJob* lmj = new LoadModelJob(&ctx, &Global::get().e->gameData, "landstal.dff", [&](Model* model) { m = model; done = true; }); ctx.queueJob(lmj); diff --git a/tests/test_vehicle.cpp b/tests/test_vehicle.cpp index 9dedd95b..1eed05b0 100644 --- a/tests/test_vehicle.cpp +++ b/tests/test_vehicle.cpp @@ -31,8 +31,8 @@ BOOST_AUTO_TEST_CASE(vehicle_frame_flags) BOOST_REQUIRE(vehicle != nullptr); BOOST_REQUIRE(vehicle->model != nullptr); - auto bonnet_ok = vehicle->model->findFrame("bonnet_hi_ok"); - auto bonnet_dam = vehicle->model->findFrame("bonnet_hi_dam"); + auto bonnet_ok = vehicle->model->model->findFrame("bonnet_hi_ok"); + auto bonnet_dam = vehicle->model->model->findFrame("bonnet_hi_dam"); BOOST_REQUIRE(bonnet_ok != nullptr); BOOST_REQUIRE(bonnet_dam != nullptr);