-Subproject commit c690bc6e1a92fae19922e48b58c4874e330b490a
+Subproject commit 5fa2c5b1e2c9b3a7411f05a6e512992f8f551125
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π
}
--- /dev/null
+#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
#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;
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) {
}
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
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;
break;
}
break;
+ case SDL_MOUSEMOTION:
+ screen_mouse.x = event.motion.x;
+ screen_mouse.y = event.motion.y;
+ break;
case SDL_QUIT:
running = false;
break;
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));
floor.DrawVAO(x, z);
}
}
+ if (cursor.Visible()) {
+ cursor_program.Use();
+ cursor_program.Uniform(vp_location, VP);
+ cursor.Draw();
+ }
window.Flip();
last = now;
--- /dev/null
+#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
#ifndef TACOS_WORLD_FLOOR_HPP_
#define TACOS_WORLD_FLOOR_HPP_
+#include "../physics/ray.hpp"
+
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
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);
+#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)
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);
+}
+
}