You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

145 lines
4.0 KiB

#include <GL/gl3w.h>
#include "camera.h"
// TODO: add these props to scene json
#define MOVE_SPEED 5.f
#define ROTATE_SPEED 0.005f
#define CAMERA_Z_CLAMP_ANGLE 85.f
#define FOV 60.f
#define ASPECT_RATIO 16.f/9.f
#define NEAR_CLIP_PLANE 0.1f
void
cameraInitPerspective(camera& cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up)
{
cam.position = position;
cam.target = target;
cam.world_up = world_up;
cam.projection = glm::infinitePerspective(glm::radians(FOV), ASPECT_RATIO, NEAR_CLIP_PLANE);
cam.forward = glm::normalize(target - position);
cam.left = glm::normalize(glm::cross(cam.world_up, cam.forward));
cam.up = glm::normalize(glm::cross(cam.forward, cam.left));
cam.hAngle = glm::atan(cam.forward.x, cam.forward.y);
// NOTE: using pythagoras' to get absolute value of relative axis for vAngle component
real32 len = glm::sqrt(glm::pow(cam.forward.y, 2) + glm::pow(cam.forward.x, 2));
cam.vAngle = glm::atan(cam.forward.z, len);
cam.view = glm::lookAt(cam.position, cam.position + cam.forward, cam.up);
cam.model = glm::mat4(1.0f);
cam.MVP = cam.projection * cam.view * cam.model;
}
void
cameraInitOrthographic(/*camera& cam, */)
{
#if 0
// left, right, bottom, top, zNear, zFar
cam.projection = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f);
cam.view = glm::lookAt(
glm::vec3(0.0f, 0.0f, 1.0f), // camera position
glm::vec3(0.0f, 0.0f, 0.0f), // look at position
glm::vec3(0,1,0) // "up" vector
);
cam.model = glm::mat4(1.0f);
cam.MVP = cam.projection * cam.view * cam.model;
#endif
}
v2f
cameraUnproject(camera& cam, int x, int y, int vp_width, int vp_height)
{
// NOTE: using depth buffer may not be as accurate as doing ray-cast
GLfloat depth;
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
glm::vec4 viewport = glm::vec4(0, 0, vp_width, vp_height);
glm::vec3 wincoord = glm::vec3(x, y, depth);
glm::vec3 vU = glm::unProject(wincoord, cam.view, cam.projection, viewport);
v2f v(vU.x, vU.y);
return v;
}
void
cameraMove(camera& cam, bool up, bool left, bool down, bool right, bool forward, bool backward)
{
if (!up && !left && !down && !right && !forward && !backward)
return;
glm::vec3 f = cam.forward;
glm::vec3 u = cam.up;
glm::vec3 old = cam.position;
glm::vec3 &p = cam.position;
glm::vec3 v(0.f); // normalized direction
// TODO: still seems like we're adding magnitude when moving in 2 directions
#if 0
if (forward) v = glm::normalize(v + f);
if (backward) v = glm::normalize(v - f);
if (up) v = glm::normalize(v + u);
if (down) v = glm::normalize(v - u);
if (left) v -= glm::normalize(glm::cross(f, u));
if (right) v -= glm::normalize(glm::cross(u, f));
#else
if (forward) v += f;
if (backward) v -= f;
if (up) v += u;
if (down) v -= u;
if (left) v -= glm::cross(f, u);
if (right) v -= glm::cross(u, f);
#endif
p += (v * MOVE_SPEED);
glm::vec3 diff = old - p;
cam.view = glm::translate(cam.view, diff);
cam.MVP = cam.projection * cam.view * cam.model;
}
void
cameraRotate(camera& cam, int32 xrel, int32 yrel)
{
float &h = cam.hAngle;
float &v = cam.vAngle;
h += ROTATE_SPEED * xrel;
v -= ROTATE_SPEED * yrel;
// clamp vAngle to prevent gimbal lock
float a = glm::radians(CAMERA_Z_CLAMP_ANGLE);
if (v < (-1 * a)) v = (-1 * a);
if (v > a) v = a;
cam.forward = glm::vec3(
glm::cos(v) * glm::sin(h),
glm::cos(v) * glm::cos(h),
glm::sin(v)
);
glm::normalize(cam.forward);
cam.left = glm::normalize(glm::cross(cam.forward, cam.world_up));
cam.up = glm::normalize(glm::cross(cam.left, cam.forward));
cam.view = glm::lookAt(cam.position, cam.position + cam.forward, cam.up);
cam.MVP = cam.projection * cam.view * cam.model;
}
void
cameraRoll(camera& cam, bool CW, bool CCW)
{
if ((!CW && !CCW) || (CW && CCW))
return;
float a = 0.005f;
if (CW) a *= 1;
if (CCW) a *= -1;
glm::mat4 m = glm::rotate(glm::mat4(1.f), a, cam.forward);
glm::vec4 v(cam.up.x, cam.up.y, cam.up.z, 0);
v = v * m;
cam.up = glm::vec3(v.x, v.y, v.z);
cam.view *= m;
cam.MVP = cam.projection * cam.view * cam.model;
}