Subversion Repositories Games.Carmageddon

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "gl_renderer.h"
2
#include "brender/brender.h"
3
#include "harness.h"
4
#include "harness/trace.h"
5
#include "resources/3d_frag.glsl.h"
6
#include "resources/3d_vert.glsl.h"
7
#include "resources/framebuffer_frag.glsl.h"
8
#include "resources/framebuffer_vert.glsl.h"
9
#include "stored_context.h"
10
 
11
#include <glad/glad.h>
12
#include <stdio.h>
13
#include <string.h>
14
 
15
static GLuint screen_buffer_vao, screen_buffer_ebo;
16
static GLuint fullscreen_quad_texture, palette_texture, depth_texture;
17
 
18
static GLuint shader_program_2d;
19
static GLuint shader_program_3d;
20
static GLuint framebuffer_id, framebuffer_texture = 0;
21
 
22
// holds the latest uploaded version of the colour_buffer. Available in shader for blending
23
static GLuint current_colourbuffer_texture;
24
 
25
static uint8_t gl_palette[4 * 256]; // RGBA
26
static uint8_t* screen_buffer_flip_pixels;
27
static uint16_t* depth_buffer_flip_pixels;
28
 
29
static int render_width, render_height;
30
static int vp_x, vp_y, vp_width, vp_height;
31
 
32
static br_pixelmap *last_colour_buffer, *last_depth_buffer;
33
static int dirty_buffers = 0;
34
 
35
static tStored_material* current_material;
36
static br_pixelmap* current_shade_table;
37
 
38
static br_matrix4 view_matrix;
39
 
40
// Increment flush_counter during flush, and upload_counter when we upload the colour_buffer texture.
41
// If the counters are equal, we can avoid re-uploading the same thing.
42
static unsigned int flush_counter = 0, colourbuffer_upload_counter = 0;
43
 
44
typedef struct gl_vertex {
45
    br_vector3 p;
46
    br_vector2 map;
47
    br_vector3 n;
48
    float colour_index; // float to allow interpolation
49
} gl_vertex;
50
 
51
struct {
52
    GLuint model, view, projection;
53
    // gl_NormalMatrix replacement
54
    GLuint normal_matrix;
55
    GLuint clip_plane_count;
56
    GLuint clip_planes[6];
57
    GLuint colour_buffer_texture;
58
    GLuint viewport_height;
59
 
60
    GLuint material_flags;
61
    GLuint material_texture_enabled;
62
    GLuint material_texture_pixelmap;
63
    GLuint material_uv_transform;
64
    GLuint material_shade_table;
65
    GLuint material_blend_enabled;
66
    GLuint material_blend_table;
67
    GLuint material_index_base;
68
    // GLuint material_index_range;  TODO: re-add when we add untextured lighting
69
    GLuint material_shade_table_height;
70
 
71
} uniforms_3d;
72
 
73
struct {
74
    GLuint pixels, palette;
75
} uniforms_2d;
76
 
77
static GLuint CreateShaderProgram(char* name, const char* vertex_shader, const int vertex_shader_len, const char* fragment_shader, const int fragment_shader_len) {
78
    int success;
79
    char log_buffer[1024];
80
    GLuint program;
81
    GLuint v_shader, f_shader;
82
 
83
    program = glCreateProgram();
84
    v_shader = glCreateShader(GL_VERTEX_SHADER);
85
    const GLchar* vertex_sources[] = { vertex_shader };
86
    glShaderSource(v_shader, 1, vertex_sources, &vertex_shader_len);
87
    glCompileShader(v_shader);
88
    glGetShaderiv(v_shader, GL_COMPILE_STATUS, &success);
89
    if (!success) {
90
        glGetShaderInfoLog(v_shader, 1024, NULL, log_buffer);
91
        LOG_PANIC("shader %s failed to compile: %s", name, log_buffer);
92
    }
93
 
94
    f_shader = glCreateShader(GL_FRAGMENT_SHADER);
95
    const GLchar* fragment_sources[] = { fragment_shader };
96
    glShaderSource(f_shader, 1, fragment_sources, &fragment_shader_len);
97
    glCompileShader(f_shader);
98
    glGetShaderiv(f_shader, GL_COMPILE_STATUS, &success);
99
    if (!success) {
100
        char log_buffer[1024];
101
        glGetShaderInfoLog(f_shader, 1024, NULL, log_buffer);
102
        LOG_PANIC("shader %s failed to compile: %s", name, log_buffer);
103
    }
104
 
105
    glAttachShader(program, v_shader);
106
    glAttachShader(program, f_shader);
107
    glLinkProgram(program);
108
    glDeleteShader(v_shader);
109
    glDeleteShader(f_shader);
110
 
111
    GLint link_ok = GL_FALSE;
112
    glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
113
    if (!link_ok) {
114
        glGetShaderInfoLog(program, 1024, NULL, log_buffer);
115
        LOG_PANIC("shader program %s failed to link: %s", name, log_buffer);
116
    }
117
    return program;
118
}
119
 
