#include #include #include #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 "World/World.hpp" #define APP_NAME "Meowcraft" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 #define ASPECT (static_cast(WINDOW_WIDTH) / WINDOW_HEIGHT) #define FOV 90 void run(); void render(MC::GFX::Mesh&, MC::GFX::Texture&); void process_input(MC::GFX::Window&, MC::GFX::Camera&, MC::Time&); void setup_gl(); void fix_macos_render(const MC::GFX::Window&); int main() { glfwInit(); try { run(); } catch (std::runtime_error& error) { std::cout << "An error occurred: " << error.what() << std::endl; glfwTerminate(); return 1; } 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{}; camera.set_position({0, MC::World::Chunk::Height / 2.0, 0}); 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(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}; 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 process_input(window, camera, time); 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(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(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(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 process_input(MC::GFX::Window& window, MC::GFX::Camera& camera, MC::Time& time) { if (window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) { window.close(); } auto r = window.mouse_delta(); auto key = [&](Int k) -> Real { return window.key(k, GLFW_PRESS); }; Real x = key(GLFW_KEY_D) - key(GLFW_KEY_A); Real y = key(GLFW_KEY_SPACE) - key(GLFW_KEY_LEFT_SHIFT); Real z = key(GLFW_KEY_S) - key(GLFW_KEY_W); Real boost = key(GLFW_KEY_LEFT_CONTROL) * 75.0f; auto move_speed = (20.0f + boost) * time.delta(); auto rotation_speed = 5.0f * time.delta(); camera.move_relative({x * move_speed, 0.0f, z * move_speed}); camera.move({0.0f, y * move_speed, 0.0f}); camera.rotate({r.y() * rotation_speed, r.x() * rotation_speed, 0.0f}); } void setup_gl() { GLenum error; if ((error = glewInit()) != GLEW_OK) { std::string error_string(reinterpret_cast(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; } }