Compare commits
8 Commits
446402c2e0
...
7e409fc14a
Author | SHA1 | Date | |
---|---|---|---|
7e409fc14a | |||
aa3cab87d2 | |||
1dc0dea762 | |||
7f56ed8421 | |||
119b706638 | |||
f2bbc1863e | |||
768daf1f54 | |||
139394c6de |
@ -8,7 +8,6 @@
|
||||
|
||||
/* a point in some space (integer) */
|
||||
typedef struct Vec2i {
|
||||
_Alignas(8)
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} Vec2i;
|
||||
@ -16,7 +15,6 @@ _Alignas(8)
|
||||
|
||||
/* a point in some space (floating point) */
|
||||
typedef struct Vec2 {
|
||||
_Alignas(8)
|
||||
float x;
|
||||
float y;
|
||||
} Vec2;
|
||||
@ -25,7 +23,6 @@ _Alignas(8)
|
||||
/* a point in some three dimension space (floating point) */
|
||||
/* y goes up, x goes to the right */
|
||||
typedef struct Vec3 {
|
||||
_Alignas(16)
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
@ -35,7 +32,6 @@ _Alignas(16)
|
||||
/* a point in some three dimension space (floating point) */
|
||||
/* y goes up, x goes to the right */
|
||||
typedef struct Vec4 {
|
||||
_Alignas(16)
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
@ -45,7 +41,6 @@ _Alignas(16)
|
||||
|
||||
/* 32-bit color data */
|
||||
typedef struct Color {
|
||||
_Alignas(4)
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
@ -55,7 +50,6 @@ _Alignas(4)
|
||||
|
||||
/* a rectangle with the origin at the upper left (integer) */
|
||||
typedef struct Recti {
|
||||
_Alignas(16)
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t w;
|
||||
@ -65,7 +59,6 @@ _Alignas(16)
|
||||
|
||||
/* a rectangle with the origin at the upper left (floating point) */
|
||||
typedef struct Rect {
|
||||
_Alignas(16)
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include "twn_util.h"
|
||||
#include "twn_engine_context_c.h"
|
||||
#include "twn_draw_c.h"
|
||||
#include "twn_draw.h"
|
||||
@ -24,22 +23,15 @@ void draw_circle(Vec2 position, float radius, Color color) {
|
||||
|
||||
|
||||
void create_circle_geometry(Vec2 position,
|
||||
Color color,
|
||||
float radius,
|
||||
size_t num_vertices,
|
||||
SDL_Vertex vertices[],
|
||||
int indices[])
|
||||
Vec2 vertices[])
|
||||
{
|
||||
/* the angle (in radians) to rotate by on each iteration */
|
||||
float seg_rotation_angle = (360.0f / (float)num_vertices) * ((float)M_PI / 180);
|
||||
|
||||
vertices[0].position.x = (float)position.x;
|
||||
vertices[0].position.y = (float)position.y;
|
||||
vertices[0].color.r = color.r;
|
||||
vertices[0].color.g = color.g;
|
||||
vertices[0].color.b = color.b;
|
||||
vertices[0].color.a = color.a;
|
||||
vertices[0].tex_coord = (SDL_FPoint){ 0, 0 };
|
||||
vertices[0].x = (float)position.x;
|
||||
vertices[0].y = (float)position.y;
|
||||
|
||||
/* this point will rotate around the center */
|
||||
float start_x = 0.0f - radius;
|
||||
@ -48,34 +40,13 @@ void create_circle_geometry(Vec2 position,
|
||||
for (size_t i = 1; i < num_vertices + 1; ++i) {
|
||||
float final_seg_rotation_angle = (float)i * seg_rotation_angle;
|
||||
|
||||
vertices[i].position.x =
|
||||
cosf(final_seg_rotation_angle) * start_x -
|
||||
sinf(final_seg_rotation_angle) * start_y;
|
||||
vertices[i].position.y =
|
||||
cosf(final_seg_rotation_angle) * start_y +
|
||||
sinf(final_seg_rotation_angle) * start_x;
|
||||
float c, s;
|
||||
sincosf(final_seg_rotation_angle, &s, &c);
|
||||
|
||||
vertices[i].position.x += position.x;
|
||||
vertices[i].position.y += position.y;
|
||||
vertices[i].x = c * start_x - s * start_y;
|
||||
vertices[i].y = c * start_y + s * start_x;
|
||||
|
||||
vertices[i].color.r = color.r;
|
||||
vertices[i].color.g = color.g;
|
||||
vertices[i].color.b = color.b;
|
||||
vertices[i].color.a = color.a;
|
||||
|
||||
vertices[i].tex_coord = (SDL_FPoint){ 0, 0 };
|
||||
|
||||
|
||||
size_t triangle_offset = 3 * (i - 1);
|
||||
|
||||
/* center point index */
|
||||
indices[triangle_offset] = 0;
|
||||
/* generated point index */
|
||||
indices[triangle_offset + 1] = (int)i;
|
||||
|
||||
size_t index = (i + 1) % num_vertices;
|
||||
if (index == 0)
|
||||
index = num_vertices;
|
||||
indices[triangle_offset + 2] = (int)index;
|
||||
vertices[i].x += position.x;
|
||||
vertices[i].y += position.y;
|
||||
}
|
||||
}
|
||||
|
@ -374,11 +374,11 @@ void render(void) {
|
||||
}
|
||||
}
|
||||
|
||||
render_space();
|
||||
render_skybox(); /* after space, as to use depth buffer for early rejection */
|
||||
render_2d();
|
||||
swap_buffers();
|
||||
clear_draw_buffer();
|
||||
start_render_frame(); {
|
||||
render_space();
|
||||
render_skybox(); /* after space, as to use depth buffer for early z rejection */
|
||||
render_2d();
|
||||
} end_render_frame();
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,7 +20,10 @@
|
||||
extern Matrix4 camera_projection_matrix;
|
||||
extern Matrix4 camera_look_at_matrix;
|
||||
|
||||
|
||||
#define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6)
|
||||
#define CIRCLE_VERTICES_MAX 2048
|
||||
#define CIRCLE_ELEMENT_BUFFER_LENGTH (CIRCLE_VERTICES_MAX * 3)
|
||||
|
||||
|
||||
typedef GLuint VertexBuffer;
|
||||
@ -129,11 +132,9 @@ void render_queue_clear(void);
|
||||
/* fills two existing arrays with the geometry data of a circle */
|
||||
/* the size of indices must be at least 3 times the number of vertices */
|
||||
void create_circle_geometry(Vec2 position,
|
||||
Color color,
|
||||
float radius,
|
||||
size_t num_vertices,
|
||||
SDL_Vertex vertices[],
|
||||
int indices[]);
|
||||
Vec2 vertices[]);
|
||||
|
||||
struct QuadBatch {
|
||||
size_t size; /* how many primitives are in current batch */
|
||||
@ -165,6 +166,8 @@ void text_cache_reset_arena(TextCache *cache);
|
||||
|
||||
VertexBuffer create_vertex_buffer(void);
|
||||
|
||||
VertexBuffer get_scratch_vertex_array(void);
|
||||
|
||||
void delete_vertex_buffer(VertexBuffer buffer);
|
||||
|
||||
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes);
|
||||
@ -187,7 +190,9 @@ void swap_buffers(void);
|
||||
|
||||
void set_depth_range(double low, double high);
|
||||
|
||||
void bind_quad_element_buffer(void);
|
||||
VertexBuffer get_quad_element_buffer(void);
|
||||
|
||||
VertexBuffer get_circle_element_buffer(void);
|
||||
|
||||
void render_circle(const CirclePrimitive *circle);
|
||||
|
||||
@ -238,4 +243,8 @@ void pop_fog(void);
|
||||
|
||||
void finally_pop_fog(void);
|
||||
|
||||
void start_render_frame(void);
|
||||
|
||||
void end_render_frame(void);
|
||||
|
||||
#endif
|
||||
|
@ -9,92 +9,113 @@
|
||||
#include <stb_ds.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
float x, y;
|
||||
} Vec2Packed;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int16_t x, y;
|
||||
} Vec2ShortPacked;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t r, g, b, a;
|
||||
} ColorPacked;
|
||||
|
||||
|
||||
#define m_vec2_packed_from(p_vec2) ((Vec2Packed){ (p_vec2).x, (p_vec2).y })
|
||||
#define m_vec2_short_packed_from(p_vec2) ((Vec2ShortPacked){ (uint16_t)((p_vec2).x * 32768 * 2), (uint16_t)((p_vec2).y * 32768 * 2) })
|
||||
#define m_color_packed_from(p_color) ((ColorPacked){ (p_color).r, (p_color).g, (p_color).b, (p_color).a })
|
||||
|
||||
|
||||
/* TODO: try using the fact we utilize edge coloring and step virtual color attributes to bogus points */
|
||||
/* this is only doable is we take out color attribute to separate array or a portion of it */
|
||||
/* interleaved vertex array data */
|
||||
typedef struct ElementIndexedQuad {
|
||||
/* upper-left */
|
||||
Vec2Packed v0;
|
||||
Vec2Packed uv0;
|
||||
ColorPacked c0;
|
||||
Vec2 v0;
|
||||
Vec2 uv0;
|
||||
Color c0;
|
||||
/* bottom-left */
|
||||
Vec2Packed v1;
|
||||
Vec2Packed uv1;
|
||||
ColorPacked c1;
|
||||
Vec2 v1;
|
||||
Vec2 uv1;
|
||||
Color c1;
|
||||
/* bottom-right */
|
||||
Vec2Packed v2;
|
||||
Vec2Packed uv2;
|
||||
ColorPacked c2;
|
||||
Vec2 v2;
|
||||
Vec2 uv2;
|
||||
Color c2;
|
||||
/* upper-right */
|
||||
Vec2Packed v3;
|
||||
Vec2Packed uv3;
|
||||
ColorPacked c3;
|
||||
Vec2 v3;
|
||||
Vec2 uv3;
|
||||
Color c3;
|
||||
} ElementIndexedQuad;
|
||||
|
||||
typedef struct ElementIndexedQuadWithoutColor {
|
||||
/* upper-left */
|
||||
Vec2Packed v0;
|
||||
Vec2Packed uv0;
|
||||
Vec2 v0;
|
||||
Vec2 uv0;
|
||||
/* bottom-left */
|
||||
Vec2Packed v1;
|
||||
Vec2Packed uv1;
|
||||
Vec2 v1;
|
||||
Vec2 uv1;
|
||||
/* bottom-right */
|
||||
Vec2Packed v2;
|
||||
Vec2Packed uv2;
|
||||
Vec2 v2;
|
||||
Vec2 uv2;
|
||||
/* upper-right */
|
||||
Vec2Packed v3;
|
||||
Vec2Packed uv3;
|
||||
Vec2 v3;
|
||||
Vec2 uv3;
|
||||
} ElementIndexedQuadWithoutColor;
|
||||
|
||||
|
||||
typedef struct ElementIndexedQuadWithoutTexture {
|
||||
/* upper-left */
|
||||
Vec2Packed v0;
|
||||
ColorPacked c0;
|
||||
Vec2 v0;
|
||||
Color c0;
|
||||
/* bottom-left */
|
||||
Vec2Packed v1;
|
||||
ColorPacked c1;
|
||||
Vec2 v1;
|
||||
Color c1;
|
||||
/* bottom-right */
|
||||
Vec2Packed v2;
|
||||
ColorPacked c2;
|
||||
Vec2 v2;
|
||||
Color c2;
|
||||
/* upper-right */
|
||||
Vec2Packed v3;
|
||||
ColorPacked c3;
|
||||
Vec2 v3;
|
||||
Color c3;
|
||||
} ElementIndexedQuadWithoutTexture;
|
||||
|
||||
|
||||
typedef struct ElementIndexedQuadWithoutColorWithoutTexture {
|
||||
/* upper-left */
|
||||
Vec2Packed v0;
|
||||
Vec2 v0;
|
||||
/* bottom-left */
|
||||
Vec2Packed v1;
|
||||
Vec2 v1;
|
||||
/* bottom-right */
|
||||
Vec2Packed v2;
|
||||
Vec2 v2;
|
||||
/* upper-right */
|
||||
Vec2Packed v3;
|
||||
Vec2 v3;
|
||||
} 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, uses_gpu_key;
|
||||
TextureKey texture_key;
|
||||
GPUTexture gpu_texture;
|
||||
|
||||
GLuint element_buffer;
|
||||
GLsizei element_count;
|
||||
GLsizei range_start, range_end;
|
||||
|
||||
double depth_range_low, depth_range_high;
|
||||
} DeferredCommandDraw;
|
||||
|
||||
|
||||
typedef struct {
|
||||
Color color;
|
||||
bool clear_color;
|
||||
bool clear_depth;
|
||||
bool clear_stencil;
|
||||
} DeferredCommandClear;
|
||||
|
||||
|
||||
typedef enum {
|
||||
PIPELINE_NO,
|
||||
PIPELINE_SPACE,
|
||||
@ -102,13 +123,266 @@ typedef enum {
|
||||
} Pipeline;
|
||||
|
||||
|
||||
typedef struct {
|
||||
Pipeline pipeline;
|
||||
} DeferredCommandUsePipeline;
|
||||
|
||||
|
||||
typedef struct {
|
||||
TextureMode mode;
|
||||
} DeferredCommandUseTextureMode;
|
||||
|
||||
|
||||
typedef struct {
|
||||
double low, high;
|
||||
} DeferredCommandDepthRange;
|
||||
|
||||
|
||||
typedef struct {
|
||||
enum DeferredCommandType {
|
||||
DEFERRED_COMMAND_TYPE_DRAW,
|
||||
DEFERRED_COMMAND_TYPE_CLEAR,
|
||||
DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
|
||||
DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE,
|
||||
DEFERRED_COMMAND_TYPE_DEPTH_RANGE,
|
||||
} type;
|
||||
|
||||
union {
|
||||
DeferredCommandDraw draw;
|
||||
DeferredCommandClear clear;
|
||||
DeferredCommandUsePipeline use_pipeline;
|
||||
DeferredCommandUseTextureMode use_texture_mode;
|
||||
DeferredCommandDepthRange depth_range;
|
||||
};
|
||||
} DeferredCommand;
|
||||
|
||||
|
||||
static TextureMode texture_mode_last_used = -1;
|
||||
static Pipeline pipeline_last_used = PIPELINE_NO;
|
||||
|
||||
|
||||
#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)[*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 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_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);
|
||||
|
||||
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.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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
restart_scratch_vertex_arrays();
|
||||
} 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();
|
||||
restart_scratch_vertex_arrays();
|
||||
glFlush();
|
||||
arrsetlen(deferred_commands, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void 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)
|
||||
return;
|
||||
|
||||
@ -141,11 +415,22 @@ void use_space_pipeline(void) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(&camera_look_at_matrix.row[0].x);
|
||||
|
||||
texture_mode_last_used = -1;
|
||||
pipeline_last_used = PIPELINE_SPACE;
|
||||
}
|
||||
|
||||
|
||||
void 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) {
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glFlush();
|
||||
@ -182,45 +467,25 @@ void use_2d_pipeline(void) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
texture_mode_last_used = -1;
|
||||
pipeline_last_used = PIPELINE_2D;
|
||||
}
|
||||
|
||||
|
||||
void render_circle(const CirclePrimitive *circle) {
|
||||
static SDL_Vertex vertices[CIRCLE_VERTICES_MAX];
|
||||
static int indices[CIRCLE_VERTICES_MAX * 3];
|
||||
int num_vertices = MIN((int)circle->radius, CIRCLE_VERTICES_MAX-1);
|
||||
void use_texture_mode(TextureMode mode) {
|
||||
DeferredCommand const command = {
|
||||
.type = DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE,
|
||||
.use_texture_mode = { mode }
|
||||
};
|
||||
|
||||
create_circle_geometry(circle->position,
|
||||
circle->color,
|
||||
circle->radius,
|
||||
num_vertices,
|
||||
vertices,
|
||||
indices);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2,
|
||||
GL_FLOAT,
|
||||
sizeof (SDL_Vertex),
|
||||
&vertices->position);
|
||||
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4,
|
||||
GL_UNSIGNED_BYTE,
|
||||
sizeof (SDL_Vertex),
|
||||
&vertices->color);
|
||||
|
||||
glDrawElements(GL_TRIANGLES,
|
||||
num_vertices * 3,
|
||||
GL_UNSIGNED_INT,
|
||||
indices);
|
||||
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
arrpush(deferred_commands, command);
|
||||
}
|
||||
|
||||
|
||||
void use_texture_mode(TextureMode mode) {
|
||||
static void finally_use_texture_mode(TextureMode mode) {
|
||||
if (texture_mode_last_used == mode)
|
||||
return;
|
||||
|
||||
static GLuint lists = 0;
|
||||
if (!lists) {
|
||||
lists = glGenLists(3);
|
||||
@ -259,6 +524,8 @@ void use_texture_mode(TextureMode mode) {
|
||||
} else {
|
||||
glCallList(lists + 2);
|
||||
}
|
||||
|
||||
texture_mode_last_used = mode;
|
||||
}
|
||||
|
||||
|
||||
@ -282,7 +549,7 @@ bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
|
||||
if (builder->bytes_left == 0)
|
||||
return false;
|
||||
|
||||
SDL_memcpy(builder->mapping, bytes, size);
|
||||
memcpy(builder->mapping, bytes, size);
|
||||
builder->bytes_left -= size;
|
||||
|
||||
/* trigger data send */
|
||||
@ -301,7 +568,7 @@ void finally_render_quads(const Primitive2D primitives[],
|
||||
const struct QuadBatch batch,
|
||||
const VertexBuffer buffer)
|
||||
{
|
||||
(void)buffer;
|
||||
DeferredCommandDraw command = {0};
|
||||
|
||||
GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;
|
||||
|
||||
@ -323,63 +590,55 @@ void finally_render_quads(const Primitive2D primitives[],
|
||||
voff = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v0);
|
||||
}
|
||||
|
||||
/* vertex specification */
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2,
|
||||
GL_FLOAT,
|
||||
off,
|
||||
(void *)(size_t)voff);
|
||||
command.vertices = (AttributeArrayPointer) {
|
||||
.arity = 2,
|
||||
.type = GL_FLOAT,
|
||||
.stride = off,
|
||||
.offset = voff,
|
||||
.buffer = buffer
|
||||
};
|
||||
|
||||
if (batch.textured) {
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexCoordPointer(2,
|
||||
GL_FLOAT,
|
||||
off,
|
||||
(void *)(size_t)uvoff);
|
||||
}
|
||||
if (batch.textured)
|
||||
command.texcoords = (AttributeArrayPointer) {
|
||||
.arity = 2,
|
||||
.type = GL_FLOAT,
|
||||
.stride = off,
|
||||
.offset = uvoff,
|
||||
.buffer = buffer
|
||||
};
|
||||
|
||||
if (!batch.constant_colored) {
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4,
|
||||
GL_UNSIGNED_BYTE,
|
||||
off,
|
||||
(void *)(size_t)coff);
|
||||
} else
|
||||
glColor4ub(primitives[0].sprite.color.r,
|
||||
primitives[0].sprite.color.g,
|
||||
primitives[0].sprite.color.b,
|
||||
primitives[0].sprite.color.a);
|
||||
command.colors = (AttributeArrayPointer) {
|
||||
.arity = 4,
|
||||
.type = GL_UNSIGNED_BYTE,
|
||||
.stride = off,
|
||||
.offset = coff,
|
||||
.buffer = buffer
|
||||
};
|
||||
} else {
|
||||
command.constant_colored = true;
|
||||
command.color = primitives[0].sprite.color;
|
||||
}
|
||||
|
||||
if (batch.textured) {
|
||||
if (!batch.repeat)
|
||||
textures_bind(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
else
|
||||
textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
/* TODO: bad, don't */
|
||||
command.textured = true;
|
||||
command.texture_key = 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);
|
||||
use_texture_mode(batch.mode);
|
||||
|
||||
/* clear the state */
|
||||
{
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
DeferredCommand final_command = {
|
||||
.type = DEFERRED_COMMAND_TYPE_DRAW,
|
||||
.draw = command
|
||||
};
|
||||
|
||||
if (batch.textured)
|
||||
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);
|
||||
}
|
||||
arrpush(deferred_commands, final_command);
|
||||
}
|
||||
|
||||
|
||||
@ -406,62 +665,62 @@ bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch,
|
||||
{
|
||||
if (!batch.constant_colored && batch.textured) {
|
||||
ElementIndexedQuad const buffer_element = {
|
||||
.v0 = m_vec2_packed_from(v0),
|
||||
.v1 = m_vec2_packed_from(v1),
|
||||
.v2 = m_vec2_packed_from(v2),
|
||||
.v3 = m_vec2_packed_from(v3),
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
.v3 = v3,
|
||||
|
||||
.uv0 = m_vec2_packed_from(uv0),
|
||||
.uv1 = m_vec2_packed_from(uv1),
|
||||
.uv2 = m_vec2_packed_from(uv2),
|
||||
.uv3 = m_vec2_packed_from(uv3),
|
||||
.uv0 = uv0,
|
||||
.uv1 = uv1,
|
||||
.uv2 = uv2,
|
||||
.uv3 = uv3,
|
||||
|
||||
/* equal for all (flat shaded) */
|
||||
.c0 = m_color_packed_from(color),
|
||||
// .c1 = m_color_packed_from(color),
|
||||
.c2 = m_color_packed_from(color),
|
||||
// .c3 = m_color_packed_from(color),
|
||||
.c0 = color,
|
||||
// .c1 = color,
|
||||
.c2 = color,
|
||||
// .c3 = color,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
|
||||
} else if (batch.constant_colored && batch.textured) {
|
||||
ElementIndexedQuadWithoutColor const buffer_element = {
|
||||
.v0 = m_vec2_packed_from(v0),
|
||||
.v1 = m_vec2_packed_from(v1),
|
||||
.v2 = m_vec2_packed_from(v2),
|
||||
.v3 = m_vec2_packed_from(v3),
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
.v3 = v3,
|
||||
|
||||
.uv0 = m_vec2_packed_from(uv0),
|
||||
.uv1 = m_vec2_packed_from(uv1),
|
||||
.uv2 = m_vec2_packed_from(uv2),
|
||||
.uv3 = m_vec2_packed_from(uv3),
|
||||
.uv0 = uv0,
|
||||
.uv1 = uv1,
|
||||
.uv2 = uv2,
|
||||
.uv3 = uv3,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
|
||||
} else if (!batch.constant_colored && !batch.textured) {
|
||||
ElementIndexedQuadWithoutTexture const buffer_element = {
|
||||
.v0 = m_vec2_packed_from(v0),
|
||||
.v1 = m_vec2_packed_from(v1),
|
||||
.v2 = m_vec2_packed_from(v2),
|
||||
.v3 = m_vec2_packed_from(v3),
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
.v3 = v3,
|
||||
|
||||
/* equal for all (flat shaded) */
|
||||
.c0 = m_color_packed_from(color),
|
||||
// .c1 = m_color_packed_from(color),
|
||||
.c2 = m_color_packed_from(color),
|
||||
// .c3 = m_color_packed_from(color),
|
||||
.c0 = color,
|
||||
// .c1 = color,
|
||||
.c2 = color,
|
||||
// .c3 = color,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
|
||||
} else if (batch.constant_colored && !batch.textured) {
|
||||
ElementIndexedQuadWithoutColorWithoutTexture const buffer_element = {
|
||||
.v0 = m_vec2_packed_from(v0),
|
||||
.v1 = m_vec2_packed_from(v1),
|
||||
.v2 = m_vec2_packed_from(v2),
|
||||
.v3 = m_vec2_packed_from(v3),
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
.v3 = v3,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
@ -517,15 +776,15 @@ bool push_text_payload_to_vertex_buffer_builder(FontData const *font_data,
|
||||
(void)font_data;
|
||||
|
||||
ElementIndexedQuadWithoutColor buffer_element = {
|
||||
.v0 = (Vec2Packed){ quad.x0, quad.y0 },
|
||||
.v1 = (Vec2Packed){ quad.x1, quad.y0 },
|
||||
.v2 = (Vec2Packed){ quad.x1, quad.y1 },
|
||||
.v3 = (Vec2Packed){ quad.x0, quad.y1 },
|
||||
.v0 = (Vec2){ quad.x0, quad.y0 },
|
||||
.v1 = (Vec2){ quad.x1, quad.y0 },
|
||||
.v2 = (Vec2){ quad.x1, quad.y1 },
|
||||
.v3 = (Vec2){ quad.x0, quad.y1 },
|
||||
|
||||
.uv0 = (Vec2Packed){ quad.s0, quad.t0 },
|
||||
.uv1 = (Vec2Packed){ quad.s1, quad.t0 },
|
||||
.uv2 = (Vec2Packed){ quad.s1, quad.t1 },
|
||||
.uv3 = (Vec2Packed){ quad.s0, quad.t1 },
|
||||
.uv0 = (Vec2){ quad.s0, quad.t0 },
|
||||
.uv1 = (Vec2){ quad.s1, quad.t0 },
|
||||
.uv2 = (Vec2){ quad.s1, quad.t1 },
|
||||
.uv3 = (Vec2){ quad.s0, quad.t1 },
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
@ -537,44 +796,46 @@ void finally_draw_text(FontData const *font_data,
|
||||
Color color,
|
||||
VertexBuffer buffer)
|
||||
{
|
||||
(void)buffer;
|
||||
DeferredCommandDraw command = {0};
|
||||
|
||||
/* vertex specification */
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2,
|
||||
GL_FLOAT,
|
||||
offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||
(void *)(size_t)offsetof(ElementIndexedQuadWithoutColor, v0));
|
||||
command.vertices = (AttributeArrayPointer) {
|
||||
.arity = 2,
|
||||
.type = GL_FLOAT,
|
||||
.stride = offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||
.offset = offsetof(ElementIndexedQuadWithoutColor, v0),
|
||||
.buffer = buffer
|
||||
};
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexCoordPointer(2,
|
||||
GL_FLOAT,
|
||||
offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||
(void *)(size_t)offsetof(ElementIndexedQuadWithoutColor, uv0));
|
||||
command.texcoords = (AttributeArrayPointer) {
|
||||
.arity = 2,
|
||||
.type = GL_FLOAT,
|
||||
.stride = offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||
.offset = offsetof(ElementIndexedQuadWithoutColor, uv0),
|
||||
.buffer = buffer
|
||||
};
|
||||
|
||||
bind_quad_element_buffer();
|
||||
command.constant_colored = true;
|
||||
command.color = color;
|
||||
|
||||
command.gpu_texture = font_data->texture;
|
||||
command.uses_gpu_key = true;
|
||||
command.textured = true;
|
||||
|
||||
command.element_buffer = get_quad_element_buffer();
|
||||
command.element_count = 6 * (GLsizei)len;
|
||||
command.range_end = 6 * (GLsizei)len;
|
||||
|
||||
use_texture_mode(TEXTURE_MODE_GHOSTLY);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, font_data->texture);
|
||||
DeferredCommand final_command = {
|
||||
.type = DEFERRED_COMMAND_TYPE_DRAW,
|
||||
.draw = command
|
||||
};
|
||||
|
||||
glColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6 * (GLsizei)len, GL_UNSIGNED_SHORT, NULL);
|
||||
|
||||
/* clear the state */
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
arrpush(deferred_commands, final_command);
|
||||
|
||||
/* TODO: why doesn't it get restored if not placed here? */
|
||||
glDepthMask(GL_TRUE);
|
||||
// glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
|
||||
@ -603,6 +864,47 @@ static void load_cubemap_side(const char *path, GLenum target) {
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
|
||||
void render_circle(const CirclePrimitive *circle) {
|
||||
static Vec2 vertices[CIRCLE_VERTICES_MAX];
|
||||
int num_vertices = CIRCLE_VERTICES_MAX - 1;
|
||||
|
||||
create_circle_geometry(circle->position,
|
||||
circle->radius,
|
||||
num_vertices,
|
||||
vertices);
|
||||
|
||||
VertexBuffer buffer = get_scratch_vertex_array();
|
||||
specify_vertex_buffer(buffer, vertices, sizeof (Vec2) * num_vertices);
|
||||
|
||||
DeferredCommandDraw command = {0};
|
||||
|
||||
command.vertices = (AttributeArrayPointer) {
|
||||
.arity = 2,
|
||||
.type = GL_FLOAT,
|
||||
.stride = sizeof (Vec2),
|
||||
.offset = 0,
|
||||
.buffer = buffer
|
||||
};
|
||||
|
||||
command.constant_colored = true;
|
||||
command.color = circle->color;
|
||||
|
||||
command.element_buffer = get_circle_element_buffer();
|
||||
command.element_count = num_vertices * 3;
|
||||
command.range_end = num_vertices * 3;
|
||||
|
||||
use_texture_mode(circle->color.a == 255 ? TEXTURE_MODE_OPAQUE : TEXTURE_MODE_GHOSTLY);
|
||||
|
||||
DeferredCommand final_command = {
|
||||
.type = DEFERRED_COMMAND_TYPE_DRAW,
|
||||
.draw = command
|
||||
};
|
||||
|
||||
arrpush(deferred_commands, final_command);
|
||||
}
|
||||
|
||||
|
||||
void finally_render_skybox(char *paths) {
|
||||
static GLuint cubemap = 0;
|
||||
static char *paths_cache = NULL;
|
||||
@ -769,3 +1071,16 @@ void finally_apply_fog(float start, float end, float density, Color color) {
|
||||
void finally_pop_fog(void) {
|
||||
glDisable(GL_FOG);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -32,65 +32,60 @@ void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes)
|
||||
}
|
||||
|
||||
|
||||
void bind_quad_element_buffer(void) {
|
||||
static GLuint buffer = 0;
|
||||
VertexBuffer get_quad_element_buffer(void) {
|
||||
static VertexBuffer buffer = 0;
|
||||
|
||||
/* it's only generated once at runtime */
|
||||
/* TODO: use builder interface, not direct calls (glMapBuffer isn't portable) */
|
||||
if (buffer == 0) {
|
||||
glGenBuffers(1, &buffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
QUAD_ELEMENT_BUFFER_LENGTH * 6 * sizeof(uint16_t),
|
||||
NULL,
|
||||
GL_STATIC_DRAW);
|
||||
buffer = create_vertex_buffer();
|
||||
VertexBufferBuilder builder = build_vertex_buffer(buffer, sizeof (GLshort) * QUAD_ELEMENT_BUFFER_LENGTH * 6 );
|
||||
|
||||
uint16_t *const indices = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
GL_WRITE_ONLY);
|
||||
if (!indices)
|
||||
CRY("Quad indices generation", "glMapBuffer() failed");
|
||||
for (size_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) {
|
||||
GLshort indices[6];
|
||||
indices[0] = (GLshort)(i * 4 + 0);
|
||||
indices[1] = (GLshort)(i * 4 + 1);
|
||||
indices[2] = (GLshort)(i * 4 + 2);
|
||||
indices[3] = (GLshort)(i * 4 + 2);
|
||||
indices[4] = (GLshort)(i * 4 + 3);
|
||||
indices[5] = (GLshort)(i * 4 + 0);
|
||||
|
||||
for (uint16_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) {
|
||||
indices[i * 6 + 0] = (uint16_t)(i * 4 + 0);
|
||||
indices[i * 6 + 1] = (uint16_t)(i * 4 + 1);
|
||||
indices[i * 6 + 2] = (uint16_t)(i * 4 + 2);
|
||||
indices[i * 6 + 3] = (uint16_t)(i * 4 + 2);
|
||||
indices[i * 6 + 4] = (uint16_t)(i * 4 + 3);
|
||||
indices[i * 6 + 5] = (uint16_t)(i * 4 + 0);
|
||||
push_to_vertex_buffer_builder(&builder, indices, sizeof indices);
|
||||
}
|
||||
}
|
||||
|
||||
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||
SDL_assert_always(buffer);
|
||||
|
||||
} else
|
||||
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);
|
||||
VertexBuffer get_circle_element_buffer(void) {
|
||||
static VertexBuffer buffer = 0;
|
||||
|
||||
glDepthRange(0.0, 1.0);
|
||||
glDepthMask(GL_TRUE);
|
||||
if (buffer == 0) {
|
||||
buffer = create_vertex_buffer();
|
||||
VertexBufferBuilder builder = build_vertex_buffer(buffer, sizeof (GLshort) * CIRCLE_ELEMENT_BUFFER_LENGTH);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
void set_depth_range(double low, double high) {
|
||||
glDepthRange(low, high);
|
||||
for (size_t i = 1; i < CIRCLE_VERTICES_MAX; ++i) {
|
||||
/* first one is center point index, always zero */
|
||||
GLshort indices[3];
|
||||
|
||||
indices[0] = 0;
|
||||
|
||||
/* generated point index */
|
||||
indices[1] = (GLshort)i;
|
||||
|
||||
size_t index = (i + 1) % (CIRCLE_VERTICES_MAX - 1);
|
||||
if (index == 0) /* don't use center for outer ring */
|
||||
index = (CIRCLE_VERTICES_MAX - 1);
|
||||
indices[2] = (GLshort)index;
|
||||
|
||||
push_to_vertex_buffer_builder(&builder, indices, sizeof indices);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert_always(buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -72,9 +72,7 @@ void render_rect_batch(const Primitive2D primitives[],
|
||||
SDL_assert(primitives[0].type == PRIMITIVE_2D_RECT);
|
||||
|
||||
/* single vertex array is used for every batch with NULL glBufferData() trick at the end */
|
||||
static VertexBuffer vertex_array = 0;
|
||||
if (vertex_array == 0)
|
||||
vertex_array = create_vertex_buffer();
|
||||
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||
|
||||
use_texture_mode(batch.mode);
|
||||
|
||||
|
@ -125,16 +125,15 @@ void render_sprite_batch(const Primitive2D primitives[],
|
||||
SDL_assert(primitives && batch.size != 0);
|
||||
SDL_assert(primitives[0].type == PRIMITIVE_2D_SPRITE);
|
||||
|
||||
/* single vertex array is used for every batch with NULL glBufferData() trick at the end */
|
||||
static VertexBuffer vertex_array = 0;
|
||||
if (vertex_array == 0)
|
||||
vertex_array = create_vertex_buffer();
|
||||
|
||||
use_texture_mode(batch.mode);
|
||||
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||
|
||||
const Rect dims =
|
||||
textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
|
||||
/* cached srcrect */
|
||||
Rect cached_srcrect;
|
||||
TextureKey cached_srcrect_key = TEXTURE_KEY_INVALID;
|
||||
|
||||
/* vertex population over a vertex buffer builder interface */
|
||||
{
|
||||
VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_quad_payload_size(batch) * batch.size);
|
||||
@ -144,13 +143,16 @@ void render_sprite_batch(const Primitive2D primitives[],
|
||||
const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1;
|
||||
const SpritePrimitive sprite = primitives[cur].sprite;
|
||||
|
||||
/* TODO: try caching it */
|
||||
const Rect srcrect =
|
||||
textures_get_srcrect(&ctx.texture_cache, primitives[cur].sprite.texture_key);
|
||||
if (primitives[cur].sprite.texture_key.id != cached_srcrect_key.id) {
|
||||
cached_srcrect = textures_get_srcrect(&ctx.texture_cache, primitives[cur].sprite.texture_key);
|
||||
cached_srcrect_key = primitives[cur].sprite.texture_key;
|
||||
}
|
||||
|
||||
Rect const srcrect = cached_srcrect;
|
||||
|
||||
Vec2 uv0, uv1, uv2, uv3;
|
||||
|
||||
if (!sprite.repeat) {
|
||||
if (!batch.repeat) {
|
||||
const float wr = srcrect.w / dims.w;
|
||||
const float hr = srcrect.h / dims.h;
|
||||
const float xr = srcrect.x / dims.w;
|
||||
|
@ -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) {
|
||||
VertexBuffer vertex_array = 0;
|
||||
if (vertex_array == 0)
|
||||
vertex_array = create_vertex_buffer();
|
||||
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||
|
||||
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,
|
||||
TextureKey texture_key)
|
||||
{
|
||||
static VertexBuffer vertex_array = 0;
|
||||
if (vertex_array == 0)
|
||||
vertex_array = create_vertex_buffer();
|
||||
VertexBuffer const vertex_array = get_scratch_vertex_array();
|
||||
|
||||
const size_t primitives_len = arrlenu(batch->primitives);
|
||||
|
||||
|
@ -77,6 +77,7 @@ typedef struct EngineContext {
|
||||
bool window_size_has_changed;
|
||||
bool resync_flag;
|
||||
bool was_successful;
|
||||
bool render_double_buffered;
|
||||
} EngineContext;
|
||||
|
||||
/* 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;
|
||||
|
||||
fail:
|
||||
|
@ -50,6 +50,7 @@ typedef struct TextureCache {
|
||||
typedef struct TextureKey { uint16_t id; } TextureKey;
|
||||
|
||||
/* tests whether given key structure corresponds to any texture */
|
||||
#define TEXTURE_KEY_INVALID (TextureKey) { (uint16_t)-1 }
|
||||
#define m_texture_key_is_valid(p_key) ((p_key).id != (uint16_t)-1)
|
||||
|
||||
void textures_cache_init(struct TextureCache *cache, SDL_Window *window);
|
||||
|
@ -39,7 +39,7 @@ static inline float fast_sqrt(float x)
|
||||
|
||||
|
||||
static inline Vec2 fast_cossine(float a) {
|
||||
const float s = SDL_sinf(a);
|
||||
const float s = sinf(a);
|
||||
return (Vec2){
|
||||
.x = fast_sqrt(1.0f - s * s) * (a >= (float)M_PI_2 && a < (float)(M_PI + M_PI_2) ? -1 : 1),
|
||||
.y = s
|
||||
|
Loading…
Reference in New Issue
Block a user