120
static GLint GetValidatedUniformLocation(GLuint program, char* uniform_name) {
121
    GLint location;
122
    location = glGetUniformLocation(program, uniform_name);
123
    if (location == -1) {
124
        LOG_PANIC("glGetUniformLocation(%d, %s) failed. Check the shader uniform names.", program, uniform_name);
125
    }
126
    return location;
127
}
128
 
129
static void LoadShaders(void) {
130
    shader_program_2d = CreateShaderProgram("framebuffer", RESOURCES_FRAMEBUFFER_VERT_GLSL, sizeof(RESOURCES_FRAMEBUFFER_VERT_GLSL), RESOURCES_FRAMEBUFFER_FRAG_GLSL, sizeof(RESOURCES_FRAMEBUFFER_FRAG_GLSL));
131
    glUseProgram(shader_program_2d);
132
    uniforms_2d.pixels = GetValidatedUniformLocation(shader_program_2d, "u_pixels");
133
    uniforms_2d.palette = GetValidatedUniformLocation(shader_program_2d, "u_palette");
134
 
135
    // bind the uniform samplers to texture units:
136
    glUniform1i(uniforms_2d.pixels, 0);
137
    glUniform1i(uniforms_2d.palette, 1);
138
 
139
    shader_program_3d = CreateShaderProgram("3d", RESOURCES_3D_VERT_GLSL, sizeof(RESOURCES_3D_VERT_GLSL), RESOURCES_3D_FRAG_GLSL, sizeof(RESOURCES_3D_FRAG_GLSL));
140
    glUseProgram(shader_program_3d);
141
    uniforms_3d.clip_plane_count = GetValidatedUniformLocation(shader_program_3d, "u_clip_plane_count");
142
    for (int i = 0; i < 6; i++) {
143
        char name[32];
144
        sprintf(name, "u_clip_planes[%d]", i);
145
        uniforms_3d.clip_planes[i] = GetValidatedUniformLocation(shader_program_3d, name);
146
    }
147
 
148
    uniforms_3d.model = GetValidatedUniformLocation(shader_program_3d, "u_model");
149
    uniforms_3d.colour_buffer_texture = GetValidatedUniformLocation(shader_program_3d, "u_colour_buffer");
150
    uniforms_3d.projection = GetValidatedUniformLocation(shader_program_3d, "u_projection");
151
    uniforms_3d.view = GetValidatedUniformLocation(shader_program_3d, "u_view");
152
    uniforms_3d.viewport_height = GetValidatedUniformLocation(shader_program_3d, "u_viewport_height");
153
    uniforms_3d.normal_matrix = GetValidatedUniformLocation(shader_program_3d, "u_normal_matrix");
154
 
155
    uniforms_3d.material_flags = GetValidatedUniformLocation(shader_program_3d, "u_material_flags");
156
    uniforms_3d.material_texture_enabled = GetValidatedUniformLocation(shader_program_3d, "u_material_texture_enabled");
157
    uniforms_3d.material_texture_pixelmap = GetValidatedUniformLocation(shader_program_3d, "u_material_texture_pixelmap");
158
    uniforms_3d.material_uv_transform = GetValidatedUniformLocation(shader_program_3d, "u_material_uv_transform");
159
    uniforms_3d.material_shade_table = GetValidatedUniformLocation(shader_program_3d, "u_material_shade_table");
160
    uniforms_3d.material_shade_table_height = GetValidatedUniformLocation(shader_program_3d, "u_material_shade_table_height");
161
    uniforms_3d.material_blend_enabled = GetValidatedUniformLocation(shader_program_3d, "u_material_blend_enabled");
162
    uniforms_3d.material_blend_table = GetValidatedUniformLocation(shader_program_3d, "u_material_blend_table");
163
    uniforms_3d.material_index_base = GetValidatedUniformLocation(shader_program_3d, "u_material_index_base");
164
    // TODO: re-add when we support untextured lighting
165
    // uniforms_3d.material_index_range = GetValidatedUniformLocation(shader_program_3d, "u_material_index_range");
166
 
167
    // bind the uniform samplers to texture units
168
    glUniform1i(uniforms_3d.material_texture_pixelmap, 0);
169
    // palette occupies texture unit 1 but not required during 3d rendering
170
    glUniform1i(uniforms_3d.material_shade_table, 2);
171
    glUniform1i(uniforms_3d.material_blend_table, 3);
172
    glUniform1i(uniforms_3d.colour_buffer_texture, 4);
173
}
174
 
