summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/gameMainWindow.cpp43
-rw-r--r--ui/gameMainWindow.h27
-rw-r--r--ui/inputHandler.h18
-rw-r--r--ui/manualCameraController.cpp67
-rw-r--r--ui/manualCameraController.h26
-rw-r--r--ui/window.cpp42
-rw-r--r--ui/window.h38
7 files changed, 261 insertions, 0 deletions
diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp
new file mode 100644
index 0000000..4421098
--- /dev/null
+++ b/ui/gameMainWindow.cpp
@@ -0,0 +1,43 @@
+#include "gameMainWindow.h"
+#include "collection.hpp"
+#include "gfx/camera_controller.h"
+#include "manualCameraController.h"
+#include "ui/window.h"
+#include <GL/glew.h>
+#include <SDL2/SDL.h>
+#include <game/gamestate.h>
+#include <game/worldobject.h> // IWYU pragma: keep
+#include <gfx/renderable.h>
+#include <glm/glm.hpp>
+#include <maths.h>
+#include <memory>
+
+GameMainWindow::GameMainWindow(size_t w, size_t h) :
+ Window {static_cast<int>(w), static_cast<int>(h), "I Like Trains"}, uiShader {w, h}, camera {{-1250.0F, -1250.0F,
+ 35.0F},
+ 70.0F, rdiv(w, h),
+ 0.1F, 10000.0F}
+{
+ inputStack.create<ManualCameraController>(glm::vec2 {-1150, -1150});
+
+ shader.setUniform("lightDirection", glm::normalize(glm::vec3 {1, 0, -1}));
+ shader.setUniform("lightColor", {.6, .6, .6});
+ shader.setUniform("ambientColor", {0.5, 0.5, 0.5});
+}
+
+void
+GameMainWindow::tick(TickDuration)
+{
+ inputStack.apply<CameraController>(&CameraController::updateCamera, &camera);
+ shader.setView(camera.GetViewProjection());
+}
+
+void
+GameMainWindow::Refresh(const GameState * gameState) const
+{
+ SDL_GL_MakeCurrent(m_window, m_glContext);
+ glEnable(GL_DEPTH_TEST);
+ gameState->world.apply<Renderable>(&Renderable::render, shader);
+ glDisable(GL_DEPTH_TEST);
+ // do ui bits
+}
diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h
new file mode 100644
index 0000000..affb389
--- /dev/null
+++ b/ui/gameMainWindow.h
@@ -0,0 +1,27 @@
+#ifndef UI_GAMEMAINWINDOW_H
+#define UI_GAMEMAINWINDOW_H
+
+#include "chronology.hpp"
+#include "gfx/gl/camera.h"
+#include "gfx/gl/shader.h"
+#include "gfx/gl/uiShader.h"
+#include "window.h"
+#include <cstddef>
+
+class GameState;
+
+class GameMainWindow : public Window {
+public:
+ GameMainWindow(size_t w, size_t h);
+
+ void tick(TickDuration) override;
+
+ void Refresh(const GameState * gameState) const override;
+
+private:
+ UIShader uiShader;
+ Shader shader;
+ Camera camera;
+};
+
+#endif
diff --git a/ui/inputHandler.h b/ui/inputHandler.h
new file mode 100644
index 0000000..aac323b
--- /dev/null
+++ b/ui/inputHandler.h
@@ -0,0 +1,18 @@
+#ifndef INPUT_HANDLER_H
+#define INPUT_HANDLER_H
+
+#include <special_members.hpp>
+
+union SDL_Event;
+
+class InputHandler {
+public:
+ InputHandler() = default;
+ virtual ~InputHandler() = default;
+
+ DEFAULT_MOVE_COPY(InputHandler);
+
+ virtual bool handleInput(const SDL_Event &) = 0;
+};
+
+#endif
diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp
new file mode 100644
index 0000000..1d3a067
--- /dev/null
+++ b/ui/manualCameraController.cpp
@@ -0,0 +1,67 @@
+#include "manualCameraController.h"
+#include <algorithm>
+#include <cmath>
+#include <gfx/gl/camera.h>
+#include <maths.h>
+
+bool
+ManualCameraController::handleInput(const SDL_Event & e)
+{
+ switch (e.type) {
+ case SDL_KEYDOWN:
+ switch (e.key.keysym.sym) {
+ case SDLK_LCTRL:
+ case SDLK_RCTRL:
+ ctrl = true;
+ return true;
+ }
+ break;
+ case SDL_KEYUP:
+ switch (e.key.keysym.sym) {
+ case SDLK_LCTRL:
+ case SDLK_RCTRL:
+ ctrl = false;
+ return true;
+ }
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ switch (e.button.button) {
+ case SDL_BUTTON_RIGHT:
+ SDL_SetRelativeMouseMode(SDL_TRUE);
+ mrb = true;
+ return true;
+ }
+ break;
+ case SDL_MOUSEBUTTONUP:
+ switch (e.button.button) {
+ case SDL_BUTTON_RIGHT:
+ SDL_SetRelativeMouseMode(SDL_FALSE);
+ mrb = false;
+ return true;
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ if (mrb) {
+ if (ctrl) {
+ direction -= 0.01F * static_cast<float>(e.motion.xrel);
+ pitch = std::clamp(pitch - 0.01F * static_cast<float>(e.motion.yrel), 0.1F, half_pi);
+ }
+ else {
+ focus += rotate_flat(-direction) * glm::vec2 {-e.motion.xrel, e.motion.yrel};
+ }
+ }
+ return true;
+ case SDL_MOUSEWHEEL:
+ dist = std::clamp(dist - static_cast<float>(e.wheel.y) * 4.F, 5.F, 200.F);
+ break;
+ }
+ return false;
+}
+
+void
+ManualCameraController::updateCamera(Camera * camera) const
+{
+ camera->forward = glm::normalize(sincosf(direction) ^ -sin(pitch));
+ camera->pos = !focus + up * 3.F - (camera->forward * std::pow(dist, 1.3F));
+ camera->up = up;
+}
diff --git a/ui/manualCameraController.h b/ui/manualCameraController.h
new file mode 100644
index 0000000..ceff9ac
--- /dev/null
+++ b/ui/manualCameraController.h
@@ -0,0 +1,26 @@
+#ifndef MANUAL_CAMERA_CONTROLLER_H
+#define MANUAL_CAMERA_CONTROLLER_H
+
+#include "inputHandler.h"
+#include <SDL2/SDL.h>
+#include <gfx/camera_controller.h>
+#include <glm/glm.hpp>
+#include <maths.h>
+
+class Camera;
+
+class ManualCameraController : public CameraController, public InputHandler {
+public:
+ explicit ManualCameraController(glm::vec2 f) : focus {f} { }
+
+ bool handleInput(const SDL_Event & e) override;
+
+ void updateCamera(Camera * camera) const override;
+
+private:
+ bool ctrl {false}, mrb {false};
+ glm::vec2 focus;
+ float direction {quarter_pi};
+ float dist {40}, pitch {quarter_pi};
+};
+#endif
diff --git a/ui/window.cpp b/ui/window.cpp
new file mode 100644
index 0000000..c451367
--- /dev/null
+++ b/ui/window.cpp
@@ -0,0 +1,42 @@
+#include "window.h"
+#include "ui/inputHandler.h"
+#include <GL/glew.h>
+#include <stdexcept>
+
+Window::Window(int width, int height, const std::string & title) :
+ m_window {title.c_str(), static_cast<int>(SDL_WINDOWPOS_CENTERED), static_cast<int>(SDL_WINDOWPOS_CENTERED), width,
+ height, static_cast<Uint32>(SDL_WINDOW_OPENGL)},
+ m_glContext {m_window}
+{
+ if (glewInit() != GLEW_OK) {
+ throw std::runtime_error {"Glew failed to initialize!"};
+ }
+
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void
+Window::Clear(float r, float g, float b, float a) const
+{
+ glClearColor(r, g, b, a);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void
+Window::SwapBuffers() const
+{
+ SDL_GL_SwapWindow(m_window);
+}
+
+bool
+Window::handleInput(const SDL_Event & e)
+{
+ if (SDL_GetWindowID(m_window) == e.window.windowID) {
+ inputStack.applyOne(&InputHandler::handleInput, e);
+ return true;
+ }
+ return false;
+}
diff --git a/ui/window.h b/ui/window.h
new file mode 100644
index 0000000..f6279e2
--- /dev/null
+++ b/ui/window.h
@@ -0,0 +1,38 @@
+#ifndef DISPLAY_INCLUDED_H
+#define DISPLAY_INCLUDED_H
+
+#include "chronology.hpp"
+#include "collection.hpp"
+#include "inputHandler.h" // IWYU pragma: keep
+#include "ptr.hpp"
+#include <SDL2/SDL.h>
+#include <special_members.hpp>
+#include <string>
+#include <type_traits>
+
+class GameState;
+
+class Window {
+public:
+ Window(int width, int height, const std::string & title);
+ virtual ~Window() = default;
+
+ NO_COPY(Window);
+ NO_MOVE(Window);
+
+ void Clear(float r, float g, float b, float a) const;
+ void SwapBuffers() const;
+ virtual void tick(TickDuration elapsed) = 0;
+ virtual void Refresh(const GameState *) const = 0;
+ bool handleInput(const SDL_Event & e);
+
+protected:
+ using GL_Context = std::remove_pointer_t<SDL_GLContext>;
+ using SDL_WindowPtr = wrapped_ptrt<SDL_Window, SDL_CreateWindow, SDL_DestroyWindow>;
+ using SDL_GLContextPtr = wrapped_ptrt<GL_Context, SDL_GL_CreateContext, SDL_GL_DeleteContext>;
+ SDL_WindowPtr m_window;
+ SDL_GLContextPtr m_glContext;
+ Collection<InputHandler> inputStack;
+};
+
+#endif