summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2024-02-12 12:55:11 +0100
committerMel <einebeere@gmail.com>2024-02-12 12:55:11 +0100
commitd2b5fc5b3bc648afffa42375706429685ac63794 (patch)
treea2dfbb241e1d46e5616c5884e5f3d685de2a2cb6
parent588c7e87b7cab270698d43ca5c22d67793ae5fc4 (diff)
downloadmeowcraft-d2b5fc5b3bc648afffa42375706429685ac63794.tar.zst
meowcraft-d2b5fc5b3bc648afffa42375706429685ac63794.zip
Split rendering into own thread and sync through render action lists
-rw-r--r--CMakeLists.txt23
-rw-r--r--assets/shaders/block_outline.frag.glsl7
-rw-r--r--assets/shaders/block_outline.vert.glsl15
-rw-r--r--assets/shaders/clouds.frag.glsl16
-rw-r--r--assets/shaders/clouds.vert.glsl21
-rw-r--r--assets/shaders/image_viewer.frag.glsl10
-rw-r--r--assets/shaders/image_viewer.vert.glsl15
-rw-r--r--assets/shaders/terrain.frag.glsl (renamed from assets/shaders/fragment.glsl)0
-rw-r--r--assets/shaders/terrain.vert.glsl (renamed from assets/shaders/vertex.glsl)0
-rw-r--r--src/Assets.cpp36
-rw-r--r--src/Assets.hpp10
-rw-r--r--src/Defines.hpp13
-rw-r--r--src/Entities/Player.cpp74
-rw-r--r--src/Entities/Player.hpp18
-rw-r--r--src/GFX/Actions.hpp39
-rw-r--r--src/GFX/Resources.cpp26
-rw-r--r--src/GFX/Resources.hpp38
-rw-r--r--src/GFX/Shading/Program.cpp9
-rw-r--r--src/GFX/Shading/Program.hpp4
-rw-r--r--src/GFX/Shading/Shader.hpp8
-rw-r--r--src/GFX/Window.cpp18
-rw-r--r--src/GFX/Window.hpp6
-rw-r--r--src/Game.cpp81
-rw-r--r--src/Game.hpp20
-rw-r--r--src/Math/Rotation.hpp4
-rw-r--r--src/Render.cpp102
-rw-r--r--src/Render.hpp88
-rw-r--r--src/Util/ImageViewer.cpp68
-rw-r--r--src/Util/ImageViewer.hpp12
-rw-r--r--src/World/Clouds.cpp113
-rw-r--r--src/World/Clouds.hpp22
-rw-r--r--src/main.cpp167
32 files changed, 659 insertions, 424 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 61e57e5..c477d0e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,9 @@ endif (WIN32)
add_executable(meowcraft
src/main.cpp
+ src/Defines.hpp
+ src/Game.cpp src/Game.hpp
+ src/Render.cpp src/Render.hpp
src/Common/Sizes.hpp
src/GFX/Window.cpp src/GFX/Window.hpp
src/GFX/Mesh.cpp src/GFX/Mesh.hpp
@@ -80,6 +83,8 @@ add_executable(meowcraft
src/Common/Casts.hpp
src/World/VoxelTraversal.hpp
src/Common/Assert.hpp
+ src/GFX/Actions.hpp
+ src/GFX/Resources.cpp src/GFX/Resources.hpp
)
if (WIN32)
@@ -90,12 +95,20 @@ target_link_libraries(meowcraft PRIVATE glfw GLEW::glew_s OpenGL::GL ${LINK_FLAG
function(make_includable input_file output_file)
file(READ ${input_file} content)
- set(delim "for_c++_include")
- set(content "R\"${delim}(\n${content})${delim}\"")
+ set(delim "meowcraft_asset")
+ set(content "R\"${delim}(${content})${delim}\"")
file(WRITE ${output_file} "${content}")
endfunction(make_includable)
-make_includable(assets/shaders/fragment.glsl assets/generated/shaders/fragment.glsl.includable)
-make_includable(assets/shaders/vertex.glsl assets/generated/shaders/vertex.glsl.includable)
+function(make_assets)
+ foreach(file ${ARGN})
+ make_includable(assets/${file} assets/generated/${file}.include)
+ endforeach()
+endfunction(make_assets)
-make_includable(assets/images/atlas.ppm assets/generated/images/atlas.ppm.includable) \ No newline at end of file
+make_assets(images/atlas.ppm
+ shaders/terrain.frag.glsl shaders/terrain.vert.glsl
+ shaders/clouds.frag.glsl shaders/clouds.vert.glsl
+ shaders/image_viewer.frag.glsl shaders/image_viewer.vert.glsl
+ shaders/block_outline.frag.glsl shaders/block_outline.vert.glsl
+) \ No newline at end of file
diff --git a/assets/shaders/block_outline.frag.glsl b/assets/shaders/block_outline.frag.glsl
new file mode 100644
index 0000000..ed278d8
--- /dev/null
+++ b/assets/shaders/block_outline.frag.glsl
@@ -0,0 +1,7 @@
+#version 330 core
+
+out vec4 color;
+
+void main() {
+ color = vec4(0.0, 0.0, 0.0, 1.0);
+} \ No newline at end of file
diff --git a/assets/shaders/block_outline.vert.glsl b/assets/shaders/block_outline.vert.glsl
new file mode 100644
index 0000000..3b9dfe9
--- /dev/null
+++ b/assets/shaders/block_outline.vert.glsl
@@ -0,0 +1,15 @@
+#version 330 core
+
+uniform mat4 model_matrix;
+uniform mat4 view_matrix;
+uniform mat4 projection_matrix;
+
+layout (location = 0) in vec3 position;
+
+void main() {
+ vec4 world_position = model_matrix * vec4(position, 1.0);
+ vec4 view_position = view_matrix * world_position;
+ vec4 clip_position = projection_matrix * view_position;
+
+ gl_Position = clip_position;
+} \ No newline at end of file
diff --git a/assets/shaders/clouds.frag.glsl b/assets/shaders/clouds.frag.glsl
new file mode 100644
index 0000000..c455afd
--- /dev/null
+++ b/assets/shaders/clouds.frag.glsl
@@ -0,0 +1,16 @@
+#version 330 core
+
+uniform vec3 sky_color;
+uniform vec3 sun_direction;
+
+in vec3 surface_normal;
+in float depth;
+out vec4 color;
+
+void main() {
+ float brightness = dot(normalize(surface_normal), normalize(-sun_direction));
+ vec3 diffuse = vec3(1 - clamp(brightness, -0.3, 0.2));
+ vec3 base = vec3(1.0, 1.0, 1.0) * diffuse;
+
+ color = vec4(mix(sky_color, base, 1 - depth), 0.3);
+} \ No newline at end of file
diff --git a/assets/shaders/clouds.vert.glsl b/assets/shaders/clouds.vert.glsl
new file mode 100644
index 0000000..2a91766
--- /dev/null
+++ b/assets/shaders/clouds.vert.glsl
@@ -0,0 +1,21 @@
+#version 330 core
+
+uniform mat4 model_matrix;
+uniform mat4 view_matrix;
+uniform mat4 projection_matrix;
+
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec3 normal;
+
+out vec3 surface_normal;
+out float depth;
+
+void main() {
+ vec4 world_position = model_matrix * vec4(position, 1.0);
+ vec4 view_position = view_matrix * world_position;
+ vec4 clip_position = projection_matrix * view_position;
+
+ gl_Position = clip_position;
+ surface_normal = (model_matrix * vec4(normal, 0.0)).xyz;
+ depth = clamp((length(view_position) - 200) / 400, 0.0, 1.0);
+} \ No newline at end of file
diff --git a/assets/shaders/image_viewer.frag.glsl b/assets/shaders/image_viewer.frag.glsl
new file mode 100644
index 0000000..be2b40c
--- /dev/null
+++ b/assets/shaders/image_viewer.frag.glsl
@@ -0,0 +1,10 @@
+#version 330 core
+
+uniform sampler2D image;
+
+in vec2 frag_tex_coord;
+out vec4 color;
+
+void main() {
+ color = texture(image, frag_tex_coord);
+} \ No newline at end of file
diff --git a/assets/shaders/image_viewer.vert.glsl b/assets/shaders/image_viewer.vert.glsl
new file mode 100644
index 0000000..1ad43f4
--- /dev/null
+++ b/assets/shaders/image_viewer.vert.glsl
@@ -0,0 +1,15 @@
+#version 330 core
+
+uniform mat4 model_matrix;
+uniform mat4 view_matrix;
+uniform mat4 projection_matrix;
+
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec2 tex_coord;
+
+out vec2 frag_tex_coord;
+
+void main() {
+ gl_Position = projection_matrix * view_matrix * model_matrix * vec4(position, 1.0);
+ frag_tex_coord = tex_coord;
+} \ No newline at end of file
diff --git a/assets/shaders/fragment.glsl b/assets/shaders/terrain.frag.glsl
index c7ecf97..c7ecf97 100644
--- a/assets/shaders/fragment.glsl
+++ b/assets/shaders/terrain.frag.glsl
diff --git a/assets/shaders/vertex.glsl b/assets/shaders/terrain.vert.glsl
index 6902ad4..6902ad4 100644
--- a/assets/shaders/vertex.glsl
+++ b/assets/shaders/terrain.vert.glsl
diff --git a/src/Assets.cpp b/src/Assets.cpp
index 66fdc88..dc2495e 100644
--- a/src/Assets.cpp
+++ b/src/Assets.cpp
@@ -2,16 +2,40 @@
namespace MC::Assets {
-const Char* Shaders::fragment =
-#include "../assets/generated/shaders/fragment.glsl.includable"
+Char const* Shaders::terrain::vertex =
+#include "../assets/generated/shaders/terrain.vert.glsl.include"
;
-const Char* Shaders::vertex =
-#include "../assets/generated/shaders/vertex.glsl.includable"
+Char const* Shaders::terrain::fragment =
+#include "../assets/generated/shaders/terrain.frag.glsl.include"
;
-const Char* Images::atlas =
-#include "../assets/generated/images/atlas.ppm.includable"
+Char const* Shaders::clouds::vertex =
+#include "../assets/generated/shaders/clouds.vert.glsl.include"
+;
+
+Char const* Shaders::clouds::fragment =
+#include "../assets/generated/shaders/clouds.frag.glsl.include"
+;
+
+Char const* Shaders::image_viewer::vertex =
+#include "../assets/generated/shaders/image_viewer.vert.glsl.include"
+;
+
+Char const* Shaders::image_viewer::fragment =
+#include "../assets/generated/shaders/image_viewer.frag.glsl.include"
+;
+
+Char const* Shaders::block_outline::vertex =
+#include "../assets/generated/shaders/block_outline.vert.glsl.include"
+;
+
+Char const* Shaders::block_outline::fragment =
+#include "../assets/generated/shaders/block_outline.frag.glsl.include"
+;
+
+Char const* Images::atlas =
+#include "../assets/generated/images/atlas.ppm.include"
;
} \ No newline at end of file
diff --git a/src/Assets.hpp b/src/Assets.hpp
index 9ff5c42..f4b2f46 100644
--- a/src/Assets.hpp
+++ b/src/Assets.hpp
@@ -6,14 +6,18 @@ namespace MC::Assets {
namespace Shaders {
-extern const Char* vertex;
-extern const Char* fragment;
+#define MC_ASSETS_SHADER(name) namespace name { extern Char const* vertex; extern Char const* fragment; }
+
+MC_ASSETS_SHADER(terrain)
+MC_ASSETS_SHADER(clouds)
+MC_ASSETS_SHADER(block_outline)
+MC_ASSETS_SHADER(image_viewer)
}
namespace Images {
-extern const Char* atlas;
+extern Char const* atlas;
}
diff --git a/src/Defines.hpp b/src/Defines.hpp
new file mode 100644
index 0000000..1280e93
--- /dev/null
+++ b/src/Defines.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#define APP_NAME "Meowcraft"
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+#define ASPECT (static_cast<Real>(WINDOW_WIDTH) / WINDOW_HEIGHT)
+
+#define FOV 90
+
+// #DBDBDB
+#define SKY_COLOR {0.85, 0.85, 0.85}
+#define SUN_DIRECTION {1, -1, 0}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index b7bee24..652f3fd 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1,29 +1,8 @@
#include "Player.hpp"
#include "../Common/Casts.hpp"
-#include "../Math/MVP.hpp"
#include <unordered_set>
namespace MC::Entities {
-Player::Player(Position::World position, Real ascept, Real fov, Real near, Real far)
- : m_transform(position),
- m_outline_program(
- {GFX::Shading::Shader::Type::Vertex, outline_vertex},
- {GFX::Shading::Shader::Type::Fragment, outline_fragment}
- ),
- m_outline_mesh(create_outline_cube_mesh()),
- m_outline_model_uniform(), m_outline_view_uniform(), m_outline_projection_uniform() {
- m_outline_program.bind();
-
- m_outline_model_uniform = m_outline_program.uniform("model_matrix");
- m_outline_view_uniform = m_outline_program.uniform("view_matrix");
- m_outline_projection_uniform = m_outline_program.uniform("projection_matrix");
-
- m_outline_model_uniform.set(Math::MVP::model<F32>({}, {}, {}));
- m_outline_view_uniform.set(Math::MVP::view<F32>({}, {}));
- m_outline_projection_uniform.set(Math::MVP::perspective_projection<F32>(ascept, fov, near, far));
-
- m_outline_program.unbind();
-}
void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world) {
auto const input_direction = directional_input(window);
@@ -51,24 +30,16 @@ void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera,
actions(window, world);
}
-// TODO: Proof-of-concept, will all be moved to the rendering system.
-void Player::render(const GFX::Camera& camera) {
- // Render currently targeted block outline.
-
+void Player::render(GFX::Actions& actions) {
if (m_targeted_block.has_value()) {
- auto targeted_block = m_targeted_block.value();
-
- m_outline_program.bind();
-
- m_outline_view_uniform.set(Math::MVP::view<F32>(camera.position(), camera.angles()));
- m_outline_model_uniform.set(Math::MVP::model<F32>(Vec3(targeted_block.position), Vec3::one(), {}));
-
- m_outline_mesh.bind();
- // TODO: These are very thin lines, do we have any better easy options?
- glDrawElements(GL_LINES, m_outline_mesh.size(), GL_UNSIGNED_INT, nullptr);
- m_outline_mesh.unbind();
-
- m_outline_program.unbind();
+ auto position = Vec3(m_targeted_block->position);
+ actions.add({
+ .mesh = &m_outline_mesh,
+ .program = GFX::Resources::Program::BlockOutline,
+ .transform = Transform{position},
+ // TODO: These are very thin lines, do we have any better easy options?
+ .draw_mode = GFX::DrawMode::Lines,
+ });
}
}
@@ -371,31 +342,4 @@ GFX::Mesh Player::create_outline_cube_mesh() {
return builder.mesh();
}
-const Char* Player::outline_vertex = R"v(
-#version 330 core
-
-uniform mat4 model_matrix;
-uniform mat4 view_matrix;
-uniform mat4 projection_matrix;
-
-layout (location = 0) in vec3 position;
-
-void main() {
- vec4 world_position = model_matrix * vec4(position, 1.0);
- vec4 view_position = view_matrix * world_position;
- vec4 clip_position = projection_matrix * view_position;
-
- gl_Position = clip_position;
-}
-)v";
-
-const Char* Player::outline_fragment = R"f(
-#version 330 core
-
-out vec4 color;
-
-void main() {
- color = vec4(0.0, 0.0, 0.0, 1.0);
-}
-)f";
}
diff --git a/src/Entities/Player.hpp b/src/Entities/Player.hpp
index c829d1f..83ac091 100644
--- a/src/Entities/Player.hpp
+++ b/src/Entities/Player.hpp
@@ -2,10 +2,10 @@
#include "../Time.hpp"
#include "../Transform.hpp"
+#include "../GFX/Actions.hpp"
#include "../GFX/Camera.hpp"
#include "../World/World.hpp"
#include "../GFX/Window.hpp"
-#include "../GFX/Shading/Program.hpp"
#include "../Math/AABB.hpp"
#include "../Math/Rotation.hpp"
#include "../World/Position.hpp"
@@ -13,10 +13,13 @@
namespace MC::Entities {
class Player {
public:
- explicit Player(Position::World position, Real ascept, Real fov, Real near, Real far);
+ explicit Player(Position::World position)
+ : m_transform(position), m_outline_mesh(create_outline_cube_mesh()) {}
+
+ Position::World position() const { return m_transform.position(); }
void update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world);
- void render(const GFX::Camera& camera);
+ void render(GFX::Actions& actions);
void move(Position::WorldOffset by);
void move_to(Position::World to);
@@ -83,16 +86,7 @@ private:
Transform m_transform;
static inline AABB s_bounds{{0.35, 1.8, 0.35}};
- // TODO: Put this into the rendering system
- static const Char* outline_vertex;
- static const Char* outline_fragment;
-
- GFX::Shading::Program m_outline_program;
GFX::Mesh m_outline_mesh;
-
- GFX::Shading::Uniform m_outline_model_uniform;
- GFX::Shading::Uniform m_outline_view_uniform;
- GFX::Shading::Uniform m_outline_projection_uniform;
};
}
diff --git a/src/GFX/Actions.hpp b/src/GFX/Actions.hpp
new file mode 100644
index 0000000..cc19169
--- /dev/null
+++ b/src/GFX/Actions.hpp
@@ -0,0 +1,39 @@
+#pragma once
+#include "Mesh.hpp"
+#include "Resources.hpp"
+#include "../Transform.hpp"
+
+namespace MC::GFX {
+
+enum class DrawMode {
+ Triangles = GL_TRIANGLES,
+ Lines = GL_LINES,
+};
+
+struct Action {
+ Mesh* mesh;
+ Resources::Program program;
+ Transform transform;
+
+ F32 alpha = 1.0f;
+ DrawMode draw_mode = DrawMode::Triangles;
+};
+
+class Actions {
+public:
+ void add(Action const& action) {
+ m_actions.push_back(action);
+ }
+
+ void clear() {
+ m_actions.clear();
+ }
+
+ const std::vector<Action>& actions() const {
+ return m_actions;
+ }
+private:
+ std::vector<Action> m_actions;
+};
+
+}
diff --git a/src/GFX/Resources.cpp b/src/GFX/Resources.cpp
new file mode 100644
index 0000000..34ce32e
--- /dev/null
+++ b/src/GFX/Resources.cpp
@@ -0,0 +1,26 @@
+#include "Resources.hpp"
+
+#include "../Common/Assert.hpp"
+
+namespace MC::GFX {
+
+void Resources::initialize() {
+ ASSERT(!m_initialized, "Resources already initialized");
+ for (auto& metadata: m_program_metadata) {
+ m_programs[static_cast<USize>(metadata.id)] = create_program(metadata);
+ }
+ m_initialized = true;
+}
+
+Shading::Program const& Resources::program(Program id) const {
+ ASSERT(m_initialized, "Resources not initialized");
+ return m_programs[static_cast<USize>(id)];
+}
+
+Shading::Program Resources::create_program(ProgramMetadata const& metadata) {
+ Shading::Shader vertex(Shading::Shader::Type::Vertex, metadata.vertex);
+ Shading::Shader fragment(Shading::Shader::Type::Fragment, metadata.fragment);
+ return {vertex, fragment};
+}
+
+}
diff --git a/src/GFX/Resources.hpp b/src/GFX/Resources.hpp
new file mode 100644
index 0000000..4206e33
--- /dev/null
+++ b/src/GFX/Resources.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <array>
+#include "Shading/Program.hpp"
+
+namespace MC::GFX {
+class Resources {
+public:
+ enum class Program: USize {
+ Terrain,
+ Clouds,
+ ImageViewer,
+ BlockOutline,
+ };
+ constexpr static USize ProgramCount = 4;
+
+ void initialize();
+ Shading::Program const& program(Program id) const;
+private:
+ struct ProgramMetadata {
+ Program id;
+ Char const* vertex;
+ Char const* fragment;
+ };
+
+ static inline std::array<ProgramMetadata, ProgramCount> const m_program_metadata = {{
+ {Program::Terrain, Assets::Shaders::terrain::vertex, Assets::Shaders::terrain::fragment},
+ {Program::Clouds, Assets::Shaders::clouds::vertex, Assets::Shaders::clouds::fragment},
+ {Program::ImageViewer, Assets::Shaders::image_viewer::vertex, Assets::Shaders::image_viewer::fragment},
+ {Program::BlockOutline, Assets::Shaders::block_outline::vertex, Assets::Shaders::block_outline::fragment},
+ }};
+
+ Bool m_initialized = false;
+ std::array<Shading::Program, ProgramCount> m_programs = {};
+
+ static Shading::Program create_program(ProgramMetadata const& metadata);
+};
+}
diff --git a/src/GFX/Shading/Program.cpp b/src/GFX/Shading/Program.cpp
index ff10012..fe5d576 100644
--- a/src/GFX/Shading/Program.cpp
+++ b/src/GFX/Shading/Program.cpp
@@ -2,6 +2,8 @@
#include <stdexcept>
#include "Program.hpp"
+#include "../../Common/Assert.hpp"
+
namespace MC::GFX::Shading {
Program::Program(Shader vertex, Shader fragment) {
@@ -26,6 +28,7 @@ Program::Program(Shader vertex, Shader fragment) {
}
void Program::bind() const {
+ ASSERT(m_program != 0, "Program is not initialized");
glUseProgram(m_program);
}
@@ -33,10 +36,12 @@ void Program::unbind() const {
glUseProgram(0);
}
-Uniform Program::uniform(const std::string& name) const {
+std::optional<Uniform> Program::uniform(const std::string& name) const {
+ ASSERT(m_program != 0, "Program is not initialized");
auto index = glGetUniformLocation(m_program, name.c_str());
- return {name, static_cast<U32>(index)};
+ if (index == -1) return {};
+ return {{name, static_cast<U32>(index)}};
}
U32 Program::get() const {
diff --git a/src/GFX/Shading/Program.hpp b/src/GFX/Shading/Program.hpp
index 2f48698..67838dc 100644
--- a/src/GFX/Shading/Program.hpp
+++ b/src/GFX/Shading/Program.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <optional>
#include <string>
#include "Shader.hpp"
#include "Uniform.hpp"
@@ -8,11 +9,12 @@ namespace MC::GFX::Shading {
class Program {
public:
+ Program() : m_program(0) {}
Program(Shader vertex, Shader fragment);
U32 get() const;
- Uniform uniform(const std::string& name) const;
+ std::optional<Uniform> uniform(std::string const& name) const;
void bind() const;
void unbind() const;
diff --git a/src/GFX/Shading/Shader.hpp b/src/GFX/Shading/Shader.hpp
index 21fd899..8c6c5c8 100644
--- a/src/GFX/Shading/Shader.hpp
+++ b/src/GFX/Shading/Shader.hpp
@@ -19,14 +19,6 @@ public:
return m_shader;
}
- static Shader create_vertex() {
- return {Type::Vertex, Assets::Shaders::vertex};
- }
-
- static Shader create_fragment() {
- return {Type::Fragment, Assets::Shaders::fragment};
- }
-
private:
U32 m_shader;
};
diff --git a/src/GFX/Window.cpp b/src/GFX/Window.cpp
index bbe2ba7..c0c5b03 100644
--- a/src/GFX/Window.cpp
+++ b/src/GFX/Window.cpp
@@ -2,6 +2,8 @@
#include "../Common/Sizes.hpp"
#include "Window.hpp"
+#include "../Common/Assert.hpp"
+
namespace MC::GFX {
Window::Window(const Char* title, U32 width, U32 height) {
@@ -48,8 +50,11 @@ Bool Window::mouse(I32 key, I32 type) const {
return glfwGetMouseButton(m_window, key) == type;
}
-void Window::start_frame() {
+void Window::start_render() {
glfwSwapBuffers(m_window);
+}
+
+void Window::poll_events() {
glfwPollEvents();
}
@@ -57,4 +62,13 @@ void Window::on_size_change(void (callback)(GLFWwindow*, I32, I32)) {
glfwSetFramebufferSizeCallback(m_window, callback);
}
-} \ No newline at end of file
+void Window::attach() const {
+ glfwMakeContextCurrent(m_window);
+}
+
+void Window::detach() const {
+ ASSERT(glfwGetCurrentContext() == m_window, "Cannot detach window that is not current");
+ glfwMakeContextCurrent(nullptr);
+}
+
+}
diff --git a/src/GFX/Window.hpp b/src/GFX/Window.hpp
index ac0efd2..c26b0fd 100644
--- a/src/GFX/Window.hpp
+++ b/src/GFX/Window.hpp
@@ -16,8 +16,12 @@ public:
void on_size_change(void (* callback)(GLFWwindow*, I32, I32));
+ void attach() const;
+ void detach() const;
+
void close();
- void start_frame();
+ void start_render();
+ void poll_events();
Vector<2> mouse_delta();
Bool key(I32 key, I32 type) const;
diff --git a/src/Game.cpp b/src/Game.cpp
new file mode 100644
index 0000000..117ba09
--- /dev/null
+++ b/src/Game.cpp
@@ -0,0 +1,81 @@
+#include "Game.hpp"
+
+#include <GLFW/glfw3.h>
+#include "Time.hpp"
+#include "Common/Sizes.hpp"
+#include "Entities/Player.hpp"
+#include "GFX/Camera.hpp"
+#include "GFX/Window.hpp"
+#include "World/Clouds.hpp"
+#include "World/World.hpp"
+
+namespace MC {
+
+void Game::run() const {
+ World::World world{};
+
+ GFX::Camera camera{};
+
+ World::Clouds clouds{};
+ Entities::Player player{{0, World::Chunk::Height / 2.0, 0}};
+
+ Time time;
+
+ while (!m_window.should_close()) {
+ m_window.poll_events();
+
+#ifdef __APPLE__
+ // Needs to happen on the main thread
+ fix_macos_render();
+#endif
+
+ time.start_frame();
+
+ if (m_window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) {
+ m_window.close();
+ }
+
+ player.update(time, m_window, camera, world);
+ clouds.update(time);
+
+ GFX::Actions actions;
+
+ for (auto chunk : world.get_visible_chunks(time, camera.position())) {
+ auto position = chunk->chunk.value().position();
+ actions.add({
+ .program = GFX::Resources::Program::Terrain,
+ .mesh = &chunk->land_mesh.value(),
+ .transform = Transform(position),
+ });
+
+ actions.add({
+ .program = GFX::Resources::Program::Terrain,
+ .mesh = &chunk->water_mesh.value(),
+ .transform = Transform(position - Vec3{0, 0.2, 0}),
+ .alpha = 0.4,
+ });
+ }
+
+ player.render(actions);
+ clouds.render(actions, player.position());
+
+ m_render_control->send_render_data({actions, camera});
+ m_render_control->wait_for_render_finish();
+
+ time.end_frame();
+ }
+}
+
+void Game::fix_macos_render() const {
+ static Bool moved = false;
+
+ if(!moved) {
+ I32 x, y;
+ glfwGetWindowPos(m_window.get(), &x, &y);
+ glfwSetWindowPos(m_window.get(), ++x, y);
+
+ moved = true;
+ }
+}
+
+} \ No newline at end of file
diff --git a/src/Game.hpp b/src/Game.hpp
new file mode 100644
index 0000000..ccb0013
--- /dev/null
+++ b/src/Game.hpp
@@ -0,0 +1,20 @@
+#pragma once
+#include "Render.hpp"
+
+namespace MC {
+
+class Game {
+public:
+ explicit Game(GFX::Window& window, std::shared_ptr<Render::Control> control)
+ : m_window(window)
+ , m_render_control(std::move(control)) {}
+
+ void run() const;
+private:
+ void fix_macos_render() const;
+
+ GFX::Window& m_window;
+ std::shared_ptr<Render::Control> m_render_control;
+};
+
+}
diff --git a/src/Math/Rotation.hpp b/src/Math/Rotation.hpp
index d12ac29..d8dff72 100644
--- a/src/Math/Rotation.hpp
+++ b/src/Math/Rotation.hpp
@@ -15,6 +15,10 @@ struct Rotation {
vector = wrap({pitch, yaw, roll });
}
+ static Rotation zero() {
+ return {0, 0, 0};
+ }
+
Vector<3> radians() const {
return vector.map([](auto a) { return Math::radians(a); });
}
diff --git a/src/Render.cpp b/src/Render.cpp
new file mode 100644
index 0000000..3955f1c
--- /dev/null
+++ b/src/Render.cpp
@@ -0,0 +1,102 @@
+#include "Render.hpp"
+#include "Assets.hpp"
+#include "Defines.hpp"
+#include "Time.hpp"
+#include "Common/Assert.hpp"
+#include "GFX/Image/PPMParser.hpp"
+#include "GFX/Shading/Program.hpp"
+#include "Math/MVP.hpp"
+
+namespace MC {
+
+void Render::run() {
+ m_window.attach();
+ setup_gl();
+
+ m_resources.initialize();
+
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ m_window.on_size_change([](GLFWwindow* _, I32 w, I32 h) {
+ glViewport(0, 0, w, h);
+ });
+
+ auto image = GFX::Image::PPMParser(Assets::Images::atlas).parse();
+ auto texture = GFX::Texture(image);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable(GL_CULL_FACE);
+ glFrontFace(GL_CCW);
+ glCullFace(GL_BACK);
+
+ while (!m_window.should_close()) {
+ Scene scene = m_control->wait_for_render_data();
+
+ m_window.start_render();
+ render_scene(scene, texture);
+
+ m_control->finish_render();
+ }
+}
+
+void Render::render_scene(Scene const& scene, GFX::Texture const& texture) const {
+ Vector<3, F32> sky_color = SKY_COLOR;
+ glClearColor(sky_color.x(), sky_color.y(), sky_color.z(), 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ auto view = Math::MVP::view<F32>(scene.camera.position(), scene.camera.angles());
+ auto projection = Math::MVP::perspective_projection<F32>(ASPECT, FOV, 0.1f, 1000.0f);
+
+ for (auto& action : scene.actions.actions()) {
+ auto& program = m_resources.program(action.program);
+ program.bind();
+
+ auto model_uniform = program.uniform("model_matrix");
+ auto view_uniform = program.uniform("view_matrix");
+ auto projection_uniform = program.uniform("projection_matrix");
+ auto sun_direction_uniform = program.uniform("sun_direction");
+ auto sky_color_uniform = program.uniform("sky_color");
+ auto mesh_alpha_uniform = program.uniform("mesh_alpha");
+
+ ASSERT(model_uniform.has_value() && view_uniform.has_value() && projection_uniform.has_value(),
+ "Program does not have the necessary MVP uniforms");
+
+ auto transform = action.transform;
+ auto model = Math::MVP::model<F32>(transform.position(), transform.scale(), transform.rotation());
+
+ model_uniform->set(model);
+ view_uniform->set(view);
+ projection_uniform->set(projection);
+
+ if (sun_direction_uniform.has_value())
+ sun_direction_uniform->set(SUN_DIRECTION);
+
+ if (sky_color_uniform.has_value())
+ sky_color_uniform->set(SKY_COLOR);
+
+ if (mesh_alpha_uniform.has_value())
+ mesh_alpha_uniform->set(action.alpha);
+
+ texture.bind();
+ action.mesh->bind();
+ glDrawElements(TO(GLenum, action.draw_mode), action.mesh->size(), GL_UNSIGNED_INT, nullptr);
+ action.mesh->unbind();
+ texture.unbind();
+
+ program.unbind();
+ }
+}
+
+void Render::setup_gl() {
+ GLenum error = glewInit();
+ if (error != GLEW_OK) {
+ std::string error_string(reinterpret_cast<Char const*>(glewGetErrorString(error)));
+ throw std::runtime_error("Failed to load GL functions: " + error_string);
+ }
+}
+
+}
diff --git a/src/Render.hpp b/src/Render.hpp
new file mode 100644
index 0000000..6b7cb65
--- /dev/null
+++ b/src/Render.hpp
@@ -0,0 +1,88 @@
+#pragma once
+
+#include <condition_variable>
+#include "Defines.hpp"
+#include "Common/Sizes.hpp"
+#include "GFX/Actions.hpp"
+#include "GFX/Camera.hpp"
+#include "GFX/Texture.hpp"
+#include "GFX/Window.hpp"
+
+namespace MC {
+
+class Render {
+public:
+ struct Scene {
+ GFX::Actions actions;
+ GFX::Camera camera;
+ };
+
+ struct Control {
+ std::mutex mutex;
+ std::condition_variable cv;
+ Bool logic_done = false;
+ Bool render_done = false;
+
+ Scene scene;
+
+ void send_render_data(Scene new_scene) {
+ {
+ std::scoped_lock lock(mutex);
+ scene = std::move(new_scene);
+ logic_done = true;
+ }
+ cv.notify_one();
+ }
+
+ Scene wait_for_render_data() {
+ Scene new_scene;
+ {
+ std::unique_lock lock(mutex);
+ cv.wait(lock, [&]{
+ return logic_done;
+ });
+ new_scene = scene;
+ logic_done = false;
+ render_done = false;
+ }
+ cv.notify_one();
+ return new_scene;
+ }
+
+ void wait_for_render_finish() {
+ {
+ std::unique_lock lock(mutex);
+ cv.wait(lock, [&]{
+ return render_done;
+ });
+ logic_done = false;
+ render_done = false;
+ }
+ cv.notify_one();
+ }
+
+ void finish_render() {
+ {
+ std::scoped_lock lock(mutex);
+ render_done = true;
+ }
+ cv.notify_one();
+ }
+ };
+
+ explicit Render(GFX::Window& window, std::shared_ptr<Control> control)
+ : m_window(window)
+ , m_control(std::move(control)) {}
+
+ void run();
+
+private:
+ void render_scene(Scene const& actions, GFX::Texture const& texture) const;
+ static void setup_gl();
+
+ GFX::Resources m_resources;
+ GFX::Window& m_window;
+ std::shared_ptr<Control> m_control;
+};
+
+}
diff --git a/src/Util/ImageViewer.cpp b/src/Util/ImageViewer.cpp
index 4c78750..05d316c 100644
--- a/src/Util/ImageViewer.cpp
+++ b/src/Util/ImageViewer.cpp
@@ -1,38 +1,15 @@
-#include <GL/glew.h>
#include "ImageViewer.hpp"
-#include "../Math/MVP.hpp"
namespace MC::Util {
-ImageViewer::ImageViewer(
- const GFX::Image::RawImage& image,
- Real window_aspect
-) : m_texture(image),
- m_program(
- {GFX::Shading::Shader::Type::Vertex, vertex},
- {GFX::Shading::Shader::Type::Fragment, fragment}
- ),
- m_mesh(create_mesh(window_aspect, image.width(), image.height())) {
- m_program.bind();
- auto model_uniform = m_program.uniform("model_matrix");
- auto view_uniform = m_program.uniform("view_matrix");
- auto projection_uniform = m_program.uniform("projection_matrix");
-
- model_uniform.set(Math::MVP::model<F32>({}, Vector<3>::one(), {}));
- view_uniform.set(Math::MVP::view<F32>({}, {}));
- projection_uniform.set(Math::MVP::orthographic_projection<F32>(view_size * window_aspect, view_size, 0.0f, 100.0f));
-
- m_program.unbind();
-}
-
-void ImageViewer::render() {
- m_program.bind();
- m_texture.bind();
- m_mesh.bind();
- glDrawElements(GL_TRIANGLES, m_mesh.size(), GL_UNSIGNED_INT, nullptr);
- m_mesh.unbind();
- m_texture.unbind();
- m_program.unbind();
+void ImageViewer::render(GFX::Actions& actions) {
+ // TODO: Re-add texture support
+ // TODO: Add orthographic camera support
+ actions.add({
+ .program = GFX::Resources::Program::ImageViewer,
+ .mesh = &m_mesh,
+ .transform = Transform(),
+ });
}
GFX::Mesh ImageViewer::create_mesh(Real window_aspect, U32 image_width, U32 image_height) {
@@ -60,33 +37,4 @@ GFX::Mesh ImageViewer::create_mesh(Real window_aspect, U32 image_width, U32 imag
}, {0, 1, 2, 0, 2, 3}};
}
-const Char* ImageViewer::vertex = R"v(
-#version 330 core
-
-uniform mat4 model_matrix;
-uniform mat4 view_matrix;
-uniform mat4 projection_matrix;
-
-layout (location = 0) in vec3 position;
-layout (location = 1) in vec2 tex_coord;
-
-out vec2 frag_tex_coord;
-
-void main() {
- gl_Position = projection_matrix * view_matrix * model_matrix * vec4(position, 1.0);
- frag_tex_coord = tex_coord;
-})v";
-
-const Char* ImageViewer::fragment = R"f(
-#version 330 core
-
-uniform sampler2D image;
-
-in vec2 frag_tex_coord;
-out vec4 color;
-
-void main() {
- color = texture(image, frag_tex_coord);
-})f";
-
} \ No newline at end of file
diff --git a/src/Util/ImageViewer.hpp b/src/Util/ImageViewer.hpp
index aa48b1e..cfe9d18 100644
--- a/src/Util/ImageViewer.hpp
+++ b/src/Util/ImageViewer.hpp
@@ -1,27 +1,25 @@
#pragma once
+#include "../GFX/Actions.hpp"
#include "../GFX/Mesh.hpp"
#include "../GFX/Image/RawImage.hpp"
#include "../GFX/Texture.hpp"
-#include "../GFX/Shading/Program.hpp"
namespace MC::Util {
class ImageViewer {
public:
- explicit ImageViewer(const GFX::Image::RawImage& image, Real window_aspect);
+ explicit ImageViewer(const GFX::Image::RawImage& image, Real window_aspect)
+ : m_mesh(create_mesh(window_aspect, image.width(), image.height())),
+ m_texture(image) {}
- void render();
+ void render(GFX::Actions& actions);
private:
static GFX::Mesh create_mesh(Real window_aspect, U32 image_width, U32 image_height);
static constexpr Real view_size = 1000.0f;
- static const Char* vertex;
- static const Char* fragment;
-
GFX::Mesh m_mesh;
- GFX::Shading::Program m_program;
GFX::Texture m_texture;
};
diff --git a/src/World/Clouds.cpp b/src/World/Clouds.cpp
index b30c0ce..58b1919 100644
--- a/src/World/Clouds.cpp
+++ b/src/World/Clouds.cpp
@@ -5,65 +5,47 @@
#include "../Math/AABB.hpp"
#include "../GFX/Util/Primitives.hpp"
#include "../GFX/Util/MeshBuilder.hpp"
-#include <GL/glew.h>
#include <array>
namespace MC::World {
-Clouds::Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color, Vector<3, F32> sun_direction)
- : m_program(
- {GFX::Shading::Shader::Type::Vertex, vertex},
- {GFX::Shading::Shader::Type::Fragment, fragment}
- ),
- m_mesh(create_mesh(create_cloud_matrix())),
- m_model_uniform(), m_view_uniform(), m_projection_uniform() {
- m_program.bind();
-
- m_model_uniform = m_program.uniform("model_matrix");
- m_view_uniform = m_program.uniform("view_matrix");
- m_projection_uniform = m_program.uniform("projection_matrix");
- auto sky_color_uniform = m_program.uniform("sky_color");
- auto sun_direction_uniform = m_program.uniform("sun_direction");
-
- m_model_uniform.set(Math::MVP::model<F32>({}, {}, {}));
- m_view_uniform.set(Math::MVP::view<F32>({}, {}));
- m_projection_uniform.set(Math::MVP::perspective_projection<F32>(ascept, fov, near, far));
- sky_color_uniform.set(sky_color);
- sun_direction_uniform.set(sun_direction);
-
- m_program.unbind();
-}
-
-void Clouds::update(const Time& time) {
+void Clouds::update(Time const& time) {
m_x_offset += 5.0 * time.delta();
}
-void Clouds::render(const GFX::Camera& camera) {
- auto position = camera.position();
-
- I32 center_x = std::round((position.x() - m_x_offset) / TileSize);
- I32 center_y = std::round(position.z() / TileSize);
+void Clouds::render(GFX::Actions& actions, Position::World player_position) {
+ I32 center_x = std::round((player_position.x() - m_x_offset) / TileSize);
+ I32 center_y = std::round(player_position.z() / TileSize);
for (Int x = -1; x <= 1; x++) {
for (Int y = -1; y <= 1; y++) {
- render_single_instance(camera, center_x + x, center_y + y);
+ render_single_instance(actions, center_x + x, center_y + y);
}
}
}
-void Clouds::render_single_instance(const GFX::Camera& camera, Int x, Int y) {
+void Clouds::render_single_instance(GFX::Actions& actions, Int x, Int y) {
Vector<3> position{TileSize * x + m_x_offset, Height, TileSize * y};
- m_program.bind();
-
- m_view_uniform.set(Math::MVP::view<F32>(camera.position(), camera.angles()));
- m_model_uniform.set(Math::MVP::model<F32>(position, Vector<3>{Scale}, {}));
-
- m_mesh.bind();
- glDrawElements(GL_TRIANGLES, m_mesh.size(), GL_UNSIGNED_INT, nullptr);
- m_mesh.unbind();
-
- m_program.unbind();
+ // m_program.bind();
+ //
+ // m_view_uniform.set(Math::MVP::view<F32>(camera.position(), camera.angles()));
+ // m_model_uniform.set(Math::MVP::model<F32>(position, Vector<3>{Scale}, {}));
+ //
+ // m_mesh.bind();
+ // glDrawElements(GL_TRIANGLES, m_mesh.size(), GL_UNSIGNED_INT, nullptr);
+ // m_mesh.unbind();
+ //
+ // m_program.unbind();
+ actions.add({
+ .mesh = &m_mesh,
+ .program = GFX::Resources::Program::Clouds,
+ .transform = Transform(
+ position,
+ Rotation::zero(),
+ Vec3(Scale)
+ ),
+ });
}
Clouds::CloudMatrix Clouds::create_cloud_matrix() {
@@ -80,7 +62,7 @@ Clouds::CloudMatrix Clouds::create_cloud_matrix() {
return clouds;
}
-GFX::Mesh Clouds::create_mesh(const CloudMatrix& cloud_matrix) {
+GFX::Mesh Clouds::create_mesh(CloudMatrix const& cloud_matrix) {
GFX::Util::MeshBuilder<Vector<3, F32>> builder{};
for (Int x = 0; x < CloudMatrixSize; x++) {
@@ -112,47 +94,4 @@ GFX::Mesh Clouds::create_mesh(const CloudMatrix& cloud_matrix) {
return builder.mesh();
}
-const Char* Clouds::vertex = R"v(
-#version 330 core
-
-uniform mat4 model_matrix;
-uniform mat4 view_matrix;
-uniform mat4 projection_matrix;
-
-layout (location = 0) in vec3 position;
-layout (location = 1) in vec3 normal;
-
-out vec3 surface_normal;
-out float depth;
-
-void main() {
- vec4 world_position = model_matrix * vec4(position, 1.0);
- vec4 view_position = view_matrix * world_position;
- vec4 clip_position = projection_matrix * view_position;
-
- gl_Position = clip_position;
- surface_normal = (model_matrix * vec4(normal, 0.0)).xyz;
- depth = clamp((length(view_position) - 200) / 400, 0.0, 1.0);
-}
-)v";
-
-const Char* Clouds::fragment = R"f(
-#version 330 core
-
-uniform vec3 sky_color;
-uniform vec3 sun_direction;
-
-in vec3 surface_normal;
-in float depth;
-out vec4 color;
-
-void main() {
- float brightness = dot(normalize(surface_normal), normalize(-sun_direction));
- vec3 diffuse = vec3(1 - clamp(brightness, -0.3, 0.2));
- vec3 base = vec3(1.0, 1.0, 1.0) * diffuse;
-
- color = vec4(mix(sky_color, base, 1 - depth), 0.3);
-}
-)f";
-
}
diff --git a/src/World/Clouds.hpp b/src/World/Clouds.hpp
index 4bd0637..7246e7b 100644
--- a/src/World/Clouds.hpp
+++ b/src/World/Clouds.hpp
@@ -1,8 +1,7 @@
#pragma once
#include "../Time.hpp"
-#include "../GFX/Shading/Program.hpp"
-#include "../GFX/Shading/Uniform.hpp"
+#include "../GFX/Actions.hpp"
#include "../GFX/Camera.hpp"
#include "../GFX/Mesh.hpp"
@@ -10,10 +9,10 @@ namespace MC::World {
class Clouds {
public:
- Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color, Vector<3, F32> sun_direction);
+ Clouds() : m_mesh(create_mesh(create_cloud_matrix())) {}
- void update(const Time& time);
- void render(const GFX::Camera& camera);
+ void update(Time const& time);
+ void render(GFX::Actions& actions, Position::World player_position);
private:
constexpr static U32 CloudMatrixSize = 128;
constexpr static Int Height = 200;
@@ -22,22 +21,13 @@ private:
using CloudMatrix = Matrix<CloudMatrixSize, CloudMatrixSize, Bool>;
- void render_single_instance(const GFX::Camera& camera, Int x, Int y);
+ void render_single_instance(GFX::Actions& actions, Int x, Int y);
static CloudMatrix create_cloud_matrix();
- static GFX::Mesh create_mesh(const CloudMatrix& cloud_matrix);
-
- static const Char* vertex;
- static const Char* fragment;
+ static GFX::Mesh create_mesh(CloudMatrix const& cloud_matrix);
Real m_x_offset = 0.0;
-
- GFX::Shading::Program m_program;
GFX::Mesh m_mesh;
-
- GFX::Shading::Uniform m_model_uniform;
- GFX::Shading::Uniform m_view_uniform;
- GFX::Shading::Uniform m_projection_uniform;
};
}
diff --git a/src/main.cpp b/src/main.cpp
index 9dd42c9..9153530 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,36 +2,30 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
-#include "Time.hpp"
-#include "Common/Sizes.hpp"
-#include "GFX/Window.hpp"
-#include "GFX/Camera.hpp"
-#include "Math/MVP.hpp"
-#include "GFX/Shading/Program.hpp"
-#include "GFX/Texture.hpp"
-#include "GFX/Image/PPMParser.hpp"
-#include "World/Clouds.hpp"
+#include "Game.hpp"
+#include "Render.hpp"
#include "World/World.hpp"
-#include "Entities/Player.hpp"
-#define APP_NAME "Meowcraft"
-
-#define WINDOW_WIDTH 800
-#define WINDOW_HEIGHT 600
-#define ASPECT (static_cast<Real>(WINDOW_WIDTH) / WINDOW_HEIGHT)
+int main() {
+ if (!glfwInit()) {
+ std::cout << "Failed to initialize GLFW" << std::endl;
+ return 1;
+ }
-#define FOV 90
+ try {
+ MC::GFX::Window window(APP_NAME, WINDOW_WIDTH, WINDOW_HEIGHT);
+ window.detach();
-void run();
-void render(MC::GFX::Mesh&, MC::GFX::Texture&);
-void setup_gl();
-void fix_macos_render(const MC::GFX::Window&);
+ auto render_control = std::make_shared<MC::Render::Control>();
-int main() {
- glfwInit();
+ std::thread render_thread{[&window, render_control] {
+ MC::Render render{window, render_control};
+ render.run();
+ }};
+ render_thread.detach();
- try {
- run();
+ MC::Game game{window, render_control};
+ game.run();
} catch (std::runtime_error& error) {
std::cout << "An error occurred: " << error.what() << std::endl;
glfwTerminate();
@@ -41,128 +35,3 @@ int main() {
glfwTerminate();
return 0;
}
-
-void run() {
- MC::GFX::Window window(APP_NAME, WINDOW_WIDTH, WINDOW_HEIGHT);
- setup_gl();
-
- glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
- window.on_size_change([](GLFWwindow* _, I32 w, I32 h) {
- glViewport(0, 0, w, h);
- });
-
- auto image = MC::GFX::Image::PPMParser(MC::Assets::Images::atlas).parse();
- auto texture = MC::GFX::Texture(image);
-
- MC::World::World world;
-
- MC::GFX::Camera camera{};
-
- MC::GFX::Shading::Program program(
- MC::GFX::Shading::Shader::create_vertex(),
- MC::GFX::Shading::Shader::create_fragment()
- );
-
- auto model_uniform = program.uniform("model_matrix");
- auto view_uniform = program.uniform("view_matrix");
- auto projection_uniform = program.uniform("projection_matrix");
- auto sun_direction_uniform = program.uniform("sun_direction");
- auto sky_color_uniform = program.uniform("sky_color");
- auto mesh_alpha_uniform = program.uniform("mesh_alpha");
-
- program.bind();
- auto projection = Math::MVP::perspective_projection<F32>(ASPECT, FOV, 0.1f, 1000.0f);
- projection_uniform.set(projection);
-
- Vector<3, F32> sun_direction{1, -1, 0};
- sun_direction_uniform.set(sun_direction);
-
- Vector<3, F32> sky_color{0.85, 0.85, 0.85}; // #DBDBDB
- sky_color_uniform.set(sky_color);
-
- MC::World::Clouds clouds{ASPECT, FOV, 0.1f, 1000.0f, sky_color, sun_direction};
-
- MC::Entities::Player player{{0, MC::World::Chunk::Height / 2.0, 0}};
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glEnable(GL_CULL_FACE);
- glFrontFace(GL_CCW);
- glCullFace(GL_BACK);
-
- MC::Time time;
-
- while (!window.should_close()) {
- time.start_frame();
- window.start_frame();
-
-#ifdef __APPLE__
- fix_macos_render(window);
-#endif
-
- if (window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) {
- window.close();
- }
-
- player.update(time, window, camera, world);
- clouds.update(time);
-
- glClearColor(sky_color.x(), sky_color.y(), sky_color.z(), 1.0f); // #DBDBDB
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- program.bind();
-
- auto view = Math::MVP::view<F32>(camera.position(), camera.angles());
- view_uniform.set(view);
-
- for (auto chunk : world.get_visible_chunks(camera.position())) {
- mesh_alpha_uniform.set(1.0);
- auto land_model = Math::MVP::model<F32>(chunk->chunk.value().position(), Vector<3>::one(), {});
- model_uniform.set(land_model);
- render(chunk->land_mesh.value(), texture);
-
- mesh_alpha_uniform.set(0.4);
- auto water_model = Math::MVP::model<F32>(chunk->chunk.value().position() - Vector<3>{0, 0.2, 0}, Vector<3>::one(), {});
- model_uniform.set(water_model);
- render(chunk->water_mesh.value(), texture);
- }
-
- program.unbind();
-
- clouds.render(camera);
-
- time.end_frame();
- }
-}
-
-void render(MC::GFX::Mesh& mesh, MC::GFX::Texture& texture) {
- texture.bind();
- mesh.bind();
- glDrawElements(GL_TRIANGLES, mesh.size(), GL_UNSIGNED_INT, nullptr);
- mesh.unbind();
- texture.unbind();
-}
-
-void setup_gl() {
- GLenum error;
- if ((error = glewInit()) != GLEW_OK) {
- std::string error_string(reinterpret_cast<const Char*>(glewGetErrorString(error)));
- throw std::runtime_error("Failed to load GL functions: " + error_string);
- }
-}
-
-void fix_macos_render(const MC::GFX::Window& window) {
- static Bool moved = false;
-
- if(!moved) {
- I32 x, y;
- glfwGetWindowPos(window.get(), &x, &y);
- glfwSetWindowPos(window.get(), ++x, y);
-
- moved = true;
- }
-} \ No newline at end of file