175
static void SetupFullScreenRectGeometry(void) {
176
    float vertices[] = {
177
        // positions          // colors           // texture coords
178
        1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
179
        1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // bottom right
180
        -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
181
        -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
182
    };
183
    unsigned int indices[] = {
184
        0, 1, 3, // first triangle
185
        1, 2, 3  // second triangle
186
    };
187
 
188
    GLuint vbo;
189
    glGenVertexArrays(1, &screen_buffer_vao);
190
    glGenBuffers(1, &vbo);
191
    glGenBuffers(1, &screen_buffer_ebo);
192
 
193
    glBindVertexArray(screen_buffer_vao);
194
 
195
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
196
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
197
 
198
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screen_buffer_ebo);
199
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
200
 
201
    // position attribute
202
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
203
    glEnableVertexAttribArray(0);
204
    // color attribute
205
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
206
    glEnableVertexAttribArray(1);
207
    // texture coord attribute
208
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
209
    glEnableVertexAttribArray(2);
210
 
211
    glBindVertexArray(0);
212
}
213
 
214
void GLRenderer_Init(int pRender_width, int pRender_height) {
215
    render_width = pRender_width;
216
    render_height = pRender_height;
217
 
218
    LOG_INFO("OpenGL vendor string: %s", glGetString(GL_VENDOR));
219
    LOG_INFO("OpenGL renderer string: %s", glGetString(GL_RENDERER));
220
    LOG_INFO("OpenGL version string: %s", glGetString(GL_VERSION));
221
    LOG_INFO("OpenGL shading language version string: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
222
 
14 pmbaty 223
    if (glGetString(GL_SHADING_LANGUAGE_VERSION) == NULL) {
224
        LOG_PANIC("GL_SHADING_LANGUAGE_VERSION is null");
225
    }
226
 
1 pmbaty 227
    LoadShaders();
228
    SetupFullScreenRectGeometry();
229
 
230
    // config
231
    glDisable(GL_BLEND);
232
    glDepthFunc(GL_LESS);
233
    glClearColor(0, 0, 0, 1.0f);
234
    glClear(GL_COLOR_BUFFER_BIT);
235
    glEnable(GL_CULL_FACE);
236
    glCullFace(GL_BACK);
237
 
238
    // textures
239
    glGenTextures(1, &fullscreen_quad_texture);
240
    glGenTextures(1, &palette_texture);
241
    glGenTextures(1, &framebuffer_texture);
242
    glGenTextures(1, &depth_texture);
243
    glGenTextures(1, &current_colourbuffer_texture);
244
 
245
    // setup framebuffer
246
    glGenFramebuffers(1, &framebuffer_id);
247
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
248
 
249
    // set pixel storage alignment to 1 byte
250
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
251
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
252
 
253
    glBindTexture(GL_TEXTURE_2D, fullscreen_quad_texture);
254
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
255
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
256
 
257
    glBindTexture(GL_TEXTURE_2D, palette_texture);
258
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
259
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
260
 
261
    glBindTexture(GL_TEXTURE_2D, framebuffer_texture);
262
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, render_width, render_height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL);
263
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
264
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
265
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer_texture, 0);
266
 
