Compare commits
10 Commits
8ec5a96333
...
7c0bf39f12
Author | SHA1 | Date | |
---|---|---|---|
|
7c0bf39f12 | ||
|
4f2b8ccd01 | ||
|
472a0657f3 | ||
|
0f368e2700 | ||
|
33471b4c46 | ||
|
edcb7fc39c | ||
|
f9a8448782 | ||
|
6d5732cc2b | ||
|
62d738cbbe | ||
|
f4a3298906 |
@ -102,7 +102,7 @@ set(TWN_NONOPT_SOURCE_FILES
|
|||||||
src/twn_audio.c include/twn_audio.h
|
src/twn_audio.c include/twn_audio.h
|
||||||
src/twn_util.c include/twn_util.h
|
src/twn_util.c include/twn_util.h
|
||||||
src/twn_input.c include/twn_input.h
|
src/twn_input.c include/twn_input.h
|
||||||
src/twn_camera.c include/twn_camera.h
|
src/twn_camera.c src/twn_camera_c.h
|
||||||
src/twn_textures.c src/twn_textures_c.h
|
src/twn_textures.c src/twn_textures_c.h
|
||||||
|
|
||||||
src/rendering/twn_draw.c src/rendering/twn_draw_c.h
|
src/rendering/twn_draw.c src/rendering/twn_draw_c.h
|
||||||
|
@ -19,7 +19,7 @@ def default(parameter):
|
|||||||
return "NULL"
|
return "NULL"
|
||||||
else: return '"' + parameter["default"] + '"'
|
else: return '"' + parameter["default"] + '"'
|
||||||
elif basetype in api["types"]:
|
elif basetype in api["types"]:
|
||||||
if parameter["type"].endswith("*"):
|
if parameter["type"].endswith(" *"):
|
||||||
if parameter["default"] == {}:
|
if parameter["default"] == {}:
|
||||||
return "NULL"
|
return "NULL"
|
||||||
else:
|
else:
|
||||||
@ -103,7 +103,7 @@ for procedure, procedure_desc in api["procedures"].items():
|
|||||||
elif parameter["type"] == "char *":
|
elif parameter["type"] == "char *":
|
||||||
binding += " %s = lua_tostring(L, -1);\n" % (parameter["name"]);
|
binding += " %s = lua_tostring(L, -1);\n" % (parameter["name"]);
|
||||||
elif basetype in api["types"]:
|
elif basetype in api["types"]:
|
||||||
if parameter["type"].endswith("*"):
|
if parameter["type"].endswith(" *"):
|
||||||
binding += " { %s_value = to_%s(L, -1); %s = &%s_value; }\n" % (parameter["name"], basetype.lower(), parameter["name"], parameter["name"]);
|
binding += " { %s_value = to_%s(L, -1); %s = &%s_value; }\n" % (parameter["name"], basetype.lower(), parameter["name"], parameter["name"]);
|
||||||
else:
|
else:
|
||||||
binding += " %s = to_%s(L, -1);\n" % (parameter["name"], basetype.lower());
|
binding += " %s = to_%s(L, -1);\n" % (parameter["name"], basetype.lower());
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#!/bin/env sh
|
#!/bin/env sh
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
# check whether ninja is around (you better start running)
|
# check whether ninja is around (you better start running)
|
||||||
if [ -x "$(command -v ninja)" ]; then
|
if [ -x "$(command -v ninja)" ]; then
|
||||||
generator="-G Ninja"
|
generator="-G Ninja"
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#!/bin/env sh
|
#!/bin/env sh
|
||||||
# single header api generator with clang
|
# single header api generator with clang
|
||||||
|
|
||||||
|
set +e
|
||||||
|
|
||||||
clang -I./ -P -E -nostdinc -nobuiltininc -DTWN_NOT_C $TWNROOT/include/twn_game_api.h 2> /dev/null | clang-format
|
clang -I./ -P -E -nostdinc -nobuiltininc -DTWN_NOT_C $TWNROOT/include/twn_game_api.h 2> /dev/null | clang-format
|
||||||
|
@ -4,12 +4,13 @@ for that certain considerations are taken:
|
|||||||
|
|
||||||
* number of public api calls is kept at the minimum
|
* number of public api calls is kept at the minimum
|
||||||
* procedure parameters can only use basic types, no aggregates, with exception of Vec/Matrix types and alike,
|
* procedure parameters can only use basic types, no aggregates, with exception of Vec/Matrix types and alike,
|
||||||
with no expectation on new additions (see [/include/twn_types.h](../include/twn_types.h))
|
with no new additions, ever (see [/include/twn_types.h](../include/twn_types.h))
|
||||||
* optionals can be expressed via pointer passage of value primitives, assumed immutable, with the NULL expressing default
|
* optionals can be expressed via pointer passage of value primitives, assumed immutable, with the NULL expressing default value
|
||||||
* no opaque types, only keys
|
* no opaque types, only keys if needed
|
||||||
* when mutation on input is done, - it shouldn't be achieved from a mutable pointer, but the return value
|
* pointers to pointers aren't allowed
|
||||||
* return value could be a simple aggregate that is translatable to pure data dictionary
|
* when mutation on input is done, - it shouldn't be achieved by a mutable pointer, but the return value
|
||||||
|
* return value could be a simple aggregate that is translatable to a dictionary of primitives
|
||||||
* module prefix is used for namespacing, actual symbols come after the prefix (`<module>_<symbol>`)
|
* module prefix is used for namespacing, actual symbols come after the prefix (`<module>_<symbol>`)
|
||||||
* symbols should not contain numerics at the start nor after the namespace prefix
|
* symbols should not contain numerics at the start nor after the namespace prefix
|
||||||
* 32 bit floating point is the only numeric type
|
* 32 bit floating point is the only numeric type
|
||||||
* [/include/twn_api.json](../include/twn_api.json) file is hand-kept with a schema to aid automatic binding generation and tooling
|
* [/include/twn_api.json](../share/twn_api.json) file is hand-kept with a schema to aid automatic binding generation and tooling
|
||||||
|
1
hooks
1
hooks
@ -6,3 +6,4 @@ set +e
|
|||||||
|
|
||||||
# TODO: prevent double hooking
|
# TODO: prevent double hooking
|
||||||
export PATH=$PATH:$(realpath $(dirname -- "${BASH_SOURCE[0]}")/bin/)
|
export PATH=$PATH:$(realpath $(dirname -- "${BASH_SOURCE[0]}")/bin/)
|
||||||
|
export TWNROOT=$(realpath $(dirname -- "${BASH_SOURCE[0]}"))
|
||||||
|
@ -68,7 +68,9 @@ TWN_API void draw_triangle(char const *texture,
|
|||||||
|
|
||||||
TWN_API void draw_billboard(const char *path,
|
TWN_API void draw_billboard(const char *path,
|
||||||
Vec3 position,
|
Vec3 position,
|
||||||
Vec2 size);
|
Vec2 size,
|
||||||
|
Color color, /* optional, default: all 255 */
|
||||||
|
bool cylindrical); /* optional, default: false */
|
||||||
|
|
||||||
/* sets a perspective 3d camera to be used for all 3d commands */
|
/* sets a perspective 3d camera to be used for all 3d commands */
|
||||||
TWN_API void draw_camera(Vec3 position, float fov, Vec3 up, Vec3 direction);
|
TWN_API void draw_camera(Vec3 position, float fov, Vec3 up, Vec3 direction);
|
||||||
|
@ -49,7 +49,7 @@ typedef struct Rect {
|
|||||||
float h;
|
float h;
|
||||||
} Rect;
|
} Rect;
|
||||||
|
|
||||||
|
/* TODO: remove from here? */
|
||||||
typedef struct Matrix4 {
|
typedef struct Matrix4 {
|
||||||
Vec4 row[4];
|
Vec4 row[4];
|
||||||
} Matrix4;
|
} Matrix4;
|
||||||
|
115
src/rendering/twn_deferred_commands.h
Normal file
115
src/rendering/twn_deferred_commands.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#ifndef TWN_DEFERRED_COMMANDS_H
|
||||||
|
#define TWN_DEFERRED_COMMANDS_H
|
||||||
|
|
||||||
|
#include "twn_types.h"
|
||||||
|
#include "twn_gpu_texture_c.h"
|
||||||
|
#include "twn_textures_c.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PIPELINE_NO,
|
||||||
|
PIPELINE_SPACE,
|
||||||
|
PIPELINE_2D,
|
||||||
|
} Pipeline;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t offset;
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t stride;
|
||||||
|
uint32_t 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;
|
||||||
|
|
||||||
|
uint32_t element_buffer;
|
||||||
|
uint32_t element_count;
|
||||||
|
uint32_t range_start, range_end;
|
||||||
|
|
||||||
|
/* could be either `element_count` with supplied `element_buffer`, or this, but not both */
|
||||||
|
uint32_t primitive_count;
|
||||||
|
|
||||||
|
double depth_range_low, depth_range_high;
|
||||||
|
} DeferredCommandDraw;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *paths;
|
||||||
|
} DeferredCommandDrawSkybox;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Color color;
|
||||||
|
bool clear_color;
|
||||||
|
bool clear_depth;
|
||||||
|
bool clear_stencil;
|
||||||
|
} DeferredCommandClear;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Pipeline pipeline;
|
||||||
|
} DeferredCommandUsePipeline;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TextureMode mode;
|
||||||
|
} DeferredCommandUseTextureMode;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double low, high;
|
||||||
|
} DeferredCommandDepthRange;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float start, end, density;
|
||||||
|
Color color;
|
||||||
|
} DeferredCommandApplyFog;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum DeferredCommandType {
|
||||||
|
DEFERRED_COMMAND_TYPE_DRAW,
|
||||||
|
DEFERRED_COMMAND_TYPE_DRAW_SKYBOX,
|
||||||
|
DEFERRED_COMMAND_TYPE_CLEAR,
|
||||||
|
DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
|
||||||
|
DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE,
|
||||||
|
DEFERRED_COMMAND_TYPE_DEPTH_RANGE,
|
||||||
|
DEFERRED_COMMAND_TYPE_APPLY_FOG,
|
||||||
|
DEFERRED_COMMAND_TYPE_POP_FOG,
|
||||||
|
} type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
DeferredCommandDraw draw;
|
||||||
|
DeferredCommandDrawSkybox draw_skybox;
|
||||||
|
DeferredCommandClear clear;
|
||||||
|
DeferredCommandUsePipeline use_pipeline;
|
||||||
|
DeferredCommandUseTextureMode use_texture_mode;
|
||||||
|
DeferredCommandDepthRange depth_range;
|
||||||
|
DeferredCommandApplyFog apply_fog;
|
||||||
|
};
|
||||||
|
} DeferredCommand;
|
||||||
|
|
||||||
|
|
||||||
|
extern DeferredCommand *deferred_commands;
|
||||||
|
|
||||||
|
#endif
|
@ -3,21 +3,19 @@
|
|||||||
#include "twn_engine_context_c.h"
|
#include "twn_engine_context_c.h"
|
||||||
#include "twn_camera_c.h"
|
#include "twn_camera_c.h"
|
||||||
#include "twn_types.h"
|
#include "twn_types.h"
|
||||||
|
#include "twn_util_c.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>
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
#else
|
|
||||||
#include <glad/glad.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#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 +399,485 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void render_circle(const CirclePrimitive *circle) {
|
||||||
|
static Vec2 vertices[CIRCLE_VERTICES_MAX];
|
||||||
|
static int prev_num_vertices = 0;
|
||||||
|
static Vec2 prev_position = {0};
|
||||||
|
|
||||||
|
int const num_vertices = MIN((int)circle->radius, CIRCLE_VERTICES_MAX);
|
||||||
|
|
||||||
|
if (prev_num_vertices != num_vertices) {
|
||||||
|
create_circle_geometry(circle->position,
|
||||||
|
circle->radius,
|
||||||
|
num_vertices,
|
||||||
|
vertices);
|
||||||
|
prev_num_vertices = num_vertices;
|
||||||
|
prev_position = circle->position;
|
||||||
|
} else {
|
||||||
|
/* reuse the data, but offset it by difference with previously generated position */
|
||||||
|
/* no evil cos sin ops this way, if radius is shared in sequential calls */
|
||||||
|
Vec2 const d = { prev_position.x - circle->position.x, prev_position.y - circle->position.y };
|
||||||
|
for (int i = 0; i < num_vertices; ++i)
|
||||||
|
vertices[i] = (Vec2){ vertices[i].x - d.x, vertices[i].y - d.y };
|
||||||
|
prev_position = circle->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 - 2) * 3;
|
||||||
|
command.range_end = (num_vertices - 2) * 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_quads(const Primitive2D primitives[],
|
||||||
|
const struct QuadBatch batch,
|
||||||
|
const VertexBuffer buffer)
|
||||||
|
{
|
||||||
|
DeferredCommandDraw command = {0};
|
||||||
|
|
||||||
|
GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;
|
||||||
|
|
||||||
|
if (!batch.constant_colored && batch.textured) {
|
||||||
|
off = offsetof(ElementIndexedQuad, v1);
|
||||||
|
voff = offsetof(ElementIndexedQuad, v0);
|
||||||
|
uvoff = offsetof(ElementIndexedQuad, uv0);
|
||||||
|
coff = offsetof(ElementIndexedQuad, c0);
|
||||||
|
} else if (batch.constant_colored && batch.textured) {
|
||||||
|
off = offsetof(ElementIndexedQuadWithoutColor, v1);
|
||||||
|
voff = offsetof(ElementIndexedQuadWithoutColor, v0);
|
||||||
|
uvoff = offsetof(ElementIndexedQuadWithoutColor, uv0);
|
||||||
|
} else if (!batch.constant_colored && !batch.textured) {
|
||||||
|
off = offsetof(ElementIndexedQuadWithoutTexture, v1);
|
||||||
|
voff = offsetof(ElementIndexedQuadWithoutTexture, v0);
|
||||||
|
coff = offsetof(ElementIndexedQuad, c0);
|
||||||
|
} else if (batch.constant_colored && !batch.textured) {
|
||||||
|
off = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v1);
|
||||||
|
voff = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
command.vertices = (AttributeArrayPointer) {
|
||||||
|
.arity = 2,
|
||||||
|
.type = GL_FLOAT,
|
||||||
|
.stride = off,
|
||||||
|
.offset = voff,
|
||||||
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
if (batch.textured)
|
||||||
|
command.texcoords = (AttributeArrayPointer) {
|
||||||
|
.arity = 2,
|
||||||
|
.type = GL_FLOAT,
|
||||||
|
.stride = off,
|
||||||
|
.offset = uvoff,
|
||||||
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!batch.constant_colored) {
|
||||||
|
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) {
|
||||||
|
command.textured = true;
|
||||||
|
command.texture_key = batch.texture_key;
|
||||||
|
command.texture_repeat = batch.repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
command.element_buffer = get_quad_element_buffer();
|
||||||
|
command.element_count = 6 * (GLsizei)batch.size;
|
||||||
|
command.range_end = 6 * (GLsizei)batch.size;
|
||||||
|
|
||||||
|
use_texture_mode(batch.mode);
|
||||||
|
|
||||||
|
DeferredCommand final_command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_DRAW,
|
||||||
|
.draw = command
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, final_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t get_quad_payload_size(struct QuadBatch batch) {
|
||||||
|
if (batch.constant_colored && batch.textured)
|
||||||
|
return sizeof (ElementIndexedQuadWithoutColor);
|
||||||
|
else if (!batch.constant_colored && batch.textured)
|
||||||
|
return sizeof (ElementIndexedQuad);
|
||||||
|
else if (batch.constant_colored && !batch.textured)
|
||||||
|
return sizeof (ElementIndexedQuadWithoutColorWithoutTexture);
|
||||||
|
else if (!batch.constant_colored && !batch.textured)
|
||||||
|
return sizeof (ElementIndexedQuadWithoutTexture);
|
||||||
|
|
||||||
|
SDL_assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch,
|
||||||
|
VertexBufferBuilder *builder,
|
||||||
|
Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3,
|
||||||
|
Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
if (!batch.constant_colored && batch.textured) {
|
||||||
|
ElementIndexedQuad const buffer_element = {
|
||||||
|
.v0 = v0,
|
||||||
|
.v1 = v1,
|
||||||
|
.v2 = v2,
|
||||||
|
.v3 = v3,
|
||||||
|
|
||||||
|
.uv0 = uv0,
|
||||||
|
.uv1 = uv1,
|
||||||
|
.uv2 = uv2,
|
||||||
|
.uv3 = uv3,
|
||||||
|
|
||||||
|
/* equal for all (flat shaded) */
|
||||||
|
.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 = v0,
|
||||||
|
.v1 = v1,
|
||||||
|
.v2 = v2,
|
||||||
|
.v3 = v3,
|
||||||
|
|
||||||
|
.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 = v0,
|
||||||
|
.v1 = v1,
|
||||||
|
.v2 = v2,
|
||||||
|
.v3 = v3,
|
||||||
|
|
||||||
|
/* equal for all (flat shaded) */
|
||||||
|
.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 = v0,
|
||||||
|
.v1 = v1,
|
||||||
|
.v2 = v2,
|
||||||
|
.v3 = v3,
|
||||||
|
};
|
||||||
|
|
||||||
|
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void finally_draw_uncolored_space_traingle_batch(const MeshBatch *batch,
|
||||||
|
const TextureKey texture_key,
|
||||||
|
const VertexBuffer buffer)
|
||||||
|
{
|
||||||
|
const size_t primitives_len = arrlenu(batch->primitives);
|
||||||
|
|
||||||
|
/* nothing to do */
|
||||||
|
if (primitives_len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Rect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key);
|
||||||
|
const Rect dims = textures_get_dims(&ctx.texture_cache, texture_key);
|
||||||
|
|
||||||
|
const float wr = srcrect.w / dims.w;
|
||||||
|
const float hr = srcrect.h / dims.h;
|
||||||
|
const float xr = srcrect.x / dims.w;
|
||||||
|
const float yr = srcrect.y / dims.h;
|
||||||
|
|
||||||
|
/* update pixel-based uvs to correspond with texture atlases */
|
||||||
|
for (size_t i = 0; i < primitives_len; ++i) {
|
||||||
|
UncoloredSpaceTriangle *payload =
|
||||||
|
&((UncoloredSpaceTriangle *)(void *)batch->primitives)[i];
|
||||||
|
|
||||||
|
payload->uv0.x = xr + ((float)payload->uv0.x / srcrect.w) * wr;
|
||||||
|
payload->uv0.y = yr + ((float)payload->uv0.y / srcrect.h) * hr;
|
||||||
|
payload->uv1.x = xr + ((float)payload->uv1.x / srcrect.w) * wr;
|
||||||
|
payload->uv1.y = yr + ((float)payload->uv1.y / srcrect.h) * hr;
|
||||||
|
payload->uv2.x = xr + ((float)payload->uv2.x / srcrect.w) * wr;
|
||||||
|
payload->uv2.y = yr + ((float)payload->uv2.y / srcrect.h) * hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
specify_vertex_buffer(buffer, batch->primitives, primitives_len * sizeof (UncoloredSpaceTriangle));
|
||||||
|
|
||||||
|
DeferredCommandDraw command = {0};
|
||||||
|
|
||||||
|
command.vertices = (AttributeArrayPointer) {
|
||||||
|
.arity = 3,
|
||||||
|
.type = GL_FLOAT,
|
||||||
|
.stride = offsetof(UncoloredSpaceTriangle, v1),
|
||||||
|
.offset = offsetof(UncoloredSpaceTriangle, v0),
|
||||||
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
command.texcoords = (AttributeArrayPointer) {
|
||||||
|
.arity = 2,
|
||||||
|
.type = GL_FLOAT,
|
||||||
|
.stride = offsetof(UncoloredSpaceTriangle, v1),
|
||||||
|
.offset = offsetof(UncoloredSpaceTriangle, uv0),
|
||||||
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
command.textured = true;
|
||||||
|
command.texture_key = texture_key;
|
||||||
|
|
||||||
|
command.primitive_count = (GLsizei)(3 * primitives_len);
|
||||||
|
|
||||||
|
DeferredCommand final_command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_DRAW,
|
||||||
|
.draw = command
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, final_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool push_text_payload_to_vertex_buffer_builder(FontData const *font_data,
|
||||||
|
VertexBufferBuilder *builder,
|
||||||
|
stbtt_aligned_quad quad)
|
||||||
|
{
|
||||||
|
(void)font_data;
|
||||||
|
|
||||||
|
ElementIndexedQuadWithoutColor buffer_element = {
|
||||||
|
.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 = (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void finally_draw_text(FontData const *font_data,
|
||||||
|
size_t len,
|
||||||
|
Color color,
|
||||||
|
VertexBuffer buffer)
|
||||||
|
{
|
||||||
|
DeferredCommandDraw command = {0};
|
||||||
|
|
||||||
|
command.vertices = (AttributeArrayPointer) {
|
||||||
|
.arity = 2,
|
||||||
|
.type = GL_FLOAT,
|
||||||
|
.stride = offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||||
|
.offset = offsetof(ElementIndexedQuadWithoutColor, v0),
|
||||||
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
command.texcoords = (AttributeArrayPointer) {
|
||||||
|
.arity = 2,
|
||||||
|
.type = GL_FLOAT,
|
||||||
|
.stride = offsetof(ElementIndexedQuadWithoutColor, v1),
|
||||||
|
.offset = offsetof(ElementIndexedQuadWithoutColor, uv0),
|
||||||
|
.buffer = 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);
|
||||||
|
|
||||||
|
DeferredCommand final_command = {
|
||||||
|
.type = DEFERRED_COMMAND_TYPE_DRAW,
|
||||||
|
.draw = command
|
||||||
|
};
|
||||||
|
|
||||||
|
arrpush(deferred_commands, final_command);
|
||||||
|
|
||||||
|
/* TODO: why doesn't it get restored if not placed here? */
|
||||||
|
// glDepthMask(GL_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t get_text_payload_size(void) {
|
||||||
|
return sizeof (ElementIndexedQuadWithoutColor);
|
||||||
|
}
|
||||||
|
@ -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>
|
||||||
@ -37,12 +40,13 @@ typedef struct SpritePrimitive {
|
|||||||
Color color;
|
Color color;
|
||||||
float rotation;
|
float rotation;
|
||||||
TextureKey texture_key;
|
TextureKey texture_key;
|
||||||
bool flip_x;
|
|
||||||
bool flip_y;
|
|
||||||
bool repeat;
|
|
||||||
|
|
||||||
m_option_list(
|
m_option_list(
|
||||||
Rect, texture_region )
|
Rect, texture_region )
|
||||||
|
|
||||||
|
bool flip_x;
|
||||||
|
bool flip_y;
|
||||||
|
bool repeat;
|
||||||
} SpritePrimitive;
|
} SpritePrimitive;
|
||||||
|
|
||||||
typedef struct RectPrimitive {
|
typedef struct RectPrimitive {
|
||||||
@ -109,6 +113,73 @@ typedef struct TextCache {
|
|||||||
} TextCache;
|
} TextCache;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
Vec2 v0;
|
||||||
|
Vec2 uv0;
|
||||||
|
Color c0;
|
||||||
|
/* bottom-left */
|
||||||
|
Vec2 v1;
|
||||||
|
Vec2 uv1;
|
||||||
|
Color c1;
|
||||||
|
/* bottom-right */
|
||||||
|
Vec2 v2;
|
||||||
|
Vec2 uv2;
|
||||||
|
Color c2;
|
||||||
|
/* upper-right */
|
||||||
|
Vec2 v3;
|
||||||
|
Vec2 uv3;
|
||||||
|
Color c3;
|
||||||
|
} ElementIndexedQuad;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ElementIndexedQuadWithoutColor {
|
||||||
|
/* upper-left */
|
||||||
|
Vec2 v0;
|
||||||
|
Vec2 uv0;
|
||||||
|
/* bottom-left */
|
||||||
|
Vec2 v1;
|
||||||
|
Vec2 uv1;
|
||||||
|
/* bottom-right */
|
||||||
|
Vec2 v2;
|
||||||
|
Vec2 uv2;
|
||||||
|
/* upper-right */
|
||||||
|
Vec2 v3;
|
||||||
|
Vec2 uv3;
|
||||||
|
} ElementIndexedQuadWithoutColor;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ElementIndexedQuadWithoutTexture {
|
||||||
|
/* upper-left */
|
||||||
|
Vec2 v0;
|
||||||
|
Color c0;
|
||||||
|
/* bottom-left */
|
||||||
|
Vec2 v1;
|
||||||
|
Color c1;
|
||||||
|
/* bottom-right */
|
||||||
|
Vec2 v2;
|
||||||
|
Color c2;
|
||||||
|
/* upper-right */
|
||||||
|
Vec2 v3;
|
||||||
|
Color c3;
|
||||||
|
} ElementIndexedQuadWithoutTexture;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ElementIndexedQuadWithoutColorWithoutTexture {
|
||||||
|
/* upper-left */
|
||||||
|
Vec2 v0;
|
||||||
|
/* bottom-left */
|
||||||
|
Vec2 v1;
|
||||||
|
/* bottom-right */
|
||||||
|
Vec2 v2;
|
||||||
|
/* upper-right */
|
||||||
|
Vec2 v3;
|
||||||
|
} ElementIndexedQuadWithoutColorWithoutTexture;
|
||||||
|
|
||||||
|
|
||||||
/* renders the background, then the primitives in all render queues */
|
/* renders the background, then the primitives in all render queues */
|
||||||
void render(void);
|
void render(void);
|
||||||
|
|
||||||
@ -172,10 +243,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);
|
||||||
|
|
||||||
@ -186,10 +259,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,
|
||||||
@ -219,19 +295,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);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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