]> git.localhorst.tv Git - tacos.git/commitdiff
mouse cursor mockup
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 8 Mar 2016 16:46:48 +0000 (17:46 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 8 Mar 2016 16:46:48 +0000 (17:46 +0100)
with a fake intersection test

assets
src/graphics/camera.cpp
src/physics/ray.hpp [new file with mode: 0644]
src/tacos.cpp
src/world/Cursor.hpp [new file with mode: 0644]
src/world/Floor.hpp
src/world/world.cpp

diff --git a/assets b/assets
index c690bc6e1a92fae19922e48b58c4874e330b490a..5fa2c5b1e2c9b3a7411f05a6e512992f8f551125 160000 (submodule)
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit c690bc6e1a92fae19922e48b58c4874e330b490a
+Subproject commit 5fa2c5b1e2c9b3a7411f05a6e512992f8f551125
index d9b8e848c779a5bb5ff1c889934e906295114b40..f63785292f5f27505175cec23cdd3dcff8d4c29c 100644 (file)
@@ -25,7 +25,7 @@ void Camera::Move(const glm::vec3 &delta) noexcept {
 
 void Camera::Rotate(const glm::vec2 &delta) noexcept {
        orientation += delta;
-       orientation.x = glm::clamp(orientation.x, -1.55f, 1.55f);
+       orientation.x = glm::clamp(orientation.x, 0.0f, 1.55f);
        while (orientation.y > 3.14159265358979323844f) { // π
                orientation.y -= 6.28318530717958647688f; // 2π
        }
diff --git a/src/physics/ray.hpp b/src/physics/ray.hpp
new file mode 100644 (file)
index 0000000..355af50
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef TACOS_PHYSICS_RAY_HPP_
+#define TACOS_PHYSICS_RAY_HPP_
+
+#include <glm/glm.hpp>
+
+
+namespace tacos {
+
+struct Ray {
+
+       glm::vec3 origin;
+       glm::vec3 direction;
+
+};
+
+}
+
+#endif
index 0e47e6e27af2baa545bbd961d1d0aab3f0887fcf..e477ab4a97e00a17da46bcbd151cea7eb0608480 100644 (file)
@@ -6,13 +6,16 @@
 #include "graphics/shader.hpp"
 #include "graphics/viewport.hpp"
 #include "graphics/window.hpp"
+#include "physics/ray.hpp"
 #include "rand/SimplexNoise.hpp"
+#include "world/Cursor.hpp"
 #include "world/Floor.hpp"
 
 #include <iostream>
 #include <GL/glew.h>
 #include <glm/glm.hpp>
 #include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtx/io.hpp>
 
 using namespace tacos;
 
@@ -41,6 +44,14 @@ int main(int argc, char *argv[]) {
        GLint mv_location = floor_program.UniformLocation("MV");
        GLint mvp_location = floor_program.UniformLocation("MVP");
 
+       Shader cursor_vert(asset_loader.LoadVertexShader("cursor"));
+       Shader cursor_frag(asset_loader.LoadFragmentShader("cursor"));
+       Program cursor_program;
+       cursor_program.Attach(cursor_vert);
+       cursor_program.Attach(cursor_frag);
+       cursor_program.Link();
+       GLint vp_location = cursor_program.UniformLocation("VP");
+
        Floor floor(64, 50);
        SimplexNoise noise(0);
        for (int z = 0; z < floor.Depth(); ++z) {
@@ -50,14 +61,29 @@ int main(int argc, char *argv[]) {
        }
        floor.GenerateVertices();
 
+       Cursor cursor;
+
        Camera camera;
        camera.Warp(glm::vec3(20.0f, 0.0f, 20.0f));
 
        glm::mat4 M;
        glm::mat4 V;
+       glm::mat4 VP;
        glm::mat4 MV;
        glm::mat4 MVP;
 
+       // cursor stuff
+       glm::mat4 inverse_VP;
+       glm::vec2 screen_mouse;
+       {
+               int x, y;
+               SDL_GetMouseState(&x, &y);
+               screen_mouse.x = x;
+               screen_mouse.y = y;
+       }
+       Ray world_mouse;
+       glm::vec3 pointer;
+
        constexpr float cam_speed = 15.0f; // units per second
        constexpr float cam_rot_speed = 2.0f; // radians per second
 
@@ -68,8 +94,6 @@ int main(int argc, char *argv[]) {
        glm::vec2 cam_rot_ccw(0.0f);
        glm::vec2 cam_rot_cw(0.0f);
 
-       floor_program.Use();
-
        bool running = true;
        Uint32 last = SDL_GetTicks();
        SDL_Event event;
@@ -167,6 +191,10 @@ int main(int argc, char *argv[]) {
                                                        break;
                                        }
                                        break;
+                               case SDL_MOUSEMOTION:
+                                       screen_mouse.x = event.motion.x;
+                                       screen_mouse.y = event.motion.y;
+                                       break;
                                case SDL_QUIT:
                                        running = false;
                                        break;
@@ -186,9 +214,28 @@ int main(int argc, char *argv[]) {
                camera.BackOff((cam_far - cam_near) * cam_speed * dt);
                camera.Rotate((cam_rot_ccw - cam_rot_cw) * cam_rot_speed * dt);
 
-               // render
                V = camera.View();
+               VP = viewport.Perspective() * V;
+               { // mouse
+                       inverse_VP = glm::inverse(VP);
+                       glm::vec2 clip_mouse((screen_mouse / glm::vec2(viewport.Width(), viewport.Height()) - 0.5f) * 2.0f);
+                       // viewport space has origin in lower left, but sdl gives coordinates with orgin in upper left,
+                       // so Y is inverted here (since it maps from -1 to 1 simply by negating)
+                       glm::vec4 ray_begin(inverse_VP * glm::vec4(clip_mouse.x, -clip_mouse.y, -1.0f, 1.0f));
+                       glm::vec4 ray_end(inverse_VP * glm::vec4(clip_mouse.x, -clip_mouse.y, 0.0f, 1.0f));
+                       world_mouse.origin = glm::vec3(ray_begin) / ray_begin.w;
+                       world_mouse.direction = glm::normalize((glm::vec3(ray_end) / ray_end.w) - world_mouse.origin);
+               }
+
+               if (floor.Intersection(world_mouse, pointer)) {
+                       cursor.FloorTile(floor, int(pointer.x), int(pointer.z));
+               } else {
+                       cursor.Hide();
+               }
+
+               // render
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+               floor_program.Use();
                for (int z = 0; z < floor.VAODepth(); ++z) {
                        for (int x = 0; x < floor.VAOWidth(); ++x) {
                                M = glm::translate(glm::mat4(1.0f), floor.VAOPosition(x, z));
@@ -199,6 +246,11 @@ int main(int argc, char *argv[]) {
                                floor.DrawVAO(x, z);
                        }
                }
+               if (cursor.Visible()) {
+                       cursor_program.Use();
+                       cursor_program.Uniform(vp_location, VP);
+                       cursor.Draw();
+               }
                window.Flip();
 
                last = now;
diff --git a/src/world/Cursor.hpp b/src/world/Cursor.hpp
new file mode 100644 (file)
index 0000000..828e411
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef TACOS_WORLD_CURSOR_HPP_
+#define TACOS_WORLD_CURSOR_HPP_
+
+#include <GL/glew.h>
+#include <glm/glm.hpp>
+
+
+namespace tacos {
+
+class Floor;
+
+class Cursor {
+
+public:
+       Cursor();
+       ~Cursor();
+
+       Cursor(const Cursor &) = delete;
+       Cursor &operator =(const Cursor &) = delete;
+
+       /// hide cursor
+       void Hide() noexcept;
+       /// set top left corner of cursor to focus given floor tile
+       void FloorTile(const Floor &, int tile_x, int tile_z);
+
+       bool Visible() const noexcept { return mode != HIDDEN; }
+       void Draw() const noexcept;
+
+private:
+       GLuint vao;
+       GLuint buffers[2];
+
+       // side length in vertices (make sure it's between 2 and 8 inclusive)
+       int size;
+       // distance between cursor and ground
+       float offset;
+
+       enum Mode {
+               HIDDEN,
+               FLOOR,
+       } mode;
+
+       struct Attributes {
+               glm::vec3 position;
+       };
+
+};
+
+}
+
+#endif
index a7046b589c64f42bf4c6e4baa0a9e19660c8f156..0ecd6ed0aae384b88380db38eef19d98abc0e868 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef TACOS_WORLD_FLOOR_HPP_
 #define TACOS_WORLD_FLOOR_HPP_
 
+#include "../physics/ray.hpp"
+
 #include <vector>
 #include <GL/glew.h>
 #include <glm/glm.hpp>
@@ -45,6 +47,9 @@ public:
 
        void GenerateVertices();
 
+       /// check if ray intersects floor, write point of intersection to point
+       bool Intersection(const Ray &ray, glm::vec3 &point);
+
 private:
        void SetupVAO(int which, GLuint element_buffer, int vertex_count) noexcept;
        void FillElementBuffer(GLuint which, int tile_width, int tile_depth);
index eba12eab25ef4c334b329e0b50081c4ca2953ae1..25723ba81c052f21e7fbeda023518817fdb2c42f 100644 (file)
@@ -1,8 +1,78 @@
+#include "Cursor.hpp"
 #include "Floor.hpp"
 
 
 namespace tacos {
 
+Cursor::Cursor()
+: vao(0)
+, buffers{0}
+, size(3)
+, offset(0.1f)
+, mode(HIDDEN) {
+       glGenVertexArrays(1, &vao);
+       glGenBuffers(2, buffers);
+
+       glBindVertexArray(vao);
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(0, 3, GL_FLOAT, 0, sizeof(Attributes), reinterpret_cast<const void *>(offsetof(Attributes, position)));
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
+       glBindVertexArray(0);
+}
+
+Cursor::~Cursor() {
+       glDeleteBuffers(2, buffers);
+       glDeleteVertexArrays(1, &vao);
+}
+
+void Cursor::Hide() noexcept {
+       mode = HIDDEN;
+}
+
+void Cursor::FloorTile(const Floor &floor, int tile_x, int tile_z) {
+       // TODO: only update if changed
+       mode = FLOOR;
+
+       int x_begin = glm::clamp(tile_x, 0, floor.Width() - size);
+       int x_end = x_begin + size;
+       int z_begin = glm::clamp(tile_z, 0, floor.Depth() - size);
+       int z_end = z_begin + size;
+
+       glBindVertexArray(vao);
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       glBufferData(GL_ARRAY_BUFFER, size * size * sizeof(Attributes), nullptr, GL_DYNAMIC_DRAW);
+       Attributes *attrib = reinterpret_cast<Attributes *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
+       for (int z = z_begin, index = 0; z < z_end; ++z) {
+               for (int x = x_begin; x < x_end; ++x, ++index) {
+                       attrib[index].position = glm::vec3(x, floor.GetElevation(x, z) + offset, z);
+               }
+       }
+       glUnmapBuffer(GL_ARRAY_BUFFER);
+
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
+       glBufferData(GL_ELEMENT_ARRAY_BUFFER, (size - 1) * (size - 1) * 6, nullptr, GL_DYNAMIC_DRAW);
+       unsigned char *element = reinterpret_cast<unsigned char *>(glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY));
+       for (int z = 0, index = 0; z < size - 1; ++z) {
+               for (int x = 0; x < size - 1; ++x, ++index) {
+                       element[index * 6 + 0] = (z + 0) * size + (x + 0);
+                       element[index * 6 + 1] = (z + 0) * size + (x + 1);
+                       element[index * 6 + 2] = (z + 1) * size + (x + 0);
+                       element[index * 6 + 3] = (z + 0) * size + (x + 1);
+                       element[index * 6 + 4] = (z + 1) * size + (x + 1);
+                       element[index * 6 + 5] = (z + 1) * size + (x + 0);
+               }
+       }
+       glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+       glBindVertexArray(0);
+}
+
+void Cursor::Draw() const noexcept {
+       glBindVertexArray(vao);
+       glDrawElements(GL_TRIANGLES, (size - 1) * (size - 1) * 6, GL_UNSIGNED_BYTE, nullptr);
+}
+
+
 constexpr int Floor::VAO_DIVISOR;
 
 Floor::Floor(int w, int d)
@@ -140,4 +210,21 @@ void Floor::DrawVAO(int vao_x, int vao_z) const noexcept {
        glDrawElements(GL_TRIANGLES, NumTiles(vao_x, vao_z) * 6, GL_UNSIGNED_SHORT, nullptr);
 }
 
+bool Floor::Intersection(const Ray &ray, glm::vec3 &point) {
+       // TODO: this tests for Y=0 plane intersection, change to respect heightmap
+       if (std::abs(ray.direction.y) < std::numeric_limits<float>::epsilon()) {
+               // ray parallel to plane
+               return false;
+       }
+       float factor = ray.origin.y / ray.direction.y;
+       if (factor > 0.0f) {
+               // intersection "behind" the ray
+               return false;
+       }
+       point.x = ray.origin.x - (ray.direction.x * factor);
+       point.y = 0.0f;
+       point.z = ray.origin.z - (ray.direction.z * factor);
+       return point.x >= 0.0f && point.x <= float(width) && point.z >= 0.0f && point.z <= float(depth);
+}
+
 }