generalization of deferred commands and any_gl rendering where appropriate
This commit is contained in:
parent
edcb7fc39c
commit
33471b4c46
@ -109,4 +109,7 @@ typedef struct {
|
|||||||
};
|
};
|
||||||
} DeferredCommand;
|
} DeferredCommand;
|
||||||
|
|
||||||
|
|
||||||
|
extern DeferredCommand *deferred_commands;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "twn_camera_c.h"
|
#include "twn_camera_c.h"
|
||||||
#include "twn_types.h"
|
#include "twn_types.h"
|
||||||
#include "twn_vec.h"
|
#include "twn_vec.h"
|
||||||
|
#include "twn_deferred_commands.h"
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <stb_ds.h>
|
#include <stb_ds.h>
|
||||||
@ -18,6 +19,8 @@
|
|||||||
#include <tgmath.h>
|
#include <tgmath.h>
|
||||||
|
|
||||||
|
|
||||||
|
DeferredCommand *deferred_commands;
|
||||||
|
|
||||||
/* TODO: have a default initialized one */
|
/* TODO: have a default initialized one */
|
||||||
Matrix4 camera_projection_matrix;
|
Matrix4 camera_projection_matrix;
|
||||||
Matrix4 camera_look_at_matrix;
|
Matrix4 camera_look_at_matrix;
|
||||||
@ -401,3 +404,125 @@ DrawCameraFromPrincipalAxesResult draw_camera_from_principal_axes(Vec3 position,
|
|||||||
.up = camera.up,
|
.up = camera.up,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_depth_range(double low, double high) {
|
||||||
|
DeferredCommand const command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_DEPTH_RANGE,
|
||||||
|
.depth_range = {
|
||||||
|
.low = low,
|
||||||
|
.high = high
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clear_draw_buffer(void) {
|
||||||
|
/* TODO: we can optimize a rectangle drawn over whole window to a clear color call*/
|
||||||
|
|
||||||
|
DeferredCommand command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_CLEAR,
|
||||||
|
.clear = (DeferredCommandClear) {
|
||||||
|
.clear_color = true,
|
||||||
|
.clear_depth = true,
|
||||||
|
.clear_stencil = true,
|
||||||
|
.color = (Color) { 230, 230, 230, 1 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void use_texture_mode(TextureMode mode) {
|
||||||
|
DeferredCommand const command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE,
|
||||||
|
.use_texture_mode = { mode }
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void use_2d_pipeline(void) {
|
||||||
|
DeferredCommand const command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
|
||||||
|
.use_pipeline = { PIPELINE_2D }
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void use_space_pipeline(void) {
|
||||||
|
DeferredCommand const command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
|
||||||
|
.use_pipeline = { PIPELINE_SPACE }
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void issue_deferred_draw_commands(void) {
|
||||||
|
for (size_t i = 0; i < arrlenu(deferred_commands); ++i) {
|
||||||
|
switch (deferred_commands[i].type) {
|
||||||
|
case DEFERRED_COMMAND_TYPE_DEPTH_RANGE: {
|
||||||
|
finally_set_depth_range(deferred_commands[i].depth_range);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_CLEAR: {
|
||||||
|
finally_clear_draw_buffer(deferred_commands[i].clear);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_DRAW: {
|
||||||
|
finally_draw_command(deferred_commands[i].draw);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_DRAW_SKYBOX: {
|
||||||
|
finally_render_skybox(deferred_commands[i].draw_skybox);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_USE_PIPIELINE: {
|
||||||
|
switch (deferred_commands[i].use_pipeline.pipeline) {
|
||||||
|
case PIPELINE_2D:
|
||||||
|
finally_use_2d_pipeline();
|
||||||
|
break;
|
||||||
|
case PIPELINE_SPACE:
|
||||||
|
finally_use_space_pipeline();
|
||||||
|
break;
|
||||||
|
case PIPELINE_NO:
|
||||||
|
default:
|
||||||
|
SDL_assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE: {
|
||||||
|
finally_use_texture_mode(deferred_commands[i].use_texture_mode.mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_APPLY_FOG: {
|
||||||
|
finally_apply_fog(deferred_commands[i].apply_fog);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFERRED_COMMAND_TYPE_POP_FOG: {
|
||||||
|
finally_pop_fog();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
SDL_assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#ifndef TWN_DRAW_C_H
|
#ifndef TWN_DRAW_C_H
|
||||||
#define TWN_DRAW_C_H
|
#define TWN_DRAW_C_H
|
||||||
|
|
||||||
|
/* TODO: structure more categorically */
|
||||||
|
|
||||||
#include "twn_textures_c.h"
|
#include "twn_textures_c.h"
|
||||||
#include "twn_text_c.h"
|
#include "twn_text_c.h"
|
||||||
#include "twn_option.h"
|
#include "twn_option.h"
|
||||||
|
#include "twn_deferred_commands.h"
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <stb_truetype.h>
|
#include <stb_truetype.h>
|
||||||
@ -173,10 +176,12 @@ bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
|
|||||||
void setup_viewport(int x, int y, int width, int height);
|
void setup_viewport(int x, int y, int width, int height);
|
||||||
|
|
||||||
void clear_draw_buffer(void);
|
void clear_draw_buffer(void);
|
||||||
|
void finally_clear_draw_buffer(DeferredCommandClear command);
|
||||||
|
|
||||||
void swap_buffers(void);
|
void swap_buffers(void);
|
||||||
|
|
||||||
void set_depth_range(double low, double high);
|
void set_depth_range(double low, double high);
|
||||||
|
void finally_set_depth_range(DeferredCommandDepthRange command);
|
||||||
|
|
||||||
VertexBuffer get_quad_element_buffer(void);
|
VertexBuffer get_quad_element_buffer(void);
|
||||||
|
|
||||||
@ -187,10 +192,13 @@ void render_circle(const CirclePrimitive *circle);
|
|||||||
void render_rectangle(const RectPrimitive *rectangle);
|
void render_rectangle(const RectPrimitive *rectangle);
|
||||||
|
|
||||||
void use_space_pipeline(void);
|
void use_space_pipeline(void);
|
||||||
|
void finally_use_space_pipeline(void);
|
||||||
|
|
||||||
void use_2d_pipeline(void);
|
void use_2d_pipeline(void);
|
||||||
|
void finally_use_2d_pipeline(void);
|
||||||
|
|
||||||
void use_texture_mode(TextureMode mode);
|
void use_texture_mode(TextureMode mode);
|
||||||
|
void finally_use_texture_mode(TextureMode mode);
|
||||||
|
|
||||||
void finally_render_quads(Primitive2D const primitives[],
|
void finally_render_quads(Primitive2D const primitives[],
|
||||||
struct QuadBatch batch,
|
struct QuadBatch batch,
|
||||||
@ -220,19 +228,18 @@ void finally_draw_text(FontData const *font_data,
|
|||||||
VertexBuffer buffer);
|
VertexBuffer buffer);
|
||||||
|
|
||||||
void render_skybox(void);
|
void render_skybox(void);
|
||||||
|
void finally_render_skybox(DeferredCommandDrawSkybox);
|
||||||
void finally_render_skybox(char *paths_in_use);
|
|
||||||
|
|
||||||
void apply_fog(void);
|
void apply_fog(void);
|
||||||
|
void finally_apply_fog(DeferredCommandApplyFog);
|
||||||
void finally_apply_fog(float start, float end, float density, Color color);
|
|
||||||
|
|
||||||
void pop_fog(void);
|
void pop_fog(void);
|
||||||
|
|
||||||
void finally_pop_fog(void);
|
void finally_pop_fog(void);
|
||||||
|
|
||||||
void start_render_frame(void);
|
void start_render_frame(void);
|
||||||
|
|
||||||
void end_render_frame(void);
|
void end_render_frame(void);
|
||||||
|
|
||||||
|
void finally_draw_command(DeferredCommandDraw command);
|
||||||
|
|
||||||
|
void issue_deferred_draw_commands(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "twn_draw.h"
|
#include "twn_draw.h"
|
||||||
#include "twn_draw_c.h"
|
#include "twn_draw_c.h"
|
||||||
|
|
||||||
|
#include <stb_ds.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
static float start_cache, end_cache, density_cache;
|
static float start_cache, end_cache, density_cache;
|
||||||
@ -21,7 +23,17 @@ void apply_fog(void) {
|
|||||||
if (!fog_used)
|
if (!fog_used)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
finally_apply_fog(start_cache, end_cache, density_cache, color_cache);
|
DeferredCommand command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_APPLY_FOG,
|
||||||
|
.apply_fog = (DeferredCommandApplyFog){
|
||||||
|
.start = start_cache,
|
||||||
|
.end = end_cache,
|
||||||
|
.density = density_cache,
|
||||||
|
.color = color_cache
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -29,5 +41,9 @@ void pop_fog(void) {
|
|||||||
if (!fog_used)
|
if (!fog_used)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
finally_pop_fog();
|
DeferredCommand command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_POP_FOG,
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "twn_text_c.h"
|
#include "twn_text_c.h"
|
||||||
#include "twn_types.h"
|
#include "twn_types.h"
|
||||||
#include "twn_deferred_commands.h"
|
#include "twn_deferred_commands.h"
|
||||||
|
#include "twn_gl_any_rendering_c.h"
|
||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include <stb_ds.h>
|
#include <stb_ds.h>
|
||||||
@ -81,219 +82,6 @@ static TextureMode texture_mode_last_used = TEXTURE_MODE_UNKNOWN;
|
|||||||
static Pipeline pipeline_last_used = PIPELINE_NO;
|
static Pipeline pipeline_last_used = PIPELINE_NO;
|
||||||
|
|
||||||
|
|
||||||
/* potentially double buffered array of vertex array handles */
|
|
||||||
/* we assume they will be refilled fully each frame */
|
|
||||||
static size_t scratch_va_front_used, scratch_va_back_used;
|
|
||||||
static GLuint *front_scratch_vertex_arrays, *back_scratch_vertex_arrays;
|
|
||||||
static GLuint **current_scratch_vertex_array = &front_scratch_vertex_arrays;
|
|
||||||
|
|
||||||
static void restart_scratch_vertex_arrays(void) {
|
|
||||||
scratch_va_front_used = 0;
|
|
||||||
scratch_va_back_used = 0;
|
|
||||||
|
|
||||||
if (ctx.render_double_buffered) {
|
|
||||||
current_scratch_vertex_array = current_scratch_vertex_array == &front_scratch_vertex_arrays ?
|
|
||||||
&back_scratch_vertex_arrays : &front_scratch_vertex_arrays;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GLuint get_scratch_vertex_array(void) {
|
|
||||||
size_t *used = current_scratch_vertex_array == &front_scratch_vertex_arrays ?
|
|
||||||
&scratch_va_front_used : &scratch_va_back_used;
|
|
||||||
|
|
||||||
if (arrlenu(*current_scratch_vertex_array) <= *used) {
|
|
||||||
GLuint handle;
|
|
||||||
glGenBuffers(1, &handle);
|
|
||||||
arrpush(*current_scratch_vertex_array, handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
(*used)++;
|
|
||||||
return (*current_scratch_vertex_array)[*used - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void finally_use_2d_pipeline(void);
|
|
||||||
static void finally_use_space_pipeline(void);
|
|
||||||
static void finally_use_texture_mode(TextureMode mode);
|
|
||||||
static void deferred_render_skybox(char *paths);
|
|
||||||
static void deferred_apply_fog(float start, float end, float density, Color color);
|
|
||||||
static void deferred_pop_fog(void);
|
|
||||||
|
|
||||||
static DeferredCommand *deferred_commands;
|
|
||||||
|
|
||||||
static void issue_deferred_draw_commands(void) {
|
|
||||||
for (size_t i = 0; i < arrlenu(deferred_commands); ++i) {
|
|
||||||
switch (deferred_commands[i].type) {
|
|
||||||
case DEFERRED_COMMAND_TYPE_DEPTH_RANGE: {
|
|
||||||
glDepthRange(deferred_commands[i].depth_range.low, deferred_commands[i].depth_range.high);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DEFERRED_COMMAND_TYPE_CLEAR: {
|
|
||||||
glClearColor((1.0f / 255) * deferred_commands[i].clear.color.r,
|
|
||||||
(1.0f / 255) * deferred_commands[i].clear.color.g,
|
|
||||||
(1.0f / 255) * deferred_commands[i].clear.color.b,
|
|
||||||
(1.0f / 255) * deferred_commands[i].clear.color.a);
|
|
||||||
|
|
||||||
/* needed as we might mess with it */
|
|
||||||
glDepthRange(0.0, 1.0);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
|
|
||||||
glClear((deferred_commands[i].clear.clear_color ? GL_COLOR_BUFFER_BIT : 0) |
|
|
||||||
(deferred_commands[i].clear.clear_depth ? GL_DEPTH_BUFFER_BIT : 0) |
|
|
||||||
(deferred_commands[i].clear.clear_stencil ? GL_STENCIL_BUFFER_BIT : 0) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEFERRED_COMMAND_TYPE_DRAW: {
|
|
||||||
DeferredCommandDraw const command = deferred_commands[i].draw;
|
|
||||||
|
|
||||||
/* TODO: don't assume a single vertex array ? */
|
|
||||||
SDL_assert(command.vertices.arity != 0);
|
|
||||||
SDL_assert(command.vertices.buffer);
|
|
||||||
SDL_assert((command.element_buffer && command.element_count != 0) || command.primitive_count != 0);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, command.vertices.buffer);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, command.element_buffer);
|
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glVertexPointer(command.vertices.arity,
|
|
||||||
command.vertices.type,
|
|
||||||
command.vertices.stride,
|
|
||||||
(void *)command.vertices.offset);
|
|
||||||
|
|
||||||
if (command.texcoords.arity != 0) {
|
|
||||||
SDL_assert(command.texcoords.buffer == command.vertices.buffer);
|
|
||||||
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glClientActiveTexture(GL_TEXTURE0);
|
|
||||||
glTexCoordPointer(command.texcoords.arity,
|
|
||||||
command.texcoords.type,
|
|
||||||
command.texcoords.stride,
|
|
||||||
(void *)command.texcoords.offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command.colors.arity != 0) {
|
|
||||||
SDL_assert(command.colors.buffer == command.vertices.buffer);
|
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
|
||||||
glColorPointer(command.colors.arity,
|
|
||||||
command.colors.type,
|
|
||||||
command.colors.stride,
|
|
||||||
(void *)command.colors.offset);
|
|
||||||
} else if (command.constant_colored)
|
|
||||||
glColor4ub(command.color.r,
|
|
||||||
command.color.g,
|
|
||||||
command.color.b,
|
|
||||||
command.color.a);
|
|
||||||
|
|
||||||
if (command.textured) {
|
|
||||||
if (command.uses_gpu_key)
|
|
||||||
glBindTexture(GL_TEXTURE_2D, command.gpu_texture);
|
|
||||||
else if (command.texture_repeat)
|
|
||||||
textures_bind_repeating(&ctx.texture_cache, command.texture_key);
|
|
||||||
else
|
|
||||||
textures_bind(&ctx.texture_cache, command.texture_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command.element_buffer) {
|
|
||||||
SDL_assert(command.element_count != 0);
|
|
||||||
if (command.range_start == command.range_end)
|
|
||||||
glDrawElements(GL_TRIANGLES, command.element_count, GL_UNSIGNED_SHORT, NULL);
|
|
||||||
else
|
|
||||||
glDrawRangeElements(GL_TRIANGLES,
|
|
||||||
command.range_start,
|
|
||||||
command.range_end,
|
|
||||||
command.element_count,
|
|
||||||
GL_UNSIGNED_SHORT,
|
|
||||||
NULL);
|
|
||||||
} else {
|
|
||||||
SDL_assert(command.primitive_count != 0);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, command.primitive_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* state clearing */
|
|
||||||
|
|
||||||
if (command.textured)
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
if (command.colors.arity != 0)
|
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
if (command.texcoords.arity != 0)
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEFERRED_COMMAND_TYPE_DRAW_SKYBOX: {
|
|
||||||
deferred_render_skybox(deferred_commands[i].draw_skybox.paths);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEFERRED_COMMAND_TYPE_USE_PIPIELINE: {
|
|
||||||
switch (deferred_commands[i].use_pipeline.pipeline) {
|
|
||||||
case PIPELINE_2D:
|
|
||||||
finally_use_2d_pipeline();
|
|
||||||
break;
|
|
||||||
case PIPELINE_SPACE:
|
|
||||||
finally_use_space_pipeline();
|
|
||||||
break;
|
|
||||||
case PIPELINE_NO:
|
|
||||||
default:
|
|
||||||
SDL_assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE: {
|
|
||||||
finally_use_texture_mode(deferred_commands[i].use_texture_mode.mode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEFERRED_COMMAND_TYPE_APPLY_FOG: {
|
|
||||||
deferred_apply_fog(deferred_commands[i].apply_fog.start,
|
|
||||||
deferred_commands[i].apply_fog.end,
|
|
||||||
deferred_commands[i].apply_fog.density,
|
|
||||||
deferred_commands[i].apply_fog.color);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DEFERRED_COMMAND_TYPE_POP_FOG: {
|
|
||||||
deferred_pop_fog();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
SDL_assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void clear_draw_buffer(void) {
|
|
||||||
/* TODO: we can optimize a rectangle drawn over whole window to a clear color call*/
|
|
||||||
|
|
||||||
DeferredCommand command = {
|
|
||||||
.type = DEFERRED_COMMAND_TYPE_CLEAR,
|
|
||||||
.clear = (DeferredCommandClear) {
|
|
||||||
.clear_color = true,
|
|
||||||
.clear_depth = true,
|
|
||||||
.clear_stencil = true,
|
|
||||||
.color = (Color) { 230, 230, 230, 1 }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void start_render_frame(void) {
|
void start_render_frame(void) {
|
||||||
clear_draw_buffer();
|
clear_draw_buffer();
|
||||||
}
|
}
|
||||||
@ -318,17 +106,7 @@ void end_render_frame(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void use_space_pipeline(void) {
|
void finally_use_space_pipeline(void) {
|
||||||
DeferredCommand const command = {
|
|
||||||
.type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
|
|
||||||
.use_pipeline = { PIPELINE_SPACE }
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void finally_use_space_pipeline(void) {
|
|
||||||
if (pipeline_last_used == PIPELINE_SPACE)
|
if (pipeline_last_used == PIPELINE_SPACE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -366,17 +144,7 @@ static void finally_use_space_pipeline(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void use_2d_pipeline(void) {
|
void finally_use_2d_pipeline(void) {
|
||||||
DeferredCommand const command = {
|
|
||||||
.type = DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
|
|
||||||
.use_pipeline = { PIPELINE_2D }
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void finally_use_2d_pipeline(void) {
|
|
||||||
if (pipeline_last_used == PIPELINE_SPACE) {
|
if (pipeline_last_used == PIPELINE_SPACE) {
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
glFlush();
|
glFlush();
|
||||||
@ -418,17 +186,7 @@ static void finally_use_2d_pipeline(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void use_texture_mode(TextureMode mode) {
|
void finally_use_texture_mode(TextureMode mode) {
|
||||||
DeferredCommand const command = {
|
|
||||||
.type = DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE,
|
|
||||||
.use_texture_mode = { mode }
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void finally_use_texture_mode(TextureMode mode) {
|
|
||||||
if (texture_mode_last_used == mode)
|
if (texture_mode_last_used == mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -815,6 +573,7 @@ size_t get_text_payload_size(void) {
|
|||||||
return sizeof (ElementIndexedQuadWithoutColor);
|
return sizeof (ElementIndexedQuadWithoutColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void load_cubemap_side(const char *path, GLenum target) {
|
static void load_cubemap_side(const char *path, GLenum target) {
|
||||||
SDL_Surface *surface = textures_load_surface(path);
|
SDL_Surface *surface = textures_load_surface(path);
|
||||||
/* TODO: sanity check whether all of them have same dimensions? */
|
/* TODO: sanity check whether all of them have same dimensions? */
|
||||||
@ -891,35 +650,23 @@ void render_circle(const CirclePrimitive *circle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void finally_render_skybox(char *paths) {
|
void finally_render_skybox(DeferredCommandDrawSkybox command) {
|
||||||
DeferredCommand command = {
|
|
||||||
.type = DEFERRED_COMMAND_TYPE_DRAW_SKYBOX,
|
|
||||||
.draw_skybox = (DeferredCommandDrawSkybox){
|
|
||||||
.paths = paths
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void deferred_render_skybox(char *paths) {
|
|
||||||
static GLuint cubemap = 0;
|
static GLuint cubemap = 0;
|
||||||
static char *paths_cache = NULL;
|
static char *paths_cache = NULL;
|
||||||
|
|
||||||
bool loading_needed = false;
|
bool loading_needed = false;
|
||||||
|
|
||||||
/* drop it */
|
/* drop it */
|
||||||
if (!paths_cache || (SDL_strcmp(paths_cache, paths) != 0)) {
|
if (!paths_cache || (SDL_strcmp(paths_cache, command.paths) != 0)) {
|
||||||
if (cubemap)
|
if (cubemap)
|
||||||
glDeleteTextures(1, &cubemap);
|
glDeleteTextures(1, &cubemap);
|
||||||
glGenTextures(1, &cubemap);
|
glGenTextures(1, &cubemap);
|
||||||
if (paths_cache)
|
if (paths_cache)
|
||||||
SDL_free(paths_cache);
|
SDL_free(paths_cache);
|
||||||
paths_cache = paths;
|
paths_cache = command.paths;
|
||||||
loading_needed = true;
|
loading_needed = true;
|
||||||
} else
|
} else
|
||||||
SDL_free(paths);
|
SDL_free(command.paths);
|
||||||
|
|
||||||
Matrix4 camera_look_at_matrix_solipsist = camera_look_at_matrix;
|
Matrix4 camera_look_at_matrix_solipsist = camera_look_at_matrix;
|
||||||
camera_look_at_matrix_solipsist.row[3].x = 0;
|
camera_look_at_matrix_solipsist.row[3].x = 0;
|
||||||
@ -935,27 +682,27 @@ static void deferred_render_skybox(char *paths) {
|
|||||||
|
|
||||||
if (loading_needed) {
|
if (loading_needed) {
|
||||||
/* load all the sides */
|
/* load all the sides */
|
||||||
char *expanded = expand_asterisk(paths, "up");
|
char *expanded = expand_asterisk(command.paths, "up");
|
||||||
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);
|
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);
|
||||||
SDL_free(expanded);
|
SDL_free(expanded);
|
||||||
|
|
||||||
expanded = expand_asterisk(paths, "down");
|
expanded = expand_asterisk(command.paths, "down");
|
||||||
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);
|
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);
|
||||||
SDL_free(expanded);
|
SDL_free(expanded);
|
||||||
|
|
||||||
expanded = expand_asterisk(paths, "east");
|
expanded = expand_asterisk(command.paths, "east");
|
||||||
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_X);
|
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_X);
|
||||||
SDL_free(expanded);
|
SDL_free(expanded);
|
||||||
|
|
||||||
expanded = expand_asterisk(paths, "north");
|
expanded = expand_asterisk(command.paths, "north");
|
||||||
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);
|
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);
|
||||||
SDL_free(expanded);
|
SDL_free(expanded);
|
||||||
|
|
||||||
expanded = expand_asterisk(paths, "west");
|
expanded = expand_asterisk(command.paths, "west");
|
||||||
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);
|
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);
|
||||||
SDL_free(expanded);
|
SDL_free(expanded);
|
||||||
|
|
||||||
expanded = expand_asterisk(paths, "south");
|
expanded = expand_asterisk(command.paths, "south");
|
||||||
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
|
load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
|
||||||
SDL_free(expanded);
|
SDL_free(expanded);
|
||||||
}
|
}
|
||||||
@ -1051,65 +798,132 @@ static void deferred_render_skybox(char *paths) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void finally_apply_fog(float start, float end, float density, Color color) {
|
void finally_apply_fog(DeferredCommandApplyFog command) {
|
||||||
DeferredCommand command = {
|
if (command.density < 0.0f || command.density > 1.0f)
|
||||||
.type = DEFERRED_COMMAND_TYPE_APPLY_FOG,
|
|
||||||
.apply_fog = (DeferredCommandApplyFog){
|
|
||||||
.start = start,
|
|
||||||
.end = end,
|
|
||||||
.density = density,
|
|
||||||
.color = color
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void deferred_apply_fog(float start, float end, float density, Color color) {
|
|
||||||
if (density < 0.0f || density > 1.0f)
|
|
||||||
log_warn("Invalid fog density given, should be in range [0..1]");
|
log_warn("Invalid fog density given, should be in range [0..1]");
|
||||||
|
|
||||||
/* TODO: cache it for constant parameters, which is a common case */
|
/* TODO: cache it for constant parameters, which is a common case */
|
||||||
|
|
||||||
glEnable(GL_FOG);
|
glEnable(GL_FOG);
|
||||||
|
|
||||||
glFogf(GL_FOG_DENSITY, density);
|
glFogf(GL_FOG_DENSITY, command.density);
|
||||||
glFogf(GL_FOG_START, start);
|
glFogf(GL_FOG_START, command.start);
|
||||||
glFogf(GL_FOG_END, end);
|
glFogf(GL_FOG_END, command.end);
|
||||||
|
|
||||||
float color_conv[4];
|
float color_conv[4];
|
||||||
color_conv[0] = (float)color.r / UINT8_MAX;
|
color_conv[0] = (float)command.color.r / UINT8_MAX;
|
||||||
color_conv[1] = (float)color.g / UINT8_MAX;
|
color_conv[1] = (float)command.color.g / UINT8_MAX;
|
||||||
color_conv[2] = (float)color.b / UINT8_MAX;
|
color_conv[2] = (float)command.color.b / UINT8_MAX;
|
||||||
color_conv[3] = (float)color.a / UINT8_MAX;
|
color_conv[3] = (float)command.color.a / UINT8_MAX;
|
||||||
|
|
||||||
glFogfv(GL_FOG_COLOR, color_conv);
|
glFogfv(GL_FOG_COLOR, color_conv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void finally_pop_fog(void) {
|
void finally_pop_fog(void) {
|
||||||
DeferredCommand command = {
|
|
||||||
.type = DEFERRED_COMMAND_TYPE_POP_FOG,
|
|
||||||
};
|
|
||||||
|
|
||||||
arrpush(deferred_commands, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void deferred_pop_fog(void) {
|
|
||||||
glDisable(GL_FOG);
|
glDisable(GL_FOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void set_depth_range(double low, double high) {
|
void finally_set_depth_range(DeferredCommandDepthRange command) {
|
||||||
DeferredCommand const command = {
|
glDepthRange(command.low, command.high);
|
||||||
.type = DEFERRED_COMMAND_TYPE_DEPTH_RANGE,
|
}
|
||||||
.depth_range = {
|
|
||||||
.low = low,
|
|
||||||
.high = high
|
void finally_clear_draw_buffer(DeferredCommandClear command) {
|
||||||
}
|
glClearColor((1.0f / 255) * command.color.r,
|
||||||
};
|
(1.0f / 255) * command.color.g,
|
||||||
|
(1.0f / 255) * command.color.b,
|
||||||
arrpush(deferred_commands, command);
|
(1.0f / 255) * command.color.a);
|
||||||
|
|
||||||
|
/* needed as we might mess with it */
|
||||||
|
glDepthRange(0.0, 1.0);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
|
||||||
|
glClear((command.clear_color ? GL_COLOR_BUFFER_BIT : 0) |
|
||||||
|
(command.clear_depth ? GL_DEPTH_BUFFER_BIT : 0) |
|
||||||
|
(command.clear_stencil ? GL_STENCIL_BUFFER_BIT : 0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void finally_draw_command(DeferredCommandDraw command) {
|
||||||
|
/* TODO: don't assume a single vertex array ? */
|
||||||
|
SDL_assert(command.vertices.arity != 0);
|
||||||
|
SDL_assert(command.vertices.buffer);
|
||||||
|
SDL_assert((command.element_buffer && command.element_count != 0) || command.primitive_count != 0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, command.vertices.buffer);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, command.element_buffer);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(command.vertices.arity,
|
||||||
|
command.vertices.type,
|
||||||
|
command.vertices.stride,
|
||||||
|
(void *)command.vertices.offset);
|
||||||
|
|
||||||
|
if (command.texcoords.arity != 0) {
|
||||||
|
SDL_assert(command.texcoords.buffer == command.vertices.buffer);
|
||||||
|
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glClientActiveTexture(GL_TEXTURE0);
|
||||||
|
glTexCoordPointer(command.texcoords.arity,
|
||||||
|
command.texcoords.type,
|
||||||
|
command.texcoords.stride,
|
||||||
|
(void *)command.texcoords.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.colors.arity != 0) {
|
||||||
|
SDL_assert(command.colors.buffer == command.vertices.buffer);
|
||||||
|
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glColorPointer(command.colors.arity,
|
||||||
|
command.colors.type,
|
||||||
|
command.colors.stride,
|
||||||
|
(void *)command.colors.offset);
|
||||||
|
} else if (command.constant_colored)
|
||||||
|
glColor4ub(command.color.r,
|
||||||
|
command.color.g,
|
||||||
|
command.color.b,
|
||||||
|
command.color.a);
|
||||||
|
|
||||||
|
if (command.textured) {
|
||||||
|
if (command.uses_gpu_key)
|
||||||
|
glBindTexture(GL_TEXTURE_2D, command.gpu_texture);
|
||||||
|
else if (command.texture_repeat)
|
||||||
|
textures_bind_repeating(&ctx.texture_cache, command.texture_key);
|
||||||
|
else
|
||||||
|
textures_bind(&ctx.texture_cache, command.texture_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.element_buffer) {
|
||||||
|
SDL_assert(command.element_count != 0);
|
||||||
|
if (command.range_start == command.range_end)
|
||||||
|
glDrawElements(GL_TRIANGLES, command.element_count, GL_UNSIGNED_SHORT, NULL);
|
||||||
|
else
|
||||||
|
glDrawRangeElements(GL_TRIANGLES,
|
||||||
|
command.range_start,
|
||||||
|
command.range_end,
|
||||||
|
command.element_count,
|
||||||
|
GL_UNSIGNED_SHORT,
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
SDL_assert(command.primitive_count != 0);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, command.primitive_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* state clearing */
|
||||||
|
|
||||||
|
if (command.textured)
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
if (command.colors.arity != 0)
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
if (command.texcoords.arity != 0)
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
#include "twn_gl_any_rendering_c.h"
|
||||||
#include "twn_draw_c.h"
|
#include "twn_draw_c.h"
|
||||||
|
#include "twn_engine_context_c.h"
|
||||||
|
|
||||||
|
#include <stb_ds.h>
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
#include <GLES2/gl2.h>
|
#include <GLES2/gl2.h>
|
||||||
@ -84,3 +88,35 @@ VertexBuffer get_circle_element_buffer(void) {
|
|||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* potentially double buffered array of vertex array handles */
|
||||||
|
/* we assume they will be refilled fully each frame */
|
||||||
|
static size_t scratch_va_front_used, scratch_va_back_used;
|
||||||
|
static GLuint *front_scratch_vertex_arrays, *back_scratch_vertex_arrays;
|
||||||
|
static GLuint **current_scratch_vertex_array = &front_scratch_vertex_arrays;
|
||||||
|
|
||||||
|
void restart_scratch_vertex_arrays(void) {
|
||||||
|
scratch_va_front_used = 0;
|
||||||
|
scratch_va_back_used = 0;
|
||||||
|
|
||||||
|
if (ctx.render_double_buffered) {
|
||||||
|
current_scratch_vertex_array = current_scratch_vertex_array == &front_scratch_vertex_arrays ?
|
||||||
|
&back_scratch_vertex_arrays : &front_scratch_vertex_arrays;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLuint get_scratch_vertex_array(void) {
|
||||||
|
size_t *used = current_scratch_vertex_array == &front_scratch_vertex_arrays ?
|
||||||
|
&scratch_va_front_used : &scratch_va_back_used;
|
||||||
|
|
||||||
|
if (arrlenu(*current_scratch_vertex_array) <= *used) {
|
||||||
|
GLuint handle;
|
||||||
|
glGenBuffers(1, &handle);
|
||||||
|
arrpush(*current_scratch_vertex_array, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*used)++;
|
||||||
|
return (*current_scratch_vertex_array)[*used - 1];
|
||||||
|
}
|
||||||
|
16
src/rendering/twn_gl_any_rendering_c.h
Normal file
16
src/rendering/twn_gl_any_rendering_c.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef TWN_GL_ANY_RENDERING_C_H
|
||||||
|
#define TWN_GL_ANY_RENDERING_C_H
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#else
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void restart_scratch_vertex_arrays(void);
|
||||||
|
|
||||||
|
GLuint get_scratch_vertex_array(void);
|
||||||
|
|
||||||
|
#endif
|
@ -2,6 +2,7 @@
|
|||||||
#include "twn_draw_c.h"
|
#include "twn_draw_c.h"
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
#include <stb_ds.h>
|
||||||
|
|
||||||
static char *paths_in_use;
|
static char *paths_in_use;
|
||||||
|
|
||||||
@ -21,6 +22,14 @@ void render_skybox(void) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* note: ownership of 'paths_in_use' goes there */
|
/* note: ownership of 'paths_in_use' goes there */
|
||||||
finally_render_skybox(paths_in_use);
|
DeferredCommand command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_DRAW_SKYBOX,
|
||||||
|
.draw_skybox = (DeferredCommandDrawSkybox){
|
||||||
|
.paths = paths_in_use
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, command);
|
||||||
|
|
||||||
paths_in_use = NULL;
|
paths_in_use = NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user