diff --git a/CMakeLists.txt b/CMakeLists.txt index 9853e79..140cca3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/src) # choose source file file(GLOB LIB_SRC_LIST src/*.cpp src/tools/*.cpp src/scene/*.cpp src/sparrowshell/*.cpp) file(GLOB LIB_HEAD_LIST src/*.h src/tools/*.h src/scene/*.h src/sparrowshell/*.h) -set(EXEC_SRC_LIST src/test/main.cpp) +file(GLOB EXEC_SRC_LIST src/test/*.cpp) #set compilation option set(IS_LIBRARY True) diff --git a/src/engine.cpp b/src/engine.cpp index e3a0189..edb1950 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -10,11 +10,14 @@ #include "resourcemanager.h" #include "scene/scenetree.h" #include "sparrowshell/sparrowshell.h" +#include "scene/physicsdebugnode.h" Engine::Engine() : - m_window(NULL), - m_input(NULL), - m_world(NULL) + m_window(nullptr), + m_input(nullptr), + m_world(nullptr), + m_physicsDebugNode(nullptr), + m_togglePhysicsDebugAction(NO_ACTION) { m_clock = new sf::Clock(); m_clock->restart(); @@ -67,12 +70,22 @@ void Engine::update() m_timeStamp = (unsigned int) m_clock->getElapsedTime().asMilliseconds(); // update Events m_input->updateEvents(); + checkSpecialInputs(); + + // update Physics + if(m_world != nullptr) + { + m_world->stepSimulation(1000.f*(float)getDeltaTime()); + if(m_physicsDebugNode != nullptr) + { + m_physicsDebugNode->clearBuffers(); + m_world->debugDrawWorld(); + } + } // update Scene m_scene->update(); - // update Physics - if(m_world != NULL) - m_world->stepSimulation(1000.f*(float)getDeltaTime()); + // update Display if(m_input->isResized()) m_renderer->resizeGL(m_window->getSize().x, m_window->getSize().y); @@ -94,18 +107,24 @@ void Engine::stop() m_running = false; } -unsigned int Engine::getTime() +unsigned int Engine::getTime() const { return m_timeStamp; } -unsigned int Engine::getDeltaTime() +unsigned int Engine::getDeltaTime() const { return m_timeStamp - m_lastTimeStamp; } void Engine::setScene(SceneTree *scene) { + if(m_physicsDebugNode != nullptr) + { + m_scene->removeFromIndex(m_physicsDebugNode); + scene->addToIndex(m_physicsDebugNode); + } + scene->getRootObject()->removeChild(m_sparrowshell); m_scene = scene; m_renderer->setScene(m_scene); m_renderer->resizeGL(m_window->getSize().x, m_window->getSize().y); @@ -114,7 +133,56 @@ void Engine::setScene(SceneTree *scene) scene->updateShaders(); } -void Engine::outputShell(std::string str) +void Engine::enablePhysicsDebug() +{ + if(m_world != nullptr && m_physicsDebugNode == nullptr) + { + m_physicsDebugNode = new PhysicsDebugNode(); + m_scene->addToIndex(m_physicsDebugNode); + m_world->setDebugDrawer(m_physicsDebugNode); + m_world->getDebugDrawer()->setDebugMode(btIDebugDraw::DBG_DrawWireframe); + m_scene->updateShaders(); + } +} + +void Engine::disablePhysicsDebug() +{ + if(m_world != nullptr && m_physicsDebugNode != nullptr) + { + m_world->setDebugDrawer(nullptr); + m_scene->removeFromIndex(m_physicsDebugNode); + delete m_physicsDebugNode; + m_physicsDebugNode = nullptr; + } +} + +void Engine::setTogglePhysicsDebugAction(int action) +{ + m_togglePhysicsDebugAction = action; +} + +void Engine::outputShell(std::string str) const { m_sparrowshell->out(str); } + +void Engine::checkSpecialInputs() +{ + for(int action : m_input->getActions()) + { + if(action == m_togglePhysicsDebugAction) + { + if(m_physicsDebugNode == nullptr) + enablePhysicsDebug(); + else + disablePhysicsDebug(); + } + } +} + + + +SceneTree* Engine::createScene() +{ + return new SceneTree(*this); +} diff --git a/src/engine.h b/src/engine.h index 37ed793..e197f9c 100644 --- a/src/engine.h +++ b/src/engine.h @@ -7,6 +7,7 @@ class Input; class SparrowRenderer; class SceneTree; class SparrowShell; +class PhysicsDebugNode; namespace sf { @@ -28,18 +29,24 @@ public: void setScene(SceneTree *scene); void initPhysics(); + void enablePhysicsDebug(); + void disablePhysicsDebug(); + void setTogglePhysicsDebugAction(int action); + void start(); void stop(); - Input* getInput() {return m_input;} - sf::Window* getWindow(){return m_window;} - SparrowRenderer* getRenderer() {return m_renderer;} - btDiscreteDynamicsWorld* getPhysics() {return m_world;} + Input* getInput() const {return m_input;} + sf::Window* getWindow() const {return m_window;} + SparrowRenderer* getRenderer() const {return m_renderer;} + btDiscreteDynamicsWorld* getPhysics() const {return m_world;} - void outputShell(std::string str); + void outputShell(std::string str) const; - unsigned int getTime(); - unsigned int getDeltaTime(); + unsigned int getTime() const; + unsigned int getDeltaTime() const; + + SceneTree* createScene(); private: sf::Clock* m_clock; @@ -53,9 +60,13 @@ private: SceneTree* m_scene; SparrowShell* m_sparrowshell; btDiscreteDynamicsWorld* m_world; + PhysicsDebugNode *m_physicsDebugNode; + int m_togglePhysicsDebugAction; SparrowRenderer* m_renderer; void update(); + + void checkSpecialInputs(); }; #endif diff --git a/src/scene/containernode.cpp b/src/scene/containernode.cpp index 0ec47df..7202193 100644 --- a/src/scene/containernode.cpp +++ b/src/scene/containernode.cpp @@ -1,4 +1,11 @@ #include "containernode.h" +#include + +ContainerNode::~ContainerNode() +{ + for(SceneNode *child : m_children) + delete child; +} // Container Node void ContainerNode::update() @@ -21,14 +28,17 @@ void ContainerNode::removeChild(SceneNode* node) { if(node != nullptr) { - for(auto it = m_children.begin(); it != m_children.end(); ++it) + for(auto it = m_children.begin(); it != m_children.end();) { if(*it == node) { - m_children.erase(it); + it = m_children.erase(it); node->m_parent = nullptr; + node->setSceneTree(nullptr); // break; } + else + ++it; } } } diff --git a/src/scene/containernode.h b/src/scene/containernode.h index 8d982a6..adfecee 100644 --- a/src/scene/containernode.h +++ b/src/scene/containernode.h @@ -10,6 +10,8 @@ class ContainerNode : public SceneNode { public: + virtual ~ContainerNode(); + virtual void update(); /** * @brief addChild adds node in the ContainerNode's children list diff --git a/src/scene/gibgeneratornode.cpp b/src/scene/gibgeneratornode.cpp new file mode 100644 index 0000000..a65dce6 --- /dev/null +++ b/src/scene/gibgeneratornode.cpp @@ -0,0 +1,52 @@ +#include "gibgeneratornode.h" +#include +#include +#include "scenetree.h" +#include "graphicalnode.h" + +void GibGeneratorNode::createGib(GraphicalNode* graphicalPart, + btCollisionShape *physicsShape, + float mass, + const glm::vec3 &pos, + const glm::vec3 &velocity, + unsigned int lifeSpan) +{ + if(m_scene != nullptr) + { + graphicalPart->moveTo(pos); + + // Create the rigid body object + btMotionState *motionState = graphicalPart->getMotionState(); + btVector3 localInertia; + physicsShape->calculateLocalInertia(mass, localInertia); + btRigidBody *body = new btRigidBody(mass, motionState, physicsShape, localInertia); + body->setLinearVelocity(btVector3(velocity.x, velocity.y, velocity.z)); + + getEngine().getPhysics()->addRigidBody(body); + + m_gibs.push_back(new Gib(body, graphicalPart, getEngine().getTime()+lifeSpan)); + addChild(graphicalPart); + m_scene->updateShaders(); // TODO : optimisations needed + } +} + +void GibGeneratorNode::update() +{ + // TODO : optimisation possible : use some kind of heap stack structure instead of vector + for(auto it = m_gibs.begin(); it != m_gibs.end();) + { + Gib *g = *it; + if(g->expiration < getEngine().getTime()) + { + removeChild(g->graphics); + delete g->graphics; + it = m_gibs.erase(it); + getEngine().getPhysics()->removeCollisionObject(g->body); + delete g; + } + else + ++it; + } + for(SceneNode* child : m_children) + child->update(); +} diff --git a/src/scene/gibgeneratornode.h b/src/scene/gibgeneratornode.h new file mode 100644 index 0000000..c5825dc --- /dev/null +++ b/src/scene/gibgeneratornode.h @@ -0,0 +1,45 @@ +#ifndef GIBGENERATORNODE_H +#define GIBGENERATORNODE_H + +#include "containernode.h" +#include +#include + +class btCollisionShape; +class btRigidBody; +class GraphicalNode; + +class GibGeneratorNode : public ContainerNode +{ + struct Gib + { + btRigidBody* body; + GraphicalNode* graphics; + unsigned int expiration; + + Gib(btRigidBody* b, GraphicalNode* g, unsigned int e) : + body(b), + graphics(g), + expiration(e) + {} + + ~Gib() + { + delete body; + } + }; + + std::vector m_gibs; + +public: + void createGib(GraphicalNode* graphicalPart, + btCollisionShape *physicsShape, + float mass, + const glm::vec3 &pos = glm::vec3(0), + const glm::vec3 &velocity = glm::vec3(0), + unsigned int lifeSpan = 5000); + + virtual void update(); +}; + +#endif // GIBGENERATORNODE_H diff --git a/src/scene/graphicalcontainernode.cpp b/src/scene/graphicalcontainernode.cpp index 9a1de2c..848e6d5 100644 --- a/src/scene/graphicalcontainernode.cpp +++ b/src/scene/graphicalcontainernode.cpp @@ -1,4 +1,12 @@ #include "graphicalcontainernode.h" +#include "scenetree.h" + +GraphicalContainerNode::~GraphicalContainerNode() +{ + setVisible(false); // renderer de-indexing + for(GraphicalNode* child : m_children) + delete child; +} void GraphicalContainerNode::update() { @@ -15,7 +23,7 @@ void GraphicalContainerNode::update() void GraphicalContainerNode::setSceneTree(SceneTree* tree) { SceneNode::setSceneTree(tree); - for(auto child : m_children) + for(GraphicalNode* child : m_children) child->setSceneTree(tree); } @@ -27,6 +35,8 @@ void GraphicalContainerNode::addChild(GraphicalNode *node) node->setSceneTree(m_scene); m_children.push_back(node); node->m_parent = this; + node->setParentTransform(m_transform); + node->setParentVisible(isVisible()); } } @@ -44,3 +54,9 @@ void GraphicalContainerNode::removeChild(GraphicalNode *node) } } } + +void GraphicalContainerNode::updateVisibility(bool visible) +{ + for(GraphicalNode* child : m_children) + child->setParentVisible(visible); +} diff --git a/src/scene/graphicalcontainernode.h b/src/scene/graphicalcontainernode.h index 7e43427..a51c630 100644 --- a/src/scene/graphicalcontainernode.h +++ b/src/scene/graphicalcontainernode.h @@ -12,10 +12,14 @@ protected: glm::mat4 m_combinedTransform; public: + virtual ~GraphicalContainerNode(); + virtual void update(); virtual void setSceneTree(SceneTree* tree); + virtual void updateVisibility(bool visible); + void addChild(GraphicalNode* node); void removeChild(GraphicalNode* node); }; diff --git a/src/scene/graphicalnode.cpp b/src/scene/graphicalnode.cpp index ed714ae..16c74d5 100644 --- a/src/scene/graphicalnode.cpp +++ b/src/scene/graphicalnode.cpp @@ -3,18 +3,14 @@ #include "glm/ext.hpp" void GraphicalNode::setSceneTree(SceneTree *tree){ - SceneNode::setSceneTree(tree); - if(tree && m_visible) - tree->addToIndex(this); -} - -void GraphicalNode::toggleVisibility(){ - m_visible = !m_visible; - if(m_visible){ - m_scene->addToIndex(this); - }else{ - m_scene->removeFromIndex(this); + if(isVisible()) + { + if(m_scene != nullptr) + m_scene->removeFromIndex(this); + if(tree != nullptr) + tree->addToIndex(this); } + m_scene = tree; } // tools @@ -62,3 +58,52 @@ void GraphicalNode::setParentTransform(const glm::mat4 &transform) m_parentTransform = transform; m_transformChanged = true; } + +void GraphicalNode::toggleVisibility() +{ + setVisible(!m_visible); +} + +void GraphicalNode::setVisible(bool visible) +{ + if(m_parentVisible) + { + if(m_visible && !visible) + updateVisibility(false); + if(visible && !m_visible) + updateVisibility(true); + } + m_visible = visible; +} + +void GraphicalNode::setParentVisible(bool visible) +{ + if(m_visible) + { + if(m_parentVisible && !visible) + updateVisibility(false); + if(visible && !m_parentVisible) + updateVisibility(true); + } + m_parentVisible = visible; +} + +void GraphicalNode::updateVisibility(bool visible) +{ + if(visible) + m_scene->addToIndex(this); + else + m_scene->removeFromIndex(this); +} + +void GraphicalNode::SparrowMotionState::getWorldTransform(btTransform& worldTrans ) const +{ + worldTrans.setFromOpenGLMatrix(glm::value_ptr(m_node->getTransform())); +} + +void GraphicalNode::SparrowMotionState::setWorldTransform(const btTransform& worldTrans) +{ + glm::mat4 t; + worldTrans.getOpenGLMatrix(glm::value_ptr(t)); + m_node->setTransform(t); +} diff --git a/src/scene/graphicalnode.h b/src/scene/graphicalnode.h index d44f002..ba06e8f 100644 --- a/src/scene/graphicalnode.h +++ b/src/scene/graphicalnode.h @@ -4,37 +4,58 @@ #include "scenenode.h" #include #include +#include "LinearMath/btMotionState.h" class SceneTree; class GraphicalNode : public SceneNode { +public: + class SparrowMotionState : public btMotionState + { + GraphicalNode* m_node; + + public: + SparrowMotionState(GraphicalNode* node) : m_node(node) {} + + virtual void getWorldTransform(btTransform& worldTrans ) const; + + //Bullet only calls the update of worldtransform for active objects + virtual void setWorldTransform(const btTransform& worldTrans); + }; + protected: // m_parentTransform is the base transform for this element glm::mat4 m_parentTransform; // m_transform is the relative transformation matrix of this node glm::mat4 m_transform; + bool m_parentVisible; bool m_visible; bool m_transformChanged; + SparrowMotionState m_motionState; + + virtual void updateVisibility(bool visible); + public: -// GraphicalNode(); -// GraphicalNode(bool); - GraphicalNode(bool visible = true) : m_visible(visible), m_transformChanged(true) {} + GraphicalNode(bool visible = true) : m_parentVisible(true), m_visible(visible), m_transformChanged(true), m_motionState(this) {} + virtual ~GraphicalNode() { setVisible(false); } - - bool isVisible(){return m_visible;} - void toggleVisibility(); virtual void setSceneTree(SceneTree* tree); + // transform methods void setTransform(const glm::mat4 &transform); - + const glm::mat4& getTransform() { return m_transform; } void setParentTransform(const glm::mat4 &transform); - const glm::mat4& getTransform() { return m_transform; } + // visibility methods + bool isVisible(){return m_parentVisible && m_visible;} + void toggleVisibility(); + void setVisible(bool visible); + void setParentVisible(bool visible); // transformation tools : void moveTo(const glm::vec3 &position); @@ -42,6 +63,9 @@ public: void lookAt(const glm::vec3 &target, const glm::vec3 &upVector = glm::vec3(0, 1, 0)); void rotate(float angle, const glm::vec3 &vector); void scale(const glm::vec3 &scaleFactor); + + // this is used to synchronize a bullet rigidbody's transform with a GraphicalNode transform + SparrowMotionState* getMotionState() { return &m_motionState; } }; #endif // GRAPHICALNODE_H diff --git a/src/scene/meshnode.cpp b/src/scene/meshnode.cpp index 2ed74e6..8fc156b 100644 --- a/src/scene/meshnode.cpp +++ b/src/scene/meshnode.cpp @@ -12,21 +12,8 @@ void MeshNode::setDepth(float depth){ void MeshNode::update() { - // temp animation system - m_movement = m_acceleration * m_movement; - m_geometry.modelMatrix = m_movement * m_geometry.modelMatrix; - if(m_transformChanged) - { m_geometry.modelMatrix = m_parentTransform * m_transform; - if(m_rigidBody != nullptr) - { - btTransform transform; - transform.setFromOpenGLMatrix(glm::value_ptr(m_geometry.modelMatrix)); - m_rigidBody->setWorldTransform(transform); - m_rigidBody->setLinearVelocity(btVector3(0,0,0)); - } - } } btRigidBody* MeshNode::buildStaticCollider() @@ -45,11 +32,16 @@ btRigidBody* MeshNode::buildStaticCollider() bulletMesh->m_indexType = PHY_INTEGER; // building bullet rigidbody - btTriangleIndexVertexArray* collisionShape = new btTriangleIndexVertexArray(); - collisionShape->addIndexedMesh(*bulletMesh, PHY_INTEGER); - btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape(collisionShape, false); + btTriangleIndexVertexArray* indexArray = new btTriangleIndexVertexArray(); + indexArray->addIndexedMesh(*bulletMesh, PHY_INTEGER); + btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape(indexArray, true); + shape->setLocalScaling(btVector3(m_transform[0].x, m_transform[1].y, m_transform[2].z)); - btMotionState *motionState = new btDefaultMotionState(); - m_rigidBody = new btRigidBody(0, motionState, shape); + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(m_transform[3].x, m_transform[3].y, m_transform[3].z)); + // IMPORTANT ! collisions on static meshes does not work if the transform is modified after the rigidbody construction + m_rigidBody = new btRigidBody(0., nullptr, shape); + m_rigidBody->setWorldTransform(transform); return m_rigidBody; } diff --git a/src/scene/meshnode.h b/src/scene/meshnode.h index 496a99e..a5393c9 100644 --- a/src/scene/meshnode.h +++ b/src/scene/meshnode.h @@ -15,16 +15,15 @@ class btRigidBody; class MeshNode : public GraphicalNode { +protected: GeometryNode m_geometry; // physics btRigidBody *m_rigidBody; public: - // temp - glm::mat4 m_movement; - glm::mat4 m_acceleration; - + // WARNING ! this class doesn't handle the destruction of the rendered mesh and the eventually generated rigidbody + // this behaviour allows the use of the same meshes in multiple nodes MeshNode(Mesh* mesh, bool visible = true) : GraphicalNode(visible), m_geometry(mesh, glm::mat4()), m_rigidBody(nullptr) {} virtual void update(); @@ -33,6 +32,7 @@ public: virtual GeometryNode* getGeometryNode() { return &m_geometry; } + // this creates a new rigidbody, you must handle its destruction manually btRigidBody* buildStaticCollider(); }; diff --git a/src/scene/physicsdebugnode.cpp b/src/scene/physicsdebugnode.cpp new file mode 100644 index 0000000..f3eb720 --- /dev/null +++ b/src/scene/physicsdebugnode.cpp @@ -0,0 +1,42 @@ +#include "physicsdebugnode.h" +#include "mesh.h" +#include "phongmaterial.h" + +PhysicsDebugNode::PhysicsDebugNode() : + MeshNode(new Mesh()) +{ + PhongMaterial* mat = new PhongMaterial(); + mat->emission = glm::vec3(1, 0, 0); + mat->diffuse = glm::vec3(0); + mat->specular = glm::vec3(0); + + m_geometry.mesh->setMaterial(mat); + m_geometry.mesh->setPrimitiveType(GL_LINES); + m_geometry.mesh->setWireframe(true); + + glm::vec3 pos1(0, 1, 0); + glm::vec3 pos2(0, 0, 0); + glm::vec3 color(1, 0, 0); + m_geometry.mesh->addVertex(pos1, color); + m_geometry.mesh->addVertex(pos2, color); + m_geometry.mesh->updateFlags(); +} + +void PhysicsDebugNode::drawLine(const btVector3& from, const btVector3& to, const btVector3& color) +{ + glm::vec3 glColor(color.x(), color.y(), color.z()); + m_geometry.mesh->addVertex(glm::vec3(from.x(), from.y(), from.z()), glColor); + m_geometry.mesh->addVertex(glm::vec3(to.x(), to.y(), to.z()), glColor); +} + +void PhysicsDebugNode::flushLines() +{ + // a little heavy, but it's a debug mode so it shouldn't be a problem + m_geometry.mesh->initGL(); +} + +void PhysicsDebugNode::clearBuffers() +{ + m_geometry.mesh->positions3D.clear(); + m_geometry.mesh->normals.clear(); +} diff --git a/src/scene/physicsdebugnode.h b/src/scene/physicsdebugnode.h new file mode 100644 index 0000000..2d2b43a --- /dev/null +++ b/src/scene/physicsdebugnode.h @@ -0,0 +1,32 @@ +#ifndef PHYSICSDEBUGNODE_H +#define PHYSICSDEBUGNODE_H + +#include "meshnode.h" +#include + +class PhysicsDebugNode : public MeshNode, public btIDebugDraw +{ + Mesh* m_debugMesh; + int m_debugMode; + +public: + PhysicsDebugNode(); + + virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color); + + virtual void flushLines(); + + virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) {} // not supported yet + + virtual void reportErrorWarning(const char* warningString) {} // not supported yet + + virtual void draw3dText(const btVector3& location, const char* textString) {} // not supported yet + + // currently useless + virtual void setDebugMode(int debugMode) { m_debugMode = debugMode; } + virtual int getDebugMode() const { return m_debugMode; } + + void clearBuffers(); +}; + +#endif // PHYSICSDEBUGNODE_H diff --git a/src/scene/playercharacternode.cpp b/src/scene/playercharacternode.cpp index f543d77..9475af2 100644 --- a/src/scene/playercharacternode.cpp +++ b/src/scene/playercharacternode.cpp @@ -5,6 +5,8 @@ #include +#include "scenetree.h" + #define DEFAULT_ROTATION_SPEED 0.01f void FirstPersonCamera::computeView() @@ -54,13 +56,12 @@ const float PLAYER_RADIUS = 0.30f; const float PLAYER_HEIGHT = 1.75f; const float EYES_OFFSET = 0.775f; -PlayerCharacterNode::PlayerCharacterNode(Input *input) : - m_input(input), - m_noclipMode(true), +PlayerCharacterNode::PlayerCharacterNode(bool noClip) : + m_noclipMode(noClip), m_inputActions({NO_ACTION, NO_ACTION, NO_ACTION, NO_ACTION, NO_ACTION}) { - btDefaultMotionState *motionState = new btDefaultMotionState(); + m_motionState = new btDefaultMotionState(); // Create the shape btCollisionShape *shape = new btCapsuleShape(PLAYER_RADIUS, PLAYER_HEIGHT); @@ -70,7 +71,7 @@ PlayerCharacterNode::PlayerCharacterNode(Input *input) : shape->calculateLocalInertia(1.0, localInertia); // Create the rigid body object - m_rigidBody = new btRigidBody(1.0, motionState, shape, localInertia); + m_rigidBody = new btRigidBody(1.0, m_motionState, shape, localInertia); // capsule always pointing up m_rigidBody->setSleepingThresholds(0.0, 0.0); @@ -98,10 +99,11 @@ void PlayerCharacterNode::setPosition(float x, float y, float z) void PlayerCharacterNode::update() { + Input *input = getEngine().getInput(); // get events int walk = 0; int strafe = 0; - for(int action : m_input->getActions()) + for(int action : input->getActions()) { if(action == m_inputActions[FORWARD]) ++walk; @@ -116,7 +118,7 @@ void PlayerCharacterNode::update() } // update camera rotation - sf::Vector2i diff = m_input->getDeltaPosition(); + sf::Vector2i diff = input->getDeltaPosition(); m_fpsCamera.rotate(diff.x, diff.y); // update camera position diff --git a/src/scene/playercharacternode.h b/src/scene/playercharacternode.h index 354983f..27bda22 100644 --- a/src/scene/playercharacternode.h +++ b/src/scene/playercharacternode.h @@ -6,6 +6,7 @@ #include class btRigidBody; +class btDefaultMotionState; class FirstPersonCamera : public BasicCamera { @@ -26,15 +27,14 @@ public: void lookAt(const glm::vec3 &targetPos); void setUpVector(const glm::vec3 &up); + const glm::vec3& getEyePosition() { return m_eye; } const glm::vec3& getDirection() { return m_direction; } }; class PlayerCharacterNode : public CameraNode { - Input *m_input; - btRigidBody* m_rigidBody; - + btDefaultMotionState *m_motionState; FirstPersonCamera m_fpsCamera; bool m_noclipMode; @@ -45,12 +45,15 @@ class PlayerCharacterNode : public CameraNode enum PlayerAction {FORWARD, BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP}; public: - PlayerCharacterNode(Input *input); + PlayerCharacterNode(bool noClip = true); void setInputs(int forward, int backward, int strafe_left, int strafe_right, int toggleNoClip = NO_ACTION); void setPosition(float x, float y, float z); + glm::vec3 getEyePosition() { return m_fpsCamera.getEyePosition(); } + glm::vec3 getDirection() { return m_fpsCamera.getDirection(); } + virtual void update(); void toggleNoClip(); diff --git a/src/scene/scenenode.cpp b/src/scene/scenenode.cpp new file mode 100644 index 0000000..81c6636 --- /dev/null +++ b/src/scene/scenenode.cpp @@ -0,0 +1,8 @@ +#include "scenenode.h" +#include "scenetree.h" + +const Engine& SceneNode::getEngine() +{ + return m_scene->getEngine(); +} + diff --git a/src/scene/scenenode.h b/src/scene/scenenode.h index 99bebd7..f193400 100644 --- a/src/scene/scenenode.h +++ b/src/scene/scenenode.h @@ -4,9 +4,12 @@ class SceneTree; class Light; class GeometryNode; +class Engine; class SceneNode { +protected: + const Engine& getEngine(); public: SceneNode() : m_parent(nullptr), m_scene(nullptr) {} @@ -16,7 +19,7 @@ public: virtual void update() = 0; virtual Light* getLight() {return nullptr;} virtual GeometryNode* getGeometryNode() {return nullptr;} - virtual void setSceneTree(SceneTree* tree){m_scene = tree;} + virtual void setSceneTree(SceneTree* tree) {m_scene = tree;} // virtual void toggleNode(){m_enabled = !m_enabled;} }; diff --git a/src/scene/scenetree.cpp b/src/scene/scenetree.cpp index 65eb305..89af229 100644 --- a/src/scene/scenetree.cpp +++ b/src/scene/scenetree.cpp @@ -9,8 +9,9 @@ #include "scene/scenenode.h" #include "scene/cameranode.h" -SceneTree::SceneTree() : +SceneTree::SceneTree(const Engine &engine) : Scene(), + m_engine(engine), m_skybox(NULL) { DeferredPipeline *pipeline = new DeferredPipeline(); @@ -48,25 +49,29 @@ void SceneTree::addToIndex(SceneNode* node){ Light *light = node->getLight(); GeometryNode *geometrynode = node->getGeometryNode(); //TODO : Check for doublon in m_lights et m_geometries => not necessary if correctly removed ? - if (light) m_lights.push_back(light); - if (geometrynode) m_geometries.push_back(geometrynode); -} - -void SceneTree::removeObject(ContainerNode* parent,SceneNode *node){ - parent->removeChild(node); - removeFromIndex(node); + if (light != nullptr) m_lights.push_back(light); + if (geometrynode != nullptr) m_geometries.push_back(geometrynode); } void SceneTree::removeFromIndex(SceneNode *node){ - auto it_l = std::find(m_lights.begin(),m_lights.end(),node->getLight()); - if (it_l != m_lights.end()){ - std::iter_swap(it_l,m_lights.end()-1); - m_lights.pop_back(); + Light *light = node->getLight(); + GeometryNode *geometrynode = node->getGeometryNode(); + + if(light != nullptr) + { + auto it_l = std::find(m_lights.begin(),m_lights.end(),node->getLight()); + if (it_l != m_lights.end()){ + std::iter_swap(it_l,m_lights.end()-1); + m_lights.pop_back(); + } } - auto it_g = std::find(m_geometries.begin(),m_geometries.end(),node->getGeometryNode()); - if (it_g != m_geometries.end()){ - std::iter_swap(it_g,m_geometries.end()-1); - m_geometries.pop_back(); + if(geometrynode != nullptr) + { + auto it_g = std::find(m_geometries.begin(),m_geometries.end(),node->getGeometryNode()); + if (it_g != m_geometries.end()){ + std::iter_swap(it_g,m_geometries.end()-1); + m_geometries.pop_back(); + } } } diff --git a/src/scene/scenetree.h b/src/scene/scenetree.h index 869301a..3f67ebb 100644 --- a/src/scene/scenetree.h +++ b/src/scene/scenetree.h @@ -4,11 +4,10 @@ #include #include #include "scene.h" -#include "light.h" -#include "resourcemanager.h" - #include "containernode.h" +#include "engine.h" +class Light; class CameraNode; /** @@ -19,7 +18,6 @@ class CameraNode; class SceneTree : public Scene { public: - SceneTree(); ~SceneTree(); virtual SceneIterator* getLights(); @@ -34,10 +32,17 @@ public: ContainerNode* getRootObject(){return &m_root;} void addToIndex(SceneNode* node); - void removeObject(ContainerNode* parent,SceneNode *node); void removeFromIndex(SceneNode *node); void updateShaders(); + + const Engine& getEngine() { return m_engine; } + private: + // A SceneTree can only be constructed by the engine by using Engine::createScene() + friend SceneTree* Engine::createScene(); + SceneTree(const Engine &engine); + + const Engine &m_engine; ContainerNode m_root; std::vector m_lights; std::vector m_geometries; diff --git a/src/sparrowshell/sparrowshell.cpp b/src/sparrowshell/sparrowshell.cpp index 8cbc920..248aa06 100644 --- a/src/sparrowshell/sparrowshell.cpp +++ b/src/sparrowshell/sparrowshell.cpp @@ -9,6 +9,7 @@ #include "phongmaterial.h" #include "tools/utils.h" #include "tools/font.h" +#include "resourcemanager.h" const unsigned int SparrowShell::BUFFER_MAX_LENGTH = 50; const unsigned int SparrowShell::BUFFER_DISPLAYED_NUMBER = 10; diff --git a/src/test/main.cpp b/src/test/main.cpp index 4c04a55..f93e966 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -27,57 +27,27 @@ #include +#include "potator.h" + class myKeysMap : public IKeysMap{ public: - enum{MAIN_ACTION, SECONDARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_CONSOLE = 15}; + enum{MAIN_ACTION, SECONDARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_PHYSICS_DEBUG, TOGGLE_CONSOLE = 15}; myKeysMap(){ - Binding b; - - b.action = TOGGLE_CONSOLE; - b.key = sf::Keyboard::F3; - b.type = IKeysMap::PRESSED; - keys.push_back(b); - - b.action = MAIN_ACTION; - b.type = IKeysMap::HOLD; - b.key = sf::Keyboard::KeyCount + sf::Mouse::Left; - keys.push_back(b); - - b.action = SECONDARY_ACTION; - b.type = IKeysMap::HOLD; - b.key = sf::Keyboard::KeyCount + sf::Mouse::Right; - keys.push_back(b); - - b.action = MOVE_FORWARD; - b.type = IKeysMap::HOLD; - b.key = sf::Keyboard::Z; - keys.push_back(b); - - b.action = MOVE_BACKWARD; - b.type = IKeysMap::HOLD; - b.key = sf::Keyboard::S; - keys.push_back(b); - - b.action = STRAFE_LEFT; - b.type = IKeysMap::HOLD; - b.key = sf::Keyboard::Q; - keys.push_back(b); - - b.action = STRAFE_RIGHT; - b.type = IKeysMap::HOLD; - b.key = sf::Keyboard::D; - keys.push_back(b); - - b.action = TOGGLE_NOCLIP; - b.type = IKeysMap::PRESSED; - b.key = sf::Keyboard::G; - keys.push_back(b); + keys.push_back( {MAIN_ACTION, sf::Keyboard::KeyCount + sf::Mouse::Left, IKeysMap::PRESSED} ); + keys.push_back( {SECONDARY_ACTION, sf::Keyboard::KeyCount + sf::Mouse::Right, IKeysMap::PRESSED} ); + keys.push_back( {MOVE_FORWARD, sf::Keyboard::Z, IKeysMap::HOLD} ); + keys.push_back( {MOVE_BACKWARD, sf::Keyboard::S, IKeysMap::HOLD} ); + keys.push_back( {STRAFE_LEFT, sf::Keyboard::Q, IKeysMap::HOLD} ); + keys.push_back( {STRAFE_RIGHT, sf::Keyboard::D, IKeysMap::HOLD} ); + keys.push_back( {TOGGLE_NOCLIP, sf::Keyboard::G, IKeysMap::PRESSED} ); + keys.push_back( {TOGGLE_PHYSICS_DEBUG, sf::Keyboard::P, IKeysMap::PRESSED} ); + keys.push_back( {TOGGLE_CONSOLE, sf::Keyboard::F5, IKeysMap::PRESSED} ); } static std::vector getMap() { - return {MAIN_ACTION, SECONDARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_CONSOLE}; + return {MAIN_ACTION, SECONDARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_PHYSICS_DEBUG, TOGGLE_CONSOLE}; } }; @@ -154,92 +124,54 @@ int main(){ // this creates the opengl context // the opengl context must exist before any opengl class is used (texture, pipeline, etc..) - engine.createWindow("test"); + engine.createWindow("Sparrow Engine Testing Environment"); + + // setting up SparrowEngine engine.initPhysics(); - SceneTree scene; + SceneTree *scene = engine.createScene(); + engine.setScene(scene); + + // settin gup SparrowInput + Input* input = engine.getInput(); + input->setKeysMap(myKeysMap()); + input->addContext(Context("default", myKeysMap::getMap())); + input->setCurrentContext("default"); + input->updateKeyBindings(); + engine.setTogglePhysicsDebugAction(myKeysMap::TOGGLE_PHYSICS_DEBUG); /* - TrackBallCameraNode *cam = new TrackBallCameraNode(engine.getInput()); - cam->setInputs(myKeysMap::SECONDARY_ACTION, myKeysMap::MAIN_ACTION); - scene.getRootObject()->addChild(cam); - scene.setMainCamera(cam); + // trackball camera + TrackBallCameraNode *trackBallCam = new TrackBallCameraNode(engine.getInput()); + trackBallCam->setInputs(myKeysMap::SECONDARY_HOLD, myKeysMap::MAIN_HOLD); + scene.getRootObject()->addChild(trackBallCam); + scene.setMainCamera(trackBallCam); */ + // first person player controller + PlayerCharacterNode *player = new PlayerCharacterNode(); + player->setInputs(myKeysMap::MOVE_FORWARD, myKeysMap::MOVE_BACKWARD, myKeysMap::STRAFE_LEFT, myKeysMap::STRAFE_RIGHT, myKeysMap::TOGGLE_NOCLIP); + scene->getRootObject()->addChild(player); + scene->setMainCamera(player); + player->setPosition(0.f, 10.f, 0.f); + engine.getPhysics()->addRigidBody(player->getRigidbody()); - PlayerCharacterNode *cam = new PlayerCharacterNode(engine.getInput()); - cam->setInputs(myKeysMap::MOVE_FORWARD, myKeysMap::MOVE_BACKWARD, myKeysMap::STRAFE_LEFT, myKeysMap::STRAFE_RIGHT, myKeysMap::TOGGLE_NOCLIP); - scene.getRootObject()->addChild(cam); - scene.setMainCamera(cam); - cam->setPosition(0.f, 4.f, 0.f); - engine.getPhysics()->addRigidBody(cam->getRigidbody()); + // throw cubes and spheres with mouse clicks + Potator *potator = new Potator(player, myKeysMap::MAIN_ACTION, myKeysMap::SECONDARY_ACTION); + scene->getRootObject()->addChild(potator); + // lighting LightNode *sunLight = new LightNode(new DirectionnalLight(glm::vec3(5, 8, -2), glm::vec3(1.f))); LightNode *ambientLight = new LightNode(new AmbientLight()); - scene.getRootObject()->addChild(ambientLight); - scene.getRootObject()->addChild(sunLight); - - /* Exemple creation mesh 2D - * - Mesh* mesh = new Mesh(); - mesh->addRectangle2D(180, 400,10,64); - PhongMaterial *mat = new PhongMaterial(); - mat->diffuse = glm::vec3(1, 0.5, 0); - mesh->setMaterial(mat); - mesh->setDepth(1); - mesh->initGL(); - scene.getRootObject()->addChild(new MeshNode(mesh)); - */ - -/* Exemple ajout d'un objet a la scene - * - SparrowShell *shell = new SparrowShell(engine.getWindow(),engine.getInput()); - scene.getRootObject()->addChild(shell); -*/ - - // the pipeline needs to updates his shaders because the scene changed - // this should be handled somewhere else in the future - //DeferredPipeline* pipeline = (DeferredPipeline*)scene.getPipeline(); - //pipeline->refreshScene(&scene); + scene->getRootObject()->addChild(ambientLight); + scene->getRootObject()->addChild(sunLight); + // TODO : set this elsewhere, since the shell needs it Font* fonte_des_neiges = Loader::loadFont("../data/consolas.fnt","../data/consolas.png"); RESOURCE_ADD(fonte_des_neiges,Font,"shellfont"); - TextNode* tnode/* = new MeshNode(fonte_des_neiges->getTextMesh("Hello World!")); - scene.getRootObject()->addChild(mnode)*/; - -// mnode = new MeshNode(fonte_des_neiges->getTextMesh("Portez ce vieux whisky au juge blond qui fume.", glm::vec3(0.5, 0.7, 0.2))); -// mnode->setTransform(glm::rotate(glm::translate(glm::mat4(), glm::vec3(70, 30, 0)), 0.4f, glm::vec3(0, 0, 1))); -// utils::setPosition2D(mnode,glm::vec2(0, 400)); - // utils::rotate2D(mnode, glm::vec2(10,10),0.5); -// scene.getRootObject()->addChild(mnode); - - tnode = fonte_des_neiges->getTextNode("Such Text", glm::vec3(0.7, 0.4, 0.2), 32.f); - - utils::setPosition2D((MeshNode*)tnode,glm::vec2(200, 170)); - utils::rotate2D((MeshNode*)tnode, glm::vec2(0),-0.5); - - tnode->m_movement = glm::translate(glm::rotate(glm::translate(glm::mat4(), glm::vec3(240, 180, 0)), 0.03f, glm::vec3(0, 0, 1)), glm::vec3(-240, -180, 0)); - - // mnode->setTransform(glm::rotate(glm::translate(glm::mat4(), glm::vec3(200, 170, 0)), -0.5f, glm::vec3(0, 0, 1))); - scene.getRootObject()->addChild((SceneNode*)tnode); - - //tnode = fonte_des_neiges->getTextNode("Such Text", glm::vec3(0.7, 0.4, 0.2)); - //tnode->setTransform(glm::rotate(glm::translate(glm::mat4(), glm::vec3(200, 170, 0)), -0.5f, glm::vec3(0, 0, 1))); - //scene.getRootObject()->addChild(tnode); - - - // mnode = new MeshNode(fonte_des_neiges->getTextMesh("Very font", glm::vec3(0.7, 0.2, 0.8))); - // mnode->setTransform(glm::rotate(glm::translate(glm::mat4(), glm::vec3(180, 400, 0)), 0.1f, glm::vec3(0, 0, 1))); - // scene.getRootObject()->addChild(mnode); - - // mnode = new MeshNode(fonte_des_neiges->getTextMesh("Much animation", glm::vec3(0.3, 0.3, 0.8))); - // mnode->setTransform(glm::translate(glm::mat4(), glm::vec3(400, 250, 0))); - // mnode->m_movement = glm::translate(glm::rotate(glm::translate(glm::mat4(), glm::vec3(580, 280, 0)), 0.03f, glm::vec3(0, 0, 1)), glm::vec3(-580, -280, 0)); - // scene.getRootObject()->addChild(mnode); - - generateTerrain(&scene, engine.getPhysics()); - - engine.setScene(&scene); + // terrain + generateTerrain(scene, engine.getPhysics()); + // shell output tests engine.outputShell("Hello World!"); engine.outputShell("Starting test :"); @@ -247,15 +179,12 @@ int main(){ engine.outputShell(std::to_string(i)); } - Input* input = engine.getInput(); - - input->setKeysMap(myKeysMap()); - input->addContext(Context("default", myKeysMap::getMap())); - input->setCurrentContext("default"); - input->updateKeyBindings(); + // preparing shaders and launching the engine + scene->updateShaders(); engine.start(); - /* GraphNode n1 = GraphNode(); + // pathfinding tests +/* GraphNode n1 = GraphNode(); n1.setValue(1); GraphNode n2 = GraphNode(); n2.setValue(2); @@ -279,6 +208,7 @@ int main(){ std::cout << gn->getValue() << std::endl; } + // loaders tests Loader::setObjDirectory("../data/"); Loader::setMtlDirectory("../data/"); Loader::setTexDirectory("../data/"); diff --git a/src/test/potator.cpp b/src/test/potator.cpp new file mode 100644 index 0000000..4fc7bcb --- /dev/null +++ b/src/test/potator.cpp @@ -0,0 +1,137 @@ +#include "potator.h" +#include "scene/playercharacternode.h" +#include +#include +#include "scene/scenetree.h" +#include "parametricmesh.h" +#include "phongmaterial.h" +#include "scene/meshnode.h" + +#define PHYSICS_OFFSET 0.05f + +Potator::Potator(PlayerCharacterNode * player, + int cube_action, + int sphere_action) : + m_player(player), + m_throwCubeAction(cube_action), + m_throwSphereAction(sphere_action) +{ + glm::vec3 cubeDim(1); + float sphereRadius = 0.5f; + glm::vec3 s = cubeDim*0.5f; + float density = 1.f; + + // creating cube + m_cubeMesh = new Mesh(); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, -1*s.y, 1*s.z),glm::vec3(0, 0, 1),glm::vec2(0, 0)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, 1*s.y, 1*s.z),glm::vec3(0, 0, 1),glm::vec2(0, 1)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, -1*s.y, 1*s.z),glm::vec3(0, 0, 1),glm::vec2(1, 0)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, 1*s.y, 1*s.z),glm::vec3(0, 0, 1),glm::vec2(1, 1)); + + m_cubeMesh->addVertex(glm::vec3(-1*s.x, -1*s.y, -1*s.z),glm::vec3(0, 0, -1),glm::vec2(1, 0)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, 1*s.y, -1*s.z),glm::vec3(0, 0, -1),glm::vec2(1, 1)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, -1*s.y, -1*s.z),glm::vec3(0, 0, -1),glm::vec2(0, 0)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, 1*s.y, -1*s.z),glm::vec3(0, 0, -1),glm::vec2(0, 1)); + + m_cubeMesh->addVertex(glm::vec3(-1*s.x, 1*s.y, -1*s.z),glm::vec3(0, 1, 0),glm::vec2(0, 0)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, 1*s.y, 1*s.z),glm::vec3(0, 1, 0),glm::vec2(0, 1)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, 1*s.y, -1*s.z),glm::vec3(0, 1, 0),glm::vec2(1, 0)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, 1*s.y, 1*s.z),glm::vec3(0, 1, 0),glm::vec2(1, 1)); + + m_cubeMesh->addVertex(glm::vec3(-1*s.x, -1*s.y, -1*s.z),glm::vec3(0, -1, 0),glm::vec2(1, 0)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, -1*s.y, 1*s.z),glm::vec3(0, -1, 0),glm::vec2(1, 1)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, -1*s.y, -1*s.z),glm::vec3(0, -1, 0),glm::vec2(0, 0)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, -1*s.y, 1*s.z),glm::vec3(0, -1, 0),glm::vec2(0, 1)); + + m_cubeMesh->addVertex(glm::vec3( 1*s.x, -1*s.y, 1*s.z),glm::vec3( 1, 0, 0),glm::vec2(0, 0)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, 1*s.y, 1*s.z),glm::vec3( 1, 0, 0),glm::vec2(0, 1)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, -1*s.y, -1*s.z),glm::vec3( 1, 0, 0),glm::vec2(1, 0)); + m_cubeMesh->addVertex(glm::vec3( 1*s.x, 1*s.y, -1*s.z),glm::vec3( 1, 0, 0),glm::vec2(1, 1)); + + m_cubeMesh->addVertex(glm::vec3(-1*s.x, -1*s.y, 1*s.z),glm::vec3(-1, 0, 0),glm::vec2(1, 0)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, 1*s.y, 1*s.z),glm::vec3(-1, 0, 0),glm::vec2(1, 1)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, -1*s.y, -1*s.z),glm::vec3(-1, 0, 0),glm::vec2(0, 0)); + m_cubeMesh->addVertex(glm::vec3(-1*s.x, 1*s.y, -1*s.z),glm::vec3(-1, 0, 0),glm::vec2(0, 1)); + + for(int id=0; id<24; id+=8) + { + m_cubeMesh->addTriangle(id+0, id+1, id+2); + m_cubeMesh->addTriangle(id+2, id+1, id+3); + m_cubeMesh->addTriangle(id+6, id+5, id+4); + m_cubeMesh->addTriangle(id+7, id+5, id+6); + } + + PhongMaterial *mat = new PhongMaterial(); + mat->diffuse = glm::vec3(0.6f, 0.2f, 0.3f); + mat->specular = glm::vec3(0.3f); + mat->shininess = 5.f; + mat->emission = glm::vec3(0.0f); + + m_cubeMesh->setMaterial(mat); + + m_cubeMesh->initGL(); + + btVector3 halfExtents(s.x+PHYSICS_OFFSET, s.y+PHYSICS_OFFSET, s.z+PHYSICS_OFFSET); + m_cubeShape = new btBoxShape(halfExtents); + + m_cubeMass = cubeDim.x*cubeDim.y*cubeDim.z*density; + + // creating sphere + mat = new PhongMaterial(); + mat->diffuse = glm::vec3(0.1f, 0.6f, 0.3f); + mat->specular = glm::vec3(0.7f); + mat->shininess = 35.f; + mat->emission = glm::vec3(0.0f); + + SphereGenerator sphereGen; + m_sphereMesh = sphereGen.generateGeodesicMesh(mat, 2, sphereRadius); + m_sphereMesh->computeNormals(); + m_sphereMesh->mergeVertices(); + m_sphereMesh->initGL(); + + m_sphereShape = new btSphereShape(sphereRadius+PHYSICS_OFFSET); + + float sphereVolume = 4.18879020479f*(sphereRadius*sphereRadius*sphereRadius); // (4*pi)/3 = 4.18879020479 + m_sphereMass = sphereVolume*density; +} + +void Potator::throwCube() +{ + glm::vec3 pos(0, 10, 0); + glm::vec3 dir(0, 1, 0); + if(m_player != nullptr) + { + dir = m_player->getDirection(); + pos = m_player->getEyePosition() + dir*2.f; + } + float throwForce = 20.f; + + createGib(new MeshNode(m_cubeMesh), m_cubeShape, m_cubeMass, pos, dir*throwForce, 10000); +} + +void Potator::throwSphere() +{ + glm::vec3 pos(0, 10, 0); + glm::vec3 dir(0, 1, 0); + if(m_player != nullptr) + { + pos = m_player->getEyePosition(); + dir = m_player->getDirection(); + } + float throwForce = 20.f; + + createGib(new MeshNode(m_sphereMesh), m_sphereShape, m_sphereMass, pos, dir*throwForce, 10000); +} + +void Potator::update() +{ + GibGeneratorNode::update(); + Input *input = getEngine().getInput(); + for(int action : input->getActions()) + { + if(action == m_throwCubeAction) + throwCube(); + else if(action == m_throwSphereAction) + throwSphere(); + } +} diff --git a/src/test/potator.h b/src/test/potator.h new file mode 100644 index 0000000..7d2b623 --- /dev/null +++ b/src/test/potator.h @@ -0,0 +1,39 @@ +#ifndef POTATOR_H +#define POTATOR_H + +#include "scene/gibgeneratornode.h" +#include "input.h" + +class PlayerCharacterNode; +class Mesh; + +class Potator : public GibGeneratorNode +{ + PlayerCharacterNode *m_player; + int m_throwCubeAction; + int m_throwSphereAction; + + Mesh* m_cubeMesh; + btCollisionShape* m_cubeShape; + float m_cubeMass; + Mesh* m_sphereMesh; + btCollisionShape* m_sphereShape; + float m_sphereMass; + + void throwCube(); + void throwSphere(); + +public: + Potator(PlayerCharacterNode * player = nullptr, + int cube_action = NO_ACTION, + int sphere_action = NO_ACTION); + + void setPlayer(PlayerCharacterNode *player) { m_player = player; } + + void setCubeThrowingAction(int action) { m_throwCubeAction = action; } + void setSphereThrowingAction(int action) { m_throwSphereAction = action; } + + virtual void update(); +}; + +#endif // POTATOR_H