renderer.cpp 8.15 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3

#include <imgui/imgui.h>

TheNumbat's avatar
TheNumbat committed
4
#include "../geometry/util.h"
TheNumbat's avatar
TheNumbat committed
5
6
7
8
9
10
11
12
#include "../gui/manager.h"
#include "../lib/mathlib.h"

#include "renderer.h"
#include "scene.h"

static const int DEFAULT_SAMPLES = 4;

TheNumbat's avatar
TheNumbat committed
13
14
15
16
17
18
19
20
21
22
Renderer::Renderer(Vec2 dim)
    : framebuffer(2, dim, DEFAULT_SAMPLES, true), id_resolve(1, dim, 1, false),
      save_buffer(1, dim, DEFAULT_SAMPLES, true), save_output(1, dim, 1, false),
      mesh_shader(GL::Shaders::mesh_v, GL::Shaders::mesh_f),
      line_shader(GL::Shaders::line_v, GL::Shaders::line_f),
      inst_shader(GL::Shaders::inst_v, GL::Shaders::mesh_f),
      dome_shader(GL::Shaders::dome_v, GL::Shaders::dome_f), _sphere(Util::sphere_mesh(1.0f, 3)),
      _cyl(Util::cyl_mesh(1.0f, 1.0f, 64, false)), _hemi(Util::hemi_mesh(1.0f)),
      samples(DEFAULT_SAMPLES), window_dim(dim),
      id_buffer(new GLubyte[(int)dim.x * (int)dim.y * 4]) {}
TheNumbat's avatar
TheNumbat committed
23
24

Renderer::~Renderer() {
TheNumbat's avatar
TheNumbat committed
25
26
    delete[] id_buffer;
    id_buffer = nullptr;
TheNumbat's avatar
TheNumbat committed
27
28
}

TheNumbat's avatar
TheNumbat committed
29
30
31
Renderer &Renderer::get() {
    assert(data);
    return *data;
TheNumbat's avatar
TheNumbat committed
32
33
}

TheNumbat's avatar
TheNumbat committed
34
void Renderer::setup(Vec2 dim) { data = new Renderer(dim); }
TheNumbat's avatar
TheNumbat committed
35
36
37

void Renderer::update_dim(Vec2 dim) {

TheNumbat's avatar
TheNumbat committed
38
39
40
41
42
43
44
    window_dim = dim;
    delete[] id_buffer;
    id_buffer = new GLubyte[(int)dim.x * (int)dim.y * 4]();
    framebuffer.resize(dim, samples);
    save_buffer.resize(dim, save_buffer.samples());
    id_resolve.resize(dim);
    save_output.resize(dim);
TheNumbat's avatar
TheNumbat committed
45
46
47
}

void Renderer::shutdown() {
TheNumbat's avatar
TheNumbat committed
48
49
    delete data;
    data = nullptr;
TheNumbat's avatar
TheNumbat committed
50
51
}

TheNumbat's avatar
TheNumbat committed
52
void Renderer::proj(const Mat4 &proj) { _proj = proj; }
TheNumbat's avatar
TheNumbat committed
53
54
55

void Renderer::complete() {

TheNumbat's avatar
TheNumbat committed
56
57
58
59
    framebuffer.blit_to(1, id_resolve, false);

    if (!id_resolve.can_read_at())
        id_resolve.read(0, id_buffer);
TheNumbat's avatar
TheNumbat committed
60

TheNumbat's avatar
TheNumbat committed
61
    framebuffer.blit_to_screen(0, window_dim);
TheNumbat's avatar
TheNumbat committed
62
63
64
65
}

void Renderer::begin() {

TheNumbat's avatar
TheNumbat committed
66
67
68
69
70
    framebuffer.clear(0, Vec4(Gui::Color::background, 1.0f));
    framebuffer.clear(1, Vec4{0.0f, 0.0f, 0.0f, 1.0f});
    framebuffer.clear_d();
    framebuffer.bind();
    GL::viewport(window_dim);
TheNumbat's avatar
TheNumbat committed
71
72
}

