rnr/Projects/Engine/Source/App/V8/World/World.cpp

264 lines
9.4 KiB
C++

#include <App/V8/World/World.hpp>
#include <App/V8/Tree/InstanceFactory.hpp>
#include <App/V8/DataModel/PartInstance.hpp>
#include <App/V8/DataModel/Lighting.hpp>
#include <App/GUI/SelectionBox.hpp>
#include <App/Humanoid/Humanoid.hpp>
#include <App/InputManager.hpp>
#include <Network/Player.hpp>
#include <stdexcept>
#include <pugixml.hpp>
#include <Helpers/Bullet.hpp>
namespace RNR
{
void physicsThread(World* world)
{
float delta;
float time;
while(world->getPhysicsShouldBeRunningPleaseStopIfItIsStillRunning())
{
delta = world->getPhysicsTimer()->getMicroseconds() / 1000000.0;
time += world->getPhysicsTimer()->getMilliseconds() / 1000.0;
world->setPhysicsTime(time);
world->getPhysicsTimer()->reset();
world->preStep();
world->step(delta);
}
}
World::World(Ogre::Root* ogre, Ogre::SceneManager* ogreSceneManager)
{
Instance::setWorld(this);
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
m_dynamicsWorld->setGravity(btVector3(0, -64, 0));
m_inputManager = 0;
m_instanceFactory = new InstanceFactory();
m_instanceFactory->registerInstance("Camera", InstanceFactory::instanceBuilder<Camera>);
m_instanceFactory->registerInstance("Model", InstanceFactory::instanceBuilder<ModelInstance>);
m_instanceFactory->registerInstance("SelectionBox", InstanceFactory::instanceBuilder<SelectionBox>);
m_instanceFactory->registerInstance("Part", InstanceFactory::instanceBuilder<PartInstance>);
m_instanceFactory->registerInstance("Workspace", InstanceFactory::instanceBuilder<Workspace>);
m_instanceFactory->registerInstance("Humanoid", InstanceFactory::instanceBuilder<Humanoid>);
m_instanceFactory->registerInstance("RunService", InstanceFactory::instanceBuilder<RunService>);
m_instanceFactory->registerInstance("Players", InstanceFactory::instanceBuilder<Players>);
m_instanceFactory->registerInstance("Player", InstanceFactory::instanceBuilder<Player>);
m_instanceFactory->registerInstance("Lighting", InstanceFactory::instanceBuilder<Lighting>);
m_ogreRoot = ogre;
m_ogreSceneManager = ogreSceneManager;
m_datamodel = new DataModel();
m_datamodel->setName("DataModel");
m_workspace = (Workspace*)m_datamodel->getService("Workspace");
m_runService = (RunService*)m_datamodel->getService("RunService");
m_players = (Players*)m_datamodel->getService("Players");
m_runPhysics = true;
m_physicsTimer = new Ogre::Timer();
m_physicsThread = std::thread(physicsThread, this);
m_physicsTime = 0.0;
m_tmb = new TopMenuBar(this);
Camera* start_cam = new Camera();
start_cam->setParent(m_workspace);
m_workspace->setCurrentCamera(start_cam);
}
World::~World()
{
m_runPhysics = false;
m_physicsThread.join();
}
void World::xmlAddItem(pugi::xml_node node, Instance* parent)
{
pugi::xml_attribute class_attr = node.attribute("class");
Instance* instance;
try{
if(parent == m_datamodel && m_datamodel->findFirstChildOfType(class_attr.as_string()))
instance = m_datamodel->findFirstChildOfType(class_attr.as_string());
else
{
std::string class_name = class_attr.value();
instance = m_instanceFactory->build(class_name);
}
}
catch(std::runtime_error e)
{
printf("World::xmlAddItem: InstanceFactory::build failed '%s'\n", e.what());
return;
}
pugi::xml_attribute referent = node.attribute("referent");
if(!referent.empty())
m_refs[referent.as_string()] = instance;
WorldUndeserialized s;
s.instance = instance;
s.parent = parent;
s.node = node;
m_undeserialized.push(s);
for(pugi::xml_node item = node.child("Item"); item; item = item.next_sibling("Item"))
xmlAddItem(item, instance);
}
void World::load(char* path)
{
m_refs.clear();
Camera* old_camera = m_workspace->getCurrentCamera();
if(old_camera)
{
m_workspace->setCurrentCamera(0);
old_camera->setParent(NULL);
}
pugi::xml_document rbxl_doc;
pugi::xml_parse_result result = rbxl_doc.load_file(path);
if(result)
{
printf("World::load: XML parsed without errors\n");
pugi::xml_node root = rbxl_doc.child("roblox");
for(pugi::xml_node item = root.child("Item"); item; item = item.next_sibling("Item"))
{
xmlAddItem(item, m_datamodel);
}
while(!m_undeserialized.empty())
{
WorldUndeserialized s = m_undeserialized.top();
m_undeserialized.pop();
pugi::xml_node props = s.node.child("Properties");
for(pugi::xml_node prop : props.children())
{
s.instance->deserializeXmlProperty(prop);
}
s.instance->setParent(s.parent);
if(s.instance->getClassName() == "Model")
{
ModelInstance* m = (ModelInstance*)s.instance;
m->build();
}
}
}
else
{
printf("World::load: XML parsed with errors, description '%s', offset %i\n", result.description(), result.offset);
}
m_workspace->build();
}
void World::preRender(float timestep)
{
if(m_inputManager)
m_inputManager->frame();
m_tmb->frame();
m_lastDelta = timestep;
if(m_runService && m_runService->getRunning() && !m_runService->getPaused())
{
physicsIterateLock.lock();
for(int j = m_dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[j];
if(!obj->isActive())
continue;
PartInstance* part = (PartInstance*)obj->getUserPointer();
part->updateMatrix();
}
update();
physicsIterateLock.unlock();
}
}
void World::preStep()
{
}
double World::step(float timestep)
{
if(m_runService && m_runService->getRunning() && !m_runService->getPaused())
{
m_runService->step(timestep);
m_dynamicsWorld->stepSimulation(timestep, 2);
physicsIterateLock.lock();
for(int j = m_dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[j];
if(!obj->isActive())
continue;
btRigidBody* body = btRigidBody::upcast(obj);
btTransform trans;
if(body && body->getMotionState())
{
body->getMotionState()->getWorldTransform(trans);
}
else
{
trans = obj->getWorldTransform();
}
PartInstance* part = (PartInstance*)obj->getUserPointer();
part->getCFrame().setPosition(Bullet::v3ToOgre(trans.getOrigin()));
Ogre::Matrix3 partRot;
Ogre::Quaternion transOgre = Bullet::qtToOgre(trans.getRotation());
transOgre.ToRotationMatrix(partRot);
part->getCFrame().setRotation(partRot);
}
physicsIterateLock.unlock();
}
m_lastPhysicsDelta = timestep;
return 0.0;
}
void World::update()
{
m_workspace->buildGeom();
}
void World::registerPhysicsPart(PartInstance* partRegistered)
{
btCollisionShape* partShape = new btBoxShape(Bullet::v3ToBullet(partRegistered->getSize() / 2.f));
partShape->setUserPointer(partRegistered);
btTransform partTransform;
partTransform.setIdentity();
partTransform.setOrigin(Bullet::v3ToBullet(partRegistered->getPosition()));
partTransform.setRotation(Bullet::qtToBullet(partRegistered->getRotation()));
btScalar mass = partRegistered->getSize().length();
if(partRegistered->getAnchored())
mass = 0;
btVector3 localInertia = btVector3(0,0,0);
if(mass)
partShape->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* partMotionState = new btDefaultMotionState(partTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, partMotionState, partShape, localInertia);
btRigidBody* body = new btRigidBody(rbInfo);
body->setUserPointer(partRegistered);
m_dynamicsWorld->addRigidBody(body);
}
void World::deletePhysicsPart(PartInstance* partDelete)
{
}
}