267
    glBindTexture(GL_TEXTURE_2D, current_colourbuffer_texture);
268
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
270
 
271
    glBindTexture(GL_TEXTURE_2D, depth_texture);
272
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, render_width, render_height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0);
273
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
274
 
275
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
276
        LOG_PANIC("Framebuffer is not complete!");
277
    }
278
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
279
 
280
    screen_buffer_flip_pixels = malloc(sizeof(uint8_t) * render_width * render_height);
281
    depth_buffer_flip_pixels = malloc(sizeof(uint16_t) * render_width * render_height);
282
 
283
    CHECK_GL_ERROR("initializeOpenGLContext");
284
}
285
 
286
void GLRenderer_SetPalette(uint8_t* rgba_colors) {
287
    for (int i = 0; i < 256; i++) {
288
        gl_palette[i * 4] = rgba_colors[i * 4 + 2];
289
        gl_palette[i * 4 + 1] = rgba_colors[i * 4 + 1];
290
        gl_palette[i * 4 + 2] = rgba_colors[i * 4];
291
        // palette index 0 is transparent, so set alpha to 0
292
        if (i == 0) {
293
            gl_palette[i * 4 + 3] = 0;
294
        } else {
295
            gl_palette[i * 4 + 3] = 0xff;
296
        }
297
    }
298
 
299
    glActiveTexture(GL_TEXTURE1);
300
    glBindTexture(GL_TEXTURE_2D, palette_texture);
301
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gl_palette);
302
 
303
    // reset active texture back to default
304
    glActiveTexture(GL_TEXTURE0);
305
 
306
    CHECK_GL_ERROR("GLRenderer_SetPalette");
307
}
308
 
309
void GLRenderer_SetShadeTable(br_pixelmap* table) {
310
    if (current_shade_table == table) {
311
        return;
312
    }
313
 
314
    // shade table uses texture unit 2
315
    glActiveTexture(GL_TEXTURE2);
316
    tStored_pixelmap* stored = table->stored;
317
    glBindTexture(GL_TEXTURE_2D, stored->id);
318
 
319
    // reset active texture back to default
320
    glActiveTexture(GL_TEXTURE0);
321
    current_shade_table = table;
322
}
323
 
324
void GLRenderer_SetBlendTable(br_pixelmap* table) {
325
 
326
    if (flush_counter != colourbuffer_upload_counter) {
327
        GLRenderer_FlushBuffer(eFlush_color_buffer);
328
        glActiveTexture(GL_TEXTURE4);
329
        glBindTexture(GL_TEXTURE_2D, current_colourbuffer_texture);
330
        glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, render_width, render_height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, last_colour_buffer->pixels);
331
        colourbuffer_upload_counter = flush_counter;
332
    }
333
 
334
    // blend table uses texture unit 3
335
    glActiveTexture(GL_TEXTURE3);
336
    tStored_pixelmap* stored = table->stored;
337
    glBindTexture(GL_TEXTURE_2D, stored->id);
338
 
339
    // reset active texture back to default
340
    glActiveTexture(GL_TEXTURE0);
341
}
342
 
343
extern br_v1db_state v1db;
344
 
