diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 21:57:46 +1100 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 21:57:46 +1100 |
| commit | e4483eca01b48b943cd0461e24a74ae1a3139ed4 (patch) | |
| tree | ed58c3c246e3af1af337697695d780aa31f6ad9a /src/client/draw.cc | |
| parent | 1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (diff) | |
Update to most recent version (old initial commit)
Diffstat (limited to 'src/client/draw.cc')
| -rw-r--r-- | src/client/draw.cc | 432 |
1 files changed, 0 insertions, 432 deletions
diff --git a/src/client/draw.cc b/src/client/draw.cc deleted file mode 100644 index c549ffe..0000000 --- a/src/client/draw.cc +++ /dev/null @@ -1,432 +0,0 @@ -#include "draw.hh" - -namespace client { -namespace draw { - -void draw_rectangle(const rectangle_args& ra) noexcept { - const glm::vec2 pos = ra.pos.to_vec2(); - const glm::vec2 size = ra.size.to_vec2(); - - // We want to render from the bottom left corner. - render::render_rectangle(pos + (size / 2.0f), size, ra.colour); -} - -void draw_colour(const glm::vec4& colour) noexcept { - const rectangle_args args = { - .pos = {.extent = {0.0f, 0.0f}}, - .size = {.extent = {1.0f, 1.0f}}, - .colour = colour, - }; - draw_rectangle(args); -} - -void draw_text(const std::string_view text, const text_args& args) noexcept { - const glm::vec2& window = render::get_window_size(); - const float x = floorf(window.x * args.pos.extent.x + args.pos.offset.x); - const float y = floorf(window.y * args.pos.extent.y + args.pos.offset.y); - const unsigned height = static_cast<unsigned>( - args.extent_height * window.y + args.offset_height); - - const auto make_matrix = [&](const float xo, const float yo) -> glm::mat4 { - constexpr auto identity = glm::mat4(1.0f); - const auto proj = glm::ortho(0.f, window.x, 0.f, window.y); - const auto tran = - glm::translate(identity, glm::vec3{x + xo, y + yo, 0.0f}); - return proj * tran; - }; - - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - if (args.has_backing) { - constexpr glm::vec4 black{0.0f, 0.0f, 0.0f, 1.0f}; - render::render_text(text, height, args.is_centered, args.is_vcentered, - black, make_matrix(1.0f, -2.0f)); - } - glEnable(GL_BLEND); - - render::render_text(text, height, args.is_centered, args.is_vcentered, - args.colour, make_matrix(0, 0)); - glEnable(GL_DEPTH_TEST); -} - -static void draw_state_info(const shared::player& lp) noexcept { - - constexpr auto nstr = [](const auto d) -> std::string { - auto str = std::to_string(d); - str.erase(std::prev(std::end(str), 4), std::end(str)); - return str; - }; - - const auto make_position = [&]() -> std::string { - const auto chunk_x = lp.chunk_pos.x; - const auto chunk_z = lp.chunk_pos.z; - const auto x = static_cast<double>(lp.local_pos.x); - const auto y = static_cast<double>(lp.local_pos.y); - const auto z = static_cast<double>(lp.local_pos.z); - constexpr auto WIDTH = shared::world::chunk::WIDTH; - const auto abs_x = static_cast<double>(lp.chunk_pos.x) * WIDTH + x; - const auto abs_z = static_cast<double>(lp.chunk_pos.z) * WIDTH + z; - - constexpr auto nstr = [](const double d) -> std::string { - auto str = std::to_string(d); - str.erase(std::prev(std::end(str), 4), std::end(str)); - return str; - }; - const std::string chk_str = '[' + std::to_string(chunk_x) + ", " + - std::to_string(chunk_z) + ']'; - const std::string abs_str = - '(' + nstr(abs_x) + ", " + nstr(y) + ", " + nstr(abs_z) + ')'; - return "position: " + abs_str + chk_str; - }; - - const auto make_direction = [&]() -> std::string { - const float yaw = glm::degrees(lp.viewangles.yaw); - const float pitch = glm::degrees(lp.viewangles.pitch); - - const std::string bearing = [&]() -> std::string { - if (yaw >= 315.0f || yaw < 45.0f) { - return "North"; - } else if (yaw >= 45.0f && yaw < 135.0f) { - return "East"; - } else if (yaw >= 135.0f && yaw < 225.0f) { - return "South"; - } else { - return "West"; - } - }(); - const std::string face_str = '(' + nstr(pitch) + ", " + nstr(yaw) + ')'; - // Yaw is between 0 and 360. - return "perspective: " + face_str + " -> " + bearing; - }; - - const auto make_address = []() -> std::string { - const std::string address = std::string(client::state.address); - const std::string port = std::string(client::state.port); - return "address: " + address + ":" + port; - }; - - const auto make_seed = []() -> std::string { - return "seed: " + std::to_string(client::state.seed); - }; - - const auto make_players = []() -> std::string { - const auto index = std::to_string(client::state.localplayer); - return "index: " + index; - }; - - const auto make_chunks = []() -> std::string { - return "chunks [req, rcv]: " + - std::to_string(client::state.requested_chunk_count) + ", " + - std::to_string(client::state.networked_chunk_count) + " @ " + - std::to_string(client::state.draw_distance) + " draw distance"; - }; - - const auto make_speed = [&]() -> std::string { - return "speed: " + nstr(glm::length(lp.velocity)) + " b/s"; - }; - - const auto make_velocity = [&]() -> std::string { - return "velocity: (" + nstr(lp.velocity.x) + ", " + - nstr(lp.velocity.y) + ", " + nstr(lp.velocity.z) + ")"; - }; - - // Draws all of our strings and works its way down the top of the screen. - text_args args{.pos = {.extent = {0.0f, 1.0f - 0.015f}}, - .extent_height = 0.0165f, - .colour = {1.0f, 1.0f, 1.0f, 1.0f}, - .has_backing = true}; - const auto draw_str_trail = [&args](const std::string& str) { - draw_text(str, args); - args.pos.extent.y -= 0.02f; - }; - draw_str_trail("blockgame_linux v0.20"); - draw_str_trail(make_address()); - draw_str_trail(make_seed()); - draw_str_trail(make_players()); - draw_str_trail(make_chunks()); - draw_str_trail(make_position()); - draw_str_trail(make_direction()); - draw_str_trail(make_speed()); - draw_str_trail(make_velocity()); -} - -static void draw_fps() noexcept { - const auto get_fps_colour = [](const int fps) -> glm::vec4 { - if (fps == 0) { - return {1.0f, 1.0f, 1.0f, 1.0f}; - } else if (fps < 30) { - return {1.0f, 0.0f, 0.0f, 1.0f}; - } else if (fps < 60) { - return {1.0f, 0.5f, 0.0f, 1.0f}; - } else if (fps < 120) { - return {0.0f, 1.0f, 0.0f, 1.0f}; - } - return {0.0f, 1.0f, 1.0f, 1.0f}; - }; - - const int fps = client::render::get_fps(); - const std::string fps_str = fps != 0 ? std::to_string(fps) : "~"; - draw_text("FPS: " + fps_str, {.pos = relative_arg{.offset = {0.0f, 2.0f}}, - .extent_height = 0.0165f, - .colour = get_fps_colour(fps), - .has_backing = true}); -} - -// Player position, version, fps etc -// Just don't read past this point, doing this is unbelievably ugly. -// I don't know why I write this like someone else will read it. -static void draw_overlay(const shared::player& lp) noexcept { - draw_state_info(lp); - draw_fps(); -} - -static void draw_main_pass(const shared::player& localplayer, - client::players& players, - client::world::chunk::map& chunks) noexcept { - for (auto& chunk : chunks) { - if (!chunk.second.has_value()) { - continue; - } - chunk.second->draw(chunks, localplayer, - client::world::chunk::pass::solid); - } - - // Draw players while ignoring the localplayer, which is always 0'th! - // This also handles drawing messages. - for (auto i = 1u; i < std::size(players); ++i) { - players[i].draw_playermodel(localplayer); - } -} - -static void draw_water_pass(const shared::player& localplayer, - client::world::chunk::map& chunks) noexcept { - for (auto& chunk : chunks) { - if (!chunk.second.has_value()) { - continue; - } - chunk.second->draw(chunks, localplayer, - client::world::chunk::pass::water); - } -} - -static void draw_wts_text(const shared::player& localplayer, - client::players& players) noexcept { - for (auto i = 1u; i < std::size(players); ++i) { - players[i].draw_message(localplayer); - } -} - -static void draw_hud(const client::player& localplayer, - const client::world::chunk::map& chunks) noexcept { - if (client::input::is_key_toggled(SDLK_F3)) { - draw_overlay(localplayer); - } - - if (const auto& msg = localplayer.get_message(); msg.has_value()) { - if (msg->receive_time + player::MSG_SHOW_TIME >= - std::chrono::steady_clock::now()) { - draw_text(msg->text, {.pos = relative_arg{.extent = {0.5f, 0.0f}, - .offset = {0.0f, 2.0f}}, - .extent_height = 0.0165f, - .colour = {1.0f, 1.0f, 1.0f, 1.0f}, - .has_backing = true, - .is_centered = true}); - } - } - - if (client::window::is_open()) { - return; - } - - // crosshair - client::draw::draw_rectangle( - {.pos = {.extent = {0.5f, 0.5f}, .offset = {-3.0f, -3.0f}}, - .size = {.offset = {6.0f, 6.0f}}, - .colour = {1.0f, 1.0f, 1.0f, 1.0f}}); - - // Draw the outline of the block we're aiming at. - if (const auto interact = client::movement::interact( - localplayer, movement::interact_mode::remove, chunks); - interact.has_value()) { - - const auto [world_x, world_z] = [&]() -> std::pair<float, float> { - const float offset_x = - static_cast<float>(interact->first.x - localplayer.chunk_pos.x); - const float offset_z = - static_cast<float>(interact->first.z - localplayer.chunk_pos.z); - return {offset_x * shared::world::chunk::WIDTH, - offset_z * shared::world::chunk::WIDTH}; - }(); - - const glm::vec3 render_pos = { - world_x + static_cast<float>(interact->second.x), - interact->second.y, - world_z + static_cast<float>(interact->second.z)}; - - client::render::render_cube_outline(render_pos + 0.5f, - {0.8f, 0.8f, 0.8f, 1.0f}); - } -} - -static void update_camera(const shared::player& localplayer) noexcept { - // approximately encompasses everything we could possibly see - - // if our zfar is too low, our fog breaks - // bit of maths for calculating the max distance we could can see - client::render::camera::get_zfar() = std::hypot( - static_cast<float>(world::chunk::HEIGHT), - float(client::state.draw_distance) * std::hypot(16.0f, 16.0f)); - client::render::camera::get_pos() = - localplayer.local_pos + - glm::vec3{0.0f, shared::player::EYE_HEIGHT, 0.0f}; - client::render::camera::get_front() = - shared::math::angle_to_dir(localplayer.viewangles); - client::render::camera::update(); -} - -// We create framebuffer here to enable postprocessing and solve some -// rendering problems. -static void draw_buffers(const shared::player& localplayer, - client::players& players, - client::world::chunk::map& chunks) noexcept { - const auto make_vbo = [](const auto& vertices) -> GLuint { - GLuint vbo = 0; - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), std::data(vertices), - GL_STATIC_DRAW); - return vbo; - }; - const auto make_vao = []() -> GLuint { - GLuint vao = 0; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - // position - glVertexAttribPointer(0, sizeof(glm::vec2) / sizeof(float), GL_FLOAT, - GL_FALSE, sizeof(glm::vec2), nullptr); - glEnableVertexAttribArray(0); - return vao; - }; - const auto make_ebo = [](const auto& indices) -> GLuint { - GLuint ebo = 0; - glGenBuffers(1, &ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, - GL_STATIC_DRAW); - return ebo; - }; - const auto make_fbo = []() -> GLuint { - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - return fbo; - }; - const auto make_texture = [](const auto& internal_format, - const auto& format, - const int texture_offset) -> GLuint { - GLuint texture; - glGenTextures(1, &texture); - glActiveTexture(GL_TEXTURE2 + texture_offset); - glBindTexture(GL_TEXTURE_2D, texture); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - - const glm::vec2& window = client::render::get_window_size(); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, window.x, window.y, 0, - internal_format, GL_UNSIGNED_BYTE, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, format, GL_TEXTURE_2D, texture, - 0); - return texture; - }; - - static constexpr std::array<glm::vec2, 4> vertices = { - glm::vec2{-1.0f, -1.0f}, glm::vec2{1.0f, -1.0f}, glm::vec2{1.0f, 1.0f}, - glm::vec2{-1.0f, 1.0f}}; - static constexpr std::array<unsigned, 6> indices = {0, 1, 2, 2, 3, 0}; - static const client::render::program framebuffer_program{ - "res/shaders/framebuffer.vs", "res/shaders/framebuffer.fs"}; - static const GLuint vbo [[maybe_unused]] = make_vbo(vertices); - static const GLuint vao = make_vao(); - static const GLuint ebo [[maybe_unused]] = make_ebo(indices); - // Main frame buffer object. - static const GLuint fbo_main = make_fbo(); - static const GLuint main_colour [[maybe_unused]] = - make_texture(GL_RGB, GL_COLOR_ATTACHMENT0, 0); - static const GLuint main_depth [[maybe_unused]] = - make_texture(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT, 1); - // Water frame buffer object. - static const GLuint fbo_water = make_fbo(); - static const GLuint water_colour [[maybe_unused]] = - make_texture(GL_RGB, GL_COLOR_ATTACHMENT0, 2); - static const GLuint water_depth [[maybe_unused]] = - make_texture(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT, 3); - static const GLint u_is_underwater = - glGetUniformLocation(framebuffer_program, "_u_is_underwater"); - - // We render our main scene on the main framebuffer. - glBindFramebuffer(GL_FRAMEBUFFER, fbo_main); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - draw_main_pass(localplayer, players, chunks); - - // We render our water scene on the water framebuffer. - glBindFramebuffer(GL_FRAMEBUFFER, fbo_water); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - const bool is_underwater = [&]() -> bool { - const glm::ivec3 pos{client::render::camera::get_pos()}; - - const auto find_it = chunks.find(localplayer.chunk_pos); - if (find_it == std::end(chunks) || !find_it->second.has_value()) { - return false; - } - if (shared::world::chunk::is_outside_chunk(pos)) { - return false; - } - - const auto block = find_it->second->get_block(pos); - return block.type == shared::world::block::type::water; - }(); - if (is_underwater) { - glFrontFace(GL_CW); - draw_water_pass(localplayer, chunks); - glFrontFace(GL_CCW); - } else { - draw_water_pass(localplayer, chunks); - } - - glBindFramebuffer(GL_FRAMEBUFFER, main_colour); - glDisable(GL_DEPTH_TEST); - glUseProgram(framebuffer_program); - glBindVertexArray(vao); - - glUniform1i(u_is_underwater, is_underwater); - - glDrawElements(GL_TRIANGLES, std::size(indices), GL_UNSIGNED_INT, nullptr); - - static client::render::program postprocess_program{ - "res/shaders/framebuffer.vs", "res/shaders/postprocess.fs"}; - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glUseProgram(postprocess_program); - glDrawElements(GL_TRIANGLES, std::size(indices), GL_UNSIGNED_INT, nullptr); - - glEnable(GL_DEPTH_TEST); -} - -void draw(client::players& players, - client::world::chunk::map& chunks) noexcept { - const auto& localplayer = client::get_localplayer(players); - - update_camera(localplayer); - client::render::update_uniforms(); - - draw_buffers(localplayer, players, chunks); - draw_hud(localplayer, chunks); - draw_wts_text(localplayer, players); - - client::window::draw(); - - client::render::swap_window(); -} - -} // namespace draw -} // namespace client |