TheNumbat's avatar
TheNumbat committed
73
74
75
void Renderer::save(Scene &scene, const Camera &cam, int w, int h, int s) {

    Vec2 dim((float)w, (float)h);
TheNumbat's avatar
TheNumbat committed
76

TheNumbat's avatar
TheNumbat committed
77
78
79
80
81
    save_buffer.resize(dim, s);
    save_output.resize(dim);
    save_buffer.clear(0, Vec4{0.0f, 0.0f, 0.0f, 1.0f});
    save_buffer.bind();
    GL::viewport(dim);
TheNumbat's avatar
TheNumbat committed
82

TheNumbat's avatar
TheNumbat committed
83
84
85
86
87
88
    Mat4 view = cam.get_view();
    scene.for_items([&](Scene_Item &item) {
        if (item.is<Scene_Light>())
            return;
        item.render(view);
    });
TheNumbat's avatar
TheNumbat committed
89

TheNumbat's avatar
TheNumbat committed
90
    save_buffer.blit_to(0, save_output, true);
TheNumbat's avatar
TheNumbat committed
91

TheNumbat's avatar
TheNumbat committed
92
93
    framebuffer.bind();
    GL::viewport(window_dim);
TheNumbat's avatar
TheNumbat committed
94
95
}

TheNumbat's avatar
TheNumbat committed
96
97
98
99
void Renderer::saved(std::vector<unsigned char> &out) const {
    save_output.flush();
    out.resize(save_output.bytes());
    save_output.read(0, out.data());
TheNumbat's avatar
TheNumbat committed
100
101
102
}

GLuint Renderer::saved() const {
TheNumbat's avatar
TheNumbat committed
103
104
    save_output.flush();
    return save_output.get_output(0);
TheNumbat's avatar
TheNumbat committed
105
106
}

TheNumbat's avatar
TheNumbat committed
107
void Renderer::lines(const GL::Lines &lines, const Mat4 &view, const Mat4 &model, float alpha) {
TheNumbat's avatar
TheNumbat committed
108

TheNumbat's avatar
TheNumbat committed
109
110
111
112
113
    Mat4 mvp = _proj * view * model;
    line_shader.bind();
    line_shader.uniform("mvp", mvp);
    line_shader.uniform("alpha", alpha);
    lines.render(framebuffer.is_multisampled());
TheNumbat's avatar
TheNumbat committed
114
115
}

TheNumbat's avatar
TheNumbat committed
116
void Renderer::skydome(const Mat4 &rotation, Vec3 color, float cosine, const GL::Tex2D &tex) {
TheNumbat's avatar
TheNumbat committed
117

TheNumbat's avatar
TheNumbat committed
118
119
120
121
122
123
124
125
    tex.bind();
    dome_shader.bind();
    dome_shader.uniform("tex", 0);
    dome_shader.uniform("use_texture", true);
    dome_shader.uniform("color", color);
    dome_shader.uniform("cosine", cosine);
    dome_shader.uniform("transform", _proj * rotation);
    _sphere.render();
TheNumbat's avatar
TheNumbat committed
126
127
}

TheNumbat's avatar
TheNumbat committed
128
void Renderer::skydome(const Mat4 &rotation, Vec3 color, float cosine) {
TheNumbat's avatar
TheNumbat committed
129

TheNumbat's avatar
TheNumbat committed
130
131
132
133
134
135
    dome_shader.bind();
    dome_shader.uniform("use_texture", false);
    dome_shader.uniform("color", color);
    dome_shader.uniform("cosine", cosine);
    dome_shader.uniform("transform", _proj * rotation);
    _sphere.render();
TheNumbat's avatar
TheNumbat committed
136
137
}

TheNumbat's avatar
TheNumbat committed
138
void Renderer::sphere(MeshOpt opt) { mesh(_sphere, opt); }
TheNumbat's avatar
TheNumbat committed
139

