aboutsummaryrefslogtreecommitdiff
path: root/apps/openmb/scene/Camera.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'apps/openmb/scene/Camera.cpp')
-rw-r--r--apps/openmb/scene/Camera.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/apps/openmb/scene/Camera.cpp b/apps/openmb/scene/Camera.cpp
new file mode 100644
index 0000000..d3a3e7d
--- /dev/null
+++ b/apps/openmb/scene/Camera.cpp
@@ -0,0 +1,203 @@
+#include "Camera.hpp"
+
+#include <algorithm>
+#include <glm/gtc/matrix_transform.hpp>
+#include <vector>
+
+namespace scene {
+Camera::Camera ()
+ : mPosition( 0.0f, 0.0f, 3.0f ), mFront( 0.0f, 0.0f, -1.0f ), mWorldUp( 0.0f, 1.0f, 0.0f ), mYaw( -90.0f ),
+ mPitch( 0.0f ), mMovementSpeed( 3.0f ), mMouseSensitivity( 0.1f ), mFov( 60.0f ),
+ mVelocity( 0.0f, 0.0f, 0.0f ), mFlying( true ), mGrounded( false ), mSpeedMultiplier( 1.0f ) {
+ updateCameraVectors();
+}
+
+Camera::Camera ( const glm::vec3& position, const glm::vec3& up, float yaw, float pitch )
+ : mPosition( position ), mWorldUp( up ), mYaw( yaw ), mPitch( pitch ), mMovementSpeed( 3.0f ),
+ mMouseSensitivity( 0.1f ), mFov( 60.0f ), mVelocity( 0.0f, 0.0f, 0.0f ), mFlying( true ), mGrounded( false ),
+ mSpeedMultiplier( 1.0f ) {
+ mFront = glm::vec3( 0.0f, 0.0f, -1.0f );
+ updateCameraVectors();
+}
+
+glm::mat4 Camera::getViewMatrix () const {
+ return glm::lookAt( mPosition, mPosition + mFront, mUp );
+}
+
+glm::mat4 Camera::getProjectionMatrix ( float aspect ) const {
+ return glm::perspective( glm::radians( mFov ), aspect, 0.1f, 100.0f );
+}
+
+void Camera::processKeyboard ( Movement dir, float deltaTime ) {
+ float velocity = mMovementSpeed * mSpeedMultiplier * deltaTime;
+
+ glm::vec3 moveForward = mFront;
+ glm::vec3 moveRight = mRight;
+ if( !mFlying ) {
+ moveForward.y = 0.0f;
+ if( glm::length( moveForward ) < 1e-6f )
+ moveForward = glm::vec3( 0.0f, 0.0f, -1.0f );
+ moveForward = glm::normalize( moveForward );
+ moveRight = glm::normalize( glm::cross( moveForward, mWorldUp ) );
+ }
+
+ if( dir == Movement::Forward )
+ mPosition += moveForward * velocity;
+ if( dir == Movement::Backward )
+ mPosition -= moveForward * velocity;
+ if( dir == Movement::Left )
+ mPosition -= moveRight * velocity;
+ if( dir == Movement::Right )
+ mPosition += moveRight * velocity;
+ if( dir == Movement::Up && mFlying )
+ mPosition += mWorldUp * velocity;
+ if( dir == Movement::Down && mFlying )
+ mPosition -= mWorldUp * velocity;
+}
+
+void Camera::toggleFly () {
+ mFlying = !mFlying;
+ if( mFlying ) {
+
+ mVelocity.y = 0.0f;
+ }
+}
+
+void Camera::setSpeedMultiplier ( float m ) {
+ mSpeedMultiplier = m;
+}
+
+static bool aabbOverlap ( const glm::vec3& amin, const glm::vec3& amax, const glm::vec3& bmin,
+ const glm::vec3& bmax ) {
+ return ( amin.x <= bmax.x && amax.x >= bmin.x ) && ( amin.y <= bmax.y && amax.y >= bmin.y ) &&
+ ( amin.z <= bmax.z && amax.z >= bmin.z );
+}
+
+void Camera::updatePhysics ( float deltaTime, const std::vector<std::pair<glm::vec3, glm::vec3>>& worldAABBs,
+ float floorY ) {
+ const glm::vec3 halfExtents( 0.3f, 0.9f, 0.3f );
+
+ if( mFlying ) {
+ mGrounded = false;
+ return;
+ }
+
+ if( !mFlying ) {
+ const float gravity = -9.8f;
+ mVelocity.y += gravity * deltaTime;
+ if( mVelocity.y < -50.0f )
+ mVelocity.y = -50.0f;
+ }
+
+ glm::vec3 newPos = mPosition + mVelocity * deltaTime;
+
+ float camBottom = newPos.y - halfExtents.y;
+ if( camBottom < floorY ) {
+ newPos.y = floorY + halfExtents.y;
+ mVelocity.y = 0.0f;
+ mGrounded = true;
+ } else {
+ mGrounded = false;
+ }
+
+ for( const auto& box : worldAABBs ) {
+ glm::vec3 bmin = box.first;
+ glm::vec3 bmax = box.second;
+
+ glm::vec3 camMin = newPos - halfExtents;
+ glm::vec3 camMax = newPos + halfExtents;
+
+ if( !aabbOverlap( camMin, camMax, bmin, bmax ) )
+ continue;
+
+ float ox = std::min( camMax.x, bmax.x ) - std::max( camMin.x, bmin.x );
+ float oy = std::min( camMax.y, bmax.y ) - std::max( camMin.y, bmin.y );
+ float oz = std::min( camMax.z, bmax.z ) - std::max( camMin.z, bmin.z );
+
+ if( ox <= oy && ox <= oz ) {
+
+ float boxCenterX = ( bmin.x + bmax.x ) * 0.5f;
+ if( newPos.x < boxCenterX )
+ newPos.x -= ox;
+ else
+ newPos.x += ox;
+ } else if( oy <= ox && oy <= oz ) {
+ float boxCenterY = ( bmin.y + bmax.y ) * 0.5f;
+ if( newPos.y < boxCenterY ) {
+ newPos.y -= oy;
+ mVelocity.y = 0.0f;
+ } else {
+ newPos.y += oy;
+ mVelocity.y = 0.0f;
+ mGrounded = true;
+ }
+ } else {
+ float boxCenterZ = ( bmin.z + bmax.z ) * 0.5f;
+ if( newPos.z < boxCenterZ )
+ newPos.z -= oz;
+ else
+ newPos.z += oz;
+ }
+ }
+
+ mPosition = newPos;
+}
+
+void Camera::jump () {
+ if( mFlying )
+ return;
+ if( mGrounded ) {
+ const float jumpImpulse = 5.0f;
+ mVelocity.y = jumpImpulse;
+ mGrounded = false;
+ }
+}
+
+bool Camera::isFlying () const {
+ return mFlying;
+}
+
+bool Camera::isGrounded () const {
+ return mGrounded;
+}
+
+float Camera::getSpeedMultiplier () const {
+ return mSpeedMultiplier;
+}
+
+void Camera::processMouseMovement ( float xoffset, float yoffset, bool constrainPitch ) {
+ xoffset *= mMouseSensitivity;
+ yoffset *= mMouseSensitivity;
+
+ mYaw += xoffset;
+ mPitch += yoffset;
+
+ if( constrainPitch ) {
+ if( mPitch > 89.0f )
+ mPitch = 89.0f;
+ if( mPitch < -89.0f )
+ mPitch = -89.0f;
+ }
+
+ updateCameraVectors();
+}
+
+void Camera::processMouseScroll ( float yoffset ) {
+ mFov -= yoffset;
+ if( mFov < 1.0f )
+ mFov = 1.0f;
+ if( mFov > 90.0f )
+ mFov = 90.0f;
+}
+
+void Camera::updateCameraVectors () {
+ glm::vec3 front;
+ front.x = cos( glm::radians( mYaw ) ) * cos( glm::radians( mPitch ) );
+ front.y = sin( glm::radians( mPitch ) );
+ front.z = sin( glm::radians( mYaw ) ) * cos( glm::radians( mPitch ) );
+ mFront = glm::normalize( front );
+ mRight = glm::normalize( glm::cross( mFront, mWorldUp ) );
+ mUp = glm::normalize( glm::cross( mRight, mFront ) );
+}
+
+} // namespace scene