2013-07-02 08:40:43 +02:00
|
|
|
#include <renderwure/engine/GTAEngine.hpp>
|
|
|
|
#include <renderwure/loaders/LoaderIPL.hpp>
|
2013-07-02 14:49:20 +02:00
|
|
|
#include <renderwure/loaders/LoaderIDE.hpp>
|
2013-07-02 08:06:03 +02:00
|
|
|
|
|
|
|
GTAEngine::GTAEngine(const std::string& path)
|
2013-07-24 01:42:50 +02:00
|
|
|
: renderer(this), itemCount(0), gameData(path), gameTime(0.f), randomEngine(rand())
|
2013-07-02 08:06:03 +02:00
|
|
|
{
|
2013-07-06 02:39:54 +02:00
|
|
|
gameData.engine = this;
|
2013-07-02 08:06:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GTAEngine::load()
|
|
|
|
{
|
2013-07-21 06:12:27 +02:00
|
|
|
collisionConfig = new btDefaultCollisionConfiguration;
|
|
|
|
collisionDispatcher = new btCollisionDispatcher(collisionConfig);
|
|
|
|
broadphase = new btDbvtBroadphase();
|
|
|
|
solver = new btSequentialImpulseConstraintSolver;
|
|
|
|
dynamicsWorld = new btDiscreteDynamicsWorld(collisionDispatcher, broadphase, solver, collisionConfig);
|
|
|
|
|
2013-07-02 08:06:03 +02:00
|
|
|
gameData.load();
|
|
|
|
|
2013-07-02 14:49:20 +02:00
|
|
|
// Loade all of the IDEs.
|
|
|
|
for(std::map<std::string, std::string>::iterator it = gameData.ideLocations.begin();
|
|
|
|
it != gameData.ideLocations.end();
|
|
|
|
++it) {
|
|
|
|
defineItems(it->second);
|
|
|
|
}
|
|
|
|
|
2013-07-02 18:29:20 +02:00
|
|
|
// Load the .zon IPLs since we want to have the zones loaded
|
|
|
|
for(std::map<std::string, std::string>::iterator it = gameData.iplLocations.begin();
|
|
|
|
it != gameData.iplLocations.end();
|
|
|
|
++it) {
|
|
|
|
loadZone(it->second);
|
|
|
|
placeItems(it->second);
|
|
|
|
}
|
|
|
|
|
2013-07-02 08:06:03 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-02 12:48:01 +02:00
|
|
|
void GTAEngine::logInfo(const std::string& info)
|
|
|
|
{
|
2013-07-06 02:39:54 +02:00
|
|
|
log.push_back({LogEntry::Info, gameTime, info});
|
2013-07-02 12:48:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void GTAEngine::logError(const std::string& error)
|
|
|
|
{
|
2013-07-06 02:39:54 +02:00
|
|
|
log.push_back({LogEntry::Error, gameTime, error});
|
|
|
|
}
|
|
|
|
|
|
|
|
void GTAEngine::logWarning(const std::string& warning)
|
|
|
|
{
|
|
|
|
log.push_back({LogEntry::Warning, gameTime, warning});
|
2013-07-02 12:48:01 +02:00
|
|
|
}
|
|
|
|
|
2013-07-02 14:49:20 +02:00
|
|
|
bool GTAEngine::defineItems(const std::string& name)
|
|
|
|
{
|
|
|
|
auto i = gameData.ideLocations.find(name);
|
|
|
|
std::string path = name;
|
|
|
|
|
|
|
|
if( i != gameData.ideLocations.end()) {
|
|
|
|
path = i->second;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::cout << "IDE not pre-listed" << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
LoaderIDE idel;
|
|
|
|
|
|
|
|
if(idel.load(path)) {
|
|
|
|
for( size_t o = 0; o < idel.OBJSs.size(); ++o) {
|
|
|
|
objectTypes.insert({
|
|
|
|
idel.OBJSs[o].ID,
|
|
|
|
std::shared_ptr<LoaderIDE::OBJS_t>(new LoaderIDE::OBJS_t(idel.OBJSs[o]))
|
|
|
|
});
|
|
|
|
}
|
2013-07-02 19:37:19 +02:00
|
|
|
|
|
|
|
for( size_t v = 0; v < idel.CARSs.size(); ++v) {
|
|
|
|
std::cout << "Vehicle ID " << idel.CARSs[v].ID << ": " << idel.CARSs[v].gameName << std::endl;
|
|
|
|
vehicleTypes.insert({
|
|
|
|
idel.CARSs[v].ID,
|
|
|
|
std::shared_ptr<LoaderIDE::CARS_t>(new LoaderIDE::CARS_t(idel.CARSs[v]))
|
|
|
|
});
|
|
|
|
}
|
2013-07-22 05:39:58 +02:00
|
|
|
|
|
|
|
for( size_t v = 0; v < idel.PEDSs.size(); ++v) {
|
|
|
|
pedestrianTypes.insert({
|
|
|
|
idel.PEDSs[v].ID,
|
|
|
|
std::shared_ptr<LoaderIDE::PEDS_t>(new LoaderIDE::PEDS_t(idel.PEDSs[v]))
|
|
|
|
});
|
|
|
|
}
|
2013-07-02 14:49:20 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::cerr << "Failed to load IDE " << path << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GTAEngine::placeItems(const std::string& name)
|
2013-07-02 08:06:03 +02:00
|
|
|
{
|
|
|
|
auto i = gameData.iplLocations.find(name);
|
|
|
|
std::string path = name;
|
|
|
|
|
|
|
|
if(i != gameData.iplLocations.end())
|
|
|
|
{
|
|
|
|
path = i->second;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cout << "IPL not pre-listed" << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
LoaderIPL ipll;
|
|
|
|
|
|
|
|
if(ipll.load(path))
|
|
|
|
{
|
2013-07-02 14:49:20 +02:00
|
|
|
// Find the object.
|
|
|
|
for( size_t i = 0; i < ipll.m_instances.size(); ++i) {
|
|
|
|
LoaderIPLInstance& inst = ipll.m_instances[i];
|
|
|
|
auto oi = objectTypes.find(inst.id);
|
|
|
|
if( oi != objectTypes.end()) {
|
2013-07-02 16:33:15 +02:00
|
|
|
// Make sure the DFF and TXD are loaded
|
|
|
|
if(! oi->second->modelName.empty()) {
|
|
|
|
gameData.loadDFF(oi->second->modelName + ".dff");
|
|
|
|
}
|
|
|
|
if(! oi->second->textureName.empty()) {
|
|
|
|
gameData.loadTXD(oi->second->textureName + ".txd");
|
|
|
|
}
|
|
|
|
|
2013-07-22 02:49:02 +02:00
|
|
|
static size_t bodycount = 0;
|
|
|
|
|
2013-07-21 06:12:27 +02:00
|
|
|
btRigidBody* body = nullptr;
|
|
|
|
auto phyit = gameData.collisions.find(oi->second->modelName);
|
2013-07-22 02:49:02 +02:00
|
|
|
if( phyit != gameData.collisions.end()) {
|
2013-07-21 06:12:27 +02:00
|
|
|
btCompoundShape* cmpShape = new btCompoundShape;
|
|
|
|
btDefaultMotionState* msta = new btDefaultMotionState;
|
|
|
|
msta->setWorldTransform(btTransform(
|
|
|
|
btQuaternion(
|
|
|
|
inst.rotX, inst.rotY, inst.rotZ, inst.rotW
|
|
|
|
),
|
|
|
|
btVector3(
|
|
|
|
inst.posX, inst.posY, inst.posZ
|
|
|
|
)
|
|
|
|
));
|
|
|
|
btRigidBody::btRigidBodyConstructionInfo info(0.f, msta, cmpShape);
|
|
|
|
CollisionInstance& physInst = *phyit->second.get();
|
|
|
|
|
|
|
|
// Boxes
|
|
|
|
for( size_t i = 0; i < physInst.boxes.size(); ++i ) {
|
|
|
|
CollTBox& box = physInst.boxes[i];
|
|
|
|
auto size = (box.max - box.min) / 2.f;
|
|
|
|
auto mid = (box.min + box.max) / 2.f;
|
|
|
|
btCollisionShape* bshape = new btBoxShape( btVector3(size.x, size.y, size.z) );
|
|
|
|
btTransform t(btQuaternion(0.f, 0.f, 0.f, 1.f), btVector3(mid.x, mid.y, mid.z));
|
|
|
|
cmpShape->addChildShape(t, bshape);
|
2013-07-22 02:49:02 +02:00
|
|
|
bodycount++;
|
2013-07-21 06:12:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Spheres
|
|
|
|
for( size_t i = 0; i < physInst.spheres.size(); ++i ) {
|
|
|
|
CollTSphere& sphere = physInst.spheres[i];
|
|
|
|
btCollisionShape* sshape = new btSphereShape(sphere.radius);
|
|
|
|
btTransform t(btQuaternion(0.f, 0.f, 0.f, 1.f), btVector3(sphere.center.x, sphere.center.y, sphere.center.z));
|
|
|
|
cmpShape->addChildShape(t, sshape);
|
2013-07-22 02:49:02 +02:00
|
|
|
bodycount++;
|
2013-07-21 06:12:27 +02:00
|
|
|
}
|
2013-07-22 02:49:02 +02:00
|
|
|
|
|
|
|
if( physInst.triangles.size() > 0 ) {
|
|
|
|
btTriangleIndexVertexArray* vertarray = new btTriangleIndexVertexArray(
|
|
|
|
physInst.triangles.size(),
|
2013-07-22 03:38:43 +02:00
|
|
|
(int*) physInst.triangles.data(),
|
|
|
|
sizeof(CollTFaceTriangle),
|
2013-07-22 02:49:02 +02:00
|
|
|
physInst.vertices.size(),
|
|
|
|
&(physInst.vertices[0].x),
|
|
|
|
sizeof(glm::vec3)
|
|
|
|
);
|
|
|
|
btBvhTriangleMeshShape* trishape = new btBvhTriangleMeshShape(vertarray, false);
|
|
|
|
cmpShape->addChildShape(
|
|
|
|
btTransform(btQuaternion(0.f, 0.f, 0.f, 1.f), btVector3(0.f, 0.f, 0.f)),
|
|
|
|
trishape
|
|
|
|
);
|
|
|
|
bodycount++;
|
|
|
|
}
|
|
|
|
|
2013-07-21 06:12:27 +02:00
|
|
|
|
|
|
|
// Todo: other shapes.
|
|
|
|
|
|
|
|
body = new btRigidBody(info);
|
|
|
|
//body->setWorldTransform();
|
|
|
|
dynamicsWorld->addRigidBody(body);
|
|
|
|
}
|
|
|
|
|
2013-07-02 14:49:20 +02:00
|
|
|
objectInstances.push_back({ inst, oi->second });
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::cerr << "No object for instance " << inst.id << " (" << path << ")" << std::endl;
|
|
|
|
}
|
|
|
|
}
|
2013-07-02 08:06:03 +02:00
|
|
|
itemCentroid += ipll.centroid;
|
2013-07-02 14:49:20 +02:00
|
|
|
itemCount += ipll.m_instances.size();
|
2013-07-02 08:06:03 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cerr << "Failed to load IPL: " << path << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2013-07-02 18:29:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GTAEngine::loadZone(const std::string& path)
|
|
|
|
{
|
|
|
|
LoaderIPL ipll;
|
|
|
|
|
|
|
|
if( ipll.load(path)) {
|
|
|
|
if( ipll.zones.size() > 0) {
|
|
|
|
zones.insert(zones.begin(), ipll.zones.begin(), ipll.zones.end());
|
|
|
|
std::cout << "Loaded " << ipll.zones.size() << " zones" << std::endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::cerr << "Failed to load IPL " << path << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-02 19:37:19 +02:00
|
|
|
|
2013-07-22 05:39:58 +02:00
|
|
|
void GTAEngine::createVehicle(const uint16_t id, const glm::vec3& pos, const glm::quat& rot)
|
2013-07-02 19:37:19 +02:00
|
|
|
{
|
|
|
|
auto vti = vehicleTypes.find(id);
|
|
|
|
if(vti != vehicleTypes.end()) {
|
|
|
|
std::cout << "Creating Vehicle ID " << id << " (" << vti->second->gameName << ")" << std::endl;
|
|
|
|
|
|
|
|
if(! vti->second->modelName.empty()) {
|
|
|
|
gameData.loadDFF(vti->second->modelName + ".dff");
|
|
|
|
}
|
|
|
|
if(! vti->second->textureName.empty()) {
|
|
|
|
gameData.loadTXD(vti->second->textureName + ".txd");
|
|
|
|
}
|
|
|
|
|
2013-07-04 01:23:12 +02:00
|
|
|
glm::vec3 prim = glm::vec3(1.f), sec = glm::vec3(0.5f);
|
|
|
|
auto palit = gameData.vehiclePalettes.find(vti->second->modelName); // modelname is conveniently lowercase (usually)
|
|
|
|
if(palit != gameData.vehiclePalettes.end() && palit->second.size() > 0 ) {
|
|
|
|
std::uniform_int_distribution<int> uniform(0, palit->second.size()-1);
|
|
|
|
int set = uniform(randomEngine);
|
|
|
|
prim = gameData.vehicleColours[palit->second[set].first];
|
|
|
|
sec = gameData.vehicleColours[palit->second[set].second];
|
|
|
|
}
|
|
|
|
else {
|
2013-07-06 02:39:54 +02:00
|
|
|
logWarning("No colour palette for vehicle " + vti->second->modelName);
|
2013-07-04 01:23:12 +02:00
|
|
|
}
|
|
|
|
|
2013-07-04 03:40:47 +02:00
|
|
|
auto wi = objectTypes.find(vti->second->wheelModelID);
|
|
|
|
if( wi != objectTypes.end()) {
|
|
|
|
if(! wi->second->textureName.empty()) {
|
|
|
|
gameData.loadTXD(wi->second->textureName + ".txd");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Model> &model = gameData.models[vti->second->modelName];
|
|
|
|
if(model) {
|
|
|
|
if( vti->second->wheelPositions.size() == 0 ) {
|
|
|
|
for( size_t f = 0; f < model->frames.size(); ++f) {
|
|
|
|
if( model->frameNames.size() > f) {
|
|
|
|
std::string& name = model->frameNames[f];
|
|
|
|
if( name.substr(0, 5) == "wheel" ) {
|
|
|
|
vti->second->wheelPositions.push_back(model->frames[f].position);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-22 05:39:58 +02:00
|
|
|
vehicleInstances.push_back({ vti->second, pos, rot, prim, sec });
|
2013-07-02 19:37:19 +02:00
|
|
|
}
|
|
|
|
}
|
2013-07-22 05:39:58 +02:00
|
|
|
|
|
|
|
void GTAEngine::createPedestrian(const uint16_t id, const glm::vec3 &pos, const glm::quat& rot)
|
|
|
|
{
|
|
|
|
auto pti = pedestrianTypes.find(id);
|
|
|
|
if( pti != pedestrianTypes.end() ) {
|
|
|
|
auto& pt = pti->second;
|
|
|
|
|
|
|
|
// Ensure the relevant data is loaded.
|
|
|
|
if(! pt->modelName.empty()) {
|
|
|
|
gameData.loadDFF(pt->modelName + ".dff");
|
|
|
|
}
|
|
|
|
if(! pt->textureName.empty()) {
|
|
|
|
gameData.loadTXD(pt->textureName + ".txd");
|
|
|
|
}
|
|
|
|
|
|
|
|
pedestrians.push_back({ pt, pos, rot });
|
|
|
|
}
|
|
|
|
}
|