, ctx(window.CreateContext())
 , init_glew()
 , program()
+, pitch_sensitivity(-0.0025f)
+, yaw_sensitivity(-0.001f)
 , cam()
 , model()
 , vtx_buf(0)
        glBufferData(GL_ARRAY_BUFFER, sizeof(vtx_coords), vtx_coords, GL_STATIC_DRAW);
 
        model.Position(glm::vec3(0, 0, -4));
+       cam.Position(glm::vec3(0, 0, 4));
 
        mvp_handle = program.UniformLocation("MVP");
 
 void Application::Run() {
        running = true;
        Uint32 last = SDL_GetTicks();
+       window.GrabMouse();
        while (running) {
                Uint32 now = SDL_GetTicks();
                int delta = now - last;
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
                switch (event.type) {
+                       case SDL_MOUSEMOTION:
+                               cam.RotateYaw(event.motion.xrel * yaw_sensitivity);
+                               cam.RotatePitch(event.motion.yrel * pitch_sensitivity);
+                               std::cout << "x: " << event.motion.xrel << ", y: " << event.motion.yrel
+                                               << ", pitch: " << cam.Pitch() << ", yaw: " << cam.Yaw() << std::endl;
+                               break;
                        case SDL_QUIT:
                                running = false;
                                break;
 
        InitGLEW init_glew;
        Program program;
 
+       float pitch_sensitivity;
+       float yaw_sensitivity;
+
        Camera cam;
        Model model;
 
 
 , aspect(1.0f)
 , near_clip(0.1f)
 , far_clip(100.0f)
-, position(0, 0, 0)
-, target(0, 0, -1)
-, up(0, 1, 0)
+, model()
 , projection(glm::perspective(fov, aspect, near_clip, far_clip))
-, view(glm::lookAt(position, target, up))
+, view(model.Transform())
 , vp(projection * view) {
 
 }
 }
 
 void Camera::UpdateView() {
-       view = glm::lookAt(position, target, up);
+       view = glm::inverse(model.Transform());
        vp = projection * view;
 }
 
 
 
 #include <glm/glm.hpp>
 
+#include "model.hpp"
+
 
 namespace blank {
 
        void Aspect(float w, float h);
        void Clip(float near, float far);
 
-       void Position(glm::vec3 pos) { position = pos; UpdateView(); }
-       void Move(glm::vec3 delta) { position += delta; UpdateView(); }
+       void Position(glm::vec3 pos) { model.Position(pos); UpdateView(); }
+       void Move(glm::vec3 delta) { model.Move(delta); UpdateView(); }
 
-       void LookAt(glm::vec3 tgt) { target = tgt; UpdateView(); }
+       // all angles in radians (full circle = 2π)
+       float Pitch() const { return model.Pitch(); }
+       void Pitch(float p) { model.Pitch(p); UpdateView(); }
+       void RotatePitch(float delta) { model.RotatePitch(delta); UpdateView(); }
+       float Yaw() const { return model.Yaw(); }
+       void Yaw(float y) { model.Yaw(y); UpdateView(); }
+       void RotateYaw(float delta) { model.RotateYaw(delta); UpdateView(); }
 
 private:
        void UpdateProjection();
        float near_clip;
        float far_clip;
 
-       glm::vec3 position;
-       glm::vec3 target;
-       glm::vec3 up;
+       Model model;
 
        glm::mat4 projection;
        glm::mat4 view;
 
        SDL_DestroyWindow(handle);
 }
 
+void Window::GrabInput() {
+       SDL_SetWindowGrab(handle, SDL_TRUE);
+}
+
+void Window::ReleaseInput() {
+       SDL_SetWindowGrab(handle, SDL_FALSE);
+}
+
+void Window::GrabMouse() {
+       if (SDL_SetRelativeMouseMode(SDL_TRUE) != 0) {
+               sdl_error("SDL_SetRelativeMouseMode");
+       }
+}
+
+void Window::ReleaseMouse() {
+       if (SDL_SetRelativeMouseMode(SDL_FALSE) != 0) {
+               sdl_error("SDL_SetRelativeMouseMode");
+       }
+}
+
 GLContext Window::CreateContext() {
        return GLContext(handle);
 }
 
        Window(const Window &) = delete;
        Window &operator =(const Window &) = delete;
 
+       void GrabInput();
+       void ReleaseInput();
+
+       void GrabMouse();
+       void ReleaseMouse();
+
        GLContext CreateContext();
 
        void Flip();
 
        void Move(glm::vec3 delta) { position += delta; }
 
        // all angles in radians (full circle = 2π)
+       float Pitch() const { return pitch; }
        void Pitch(float p) { pitch = p; }
        void RotatePitch(float delta) { pitch += delta; }
+       float Yaw() const { return yaw; }
        void Yaw(float y) { yaw = y; }
        void RotateYaw(float delta) { yaw += delta; }