345
void GLRenderer_BeginScene(br_actor* camera, br_pixelmap* colour_buffer, br_pixelmap* depth_buffer) {
346
    last_colour_buffer = colour_buffer;
347
    last_depth_buffer = depth_buffer;
348
    glViewport(colour_buffer->base_x, render_height - colour_buffer->height - colour_buffer->base_y, colour_buffer->width, colour_buffer->height);
349
    glUseProgram(shader_program_3d);
350
    glUniform1ui(uniforms_3d.viewport_height, render_height);
351
 
352
    br_camera* cam = camera->type_data;
353
    current_material = NULL;
354
    current_shade_table = NULL;
355
 
356
    // clip planes
357
    int enabled_clip_planes = 0;
358
    for (int i = 0; i < v1db.enabled_clip_planes.max; i++) {
359
        if (v1db.enabled_clip_planes.enabled == NULL || !v1db.enabled_clip_planes.enabled[i]) {
360
            continue;
361
        }
362
        br_vector4* v4 = v1db.enabled_clip_planes.enabled[i]->type_data;
363
        glUniform4f(uniforms_3d.clip_planes[enabled_clip_planes], v4->v[0], v4->v[1], v4->v[2], v4->v[3]);
364
        enabled_clip_planes++;
365
    }
366
    glUniform1i(uniforms_3d.clip_plane_count, enabled_clip_planes);
367
 
368
    // view matrix
369
    BrMatrix4Copy34(&view_matrix, &v1db.camera_path[0].m);
370
    BrMatrix4Inverse(&view_matrix, &view_matrix);
371
    glUniformMatrix4fv(uniforms_3d.view, 1, GL_FALSE, &view_matrix.m[0][0]);
372
 
373
    // projection matrix
374
    br_matrix4 projection;
375
    BrMatrix4Perspective(&projection, cam->field_of_view, cam->aspect, cam->hither_z, cam->yon_z);
376
    // hack: not sure why we have to do this, but this makes the result the same as `glm_perspective`
377
    projection.m[2][2] *= -1;
378
    glUniformMatrix4fv(uniforms_3d.projection, 1, GL_FALSE, &projection.m[0][0]);
379
 
380
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
381
}
382
 
383
void GLRenderer_EndScene(void) {
384
    //  switch back to default fb and reset state
385
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
386
    glDepthMask(GL_TRUE);
387
    glDepthMask(GL_TRUE);
388
    CHECK_GL_ERROR("GLRenderer_EndScene");
389
}
390
 
391
void GLRenderer_FullScreenQuad(uint8_t* screen_buffer) {
392
 
393
    glViewport(vp_x, vp_y, vp_width, vp_height);
394
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
395
    glDisable(GL_DEPTH_TEST);
396
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
397
 
398
    glBindTexture(GL_TEXTURE_2D, fullscreen_quad_texture);
399
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, render_width, render_height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, screen_buffer);
400
 
401
    glBindVertexArray(screen_buffer_vao);
402
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screen_buffer_ebo);
403
    glUseProgram(shader_program_2d);
404
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
405
    glBindVertexArray(0);
406
 
407
    glEnable(GL_DEPTH_TEST);
408
    CHECK_GL_ERROR("GLRenderer_RenderFullScreenQuad");
409
}
410
 
411
void GLRenderer_ClearBuffers(void) {
412
    // clear our virtual framebuffer
413
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
414
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
415
 
416
    // clear real framebuffer
417
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
418
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
419
 
420
    CHECK_GL_ERROR("GLRenderer_ClearBuffers");
421
}
422
 