TheNumbat's avatar
TheNumbat committed
140
void Renderer::capsule(MeshOpt opt, const Mat4 &mdl, float height, float rad, BBox &box) {
TheNumbat's avatar
TheNumbat committed
141

TheNumbat's avatar
TheNumbat committed
142
143
144
145
146
    Mat4 T = opt.modelview;
    Mat4 cyl = mdl * Mat4::scale(Vec3{rad, height, rad});
    Mat4 bot = mdl * Mat4::scale(Vec3{rad});
    Mat4 top = mdl * Mat4::translate(Vec3{0.0f, height, 0.0f}) *
               Mat4::euler(Vec3{180.0f, 0.0f, 0.0f}) * Mat4::scale(Vec3{rad});
TheNumbat's avatar
TheNumbat committed
147
148

    opt.modelview = T * cyl;
TheNumbat's avatar
TheNumbat committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    mesh(_cyl, opt);
    opt.modelview = T * bot;
    mesh(_hemi, opt);
    opt.modelview = T * top;
    mesh(_hemi, opt);

    BBox b = _cyl.bbox();
    b.transform(cyl);
    box.enclose(b);
    b = _hemi.bbox();
    b.transform(bot);
    box.enclose(b);
    b = _hemi.bbox();
    b.transform(top);
    box.enclose(b);
TheNumbat's avatar
TheNumbat committed
164
165
166
}

void Renderer::capsule(MeshOpt opt, float height, float rad) {
TheNumbat's avatar
TheNumbat committed
167
168
    BBox box;
    capsule(opt, Mat4::I, height, rad, box);
TheNumbat's avatar
TheNumbat committed
169
170
}

TheNumbat's avatar
TheNumbat committed
171
void Renderer::mesh(GL::Mesh &mesh, Renderer::MeshOpt opt) {
TheNumbat's avatar
TheNumbat committed
172
173

    mesh_shader.bind();
TheNumbat's avatar
TheNumbat committed
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
    mesh_shader.uniform("use_v_id", opt.per_vert_id);
    mesh_shader.uniform("id", opt.id);
    mesh_shader.uniform("alpha", opt.alpha);
    mesh_shader.uniform("mvp", _proj * opt.modelview);
    mesh_shader.uniform("normal", Mat4::transpose(Mat4::inverse(opt.modelview)));
    mesh_shader.uniform("solid", opt.solid_color);
    mesh_shader.uniform("sel_color", opt.sel_color);
    mesh_shader.uniform("sel_id", opt.sel_id);
    mesh_shader.uniform("hov_color", opt.hov_color);
    mesh_shader.uniform("hov_id", opt.hov_id);

    if (opt.depth_only)
        GL::color_mask(false);

    if (opt.wireframe) {
        mesh_shader.uniform("color", Vec3());
        GL::enable(GL::Opt::wireframe);
        mesh.render();
        GL::disable(GL::Opt::wireframe);
    }

    mesh_shader.uniform("color", opt.color);
    mesh.render();

    if (opt.depth_only)
        GL::color_mask(true);
TheNumbat's avatar
TheNumbat committed
200
201
202
}

void Renderer::set_samples(int s) {
TheNumbat's avatar
TheNumbat committed
203
204
    samples = s;
    framebuffer.resize(window_dim, samples);
TheNumbat's avatar
TheNumbat committed
205
206
207
208
}

Scene_ID Renderer::read_id(Vec2 pos) {

TheNumbat's avatar
TheNumbat committed
209
210
    int x = (int)pos.x;
    int y = (int)(window_dim.y - pos.y - 1);
TheNumbat's avatar
TheNumbat committed
211

TheNumbat's avatar
TheNumbat committed
212
    if (id_resolve.can_read_at()) {
TheNumbat's avatar
TheNumbat committed
213

TheNumbat's avatar
TheNumbat committed
214
215
216
        GLubyte read[4] = {};
        id_resolve.read_at(0, x, y, read);
        return (int)read[0] | (int)read[1] << 8 | (int)read[2] << 16;
TheNumbat's avatar
TheNumbat committed
217

TheNumbat's avatar
TheNumbat committed
218
    } else {
TheNumbat's avatar
TheNumbat committed
219

TheNumbat's avatar
TheNumbat committed
220
221
        int idx = y * (int)window_dim.x * 4 + x * 4;
        assert(id_buffer && idx > 0 && idx <= window_dim.x * window_dim.y * 4);
TheNumbat's avatar
TheNumbat committed
222

TheNumbat's avatar
TheNumbat committed
223
224
225
        int a = id_buffer[idx];
        int b = id_buffer[idx + 1];
        int c = id_buffer[idx + 2];
TheNumbat's avatar
TheNumbat committed
226

TheNumbat's avatar
TheNumbat committed
227
228
        return a | b << 8 | c << 16;
    }
TheNumbat's avatar
TheNumbat committed
229
230
}

