diff --git a/src/engine.cpp b/src/engine.cpp index 04ce708..e3a0189 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -47,7 +47,7 @@ void Engine::createWindow(std::string title, m_window->setFramerateLimit(60); m_input = new Input(m_window); m_renderer->initGL(w, h); - m_sparrowshell = new SparrowShell(m_window,m_input); + m_sparrowshell = new SparrowShell(m_window, m_input); } void Engine::initPhysics() @@ -57,7 +57,7 @@ void Engine::initPhysics() btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration); btSequentialImpulseConstraintSolver *solver = new btSequentialImpulseConstraintSolver(); m_world = new btDiscreteDynamicsWorld(dispatcher, broadPhase, solver, collisionConfiguration); - m_world->setGravity(btVector3(0, -10, 0)); + m_world->setGravity(btVector3(0, -9.81f, 0)); } void Engine::update() diff --git a/src/scene/cameranode.h b/src/scene/cameranode.h index a8df56d..b38c722 100644 --- a/src/scene/cameranode.h +++ b/src/scene/cameranode.h @@ -2,28 +2,15 @@ #define CAMERANODE_H #include "scenenode.h" -#include "trackballcamera.h" -#include "input.h" +#include "camera.h" /** * @brief The CameraNode class is a scene node that can be used by the renderer */ -class CameraNode : public TrackBallCamera, public SceneNode +class CameraNode : public SceneNode { - Input *m_input; - int m_action_move; - int m_action_rotate; - public: - CameraNode(Input *input); - - void setInputs(int action_move, int action_rotate) - { - m_action_move = action_move; - m_action_rotate = action_rotate; - } - - virtual void update(); + virtual Camera *getCamera() = 0; }; #endif // CAMERANODE_H diff --git a/src/scene/graphicalcontainernode.cpp b/src/scene/graphicalcontainernode.cpp index 02191c2..6eddf1c 100644 --- a/src/scene/graphicalcontainernode.cpp +++ b/src/scene/graphicalcontainernode.cpp @@ -16,7 +16,8 @@ void GraphicalContainerNode::addChild(GraphicalNode *node) { if(node != nullptr) { - node->setSceneTree(m_scene); + if(m_scene != nullptr) + node->setSceneTree(m_scene); m_children.push_back(node); node->m_parent = this; } diff --git a/src/scene/meshnode.cpp b/src/scene/meshnode.cpp index 913a875..a5c2131 100644 --- a/src/scene/meshnode.cpp +++ b/src/scene/meshnode.cpp @@ -1,7 +1,39 @@ #include "meshnode.h" #include "mesh.h" #include "scenetree.h" +#include + +#include +#include void MeshNode::setDepth(float depth){ m_geometry.mesh->setDepth(depth); } + +btRigidBody* MeshNode::buildStaticCollider() +{ + bulletMesh = new btIndexedMesh(); + Mesh *m = m_geometry.mesh; + // vertices + bulletMesh->m_numVertices = m->positions3D.size(); + bulletMesh->m_vertexBase = (unsigned char*)(m->positions3D.data()); + bulletMesh->m_vertexStride = sizeof(glm::vec3); + bulletMesh->m_vertexType = PHY_FLOAT; + // indices + bulletMesh->m_numTriangles = m->indices.size()/3; + bulletMesh->m_triangleIndexBase = (unsigned char*)(m->indices.data()); + bulletMesh->m_triangleIndexStride = 3*sizeof(GLuint); + bulletMesh->m_indexType = PHY_INTEGER; + + // building bullet rigidbody + btTriangleIndexVertexArray* collisionShape = new btTriangleIndexVertexArray(); + collisionShape->addIndexedMesh(*bulletMesh, PHY_INTEGER); + btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape(collisionShape, false); + + // positionning + btTransform transform; + transform.getOpenGLMatrix(glm::value_ptr(m_geometry.modelMatrix)); + btMotionState *motionState = new btDefaultMotionState(transform); + + return new btRigidBody(0, motionState, shape); +} diff --git a/src/scene/meshnode.h b/src/scene/meshnode.h index 13e8756..903ba00 100644 --- a/src/scene/meshnode.h +++ b/src/scene/meshnode.h @@ -5,6 +5,9 @@ #include "glm/mat4x4.hpp" #include "scene.h" +class btRigidBody; +class btIndexedMesh; + /** * @brief The MeshNode class holds a mesh */ @@ -13,12 +16,14 @@ class MeshNode : public GraphicalNode { GeometryNode m_geometry; + btIndexedMesh *bulletMesh; + public: // temp glm::mat4 m_movement; glm::mat4 m_acceleration; - MeshNode(Mesh* mesh) : m_geometry(mesh, glm::mat4()) {} + MeshNode(Mesh* mesh) : m_geometry(mesh, glm::mat4()), bulletMesh(nullptr) {} virtual void update() { @@ -31,6 +36,8 @@ public: void setDepth(float depth); virtual GeometryNode* getGeometryNode() { return &m_geometry; } + + btRigidBody* buildStaticCollider(); }; #endif // MESHNODE_H diff --git a/src/scene/playercharacternode.cpp b/src/scene/playercharacternode.cpp new file mode 100644 index 0000000..f543d77 --- /dev/null +++ b/src/scene/playercharacternode.cpp @@ -0,0 +1,156 @@ +#include "playercharacternode.h" + +#include +#include + +#include + +#define DEFAULT_ROTATION_SPEED 0.01f + +void FirstPersonCamera::computeView() +{ + m_view = glm::lookAt(m_eye, m_eye + m_direction, m_upVector); +} + +FirstPersonCamera::FirstPersonCamera(float myFov, float myNear, float myFar) : + BasicCamera(myFov, myNear, myFar), m_direction(0, 0, 1), m_upVector(0, 1, 0) +{ + computeView(); +} + +void FirstPersonCamera::move(const glm::vec3 &translation) +{ + m_eye += translation; + computeView(); +} + +void FirstPersonCamera::rotate(float dx, float dy) +{ + m_direction = glm::rotate(m_direction, -dx*DEFAULT_ROTATION_SPEED, m_upVector); + m_direction = glm::rotate(m_direction, -dy*DEFAULT_ROTATION_SPEED, glm::cross(m_direction, m_upVector)); + m_direction = glm::normalize(m_direction); + computeView(); +} + +void FirstPersonCamera::moveTo(const glm::vec3 &targetPos) +{ + m_eye = targetPos; + computeView(); +} + +void FirstPersonCamera::lookAt(const glm::vec3 &targetPos) +{ + m_view = glm::lookAt(m_eye, targetPos, m_upVector); +} + +void FirstPersonCamera::setUpVector(const glm::vec3 &up) +{ + m_upVector = up; + computeView(); +} + +const float WALK_SPEED = 0.5f; +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), + m_inputActions({NO_ACTION, NO_ACTION, NO_ACTION, NO_ACTION, NO_ACTION}) +{ + + btDefaultMotionState *motionState = new btDefaultMotionState(); + + // Create the shape + btCollisionShape *shape = new btCapsuleShape(PLAYER_RADIUS, PLAYER_HEIGHT); + + // Add mass + btVector3 localInertia; + shape->calculateLocalInertia(1.0, localInertia); + + // Create the rigid body object + m_rigidBody = new btRigidBody(1.0, motionState, shape, localInertia); + + // capsule always pointing up + m_rigidBody->setSleepingThresholds(0.0, 0.0); + m_rigidBody->setAngularFactor(0.0); +} + +void PlayerCharacterNode::setInputs(int forward, int backward, int strafeLeft, int strafeRight, int toggleNoClip) +{ + m_inputActions[FORWARD] = forward; + m_inputActions[BACKWARD] = backward; + m_inputActions[STRAFE_LEFT] = strafeLeft; + m_inputActions[STRAFE_RIGHT] = strafeRight; + m_inputActions[TOGGLE_NOCLIP] = toggleNoClip; +} + +void PlayerCharacterNode::setPosition(float x, float y, float z) +{ + btTransform transform; + btVector3 pos(x, y, z); + transform.setOrigin(pos); + m_rigidBody->setWorldTransform(transform); + m_noclip_pos = pos; + m_rigidBody->setLinearVelocity(btVector3(0,0,0)); +} + +void PlayerCharacterNode::update() +{ + // get events + int walk = 0; + int strafe = 0; + for(int action : m_input->getActions()) + { + if(action == m_inputActions[FORWARD]) + ++walk; + else if(action == m_inputActions[BACKWARD]) + --walk; + else if(action == m_inputActions[STRAFE_LEFT]) + --strafe; + else if(action == m_inputActions[STRAFE_RIGHT]) + ++strafe; + else if(action == m_inputActions[TOGGLE_NOCLIP]) + toggleNoClip(); + } + + // update camera rotation + sf::Vector2i diff = m_input->getDeltaPosition(); + m_fpsCamera.rotate(diff.x, diff.y); + + // update camera position + btVector3 pos = m_rigidBody->getCenterOfMassPosition(); + m_fpsCamera.moveTo(glm::vec3(pos.x(), pos.y()+EYES_OFFSET, pos.z())); + + // update body movement + const glm::vec3 &glmDir = m_fpsCamera.getDirection(); + if(walk != 0 || strafe != 0) + { + glm::vec3 moveDir = glm::normalize(glmDir*walk + glm::cross(glmDir, glm::vec3(0, 1, 0))*strafe); + if (m_noclipMode) + { + btVector3 dir(moveDir.x, moveDir.y, moveDir.z); + m_noclip_pos += dir*WALK_SPEED*2.f; + } + else + { + //TODO: if on ground + space pressed -> jump + glm::vec2 hPos = glm::normalize(glm::vec2(moveDir.x, moveDir.y)); + m_rigidBody->setLinearVelocity((m_rigidBody->getLinearVelocity() + btVector3(hPos.x, m_rigidBody->getLinearVelocity().getY(), hPos.y)) / 2.f); // smooth movements + } + } + if(m_noclipMode) + { + btTransform transform; + transform.setOrigin(m_noclip_pos); + m_rigidBody->setWorldTransform(transform); + m_rigidBody->setLinearVelocity(btVector3(0, 0, 0)); + } +} + +void PlayerCharacterNode::toggleNoClip() +{ + m_noclipMode = !m_noclipMode; + m_noclip_pos = m_rigidBody->getCenterOfMassPosition(); +} diff --git a/src/scene/playercharacternode.h b/src/scene/playercharacternode.h new file mode 100644 index 0000000..354983f --- /dev/null +++ b/src/scene/playercharacternode.h @@ -0,0 +1,63 @@ +#ifndef PLAYERCHARACTERNODE_H +#define PLAYERCHARACTERNODE_H + +#include "cameranode.h" +#include "input.h" +#include + +class btRigidBody; + +class FirstPersonCamera : public BasicCamera +{ +private: + // camera position + glm::vec3 m_eye; + glm::vec3 m_direction; + glm::vec3 m_upVector; + + void computeView(); + +public: + FirstPersonCamera(float myFov = 70.f, float myNear = 0.1f, float myFar = 1000.f); + + void move(const glm::vec3 &translation); + void rotate(float dx, float dy); + void moveTo(const glm::vec3 &targetPos); + void lookAt(const glm::vec3 &targetPos); + + void setUpVector(const glm::vec3 &up); + const glm::vec3& getDirection() { return m_direction; } +}; + +class PlayerCharacterNode : public CameraNode +{ + Input *m_input; + + btRigidBody* m_rigidBody; + + FirstPersonCamera m_fpsCamera; + + bool m_noclipMode; + btVector3 m_noclip_pos; + + std::vector m_inputActions; + + enum PlayerAction {FORWARD, BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP}; + +public: + PlayerCharacterNode(Input *input); + + void setInputs(int forward, int backward, int strafe_left, int strafe_right, int toggleNoClip = NO_ACTION); + + void setPosition(float x, float y, float z); + + virtual void update(); + + void toggleNoClip(); + + btRigidBody* getRigidbody() { return m_rigidBody; } + + virtual Camera *getCamera() { return &m_fpsCamera; } +}; + +#endif // PLAYERCHARACTERNODE_H diff --git a/src/scene/scenenode.h b/src/scene/scenenode.h index 95f3c2e..99bebd7 100644 --- a/src/scene/scenenode.h +++ b/src/scene/scenenode.h @@ -8,6 +8,8 @@ class GeometryNode; class SceneNode { public: + SceneNode() : m_parent(nullptr), m_scene(nullptr) {} + SceneNode* m_parent; SceneTree* m_scene; // bool m_enabled; diff --git a/src/scene/scenetree.cpp b/src/scene/scenetree.cpp index 66e2fdd..65eb305 100644 --- a/src/scene/scenetree.cpp +++ b/src/scene/scenetree.cpp @@ -7,6 +7,7 @@ #include #include #include "scene/scenenode.h" +#include "scene/cameranode.h" SceneTree::SceneTree() : Scene(), @@ -23,9 +24,9 @@ SceneTree::~SceneTree() } -void SceneTree::setMainCamera(CameraNode *camera) +void SceneTree::setMainCamera(CameraNode *camNode) { - ((DeferredPipeline*)m_pipeline)->setCamera((Camera*)camera); + ((DeferredPipeline*)m_pipeline)->setCamera(camNode->getCamera()); } SceneIterator* SceneTree::getLights() diff --git a/src/scene/scenetree.h b/src/scene/scenetree.h index 1836b3c..869301a 100644 --- a/src/scene/scenetree.h +++ b/src/scene/scenetree.h @@ -30,7 +30,7 @@ public: Texture* getSkybox() {return m_skybox;} void setSkybox(Texture* skybox) {m_skybox = skybox;} - void setMainCamera(CameraNode *camera); + void setMainCamera(CameraNode *camNode); ContainerNode* getRootObject(){return &m_root;} void addToIndex(SceneNode* node); diff --git a/src/scene/cameranode.cpp b/src/scene/trackballcameranode.cpp similarity index 76% rename from src/scene/cameranode.cpp rename to src/scene/trackballcameranode.cpp index 2a5853c..9a3c8bb 100644 --- a/src/scene/cameranode.cpp +++ b/src/scene/trackballcameranode.cpp @@ -1,12 +1,12 @@ -#include "cameranode.h" +#include "trackballcameranode.h" -CameraNode::CameraNode(Input *input) : +TrackBallCameraNode::TrackBallCameraNode(Input *input) : m_input(input), m_action_move(NO_ACTION), m_action_rotate(NO_ACTION) {} -void CameraNode::update() +void TrackBallCameraNode::update() { sf::Vector2i diff = m_input->getDeltaPosition(); for(int action : m_input->getActions()) diff --git a/src/scene/trackballcameranode.h b/src/scene/trackballcameranode.h new file mode 100644 index 0000000..d876898 --- /dev/null +++ b/src/scene/trackballcameranode.h @@ -0,0 +1,31 @@ +#ifndef TRACKBALLCAMERANODE_H +#define TRACKBALLCAMERANODE_H + +#include "cameranode.h" +#include "trackballcamera.h" +#include "input.h" + +/** + * @brief The CameraNode class is a scene node that can be used by the renderer + */ +class TrackBallCameraNode : public CameraNode, public TrackBallCamera +{ + Input *m_input; + int m_action_move; + int m_action_rotate; + +public: + TrackBallCameraNode(Input *input); + + void setInputs(int action_move, int action_rotate) + { + m_action_move = action_move; + m_action_rotate = action_rotate; + } + + virtual void update(); + + virtual Camera *getCamera() { return this; } +}; + +#endif // TRACKBALLCAMERANODE_H diff --git a/src/test/main.cpp b/src/test/main.cpp index c946cf2..ebec44c 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -11,7 +11,8 @@ #include #include -#include +#include +#include #include #include #include @@ -22,12 +23,13 @@ #include #include +#include #include class myKeysMap : public IKeysMap{ public: - enum{ROTATE_CAMERA, MOVE_CAMERA, TOGGLE_CONSOLE = 15}; + enum{MAIN_ACTION, SECONDARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_CONSOLE = 15}; myKeysMap(){ Binding b; @@ -37,20 +39,45 @@ public: b.type = IKeysMap::PRESSED; keys.push_back(b); - b.action = ROTATE_CAMERA; + b.action = MAIN_ACTION; b.type = IKeysMap::HOLD; b.key = sf::Keyboard::KeyCount + sf::Mouse::Left; keys.push_back(b); - b.action = MOVE_CAMERA; + 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); } static std::vector getMap() { - return {ROTATE_CAMERA, MOVE_CAMERA, TOGGLE_CONSOLE}; + return {MAIN_ACTION, SECONDARY_ACTION, MOVE_FORWARD, MOVE_BACKWARD, STRAFE_LEFT, STRAFE_RIGHT, TOGGLE_NOCLIP, TOGGLE_CONSOLE}; } }; @@ -94,7 +121,7 @@ public: } }; -void generateTerrain(SceneTree *scene) +void generateTerrain(SceneTree *scene, btDiscreteDynamicsWorld *world) { GraphicalContainerNode* terrainContainer = new GraphicalContainerNode(); scene->getRootObject()->addChild(terrainContainer); @@ -117,6 +144,7 @@ void generateTerrain(SceneTree *scene) MeshNode *node = new MeshNode(chunk->mesh); node->setTransform(glm::translate(glm::scale(glm::mat4(), glm::vec3(2.f)), pos*8.f)); terrainContainer->addChild(node); + //world->addRigidBody(node->buildStaticCollider()); } } } @@ -127,12 +155,22 @@ 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.initPhysics(); SceneTree scene; - CameraNode *cam = new CameraNode(engine.getInput()); - cam->setInputs(myKeysMap::MOVE_CAMERA, myKeysMap::ROTATE_CAMERA); +/* + TrackBallCameraNode *cam = new TrackBallCameraNode(engine.getInput()); + cam->setInputs(myKeysMap::SECONDARY_ACTION, myKeysMap::MAIN_ACTION); scene.getRootObject()->addChild(cam); scene.setMainCamera(cam); +*/ + + 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()); LightNode *sunLight = new LightNode(new DirectionnalLight(glm::vec3(5, 8, -2), glm::vec3(1.f))); LightNode *ambientLight = new LightNode(new AmbientLight()); @@ -198,7 +236,7 @@ int main(){ // 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); + generateTerrain(&scene, engine.getPhysics()); engine.setScene(&scene);