summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-07-11 04:52:24 +0200
committerMel <einebeere@gmail.com>2023-07-11 04:52:24 +0200
commit0ce26f2a49fd6d64a690b84b1932126edfbfbee6 (patch)
treef0846f7f0e394d3c213986a2f85e0240dc8e5402 /src
parente6812d2df6bd8a0a71375096abe46f8039d8c570 (diff)
downloadmeowcraft-0ce26f2a49fd6d64a690b84b1932126edfbfbee6.tar.zst
meowcraft-0ce26f2a49fd6d64a690b84b1932126edfbfbee6.zip
Add simple scrolling non-tiling 2D clouds
Diffstat (limited to 'src')
-rw-r--r--src/GFX/Shading/Uniform.hpp2
-rw-r--r--src/Math/MVP.hpp5
-rw-r--r--src/Math/Matrix.hpp9
-rw-r--r--src/Util/ImageViewer.cpp2
-rw-r--r--src/World/Clouds.cpp121
-rw-r--r--src/World/Clouds.hpp36
-rw-r--r--src/main.cpp18
7 files changed, 185 insertions, 8 deletions
diff --git a/src/GFX/Shading/Uniform.hpp b/src/GFX/Shading/Uniform.hpp
index 3ddbd4a..6edff7f 100644
--- a/src/GFX/Shading/Uniform.hpp
+++ b/src/GFX/Shading/Uniform.hpp
@@ -8,6 +8,8 @@ namespace MC::GFX::Shading {
 
 class Uniform {
 public:
+    Uniform() = default;
+
     Uniform(std::string name, U32 index)
         : m_name(std::move(name)), m_index(index) {}
 
diff --git a/src/Math/MVP.hpp b/src/Math/MVP.hpp
index 4046a50..b7341a8 100644
--- a/src/Math/MVP.hpp
+++ b/src/Math/MVP.hpp
@@ -5,11 +5,12 @@
 namespace Math::MVP {
 
 template<typename T = Real>
-Matrix<4, 4, T> model(Vector<3> position, Rotation angles) {
+Matrix<4, 4, T> model(Vector<3> position, Vector<3> size, Rotation angles) {
     auto transformation = Matrix<4, 4, T>::transformation(position);
+    auto scale = Matrix<4, 4, T>::scale(size);
     auto rotation = Matrix<4, 4, T>::rotation(angles);
 
-    return transformation * rotation;
+    return transformation * rotation * scale;
 }
 
 template<typename T = Real>
diff --git a/src/Math/Matrix.hpp b/src/Math/Matrix.hpp
index d51d171..41d3661 100644
--- a/src/Math/Matrix.hpp
+++ b/src/Math/Matrix.hpp
@@ -37,6 +37,15 @@ struct Matrix {
         };
     }
 
+    static Matrix<4, 4, T> scale(Vector<3> factor) {
+        return {
+            factor.x(), 0.0, 0.0, 0.0,
+            0.0, factor.y(), 0.0, 0.0,
+            0.0, 0.0, factor.z(), 0.0,
+            0.0, 0.0, 0.0, 1.0
+        };
+    }
+
     static Matrix<4, 4, T> rotation(Rotation angles) {
         auto radians = angles.vector.map([](auto a) { return Math::radians(a); });
 
diff --git a/src/Util/ImageViewer.cpp b/src/Util/ImageViewer.cpp
index 8ff8c57..6c88c78 100644
--- a/src/Util/ImageViewer.cpp
+++ b/src/Util/ImageViewer.cpp
@@ -18,7 +18,7 @@ ImageViewer::ImageViewer(
     auto view_uniform = m_program.uniform("view_matrix");
     auto projection_uniform = m_program.uniform("projection_matrix");
 
-    model_uniform.set(Math::MVP::model<F32>({}, {}));
+    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));
 
diff --git a/src/World/Clouds.cpp b/src/World/Clouds.cpp
new file mode 100644
index 0000000..6c5dba3
--- /dev/null
+++ b/src/World/Clouds.cpp
@@ -0,0 +1,121 @@
+#include "Clouds.hpp"
+#include "../Math/MVP.hpp"
+#include "../Math/Perlin.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)
+    : m_position(-1000, 120, -1000),
+    m_program(
+    {GFX::Shading::Shader::Type::Vertex, vertex},
+    {GFX::Shading::Shader::Type::Fragment, fragment}
+    ),
+    m_mesh(GFX::Binder::load(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");
+
+    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);
+
+    m_program.unbind();
+}
+
+void Clouds::update(U64 time) {
+    m_position.x() += time / 5000.0;
+}
+
+void Clouds::render(const GFX::Camera& camera) const {
+    m_program.bind();
+
+    m_view_uniform.set(Math::MVP::view<F32>(camera.position(), camera.angles()));
+    m_model_uniform.set(Math::MVP::model<F32>(m_position, Vector<3>{10.0}, {}));
+
+    m_mesh.bind();
+    glDrawElements(GL_TRIANGLES, m_mesh.size(), GL_UNSIGNED_INT, nullptr);
+    m_mesh.unbind();
+
+    m_program.unbind();
+}
+
+Clouds::CloudMatrix Clouds::create_cloud_matrix() {
+    Math::Perlin::Noise<2> noise{};
+
+    CloudMatrix clouds{false};
+    for (Int x = 0; x < CloudMatrixSize; x++) {
+        for (Int y = 0; y < CloudMatrixSize; y++) {
+            if (noise.at({x, y * 2}) > 0.55) {
+                clouds(x, y) = true;
+            }
+        }
+    }
+    return clouds;
+}
+
+GFX::Mesh Clouds::create_mesh(const CloudMatrix& cloud_matrix) {
+    GFX::Util::MeshBuilder builder{};
+
+    for (Int x = 0; x < CloudMatrixSize; x++) {
+        for (Int y = 0; y < CloudMatrixSize; y++) {
+            if (!cloud_matrix(x, y)) continue;
+
+            U32 s = builder.vertex_count();
+            std::array<Vector<3, F32>, 4> positions = {{{0, 0, 0}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1}}};
+            std::array<U32, 6> indices = { s + 0, s + 1, s + 2, s + 1, s + 3, s + 2 };
+
+            for (auto& p : positions) p += {x, 0, y};
+
+            builder.positions(positions);
+            builder.indices(indices);
+        }
+    }
+
+    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;
+
+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;
+    depth = clamp((length(view_position) - 75) / 125, 0.0, 1.0);
+}
+)v";
+
+const Char* Clouds::fragment = R"f(
+#version 330 core
+
+uniform vec3 sky_color;
+
+in float depth;
+out vec4 color;
+
+void main() {
+    vec3 white = vec3(1.0, 1.0, 1.0);
+
+    color = vec4(mix(sky_color, white, 1 - depth), 0.5);
+}
+)f";
+
+}
diff --git a/src/World/Clouds.hpp b/src/World/Clouds.hpp
new file mode 100644
index 0000000..6a91901
--- /dev/null
+++ b/src/World/Clouds.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "../GFX/Binder.hpp"
+#include "../GFX/Shading/Program.hpp"
+#include "../GFX/Shading/Uniform.hpp"
+#include "../GFX/Camera.hpp"
+
+namespace MC::World {
+
+class Clouds {
+public:
+    Clouds(Real ascept, Real fov, Real near, Real far, Vector<3, F32> sky_color);
+
+    void update(U64 time);
+    void render(const GFX::Camera& camera) const;
+private:
+    constexpr static U32 CloudMatrixSize = 128;
+    using CloudMatrix = Matrix<CloudMatrixSize, CloudMatrixSize, Bool>;
+
+    static CloudMatrix create_cloud_matrix();
+    static GFX::Mesh create_mesh(const CloudMatrix& cloud_matrix);
+
+    static const Char* vertex;
+    static const Char* fragment;
+
+    Vector<3> m_position;
+
+    GFX::Shading::Program m_program;
+    GFX::BindableMesh 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 3d193c2..1688dac 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -10,6 +10,7 @@
 #include "GFX/Shading/Program.hpp"
 #include "GFX/Texture.hpp"
 #include "GFX/Image/PPMParser.hpp"
+#include "World/Clouds.hpp"
 #include "World/World.hpp"
 
 #define APP_NAME "Meowcraft"
@@ -80,6 +81,8 @@ void run() {
     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};
+
     glEnable(GL_DEPTH_TEST);
     glDepthFunc(GL_LEQUAL);
 
@@ -100,27 +103,32 @@ void run() {
 #endif
 
         process_input(window, camera);
+        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);
 
-        glClearColor(sky_color.x(), sky_color.y(), sky_color.z(), 1.0f); // #DBDBDB
-        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
         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(), {});
+            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}, {});
+            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++;
     }
 }