TheNumbat's avatar
TheNumbat committed
231
232
233
234
235
void Renderer::reset_depth() { framebuffer.clear_d(); }

void Renderer::begin_outline() { framebuffer.clear_d(); }

void Renderer::end_outline(const Mat4 &view, BBox box) {
TheNumbat's avatar
TheNumbat committed
236

TheNumbat's avatar
TheNumbat committed
237
238
239
    Mat4 viewproj = _proj * view;
    Vec2 min, max;
    box.screen_rect(viewproj, min, max);
TheNumbat's avatar
TheNumbat committed
240

TheNumbat's avatar
TheNumbat committed
241
242
243
    Vec2 thickness = Vec2(3.0f / window_dim.x, 3.0f / window_dim.y);
    GL::Effects::outline(framebuffer, framebuffer, Gui::Color::outline, min - thickness,
                         max + thickness);
TheNumbat's avatar
TheNumbat committed
244
245
}

TheNumbat's avatar
TheNumbat committed
246
void Renderer::outline(const Mat4 &view, Scene_Item &obj) {
TheNumbat's avatar
TheNumbat committed
247

TheNumbat's avatar
TheNumbat committed
248
    Mat4 viewproj = _proj * view;
TheNumbat's avatar
TheNumbat committed
249

TheNumbat's avatar
TheNumbat committed
250
251
    framebuffer.clear_d();
    obj.render(view, false, true);
TheNumbat's avatar
TheNumbat committed
252

TheNumbat's avatar
TheNumbat committed
253
254
    Vec2 min, max;
    obj.bbox().screen_rect(viewproj, min, max);
TheNumbat's avatar
TheNumbat committed
255

TheNumbat's avatar
TheNumbat committed
256
257
258
    Vec2 thickness = Vec2(3.0f / window_dim.x, 3.0f / window_dim.y);
    GL::Effects::outline(framebuffer, framebuffer, Gui::Color::outline, min - thickness,
                         max + thickness);
TheNumbat's avatar
TheNumbat committed
259
260
261
262
}

void Renderer::halfedge_editor(Renderer::HalfedgeOpt opt) {

TheNumbat's avatar
TheNumbat committed
263
264
265
266
    auto [faces, spheres, cylinders, arrows] = opt.editor.shapes();

    MeshOpt fopt = MeshOpt();
    fopt.modelview = opt.modelview;
TheNumbat's avatar
TheNumbat committed
267
    fopt.color = opt.f_color;
TheNumbat's avatar
TheNumbat committed
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
    fopt.per_vert_id = true;
    fopt.sel_color = Gui::Color::outline;
    fopt.sel_id = opt.editor.select_id();
    fopt.hov_color = Gui::Color::hover;
    fopt.hov_id = opt.editor.hover_id();
    Renderer::mesh(faces, fopt);

    inst_shader.bind();
    inst_shader.uniform("use_v_id", true);
    inst_shader.uniform("use_i_id", true);
    inst_shader.uniform("solid", false);
    inst_shader.uniform("proj", _proj);
    inst_shader.uniform("modelview", opt.modelview);
    inst_shader.uniform("alpha", fopt.alpha);
    inst_shader.uniform("sel_color", Gui::Color::outline);
    inst_shader.uniform("hov_color", Gui::Color::hover);
    inst_shader.uniform("sel_id", fopt.sel_id);
    inst_shader.uniform("hov_id", fopt.hov_id);

TheNumbat's avatar
TheNumbat committed
287
    inst_shader.uniform("color", opt.v_color);
TheNumbat's avatar
TheNumbat committed
288
    spheres.render();
TheNumbat's avatar
TheNumbat committed
289
    inst_shader.uniform("color", opt.e_color);
TheNumbat's avatar
TheNumbat committed
290
    cylinders.render();
TheNumbat's avatar
TheNumbat committed
291
    inst_shader.uniform("color", opt.he_color);
TheNumbat's avatar
TheNumbat committed
292
    arrows.render();
TheNumbat's avatar
TheNumbat committed
293
}