aboutsummaryrefslogtreecommitdiff
path: root/src/client/item/block.cc
blob: 08f072ba020ec7d6c146ca8c55ab6e0ab0afb846 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "client/item/block.hh"

namespace client {
namespace item {

void block::regenerate_glo() noexcept {
    const auto make_vbo = [](const auto& data) -> GLuint {
        GLuint vbo = 0;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER,
                     std::size(data) * sizeof(client::world::block::glvert),
                     std::data(data), GL_STATIC_DRAW);
        return vbo;
    };
    const auto make_vao = []() -> GLuint {
        GLuint vao = 0;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
        // posiiton
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, sizeof(glm::vec3) / sizeof(float), GL_FLOAT,
                              GL_FALSE, sizeof(client::world::block::glvert),
                              nullptr);
        // texture
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, sizeof(glm::vec3) / sizeof(float), GL_FLOAT,
                              GL_FALSE, sizeof(client::world::block::glvert),
                              reinterpret_cast<void*>(sizeof(glm::vec3)));
        return vao;
    };
    std::vector<client::world::block::glvert> data;

    const float tex_yoff = static_cast<float>(this->type) - 1.0f;
    for (const auto& face :
         client::world::block::get_glfaces(this->shared::item::block::type)) {

        std::ranges::transform(face, std::back_inserter(data), [&](auto vert) {
            vert.texture.z += tex_yoff * 6.0f;
            return vert;
        });
    }

    const auto vbo = make_vbo(data);
    const auto vao = make_vao();
    this->glo.emplace(vbo, vao, std::size(data));
}

void block::draw(const glm::vec2& pos, const glm::vec2& size) noexcept {
    const auto make_matrix = [&]() -> glm::mat4 {
        const glm::vec2 window = client::render::get_window_size();

        constexpr auto identity = glm::mat4{1.0f};
        const auto proj = glm::ortho(0.0f, window.x, 0.0f, window.y);
        const auto scal =
            glm::scale(identity, glm::vec3{size.x * 0.5f, size.y * 0.5f, 0.0f});
        const auto tran =
            glm::translate(identity, glm::vec3{pos.x + size.x / 2.0f,
                                               pos.y + size.y / 2.0f, 0.0f});

        // hack for shurbs, which are already offset and look bad when rotated
        const auto rotey = client::world::block::get_draw_type(this->type) ==
                                   client::world::block::draw_type::block
                               ? glm::rotate(identity, glm::radians(45.0f),
                                             glm::vec3(0.0f, 1.0f, 0.0f))
                               : identity;
        const auto rotex = glm::rotate(identity, glm::radians(30.0f),
                                       glm::vec3(1.0f, 0.0f, 0.0f));
        return proj * tran * scal * rotex * rotey;
    };

    static const client::render::program program{"res/shaders/face.vs",
                                                 "res/shaders/face.fs"};
    static const GLint u_matrix = glGetUniformLocation(program, "_u_matrix");

    if (!this->glo.has_value()) {
        this->regenerate_glo();
    }

    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glUseProgram(program);
    glBindVertexArray(this->glo->vao);

    glUniformMatrix4fv(u_matrix, 1, GL_FALSE, glm::value_ptr(make_matrix()));

    glDrawArrays(GL_TRIANGLES, 0, this->glo->elements);
}

} // namespace item
} // namespace client