423
void GLRenderer_BufferModel(br_model* model) {
424
    tStored_model_context* ctx;
425
    v11model* v11;
426
 
427
    if (model->stored != NULL) {
428
        LOG_PANIC("trying to build a stored model");
429
    }
430
 
431
    v11 = model->prepared;
432
    ctx = NewStoredModelContext();
433
 
434
    int total_verts = 0, total_faces = 0;
435
    for (int i = 0; i < v11->ngroups; i++) {
436
        total_verts += v11->groups[i].nvertices;
437
        total_faces += v11->groups[i].nfaces;
438
    }
439
 
440
    // override normals
441
    br_vector3 v3 = { { 0, 0, 0 } };
442
    for (int g = 0; g < v11->ngroups; g++) {
443
        for (int i = 0; i < v11->groups[g].nvertices; i++) {
444
            v11->groups[g].vertices[i].n = v3;
445
        }
446
    }
447
    br_vector3 v0v1, v2v1, normal;
448
    for (int g = 0; g < v11->ngroups; g++) {
449
        v11group* group = &v11->groups[g];
450
        for (int i = 0; i < group->nfaces; i++) {
451
            v11face* f = &group->faces[i];
452
            fmt_vertex* v0 = &group->vertices[f->vertices[0]];
453
            fmt_vertex* v1 = &group->vertices[f->vertices[1]];
454
            fmt_vertex* v2 = &group->vertices[f->vertices[2]];
455
            BrVector3Sub(&v0v1, &v0->p, &v1->p);
456
            BrVector3Sub(&v2v1, &v2->p, &v1->p);
457
            BrVector3Cross(&normal, &v0v1, &v2v1);
458
            BrVector3Accumulate(&v0->n, &normal);
459
            BrVector3Accumulate(&v1->n, &normal);
460
            BrVector3Accumulate(&v2->n, &normal);
461
        }
462
    }
463
    for (int g = 0; g < v11->ngroups; g++) {
464
        for (int i = 0; i < v11->groups[g].nvertices; i++) {
465
            BrVector3Normalise(&v11->groups[g].vertices[i].n, &v11->groups[g].vertices[i].n);
466
        }
467
    }
468
 
469
    gl_vertex* verts = malloc(sizeof(gl_vertex) * total_verts);
470
    unsigned int* indices = malloc(sizeof(int) * 3 * total_faces);
471
 
472
    int v_index = 0;
473
    int i_index = 0;
474
    int face_offset = 0;
475
    for (int g = 0; g < v11->ngroups; g++) {
476
        for (int i = 0; i < v11->groups[g].nvertices; i++) {
477
            fmt_vertex* v = &v11->groups[g].vertices[i];
478
            verts[v_index].p = v->p;
479
            verts[v_index].n = v->n;
480
            verts[v_index].map = v->map;
481
            verts[v_index].colour_index = BR_ALPHA(v11->groups[g].vertex_colours[i]);
482
            v_index++;
483
        }
484
        for (int i = 0; i < v11->groups[g].nfaces; i++) {
485
            v11face* f = &v11->groups[g].faces[i];
486
            indices[i_index++] = f->vertices[0] + face_offset;
487
            indices[i_index++] = f->vertices[1] + face_offset;
488
            indices[i_index++] = f->vertices[2] + face_offset;
489
        }
490
        face_offset += v11->groups[g].nvertices;
491
    }
492
 
493
    glGenVertexArrays(1, &ctx->vao_id);
494
    glGenBuffers(1, &ctx->vbo_id);
495
    glGenBuffers(1, &ctx->ebo_id);
496
 
497
    // Vertices
498
    glBindVertexArray(ctx->vao_id);
499
    glBindBuffer(GL_ARRAY_BUFFER, ctx->vbo_id);
500
    glBufferData(GL_ARRAY_BUFFER, sizeof(gl_vertex) * total_verts, verts, GL_STATIC_DRAW);
501
    // pos
502
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, p));
503
    glEnableVertexAttribArray(0);
504
    // normal
505
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, n));
506
    glEnableVertexAttribArray(1);
507
    // uv coordinates
508
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, map));
509
    glEnableVertexAttribArray(2);
510
    // color
511
    glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(gl_vertex), (void*)offsetof(gl_vertex, colour_index));
512
    glEnableVertexAttribArray(3);
513
 
514
    // Indices
515
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx->ebo_id);
516
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 3 * total_faces, indices, GL_STATIC_DRAW);
517
    glBindVertexArray(0);
518
 
519
    free(verts);
520
    free(indices);
521
 
522
    model->stored = ctx;
523
 
524
    CHECK_GL_ERROR("after build model");
525
}
526
 
