partial implementation of double buffered render
This commit is contained in:
parent
446402c2e0
commit
139394c6de
@ -374,11 +374,11 @@ void render(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_render_frame(); {
|
||||||
render_space();
|
render_space();
|
||||||
render_skybox(); /* after space, as to use depth buffer for early rejection */
|
render_skybox(); /* after space, as to use depth buffer for early z rejection */
|
||||||
render_2d();
|
render_2d();
|
||||||
swap_buffers();
|
} end_render_frame();
|
||||||
clear_draw_buffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,6 +165,8 @@ void text_cache_reset_arena(TextCache *cache);
|
|||||||
|
|
||||||
VertexBuffer create_vertex_buffer(void);
|
VertexBuffer create_vertex_buffer(void);
|
||||||
|
|
||||||
|
VertexBuffer get_scratch_vertex_array(void);
|
||||||
|
|
||||||
void delete_vertex_buffer(VertexBuffer buffer);
|
void delete_vertex_buffer(VertexBuffer buffer);
|
||||||
|
|
||||||
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes);
|
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes);
|
||||||
@ -187,7 +189,7 @@ void swap_buffers(void);
|
|||||||
|
|
||||||
void set_depth_range(double low, double high);
|
void set_depth_range(double low, double high);
|
||||||
|
|
||||||
void bind_quad_element_buffer(void);
|
VertexBuffer get_quad_element_buffer(void);
|
||||||
|
|
||||||
void render_circle(const CirclePrimitive *circle);
|
void render_circle(const CirclePrimitive *circle);
|
||||||
|
|
||||||
@ -238,4 +240,8 @@ void pop_fog(void);
|
|||||||
|
|
||||||
void finally_pop_fog(void);
|
void finally_pop_fog(void);
|
||||||
|
|
||||||
|
void start_render_frame(void);
|
||||||
|
|
||||||
|
void end_render_frame(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -95,6 +95,58 @@ typedef struct ElementIndexedQuadWithoutColorWithoutTexture {
|
|||||||
} ElementIndexedQuadWithoutColorWithoutTexture;
|
} ElementIndexedQuadWithoutColorWithoutTexture;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t offset;
|
||||||
|
GLenum type;
|
||||||
|
GLsizei stride;
|
||||||
|
GLuint buffer;
|
||||||
|
uint8_t arity; /* leave at 0 to signal pointer as unused */
|
||||||
|
} AttributeArrayPointer;
|
||||||
|
|
||||||
|
|
||||||
|
/* allows us to have generic way to issue draws as well as */
|
||||||
|
/* deferring new draw calls while previous frame is still being drawn */
|
||||||
|
typedef struct {
|
||||||
|
AttributeArrayPointer vertices;
|
||||||
|
AttributeArrayPointer texcoords;
|
||||||
|
|
||||||
|
bool constant_colored;
|
||||||
|
union {
|
||||||
|
AttributeArrayPointer colors;
|
||||||
|
Color color;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool textured, texture_repeat;
|
||||||
|
TextureKey texture;
|
||||||
|
TextureMode texture_mode;
|
||||||
|
|
||||||
|
GLuint element_buffer;
|
||||||
|
GLsizei element_count;
|
||||||
|
GLsizei range_start, range_end;
|
||||||
|
} DeferredCommandDrawElements;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Color color;
|
||||||
|
bool clear_color;
|
||||||
|
bool clear_depth;
|
||||||
|
bool clear_stencil;
|
||||||
|
} DeferredCommandClear;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum DeferredCommandType {
|
||||||
|
DEFERRED_COMMAND_TYPE_DRAW_ELEMENTS,
|
||||||
|
DEFERRED_COMMAND_TYPE_CLEAR,
|
||||||
|
} type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
DeferredCommandDrawElements draw_elements;
|
||||||
|
DeferredCommandClear clear;
|
||||||
|
};
|
||||||
|
} DeferredCommand;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PIPELINE_NO,
|
PIPELINE_NO,
|
||||||
PIPELINE_SPACE,
|
PIPELINE_SPACE,
|
||||||
@ -108,6 +160,186 @@ static Pipeline pipeline_last_used = PIPELINE_NO;
|
|||||||
#define CIRCLE_VERTICES_MAX 2048
|
#define CIRCLE_VERTICES_MAX 2048
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)[arrlenu(*current_scratch_vertex_array) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DeferredCommand *deferred_commands;
|
||||||
|
static void issue_deferred_draw_commands(void) {
|
||||||
|
use_2d_pipeline();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arrlenu(deferred_commands); ++i) {
|
||||||
|
switch (deferred_commands[i].type) {
|
||||||
|
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_ELEMENTS: {
|
||||||
|
DeferredCommandDrawElements const command = deferred_commands[i].draw_elements;
|
||||||
|
|
||||||
|
/* TODO: don't assume a single vertex array ? */
|
||||||
|
SDL_assert(command.vertices.arity != 0);
|
||||||
|
SDL_assert(command.vertices.buffer);
|
||||||
|
SDL_assert(command.element_count != 0);
|
||||||
|
SDL_assert(command.element_buffer);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
use_texture_mode(command.texture_mode);
|
||||||
|
|
||||||
|
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.texture_repeat)
|
||||||
|
textures_bind_repeating(&ctx.texture_cache, command.texture);
|
||||||
|
else
|
||||||
|
textures_bind(&ctx.texture_cache, command.texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
restart_scratch_vertex_arrays();
|
||||||
|
clear_draw_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void end_render_frame(void) {
|
||||||
|
if (!ctx.render_double_buffered || ctx.game.frame_number == 0) {
|
||||||
|
issue_deferred_draw_commands();
|
||||||
|
SDL_GL_SwapWindow(ctx.window);
|
||||||
|
arrsetlen(deferred_commands, 0);
|
||||||
|
} else {
|
||||||
|
/* instead of waiting for frame to finish for the swap, we continue */
|
||||||
|
/* while issuing new state for the next call, but deferring any fragment emitting calls for later */
|
||||||
|
/* actual swap will happen when next frame is fully finished, introducing a delay */
|
||||||
|
SDL_GL_SwapWindow(ctx.window);
|
||||||
|
issue_deferred_draw_commands();
|
||||||
|
glFlush();
|
||||||
|
arrsetlen(deferred_commands, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void use_space_pipeline(void) {
|
void use_space_pipeline(void) {
|
||||||
if (pipeline_last_used == PIPELINE_SPACE)
|
if (pipeline_last_used == PIPELINE_SPACE)
|
||||||
return;
|
return;
|
||||||
@ -301,7 +533,7 @@ void finally_render_quads(const Primitive2D primitives[],
|
|||||||
const struct QuadBatch batch,
|
const struct QuadBatch batch,
|
||||||
const VertexBuffer buffer)
|
const VertexBuffer buffer)
|
||||||
{
|
{
|
||||||
(void)buffer;
|
DeferredCommandDrawElements command = {0};
|
||||||
|
|
||||||
GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;
|
GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;
|
||||||
|
|
||||||
@ -323,63 +555,55 @@ void finally_render_quads(const Primitive2D primitives[],
|
|||||||
voff = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v0);
|
voff = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vertex specification */
|
command.vertices = (AttributeArrayPointer) {
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
.arity = 2,
|
||||||
glVertexPointer(2,
|
.type = GL_FLOAT,
|
||||||
GL_FLOAT,
|
.stride = off,
|
||||||
off,
|
.offset = voff,
|
||||||
(void *)(size_t)voff);
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
|
||||||
if (batch.textured) {
|
if (batch.textured)
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
command.texcoords = (AttributeArrayPointer) {
|
||||||
glClientActiveTexture(GL_TEXTURE0);
|
.arity = 2,
|
||||||
glTexCoordPointer(2,
|
.type = GL_FLOAT,
|
||||||
GL_FLOAT,
|
.stride = off,
|
||||||
off,
|
.offset = uvoff,
|
||||||
(void *)(size_t)uvoff);
|
.buffer = buffer
|
||||||
}
|
};
|
||||||
|
|
||||||
if (!batch.constant_colored) {
|
if (!batch.constant_colored) {
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
command.colors = (AttributeArrayPointer) {
|
||||||
glColorPointer(4,
|
.arity = 4,
|
||||||
GL_UNSIGNED_BYTE,
|
.type = GL_UNSIGNED_BYTE,
|
||||||
off,
|
.stride = off,
|
||||||
(void *)(size_t)coff);
|
.offset = coff,
|
||||||
} else
|
.buffer = buffer
|
||||||
glColor4ub(primitives[0].sprite.color.r,
|
};
|
||||||
primitives[0].sprite.color.g,
|
} else {
|
||||||
primitives[0].sprite.color.b,
|
command.constant_colored = true;
|
||||||
primitives[0].sprite.color.a);
|
command.color = primitives[0].sprite.color;
|
||||||
|
}
|
||||||
|
|
||||||
if (batch.textured) {
|
if (batch.textured) {
|
||||||
if (!batch.repeat)
|
/* TODO: bad, don't */
|
||||||
textures_bind(&ctx.texture_cache, primitives->sprite.texture_key);
|
command.textured = true;
|
||||||
else
|
command.texture = primitives->sprite.texture_key;
|
||||||
textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key);
|
command.texture_repeat = batch.repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_quad_element_buffer();
|
command.element_buffer = get_quad_element_buffer();
|
||||||
|
command.element_count = 6 * (GLsizei)batch.size;
|
||||||
|
command.range_end = 6 * (GLsizei)batch.size;
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL);
|
command.texture_mode = batch.mode;
|
||||||
|
|
||||||
/* clear the state */
|
DeferredCommand final_command = {
|
||||||
{
|
.type = DEFERRED_COMMAND_TYPE_DRAW_ELEMENTS,
|
||||||
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
|
.draw_elements = command
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
};
|
||||||
|
|
||||||
if (batch.textured)
|
arrpush(deferred_commands, final_command);
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
|
|
||||||
if (!batch.constant_colored)
|
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
if (batch.textured)
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -553,7 +777,7 @@ void finally_draw_text(FontData const *font_data,
|
|||||||
offsetof(ElementIndexedQuadWithoutColor, v1),
|
offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||||
(void *)(size_t)offsetof(ElementIndexedQuadWithoutColor, uv0));
|
(void *)(size_t)offsetof(ElementIndexedQuadWithoutColor, uv0));
|
||||||
|
|
||||||
bind_quad_element_buffer();
|
get_quad_element_buffer();
|
||||||
|
|
||||||
use_texture_mode(TEXTURE_MODE_GHOSTLY);
|
use_texture_mode(TEXTURE_MODE_GHOSTLY);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void bind_quad_element_buffer(void) {
|
VertexBuffer get_quad_element_buffer(void) {
|
||||||
static GLuint buffer = 0;
|
static GLuint buffer = 0;
|
||||||
|
|
||||||
/* it's only generated once at runtime */
|
/* it's only generated once at runtime */
|
||||||
@ -62,32 +62,8 @@ void bind_quad_element_buffer(void) {
|
|||||||
|
|
||||||
} else
|
} else
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
||||||
}
|
|
||||||
|
|
||||||
|
return buffer;
|
||||||
void clear_draw_buffer(void) {
|
|
||||||
/* TODO: we can optimize a rectangle drawn over whole window to a clear color call*/
|
|
||||||
glClearColor((1.0f / 255) * 230,
|
|
||||||
(1.0f / 255) * 230,
|
|
||||||
(1.0f / 255) * 230, 1);
|
|
||||||
|
|
||||||
glDepthRange(0.0, 1.0);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
|
|
||||||
/* TODO: don't clear color when skybox is applied? */
|
|
||||||
/* for that window should match framebuffer */
|
|
||||||
/* also it is driver dependent, from what i can gather */
|
|
||||||
/* INFO: also, based on below, driver might prefer it staying this way */
|
|
||||||
/* https://gamedev.stackexchange.com/questions/90344/render-with-const-depth-value */
|
|
||||||
/* we could optionally load ARB_invalidate_subdata extension if it's available instead */
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT |
|
|
||||||
GL_DEPTH_BUFFER_BIT |
|
|
||||||
GL_STENCIL_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void swap_buffers(void) {
|
|
||||||
SDL_GL_SwapWindow(ctx.window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,9 +72,7 @@ void render_rect_batch(const Primitive2D primitives[],
|
|||||||
SDL_assert(primitives[0].type == PRIMITIVE_2D_RECT);
|
SDL_assert(primitives[0].type == PRIMITIVE_2D_RECT);
|
||||||
|
|
||||||
/* single vertex array is used for every batch with NULL glBufferData() trick at the end */
|
/* single vertex array is used for every batch with NULL glBufferData() trick at the end */
|
||||||
static VertexBuffer vertex_array = 0;
|
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||||
if (vertex_array == 0)
|
|
||||||
vertex_array = create_vertex_buffer();
|
|
||||||
|
|
||||||
use_texture_mode(batch.mode);
|
use_texture_mode(batch.mode);
|
||||||
|
|
||||||
|
@ -125,12 +125,7 @@ void render_sprite_batch(const Primitive2D primitives[],
|
|||||||
SDL_assert(primitives && batch.size != 0);
|
SDL_assert(primitives && batch.size != 0);
|
||||||
SDL_assert(primitives[0].type == PRIMITIVE_2D_SPRITE);
|
SDL_assert(primitives[0].type == PRIMITIVE_2D_SPRITE);
|
||||||
|
|
||||||
/* single vertex array is used for every batch with NULL glBufferData() trick at the end */
|
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||||
static VertexBuffer vertex_array = 0;
|
|
||||||
if (vertex_array == 0)
|
|
||||||
vertex_array = create_vertex_buffer();
|
|
||||||
|
|
||||||
use_texture_mode(batch.mode);
|
|
||||||
|
|
||||||
const Rect dims =
|
const Rect dims =
|
||||||
textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key);
|
textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||||
|
@ -171,9 +171,7 @@ static void text_destroy_font_data(FontData *font_data) {
|
|||||||
|
|
||||||
|
|
||||||
static void text_draw_with(FontData* font_data, char* text, Vec2 position, Color color) {
|
static void text_draw_with(FontData* font_data, char* text, Vec2 position, Color color) {
|
||||||
VertexBuffer vertex_array = 0;
|
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||||
if (vertex_array == 0)
|
|
||||||
vertex_array = create_vertex_buffer();
|
|
||||||
|
|
||||||
const size_t len = SDL_strlen(text);
|
const size_t len = SDL_strlen(text);
|
||||||
|
|
||||||
|
@ -45,9 +45,7 @@ void draw_triangle(const char *path,
|
|||||||
void draw_uncolored_space_traingle_batch(struct MeshBatch *batch,
|
void draw_uncolored_space_traingle_batch(struct MeshBatch *batch,
|
||||||
TextureKey texture_key)
|
TextureKey texture_key)
|
||||||
{
|
{
|
||||||
static VertexBuffer vertex_array = 0;
|
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||||
if (vertex_array == 0)
|
|
||||||
vertex_array = create_vertex_buffer();
|
|
||||||
|
|
||||||
const size_t primitives_len = arrlenu(batch->primitives);
|
const size_t primitives_len = arrlenu(batch->primitives);
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ typedef struct EngineContext {
|
|||||||
bool window_size_has_changed;
|
bool window_size_has_changed;
|
||||||
bool resync_flag;
|
bool resync_flag;
|
||||||
bool was_successful;
|
bool was_successful;
|
||||||
|
bool render_double_buffered;
|
||||||
} EngineContext;
|
} EngineContext;
|
||||||
|
|
||||||
/* TODO: does it need to be marked with TWN_API? */
|
/* TODO: does it need to be marked with TWN_API? */
|
||||||
|
@ -658,6 +658,8 @@ static bool initialize(void) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
ctx.render_double_buffered = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
Loading…
Reference in New Issue
Block a user