1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 18:32:44 +01:00

Threaded model and texture loading

This commit is contained in:
Daniel Evans 2014-06-06 12:18:32 +01:00
parent f24ceeb42f
commit 61931145fe
35 changed files with 345 additions and 168 deletions

View File

@ -52,6 +52,9 @@ public:
virtual void complete() {} virtual void complete() {}
}; };
// TODO: refactor everything to remove this.
class GameWorld;
class WorkContext class WorkContext
{ {
std::queue<WorkJob*> _workQueue; std::queue<WorkJob*> _workQueue;
@ -62,10 +65,12 @@ class WorkContext
std::mutex _inMutex; std::mutex _inMutex;
std::mutex _outMutex; std::mutex _outMutex;
GameWorld* _world;
public: public:
WorkContext() WorkContext(GameWorld* world = nullptr)
: _worker(this) { } : _worker(this), _world(world) { }
void queueJob( WorkJob* job ) void queueJob( WorkJob* job )
{ {
@ -79,6 +84,15 @@ public:
const std::queue<WorkJob*> getWorkQueue() const { return _workQueue; } const std::queue<WorkJob*> getWorkQueue() const { return _workQueue; }
const std::queue<WorkJob*> getCompleteQueue() const { return _completeQueue; } const std::queue<WorkJob*> getCompleteQueue() const { return _completeQueue; }
bool isEmpty() {
std::lock_guard<std::mutex> guardIn( _inMutex );
std::lock_guard<std::mutex> guardOu( _outMutex );
return (getWorkQueue().size() + getCompleteQueue().size()) == 0;
}
GameWorld* getWorld() const { return _world; }
void update(); void update();
}; };

View File

@ -11,6 +11,16 @@ class Animation;
typedef std::map<std::string, Animation*> AnimationSet; typedef std::map<std::string, Animation*> AnimationSet;
class Model;
// TODO: Make generic.
struct ModelHandle {
Model* model;
std::string name;
ModelHandle(const std::string& name) : model( nullptr ), name(name) {}
};
namespace GTATypes namespace GTATypes
{ {
@ -46,7 +56,6 @@ struct WaterRect
float xLeft, yBottom; float xLeft, yBottom;
float xRight, yTop; float xRight, yTop;
}; };
} }
#endif #endif

View File

@ -55,7 +55,7 @@ public:
struct GTAFile struct GTAFile
{ {
bool archived; /// Is the file inside an IMG or on the filesystem? 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 * 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 * 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 * Loads an IFP file containing animations
@ -131,10 +131,18 @@ public:
void loadDynamicObjects(const std::string& name); 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 * @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); char* loadFile(const std::string& name);
/** /**
@ -157,9 +165,9 @@ public:
std::map<std::string, std::string> ideLocations; std::map<std::string, std::string> ideLocations;
/** /**
* Maps file names to their locations * Maps file names to data about the file.
*/ */
std::map<std::string, GTAFile> fileLocations; std::map<std::string, GTAFile> _knownFiles;
/** /**
* Map of loaded archives * Map of loaded archives
@ -194,7 +202,7 @@ public:
/** /**
* Loaded models * Loaded models
*/ */
std::map<std::string, Model*> models; std::map<std::string, ModelHandle*> models;
/** /**
* Loaded Textures and their atlas entries. * Loaded Textures and their atlas entries.

View File

@ -9,7 +9,6 @@
#include <memory> #include <memory>
class GTAAIController; class GTAAIController;
class Model;
class ModelFrame; class ModelFrame;
class Animator; class Animator;
@ -23,7 +22,7 @@ struct GameObject
glm::vec3 position; glm::vec3 position;
glm::quat rotation; glm::quat rotation;
Model* model; /// Cached pointer to Object's Model. ModelHandle* model; /// Cached pointer to Object's Model.
GameWorld* engine; GameWorld* engine;
@ -34,7 +33,7 @@ struct GameObject
*/ */
float mHealth; 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) : position(pos), rotation(rot), model(model), engine(engine), animator(nullptr), mHealth(0.f)
{} {}