527
void setActiveMaterial(tStored_material* material) {
528
    if (material == NULL || material == current_material) {
529
        return;
530
    }
531
 
532
    glUniformMatrix2x3fv(uniforms_3d.material_uv_transform, 1, GL_TRUE, &material->map_transform.m[0][0]);
533
 
534
    if (material->pixelmap) {
535
        tStored_pixelmap* stored_px = material->pixelmap->stored;
536
        if (stored_px == NULL) {
537
            LOG_PANIC("stored_px is null for pixelmap %s", material->pixelmap->identifier);
538
        }
539
        glBindTexture(GL_TEXTURE_2D, stored_px->id);
540
        glUniform1ui(uniforms_3d.material_texture_enabled, 1);
541
    } else {
542
        glUniform1ui(uniforms_3d.material_texture_enabled, 0);
543
 
544
        // index_base and index_range are only used for untextured materials
545
        glUniform1ui(uniforms_3d.material_index_base, material->index_base);
546
        // glUniform1ui(uniforms_3d.material_index_range, material->index_range);  TODO: re-add when we support untextured lighting
547
    }
548
 
549
    if (material->shade_table) {
550
        glUniform1ui(uniforms_3d.material_shade_table_height, material->shade_table->height);
551
        GLRenderer_SetShadeTable(material->shade_table);
552
    }
553
 
554
    if (material->index_blend) {
555
        glUniform1ui(uniforms_3d.material_blend_enabled, 1);
556
        GLRenderer_SetBlendTable(material->index_blend);
557
        // materials with index_blend do not write to depth buffer (https://www.cwaboard.co.uk/viewtopic.php?p=105846&sid=58ad8910238000ca14b01dad85117175#p105846)
558
        glDepthMask(GL_FALSE);
559
    } else {
560
        glUniform1ui(uniforms_3d.material_blend_enabled, 0);
561
        glDepthMask(GL_TRUE);
562
    }
563
 
564
    glUniform1ui(uniforms_3d.material_flags, material->flags);
565
 
566
    if (material->flags & (BR_MATF_TWO_SIDED | BR_MATF_ALWAYS_VISIBLE)) {
567
        glDisable(GL_CULL_FACE);
568
    } else {
569
        glEnable(GL_CULL_FACE);
570
    }
571
 
572
    CHECK_GL_ERROR("GLRenderer_RenderModelxx");
573
}
574
 
575
void GLRenderer_Model(br_actor* actor, br_model* model, br_material* material, br_token render_type, br_matrix34 model_matrix) {
576
    tStored_model_context* ctx;
577
    v11group* group;
578
    int element_index = 0;
579
 
580
    if (model->flags & BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE) {
581
        if (model->stored) {
582
            ((br_object*)model->stored)->dispatch->_free((br_object*)model->stored);
583
            model->stored = NULL;
584
        }
585
        GLRenderer_BufferModel(model);
586
        model->flags &= ~BR_MODF_DETHRACE_FORCE_BUFFER_UPDATE;
587
    }
588
 
589
    ctx = model->stored;
590
    v11model* v11 = model->prepared;
591
 
592
    if (v11 == NULL) {
593
        // LOG_WARN("No model prepared for %s", model->identifier);
594
        return;
595
    }
596
 
597
    // model matrix
598
    br_matrix4 view_model_matrix, model_matrix4, inverse, inverse_transpose;
599
    BrMatrix4Copy34(&model_matrix4, &model_matrix);
600
    glUniformMatrix4fv(uniforms_3d.model, 1, GL_FALSE, model_matrix4.m[0]);
601
 
602
    // normal matrix (http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/)
603
    BrMatrix4Mul(&view_model_matrix, &view_matrix, &model_matrix4);
604
    BrMatrix4Inverse(&inverse, &view_model_matrix);
605
    // transpose
606
    for (int i = 0; i < 4; i++) {
607
        for (int j = 0; j < 4; j++) {
608
            inverse_transpose.m[i][j] = inverse.m[j][i];
609
        }
610
    }
611
    glUniformMatrix4fv(uniforms_3d.normal_matrix, 1, GL_FALSE, &inverse_transpose.m[0][0]);
612
 
613
    glBindVertexArray(ctx->vao_id);
614
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ctx->ebo_id);
615
 
616
    // set default material for this actor/model
617
    setActiveMaterial(material->stored);
618
 
619
    switch (render_type) {
620
    case BRT_TRIANGLE:
621
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
622
        break;
623
    case BRT_LINE:
624
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
625
        glUniform1ui(uniforms_3d.material_index_base, 255);
626
        glUniform1ui(uniforms_3d.material_flags, 0);
627
        break;
628
    default:
629
        LOG_PANIC("render_type %d is not supported?!", render_type);
630
    }
631
 
632
    for (int g = 0; g < v11->ngroups; g++) {
633
        group = &v11->groups[g];
634
        setActiveMaterial(group->stored);
635
        glDrawElements(GL_TRIANGLES, group->nfaces * 3, GL_UNSIGNED_INT, (void*)(element_index * sizeof(int)));
636
        element_index += group->nfaces * 3;
637
    }
638
 
639
    glBindVertexArray(0);
640
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
641
    dirty_buffers = 1;
642
 
643
    CHECK_GL_ERROR("GLRenderer_RenderModel");
644
}
645
 