View File

@ -8,6 +8,8 @@
#include <ai/GTAAINode.hpp> #include <ai/GTAAINode.hpp>
#include <ai/AIGraph.hpp> #include <ai/AIGraph.hpp>
class WorkContext;
class GameObject; class GameObject;
class GTACharacter; class GTACharacter;
class GTAInstance; class GTAInstance;
@ -32,6 +34,8 @@ public:
GameWorld(const std::string& gamepath); GameWorld(const std::string& gamepath);
~GameWorld();
/** /**
* Loads the game data * Loads the game data
*/ */
@ -192,6 +196,10 @@ public:
btSequentialImpulseConstraintSolver* solver; btSequentialImpulseConstraintSolver* solver;
btDiscreteDynamicsWorld* dynamicsWorld; btDiscreteDynamicsWorld* dynamicsWorld;
/**
* Work related
*/
WorkContext* _work;
}; };
#endif #endif

View File

@ -27,8 +27,6 @@ public:
#include <functional> #include <functional>
class LoaderIMG;
class LoadModelJob : public WorkJob class LoadModelJob : public WorkJob
{ {
public: public:
@ -36,13 +34,12 @@ public:
private: private:
GameData* _gameData; GameData* _gameData;
LoaderIMG* _archive;
std::string _file; std::string _file;
ModelCallback _callback; ModelCallback _callback;
char* _data; char* _data;
public: 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(); void work();

View File

@ -19,4 +19,23 @@ public:
bool loadFromMemory(char *data, GameData* gameData); bool loadFromMemory(char *data, GameData* gameData);
}; };
#include <WorkContext.hpp>
#include <functional>
// 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 #endif

View File

@ -90,7 +90,7 @@ public:
* @param model * @param model
* @param ped PEDS_t struct to use. * @param ped PEDS_t struct to use.
*/ */
GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, Model* model, std::shared_ptr<CharacterData> data); GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle *model, std::shared_ptr<CharacterData> data);
~GTACharacter(); ~GTACharacter();

View File

@ -17,7 +17,7 @@ struct GTAInstance : public GameObject
GameWorld* engine, GameWorld* engine,
const glm::vec3& pos, const glm::vec3& pos,
const glm::quat& rot, const glm::quat& rot,
Model* model, ModelHandle* model,
const glm::vec3& scale, const glm::vec3& scale,
std::shared_ptr<ObjectData> obj, std::shared_ptr<ObjectData> obj,
std::shared_ptr<GTAInstance> lod std::shared_ptr<GTAInstance> lod

View File

@ -52,7 +52,7 @@ public:
GTAVehicle(GameWorld* engine, GTAVehicle(GameWorld* engine,
const glm::vec3& pos, const glm::vec3& pos,
const glm::quat& rot, const glm::quat& rot,
Model* model, ModelHandle* model,
VehicleDataHandle data, VehicleDataHandle data,
VehicleInfoHandle info, VehicleInfoHandle info,
const glm::vec3& prim, const glm::vec3& prim,

View File

@ -82,9 +82,9 @@ void GameData::load()
parseDAT(datpath+"/data/default.dat"); parseDAT(datpath+"/data/default.dat");
parseDAT(datpath+"/data/gta3.dat"); parseDAT(datpath+"/data/gta3.dat");
fileLocations.insert({"wheels.DFF", {false, datpath+"/models/Generic/wheels.DFF"}}); _knownFiles.insert({"wheels.DFF", {false, datpath+"/models/Generic/wheels.DFF"}});
fileLocations.insert({"loplyguy.dff", {false, datpath+"/models/Generic/loplyguy.dff"}}); _knownFiles.insert({"loplyguy.dff", {false, datpath+"/models/Generic/loplyguy.dff"}});
fileLocations.insert({"particle.txd", {false, datpath+"/models/particle.txd"}}); _knownFiles.insert({"particle.txd", {false, datpath+"/models/particle.txd"}});
loadDFF("wheels.DFF"); loadDFF("wheels.DFF");
loadTXD("particle.txd"); loadTXD("particle.txd");
@ -147,7 +147,7 @@ void GameData::parseDAT(const std::string& path)
} }
texpath = findPathRealCase(datpath, texpath); texpath = findPathRealCase(datpath, texpath);
std::string texname = texpath.substr(texpath.find_last_of("/")+1); std::string texname = texpath.substr(texpath.find_last_of("/")+1);
fileLocations.insert({ texname, { false, texpath }}); _knownFiles.insert({ texname, { false, texpath }});
loadTXD(texname); loadTXD(texname);
} }
} }
@ -201,12 +201,12 @@ void GameData::loadIMG(const std::string& name)
else else
{ {
// Enter the asset twice.. // Enter the asset twice..
fileLocations.insert({ filename, { true, archivePath }}); _knownFiles.insert({ filename, { true, archivePath }});
for(size_t t = 0; t < filename.size(); ++t) for(size_t t = 0; t < filename.size(); ++t)
{ {
filename[t] = tolower(filename[t]); filename[t] = tolower(filename[t]);
} }
fileLocations.insert({ filename, { true, archivePath }}); _knownFiles.insert({ filename, { true, archivePath }});
} }
} }
archives.insert({archivePath, imgLoader}); 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; return;
} }
char* file = loadFile(name); loadedFiles[name] = true;
if(file) {
textureLoader.loadFromMemory(file, this); auto j = new LoadTextureArchiveJob(this->engine->_work, this, name);
delete[] file;
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; return;
} }
char *file = loadFile(name); // Before starting the job make sure the file isn't loaded again.
if(file) loadedFiles.insert({name, true});
{
LoaderDFF dffLoader; models[realname] = new ModelHandle(realname);
models[name.substr(0, name.size() - 4)] = dffLoader.loadFromMemory(file, this);
delete[] file; 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) 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()) { auto i = _knownFiles.find(name);
std::cerr << "File " << name << " already loaded!" << std::endl; if(i != _knownFiles.end())
return nullptr;
}
auto i = fileLocations.find(name);
if(i != fileLocations.end())
{ {
if(i->second.archived) if(i->second.archived)
{ {
@ -487,7 +504,6 @@ char* GameData::loadFile(const std::string& name)
auto ai = archives.find(i->second.path); auto ai = archives.find(i->second.path);
if(ai != archives.end()) if(ai != archives.end())
{ {
loadedFiles[name] = true;
return ai->second.loadToMemory(name); return ai->second.loadToMemory(name);
} }
else else
@ -509,8 +525,6 @@ char* GameData::loadFile(const std::string& name)
char *data = new char[length]; char *data = new char[length];
dfile.read(data, length); dfile.read(data, length);
loadedFiles[name] = true;
return data; return data;
} }
} }
@ -525,6 +539,18 @@ char* GameData::loadFile(const std::string& name)
return nullptr; 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) TextureAtlas* GameData::getAtlas(size_t i)
{ {
if( i < atlases.size() ) { if( i < atlases.size() ) {

View File

@ -4,6 +4,7 @@
#include <ai/GTADefaultAIController.hpp> #include <ai/GTADefaultAIController.hpp>
#include <BulletCollision/CollisionDispatch/btGhostObject.h> #include <BulletCollision/CollisionDispatch/btGhostObject.h>
#include <render/Model.hpp> #include <render/Model.hpp>
#include <WorkContext.hpp>
// 3 isn't enough to cause a factory. // 3 isn't enough to cause a factory.
#include <objects/GTACharacter.hpp> #include <objects/GTACharacter.hpp>
@ -11,11 +12,18 @@
#include <objects/GTAVehicle.hpp> #include <objects/GTAVehicle.hpp>
GameWorld::GameWorld(const std::string& path) 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; gameData.engine = this;
} }
GameWorld::~GameWorld()
{
delete _work;
// TODO: delete other things.
}
bool GameWorld::load() bool GameWorld::load()
{ {
collisionConfig = new btDefaultCollisionConfiguration; collisionConfig = new btDefaultCollisionConfiguration;
@ -174,10 +182,10 @@ GTAInstance *GameWorld::createInstance(const uint16_t id, const glm::vec3& pos,
if( oi != objectTypes.end()) { if( oi != objectTypes.end()) {
// Make sure the DFF and TXD are loaded // Make sure the DFF and TXD are loaded
if(! oi->second->modelName.empty()) { if(! oi->second->modelName.empty()) {
gameData.loadDFF(oi->second->modelName + ".dff"); gameData.loadDFF(oi->second->modelName + ".dff", true);
} }
if(! oi->second->textureName.empty()) { if(! oi->second->textureName.empty()) {
gameData.loadTXD(oi->second->textureName + ".txd"); gameData.loadTXD(oi->second->textureName + ".txd", true);
} }
auto instance = std::shared_ptr<GTAInstance>(new GTAInstance( auto instance = std::shared_ptr<GTAInstance>(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); auto info = gameData.vehicleInfo.find(vti->second->handlingID);
if(model && info != gameData.vehicleInfo.end()) { if(model && info != gameData.vehicleInfo.end()) {
if( info->second->wheels.size() == 0 && info->second->seats.size() == 0 ) { 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 vehicleInstances.back();
} }
return nullptr; return nullptr;
@ -280,10 +289,10 @@ GTACharacter* GameWorld::createPedestrian(const uint16_t id, const glm::vec3 &po
gameData.loadTXD(pt->textureName + ".txd"); gameData.loadTXD(pt->textureName + ".txd");
} }
Model* model = gameData.models[pt->modelName]; ModelHandle* m = gameData.models[pt->modelName];
if(model != nullptr) { if(m != nullptr) {
auto ped = new GTACharacter( this, pos, rot, model, pt ); auto ped = new GTACharacter( this, pos, rot, m, pt );
pedestrians.push_back(ped); pedestrians.push_back(ped);
new GTADefaultAIController(ped); new GTADefaultAIController(ped);
return ped; return ped;

View File

@ -312,25 +312,28 @@ RW::BSSectionHeader LoaderDFF::readHeader(char *data, size_t &dataI)
return readStructure<RW::BSSectionHeader>(data, dataI); return readStructure<RW::BSSectionHeader>(data, dataI);
} }
#include <loaders/LoaderIMG.hpp> LoadModelJob::LoadModelJob(WorkContext *context, GameData* gd, const std::string &file, ModelCallback cb)
: WorkJob(context), _gameData(gd), _file(file), _callback(cb), _data(nullptr)
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)
{ {
} }
void LoadModelJob::work() void LoadModelJob::work()
{ {
_data = _archive->loadToMemory(_file); _data = _gameData->openFile(_file);
} }
void LoadModelJob::complete() void LoadModelJob::complete()
{ {
Model* m = nullptr;
// TODO error status
if( _data ) {
// TODO allow some of the loading to process in a seperate thread. // TODO allow some of the loading to process in a seperate thread.
LoaderDFF loader; LoaderDFF loader;
Model* m = loader.loadFromMemory(_data, _gameData); m = loader.loadFromMemory(_data, _gameData);
}
_callback(m); _callback(m);

View File

@ -217,3 +217,26 @@ bool TextureLoader::loadFromMemory(char *data, GameData *gameData)
return true; 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;
}

View File

@ -7,7 +7,7 @@
// TODO: make this not hardcoded // TODO: make this not hardcoded
static glm::vec3 enter_offset(0.81756252f, 0.34800607f, -0.486281008f); 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<CharacterData> data) GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, std::shared_ptr<CharacterData> data)
: GameObject(engine, pos, rot, model), : GameObject(engine, pos, rot, model),
currentVehicle(nullptr), currentSeat(0), currentVehicle(nullptr), currentSeat(0),
_hasTargetPosition(false), _hasTargetPosition(false),
@ -35,7 +35,7 @@ GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::q
if(model) { if(model) {
animator = new Animator(); animator = new Animator();
animator->setModel(model); animator->setModel(model->model);
createActor(); createActor();
enterAction(Idle); enterAction(Idle);

View File

@ -2,11 +2,10 @@
#include <engine/GameWorld.hpp> #include <engine/GameWorld.hpp>
#include <data/CollisionModel.hpp> #include <data/CollisionModel.hpp>
GTAInstance::GTAInstance( GTAInstance::GTAInstance(GameWorld* engine,
GameWorld* engine,
const glm::vec3& pos, const glm::vec3& pos,
const glm::quat& rot, const glm::quat& rot,
Model* model, ModelHandle *model,
const glm::vec3& scale, const glm::vec3& scale,
std::shared_ptr<ObjectData> obj, std::shared_ptr<ObjectData> obj,
std::shared_ptr<GTAInstance> lod std::shared_ptr<GTAInstance> lod

View File

@ -6,7 +6,7 @@
#include <data/CollisionModel.hpp> #include <data/CollisionModel.hpp>
#include <render/Model.hpp> #include <render/Model.hpp>
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), : GameObject(engine, pos, rot, model),
steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false), steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false),
damageFlags(0), vehicle(data), info(info), colourPrimary(prim), damageFlags(0), vehicle(data), info(info), colourPrimary(prim),

View File

@ -268,9 +268,9 @@ void GTARenderer::renderWorld(float alpha)
matrixModel = glm::translate(matrixModel, charac->getPosition()); matrixModel = glm::translate(matrixModel, charac->getPosition());
matrixModel = matrixModel * glm::mat4_cast(charac->getRotation()); 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) { for(size_t i = 0; i < engine->objectInstances.size(); ++i) {
@ -284,9 +284,9 @@ void GTARenderer::renderWorld(float alpha)
} }
} }
if(!inst.model) if(!inst.model->model)
{ {
std::cout << "model " << inst.model << " not loaded (" << engine->gameData.models.size() << " models loaded)" << std::endl; continue;
} }
glm::mat4 matrixModel; glm::mat4 matrixModel;
@ -295,9 +295,9 @@ void GTARenderer::renderWorld(float alpha)
matrixModel = matrixModel * glm::mat4_cast(inst.rotation); matrixModel = matrixModel * glm::mat4_cast(inst.rotation);
float mindist = 100000.f; float mindist = 100000.f;
for (size_t g = 0; g < inst.model->geometries.size(); g++) for (size_t g = 0; g < inst.model->model->geometries.size(); g++)
{ {
RW::BSGeometryBounds& bounds = inst.model->geometries[g]->geometryBounds; 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); mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - camera.worldPos) - bounds.radius);
} }
@ -311,13 +311,13 @@ void GTARenderer::renderWorld(float alpha)
culled++; culled++;
continue; continue;
} }
else { else if (inst.LODinstance->model->model) {
renderModel(inst.LODinstance->model, matrixModel); renderModel(inst.LODinstance->model->model, matrixModel);
} }
} }
} }
else if (! inst.object->LOD ) { 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 = glm::translate(matrixModel, inst->getPosition());
matrixModel = matrixModel * glm::mat4_cast(inst->getRotation()); matrixModel = matrixModel * glm::mat4_cast(inst->getRotation());
renderModel(inst->model, matrixModel, inst); renderModel(inst->model->model, matrixModel, inst);
// Draw wheels n' stuff // Draw wheels n' stuff
for( size_t w = 0; w < inst->info->wheels.size(); ++w) { for( size_t w = 0; w < inst->info->wheels.size(); ++w) {
auto woi = engine->objectTypes.find(inst->vehicle->wheelModelID); auto woi = engine->objectTypes.find(inst->vehicle->wheelModelID);
if(woi != engine->objectTypes.end()) { if(woi != engine->objectTypes.end()) {
Model* wheelModel = engine->gameData.models["wheels"]; Model* wheelModel = engine->gameData.models["wheels"]->model;
if( wheelModel) { if( wheelModel) {
// Tell bullet to update the matrix for this wheel. // Tell bullet to update the matrix for this wheel.
inst->physVehicle->updateWheelTransform(w, false); inst->physVehicle->updateWheelTransform(w, false);

View File

@ -1,5 +1,6 @@
add_executable(rwgame add_executable(rwgame
main.cpp main.cpp
loadingstate.cpp
ingamestate.cpp ingamestate.cpp
pausestate.cpp pausestate.cpp
menustate.cpp menustate.cpp

View File

@ -120,6 +120,12 @@ struct StateManager
state->enter(); state->enter();
} }
void exec(State* state)
{
exit();
enter(state);
}
void tick(float dt) void tick(float dt)
{ {
states.back()->tick(dt); states.back()->tick(dt);

View File

@ -67,7 +67,7 @@ void IngameState::tick(float dt)
float viewDistance = 2.f; float viewDistance = 2.f;
if( _playerCharacter->getCurrentVehicle() ) { if( _playerCharacter->getCurrentVehicle() ) {
auto model = _playerCharacter->getCurrentVehicle()->model; auto model = _playerCharacter->getCurrentVehicle()->model;
for(auto& g : model->geometries) { for(auto& g : model->model->geometries) {
viewDistance = std::max( viewDistance = std::max(
(glm::length(g->geometryBounds.center) + g->geometryBounds.radius) * 1.5f, (glm::length(g->geometryBounds.center) + g->geometryBounds.radius) * 1.5f,
viewDistance); viewDistance);

55
rwgame/loadingstate.cpp Normal file
View File

@ -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<std::string, std::string>::iterator it = world->gameData.ideLocations.begin();
it != world->gameData.ideLocations.end();
++it) {
world->defineItems(it->second);
}
// Load IPLs
for(std::map<std::string, std::string>::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);
}

21
rwgame/loadingstate.hpp Normal file
View File

@ -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

View File

@ -13,7 +13,7 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "menustate.hpp" #include "loadingstate.hpp"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <memory> #include <memory>
@ -39,8 +39,8 @@ int debugMode = 0;
sf::Font font; sf::Font font;
glm::vec3 viewPosition; glm::vec3 viewPosition { -200.f, -100.f, 45.f };
glm::vec2 viewAngles; glm::vec2 viewAngles { -0.90f, 0.2f };
void setViewParameters(const glm::vec3 &center, const glm::vec2 &angles) void setViewParameters(const glm::vec3 &center, const glm::vec2 &angles)
{ {
@ -293,23 +293,6 @@ void init(std::string gtapath, bool loadWorld)
// Set time to noon. // Set time to noon.
gta->gameTime = 12.f * 60.f; gta->gameTime = 12.f * 60.f;
// Loade all of the IDEs.
for(std::map<std::string, std::string>::iterator it = gta->gameData.ideLocations.begin();
it != gta->gameData.ideLocations.end();
++it) {
gta->defineItems(it->second);
}
if(loadWorld) {
// Load IPLs
for(std::map<std::string, std::string>::iterator it = gta->gameData.iplLocations.begin();
it != gta->gameData.iplLocations.end();
++it) {
gta->loadZone(it->second);
gta->placeItems(it->second);
}
}
debugDrawer = new DebugDraw; debugDrawer = new DebugDraw;
debugDrawer->setShaderProgram(gta->renderer.worldProgram); debugDrawer->setShaderProgram(gta->renderer.worldProgram);
debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe); debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe);
@ -361,6 +344,8 @@ void update(float dt)
void render(float alpha) void render(float alpha)
{ {
gta->_work->update();
// Update aspect ratio.. // Update aspect ratio..
gta->renderer.camera.frustum.aspectRatio = window.getSize().x / (float) window.getSize().y; 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; sf::Clock clock;
MenuState* menuState = new MenuState(); StateManager::get().enter(new LoadingState);
StateManager::get().enter(menuState);
float accum = 0.f; float accum = 0.f;
float ts = 1.f / 60.f; float ts = 1.f / 60.f;

View File

@ -1,7 +1,7 @@
#include "DFFFramesTreeModel.hpp" #include "DFFFramesTreeModel.hpp"
#include <render/Model.hpp> #include <render/Model.hpp>
DFFFramesTreeModel::DFFFramesTreeModel(Model* m, QObject* parent) DFFFramesTreeModel::DFFFramesTreeModel(ModelHandle *m, QObject* parent)
: QAbstractItemModel(parent), model(m) : 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 QModelIndex DFFFramesTreeModel::index(int row, int column, const QModelIndex& parent) const
{ {
if(parent.row() == -1 && parent.column() == -1) { 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<ModelFrame*>(parent.internalPointer()); ModelFrame* f = static_cast<ModelFrame*>(parent.internalPointer());
ModelFrame* p = f->getChildren()[row]; ModelFrame* p = f->getChildren()[row];

View File

@ -2,14 +2,14 @@
#ifndef _DFFFRAMESTREEMODEL_HPP_ #ifndef _DFFFRAMESTREEMODEL_HPP_
#define _DFFFRAMESTREEMODEL_HPP_ #define _DFFFRAMESTREEMODEL_HPP_
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <engine/GTATypes.hpp>
class Model;
class DFFFramesTreeModel : public QAbstractItemModel class DFFFramesTreeModel : public QAbstractItemModel
{ {
Model* model; ModelHandle* model;
public: public:
explicit DFFFramesTreeModel(Model* m, QObject* parent = 0); explicit DFFFramesTreeModel(ModelHandle* m, QObject* parent = 0);
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const;

View File

@ -8,7 +8,7 @@ ModelFramesWidget::ModelFramesWidget(QWidget* parent, Qt::WindowFlags flags)
setWidget(tree); setWidget(tree);
} }
void ModelFramesWidget::setModel(Model* model) void ModelFramesWidget::setModel(ModelHandle *model)
{ {
if(framemodel) { if(framemodel) {
delete framemodel; delete framemodel;

View File

@ -4,20 +4,20 @@
#include <QDockWidget> #include <QDockWidget>
#include <QTreeView> #include <QTreeView>
#include "DFFFramesTreeModel.hpp" #include "DFFFramesTreeModel.hpp"
#include <engine/GTATypes.hpp>
class Model;
class ModelFramesWidget : public QDockWidget class ModelFramesWidget : public QDockWidget
{ {
Q_OBJECT Q_OBJECT
Model* gmodel; ModelHandle* gmodel;
DFFFramesTreeModel* framemodel; DFFFramesTreeModel* framemodel;
QTreeView* tree; QTreeView* tree;
public: public:
ModelFramesWidget(QWidget* parent = 0, Qt::WindowFlags flags = 0); ModelFramesWidget(QWidget* parent = 0, Qt::WindowFlags flags = 0);
void setModel(Model* model); void setModel(ModelHandle* model);
}; };
#endif #endif

View File

@ -71,7 +71,7 @@ void ViewerWidget::paintGL()
glUniformMatrix4fv(r.uniView, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(r.uniView, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(r.uniProj, 1, GL_FALSE, glm::value_ptr(proj)); 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); dummyObject = new GameObject(gworld, glm::vec3(), glm::quat(), cmodel);
float radius = 0.f; float radius = 0.f;
for(auto& g for(auto& g
: cmodel->geometries) { : cmodel->model->geometries) {
radius = std::max( radius = std::max(
radius, radius,
glm::length(g->geometryBounds.center)+g->geometryBounds.radius); glm::length(g->geometryBounds.center)+g->geometryBounds.radius);
@ -130,13 +130,13 @@ void ViewerWidget::showAnimation(Animation *anim)
if(dummyObject) { if(dummyObject) {
if(dummyObject->animator == nullptr) { if(dummyObject->animator == nullptr) {
dummyObject->animator = new Animator; dummyObject->animator = new Animator;
dummyObject->animator->setModel(dummyObject->model); dummyObject->animator->setModel(dummyObject->model->model);
} }
dummyObject->animator->setAnimation(canimation); dummyObject->animator->setAnimation(canimation);
} }
} }
Model* ViewerWidget::currentModel() const ModelHandle* ViewerWidget::currentModel() const
{ {
return cmodel; return cmodel;
} }

View File

@ -19,7 +19,7 @@ class ViewerWidget : public QGLWidget
GameObject* dummyObject; GameObject* dummyObject;
Model* cmodel; ModelHandle* cmodel;
Animation* canimation; Animation* canimation;
float viewDistance; float viewDistance;
@ -44,7 +44,7 @@ public:
FileMode fileMode() const; FileMode fileMode() const;
Model* currentModel() const; ModelHandle *currentModel() const;
GameWorld* world(); GameWorld* world();

View File

@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(test_matrix)
Animator animator; Animator animator;
Global::get().e->gameData.loadDFF("player.dff"); 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 ); BOOST_REQUIRE( test_model );
@ -34,16 +34,16 @@ BOOST_AUTO_TEST_CASE(test_matrix)
}; };
animator.setAnimation(&animation); 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]; 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 ); 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]; 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)) ); 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; Animator animator;
Global::get().e->gameData.loadDFF("player.dff"); 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 ); BOOST_REQUIRE( test_model );
@ -82,10 +82,10 @@ BOOST_AUTO_TEST_CASE(test_interpolate)
}; };
animator.setAnimation(&animation); 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]; 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 ); 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 ); 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]; 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)) ); 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 ); 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]; 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)) ); 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 ); 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]; 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)) ); BOOST_CHECK_EQUAL( 0.0f, glm::distance(glm::vec3(intp_col), glm::vec3(0.f, 0.5f, 0.0f)) );
} }