646
void GLRenderer_BufferMaterial(br_material* mat) {
647
    tStored_material* stored = mat->stored;
648
    if (!stored) {
649
        stored = NewStoredMaterial();
650
        mat->stored = stored;
651
        if (mat->identifier) {
652
            strcpy(stored->identifier, mat->identifier);
653
        }
654
    }
655
    BrMatrix23Copy(&stored->map_transform, &mat->map_transform);
656
    stored->pixelmap = mat->colour_map;
657
    stored->flags = mat->flags;
658
    stored->shade_table = mat->index_shade;
659
    stored->index_base = mat->index_base;
660
    stored->index_range = mat->index_range;
661
    stored->index_blend = mat->index_blend;
662
}
663
 
664
void GLRenderer_BufferTexture(br_pixelmap* pm) {
665
    tStored_pixelmap* stored = pm->stored;
666
    if (pm->stored) {
667
    } else {
668
        stored = NewStoredPixelmap();
669
        glGenTextures(1, &stored->id);
670
        pm->stored = stored;
671
    }
672
 
673
    // sometimes the pixelmap has row_bytes > width. OpenGL expects linear pixels, so flatten it out
674
    uint8_t* linear_pixels = malloc(sizeof(uint8_t) * pm->width * pm->height);
675
    uint8_t* original_pixels = pm->pixels;
676
    for (int y = 0; y < pm->height; y++) {
677
        for (int x = 0; x < pm->width; x++) {
678
            linear_pixels[y * pm->width + x] = original_pixels[y * pm->row_bytes + x];
679
        }
680
    }
681
 
682
    glBindTexture(GL_TEXTURE_2D, stored->id);
683
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
684
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
685
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, pm->width, pm->height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, linear_pixels);
686
    free(linear_pixels);
687
 
688
    CHECK_GL_ERROR("GLRenderer_BufferTexture");
689
}
690
 
691
void GLRenderer_FlushBuffer(tRenderer_flush_type flush_type) {
692
 
693
    if (!dirty_buffers) {
694
        return;
695
    }
696
 
697
    // pull framebuffer into cpu memory to emulate BRender behavior
698
    glBindTexture(GL_TEXTURE_2D, framebuffer_texture);
699
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, screen_buffer_flip_pixels);
700
 
701
    // flip texture to match the expected orientation
702
    int dest_y = render_height;
703
    uint8_t* pm_pixels = last_colour_buffer->pixels;
704
    uint8_t new_pixel;
705
    for (int y = 0; y < render_height; y++) {
706
        dest_y--;
707
        for (int x = 0; x < render_width; x++) {
708
            new_pixel = screen_buffer_flip_pixels[y * render_width + x];
709
            if (new_pixel != 0) {
710
                pm_pixels[dest_y * render_width + x] = new_pixel;
711
            }
712
        }
713
    }
714
 
715
    if (flush_type == eFlush_all) {
716
 
717
        // pull depthbuffer into cpu memory to emulate BRender behavior
718
        glBindTexture(GL_TEXTURE_2D, depth_texture);
719
        glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, depth_buffer_flip_pixels);
720
 
721
        dest_y = last_colour_buffer->height;
722
        int src_y = render_height - last_colour_buffer->base_y - last_colour_buffer->height;
723
        uint16_t* depth_pixels = last_depth_buffer->pixels;
724
        for (int y = 0; y < last_colour_buffer->height; y++) {
725
            dest_y--;
726
            for (int x = 0; x < last_colour_buffer->width; x++) {
727
                uint16_t new_depth = depth_buffer_flip_pixels[src_y * render_width + last_colour_buffer->base_x + x];
728
                depth_pixels[dest_y * render_width + x] = new_depth;
729
            }
730
            src_y++;
731
        }
732
    }
733
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
734
    glClear(GL_COLOR_BUFFER_BIT);
735
    flush_counter++;
736
    dirty_buffers = 0;
737
}
738
 
739
void GLRenderer_FlushBuffers(void) {
740
    GLRenderer_FlushBuffer(eFlush_all);
741
}
742
 
743
void GLRenderer_SetViewport(int x, int y, int width, int height) {
744
    vp_x = x;
745
    vp_y = y;
746
    vp_width = width;
747
    vp_height = height;
748
}