View File

@ -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()); GTAVehicle* vehicle = Global::get().e->createVehicle(90u, glm::vec3(10.f, 0.f, 0.f), glm::quat());
BOOST_REQUIRE(vehicle != nullptr); BOOST_REQUIRE(vehicle != nullptr);
BOOST_REQUIRE(vehicle->model != nullptr);
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f}); auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});

View File

@ -50,6 +50,10 @@ public:
} }
e->dynamicsWorld->setGravity(btVector3(0.f, 0.f, 0.f)); e->dynamicsWorld->setGravity(btVector3(0.f, 0.f, 0.f));
while( ! e->_work->isEmpty() ) {
std::this_thread::yield();
}
} }
~Global() { ~Global() {

View File

@ -7,12 +7,8 @@ BOOST_AUTO_TEST_SUITE(LoaderDFFTests)
BOOST_AUTO_TEST_CASE(test_open_dff) 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; LoaderDFF loader;
@ -29,16 +25,12 @@ BOOST_AUTO_TEST_CASE(test_open_dff)
BOOST_AUTO_TEST_CASE(test_modeljob) BOOST_AUTO_TEST_CASE(test_modeljob)
{ {
LoaderIMG archive;
BOOST_REQUIRE( archive.load(Global::getGamePath() + "/models/gta3") );
{ {
WorkContext ctx; WorkContext ctx;
Model* m = nullptr; Model* m = nullptr;
bool done = false; 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; }); [&](Model* model) { m = model; done = true; });
ctx.queueJob(lmj); ctx.queueJob(lmj);

View File

@ -31,8 +31,8 @@ BOOST_AUTO_TEST_CASE(vehicle_frame_flags)
BOOST_REQUIRE(vehicle != nullptr); BOOST_REQUIRE(vehicle != nullptr);
BOOST_REQUIRE(vehicle->model != nullptr); BOOST_REQUIRE(vehicle->model != nullptr);
auto bonnet_ok = vehicle->model->findFrame("bonnet_hi_ok"); auto bonnet_ok = vehicle->model->model->findFrame("bonnet_hi_ok");
auto bonnet_dam = vehicle->model->findFrame("bonnet_hi_dam"); auto bonnet_dam = vehicle->model->model->findFrame("bonnet_hi_dam");
BOOST_REQUIRE(bonnet_ok != nullptr); BOOST_REQUIRE(bonnet_ok != nullptr);
BOOST_REQUIRE(bonnet_dam != nullptr); BOOST_REQUIRE(bonnet_dam != nullptr);