big rendering overhaul (cleaning and api abstraction)
This commit is contained in:
		@@ -133,7 +133,7 @@ void finally_draw_billboard_batch(struct MeshBatch const *batch,
 | 
			
		||||
 | 
			
		||||
        command.vertices = (AttributeArrayPointer) {
 | 
			
		||||
            .arity = 3,
 | 
			
		||||
            .type = GL_FLOAT,
 | 
			
		||||
            .type = TWN_FLOAT,
 | 
			
		||||
            .stride = offsetof(ElementIndexedBillboard, v1),
 | 
			
		||||
            .offset = offsetof(ElementIndexedBillboard, v0),
 | 
			
		||||
            .buffer = buffer
 | 
			
		||||
@@ -141,7 +141,7 @@ void finally_draw_billboard_batch(struct MeshBatch const *batch,
 | 
			
		||||
 | 
			
		||||
        command.texcoords = (AttributeArrayPointer) {
 | 
			
		||||
            .arity = 2,
 | 
			
		||||
            .type = GL_FLOAT,
 | 
			
		||||
            .type = TWN_FLOAT,
 | 
			
		||||
            .stride = offsetof(ElementIndexedBillboard, v1),
 | 
			
		||||
            .offset = offsetof(ElementIndexedBillboard, uv0),
 | 
			
		||||
            .buffer = buffer
 | 
			
		||||
@@ -149,7 +149,7 @@ void finally_draw_billboard_batch(struct MeshBatch const *batch,
 | 
			
		||||
 | 
			
		||||
        command.colors = (AttributeArrayPointer) {
 | 
			
		||||
            .arity = 4,
 | 
			
		||||
            .type = GL_UNSIGNED_BYTE,
 | 
			
		||||
            .type = TWN_UNSIGNED_BYTE,
 | 
			
		||||
            .stride = offsetof(ElementIndexedBillboard, v1),
 | 
			
		||||
            .offset = offsetof(ElementIndexedBillboard, c0),
 | 
			
		||||
            .buffer = buffer
 | 
			
		||||
@@ -159,14 +159,19 @@ void finally_draw_billboard_batch(struct MeshBatch const *batch,
 | 
			
		||||
        command.texture_key = texture_key;
 | 
			
		||||
 | 
			
		||||
        command.element_buffer = get_quad_element_buffer();
 | 
			
		||||
        command.element_count = 6 * (GLsizei)primitives_len;
 | 
			
		||||
        command.range_end = 6 * (GLsizei)primitives_len;
 | 
			
		||||
        command.element_count = 6 * (uint32_t)primitives_len;
 | 
			
		||||
        command.range_end = 6 * (uint32_t)primitives_len;
 | 
			
		||||
 | 
			
		||||
        /* TODO: support alpha blended case, with distance sort */
 | 
			
		||||
        TextureMode mode = textures_get_mode(&ctx.texture_cache, texture_key);
 | 
			
		||||
        if (mode == TEXTURE_MODE_GHOSTLY)
 | 
			
		||||
            mode = TEXTURE_MODE_SEETHROUGH;
 | 
			
		||||
        use_texture_mode(mode);
 | 
			
		||||
 | 
			
		||||
        command.texture_mode = mode;
 | 
			
		||||
        command.pipeline = PIPELINE_SPACE;
 | 
			
		||||
 | 
			
		||||
        command.depth_range_high = depth_range_high;
 | 
			
		||||
        command.depth_range_low = depth_range_low;
 | 
			
		||||
 | 
			
		||||
        DeferredCommand final_command = {
 | 
			
		||||
            .type = DEFERRED_COMMAND_TYPE_DRAW,
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ void render_circle(const CirclePrimitive *circle) {
 | 
			
		||||
 | 
			
		||||
    command.vertices = (AttributeArrayPointer) {
 | 
			
		||||
        .arity = 2,
 | 
			
		||||
        .type = GL_FLOAT,
 | 
			
		||||
        .type = TWN_FLOAT,
 | 
			
		||||
        .stride = sizeof (Vec2),
 | 
			
		||||
        .offset = 0,
 | 
			
		||||
        .buffer = buffer
 | 
			
		||||
@@ -112,7 +112,11 @@ void render_circle(const CirclePrimitive *circle) {
 | 
			
		||||
    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);
 | 
			
		||||
    command.texture_mode = circle->color.a == 255 ? TEXTURE_MODE_OPAQUE : TEXTURE_MODE_GHOSTLY;
 | 
			
		||||
    command.pipeline = PIPELINE_2D;
 | 
			
		||||
 | 
			
		||||
    command.depth_range_high = depth_range_high;
 | 
			
		||||
    command.depth_range_low = depth_range_low;
 | 
			
		||||
 | 
			
		||||
    DeferredCommand final_command = {
 | 
			
		||||
        .type = DEFERRED_COMMAND_TYPE_DRAW,
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
typedef enum {
 | 
			
		||||
    PIPELINE_NO,
 | 
			
		||||
    PIPELINE_SPACE,
 | 
			
		||||
    PIPELINE_2D,
 | 
			
		||||
    PIPELINE_2D, /* TODO: rename to PIPELINE_PLANE? */
 | 
			
		||||
} Pipeline;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -30,25 +30,27 @@ typedef struct {
 | 
			
		||||
typedef struct {
 | 
			
		||||
    AttributeArrayPointer vertices;
 | 
			
		||||
    AttributeArrayPointer texcoords;
 | 
			
		||||
 | 
			
		||||
    bool constant_colored;
 | 
			
		||||
    union {
 | 
			
		||||
        AttributeArrayPointer colors;        
 | 
			
		||||
        AttributeArrayPointer colors;
 | 
			
		||||
        Color color;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool textured, texture_repeat, uses_gpu_key;
 | 
			
		||||
    double depth_range_low, depth_range_high;
 | 
			
		||||
 | 
			
		||||
    Pipeline pipeline;
 | 
			
		||||
    TextureMode texture_mode;
 | 
			
		||||
 | 
			
		||||
    TextureKey texture_key;
 | 
			
		||||
    GPUTexture gpu_texture;
 | 
			
		||||
 | 
			
		||||
    /* could be either `element_count` with supplied `element_buffer`, or this, but not both */
 | 
			
		||||
    uint32_t primitive_count;
 | 
			
		||||
    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;
 | 
			
		||||
    bool constant_colored;
 | 
			
		||||
    bool textured, texture_repeat, uses_gpu_key;
 | 
			
		||||
} DeferredCommandDraw;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -65,47 +67,17 @@ typedef struct {
 | 
			
		||||
} 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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
#include "twn_engine_context_c.h"
 | 
			
		||||
#include "twn_camera_c.h"
 | 
			
		||||
#include "twn_types.h"
 | 
			
		||||
#include "twn_util_c.h"
 | 
			
		||||
#include "twn_vec.h"
 | 
			
		||||
#include "twn_deferred_commands.h"
 | 
			
		||||
 | 
			
		||||
@@ -11,15 +10,19 @@
 | 
			
		||||
#include <stb_ds.h>
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <tgmath.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DeferredCommand *deferred_commands;
 | 
			
		||||
 | 
			
		||||
/* TODO: have a default initialized one */
 | 
			
		||||
/* TODO: with buffered render, don't we use camera of wrong frame right now ? */
 | 
			
		||||
Matrix4 camera_projection_matrix;
 | 
			
		||||
Matrix4 camera_look_at_matrix;
 | 
			
		||||
 | 
			
		||||
double depth_range_low, depth_range_high;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void render_queue_clear(void) {
 | 
			
		||||
    text_cache_reset_arena(&ctx.text_cache);
 | 
			
		||||
@@ -205,8 +208,6 @@ TWN_API void draw_quad(char const *texture,
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void render_2d(void) {
 | 
			
		||||
    use_2d_pipeline();
 | 
			
		||||
 | 
			
		||||
    const size_t render_queue_len = arrlenu(ctx.render_queue_2d);
 | 
			
		||||
 | 
			
		||||
    struct Render2DInvocation {
 | 
			
		||||
@@ -362,9 +363,6 @@ static void render_space(void) {
 | 
			
		||||
    /* nothing to do, abort */
 | 
			
		||||
    /* as space pipeline isn't used we can have fewer changes and initialization costs */
 | 
			
		||||
    if (hmlenu(ctx.uncolored_mesh_batches) != 0 || hmlenu(ctx.billboard_batches) != 0) {
 | 
			
		||||
        use_space_pipeline();
 | 
			
		||||
        apply_fog();
 | 
			
		||||
 | 
			
		||||
        for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i) {
 | 
			
		||||
            finally_draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i].value,
 | 
			
		||||
                                                        ctx.uncolored_mesh_batches[i].key);
 | 
			
		||||
@@ -373,8 +371,6 @@ static void render_space(void) {
 | 
			
		||||
        for (size_t i = 0; i < hmlenu(ctx.billboard_batches); ++i) {
 | 
			
		||||
            finally_draw_billboard_batch(&ctx.billboard_batches[i].value, ctx.billboard_batches[i].key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pop_fog();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render_skybox(); /* after everything else, as to use depth buffer for early z rejection */
 | 
			
		||||
@@ -439,15 +435,8 @@ DrawCameraFromPrincipalAxesResult draw_camera_from_principal_axes(Vec3 position,
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    depth_range_low = low;
 | 
			
		||||
    depth_range_high = high;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -468,44 +457,9 @@ void clear_draw_buffer(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
@@ -521,37 +475,6 @@ void issue_deferred_draw_commands(void) {
 | 
			
		||||
                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);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,27 +12,35 @@
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
#include <stb_truetype.h>
 | 
			
		||||
 | 
			
		||||
#ifdef EMSCRIPTEN
 | 
			
		||||
#include <GLES2/gl2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
extern Matrix4 camera_projection_matrix;
 | 
			
		||||
extern Matrix4 camera_look_at_matrix;
 | 
			
		||||
 | 
			
		||||
extern double depth_range_low, depth_range_high;
 | 
			
		||||
 | 
			
		||||
#define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6)
 | 
			
		||||
#define CIRCLE_VERTICES_MAX 2048
 | 
			
		||||
 | 
			
		||||
/* TODO: limit to only most necessary */
 | 
			
		||||
enum {
 | 
			
		||||
    TWN_FLOAT,
 | 
			
		||||
    TWN_INT,
 | 
			
		||||
    TWN_SHORT,
 | 
			
		||||
    TWN_UNSIGNED_SHORT,
 | 
			
		||||
    TWN_UNSIGNED_INT,
 | 
			
		||||
    TWN_BYTE,
 | 
			
		||||
    TWN_UNSIGNED_BYTE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef GLuint VertexBuffer;
 | 
			
		||||
 | 
			
		||||
typedef uint32_t VertexBuffer;
 | 
			
		||||
 | 
			
		||||
typedef struct VertexBufferBuilder {
 | 
			
		||||
    size_t bytes_left;
 | 
			
		||||
    size_t size;
 | 
			
		||||
    void *mapping;
 | 
			
		||||
    void *base;
 | 
			
		||||
} VertexBufferBuilder;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -209,6 +217,8 @@ typedef struct ElementIndexedBillboard {
 | 
			
		||||
} ElementIndexedBillboard;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool render_init(void);
 | 
			
		||||
 | 
			
		||||
/* renders the background, then the primitives in all render queues */
 | 
			
		||||
void render(void);
 | 
			
		||||
 | 
			
		||||
@@ -250,6 +260,8 @@ void text_cache_reset_arena(TextCache *cache);
 | 
			
		||||
 | 
			
		||||
VertexBuffer create_vertex_buffer(void);
 | 
			
		||||
 | 
			
		||||
void restart_scratch_vertex_arrays(void);
 | 
			
		||||
 | 
			
		||||
VertexBuffer get_scratch_vertex_array(void);
 | 
			
		||||
 | 
			
		||||
void delete_vertex_buffer(VertexBuffer buffer);
 | 
			
		||||
@@ -274,7 +286,6 @@ void finally_clear_draw_buffer(DeferredCommandClear command);
 | 
			
		||||
void swap_buffers(void);
 | 
			
		||||
 | 
			
		||||
void set_depth_range(double low, double high);
 | 
			
		||||
void finally_set_depth_range(DeferredCommandDepthRange command);
 | 
			
		||||
 | 
			
		||||
VertexBuffer get_quad_element_buffer(void);
 | 
			
		||||
 | 
			
		||||
@@ -284,15 +295,6 @@ void render_circle(const CirclePrimitive *circle);
 | 
			
		||||
 | 
			
		||||
void render_rectangle(const RectPrimitive *rectangle);
 | 
			
		||||
 | 
			
		||||
void use_space_pipeline(void);
 | 
			
		||||
void finally_use_space_pipeline(void);
 | 
			
		||||
 | 
			
		||||
void use_2d_pipeline(void);
 | 
			
		||||
void finally_use_2d_pipeline(void);
 | 
			
		||||
 | 
			
		||||
void use_texture_mode(TextureMode mode);
 | 
			
		||||
void finally_use_texture_mode(TextureMode mode);
 | 
			
		||||
 | 
			
		||||
void finally_render_quads(Primitive2D const primitives[],
 | 
			
		||||
                          struct QuadBatch batch,
 | 
			
		||||
                          VertexBuffer buffer);
 | 
			
		||||
@@ -325,11 +327,6 @@ void finally_draw_text(FontData const *font_data,
 | 
			
		||||
void render_skybox(void);
 | 
			
		||||
void finally_render_skybox(DeferredCommandDrawSkybox);
 | 
			
		||||
 | 
			
		||||
void apply_fog(void);
 | 
			
		||||
void finally_apply_fog(DeferredCommandApplyFog);
 | 
			
		||||
void pop_fog(void);
 | 
			
		||||
void finally_pop_fog(void);
 | 
			
		||||
 | 
			
		||||
void start_render_frame(void);
 | 
			
		||||
void end_render_frame(void);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,49 +0,0 @@
 | 
			
		||||
#include "twn_draw.h"
 | 
			
		||||
#include "twn_draw_c.h"
 | 
			
		||||
 | 
			
		||||
#include <stb_ds.h>
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
static float start_cache, end_cache, density_cache;
 | 
			
		||||
static Color color_cache;
 | 
			
		||||
static bool fog_used = false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void draw_fog(float start, float end, float density, Color color) {
 | 
			
		||||
    start_cache = start;
 | 
			
		||||
    end_cache = end;
 | 
			
		||||
    density_cache = density;
 | 
			
		||||
    color_cache = color;
 | 
			
		||||
    fog_used = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void apply_fog(void) {
 | 
			
		||||
    if (!fog_used)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void pop_fog(void) {
 | 
			
		||||
    if (!fog_used)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    DeferredCommand command = {
 | 
			
		||||
        .type = DEFERRED_COMMAND_TYPE_POP_FOG,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    arrpush(deferred_commands, command);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,71 +0,0 @@
 | 
			
		||||
#include "twn_gpu_texture_c.h"
 | 
			
		||||
#include "twn_util_c.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GPUTexture create_gpu_texture(TextureFilter filter, bool generate_mipmaps) {
 | 
			
		||||
    GLuint texture;
 | 
			
		||||
    glGenTextures(1, &texture);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, texture);
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
 | 
			
		||||
 | 
			
		||||
    if (filter == TEXTURE_FILTER_NEAREAST) {
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
			
		||||
    } else if (filter == TEXTURE_FILTER_LINEAR) {
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 | 
			
		||||
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 | 
			
		||||
 | 
			
		||||
#if !defined(EMSCRIPTEN)
 | 
			
		||||
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
    return texture;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void delete_gpu_texture(GPUTexture texture) {
 | 
			
		||||
    glDeleteTextures(1, &texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void upload_gpu_texture(GPUTexture texture, void *pixels, int channels, int width, int height) {
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, texture);
 | 
			
		||||
 | 
			
		||||
    int format_internal, format;
 | 
			
		||||
    if (channels == 4) {
 | 
			
		||||
        format_internal = GL_RGBA8;
 | 
			
		||||
        format = GL_RGBA;
 | 
			
		||||
    } else if (channels == 3) {
 | 
			
		||||
        format_internal = GL_RGBA8;
 | 
			
		||||
        format = GL_RGB;
 | 
			
		||||
    } else if (channels == 1) {
 | 
			
		||||
        format_internal = GL_ALPHA;
 | 
			
		||||
        format = GL_ALPHA;
 | 
			
		||||
    } else {
 | 
			
		||||
        CRY("upload_gpu_texture", "Unsupported channel count");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glTexImage2D(GL_TEXTURE_2D,
 | 
			
		||||
                 0,
 | 
			
		||||
                 format_internal,
 | 
			
		||||
                 width,
 | 
			
		||||
                 height,
 | 
			
		||||
                 0,
 | 
			
		||||
                 format,
 | 
			
		||||
                 GL_UNSIGNED_BYTE,
 | 
			
		||||
                 pixels);
 | 
			
		||||
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void bind_gpu_texture(GPUTexture texture) {
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, texture);
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
#include "twn_engine_context_c.h"
 | 
			
		||||
#include "twn_types.h"
 | 
			
		||||
#include "twn_deferred_commands.h"
 | 
			
		||||
#include "twn_gl_any_rendering_c.h"
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include <stb_ds.h>
 | 
			
		||||
@@ -14,8 +13,49 @@ static TextureMode texture_mode_last_used = TEXTURE_MODE_UNKNOWN;
 | 
			
		||||
static Pipeline pipeline_last_used = PIPELINE_NO;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void APIENTRY opengl_log(GLenum source,
 | 
			
		||||
                                GLenum type,
 | 
			
		||||
                                GLuint id,
 | 
			
		||||
                                GLenum severity,
 | 
			
		||||
                                GLsizei length,
 | 
			
		||||
                                const GLchar* message,
 | 
			
		||||
                                const void* userParam)
 | 
			
		||||
{
 | 
			
		||||
    (void)source;
 | 
			
		||||
    (void)type;
 | 
			
		||||
    (void)id;
 | 
			
		||||
    (void)severity;
 | 
			
		||||
    (void)userParam;
 | 
			
		||||
 | 
			
		||||
    log_info("OpenGL: %.*s\n", length, message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool render_init(void) {
 | 
			
		||||
    if (gladLoadGL() == 0) {
 | 
			
		||||
        CRY("Init", "GLAD failed");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
 | 
			
		||||
 | 
			
		||||
    glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
 | 
			
		||||
    glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
 | 
			
		||||
    glHint(GL_FOG_HINT, GL_FASTEST);
 | 
			
		||||
 | 
			
		||||
    /* hook up opengl debugging callback */
 | 
			
		||||
    if (ctx.game.debug) {
 | 
			
		||||
        glEnable(GL_DEBUG_OUTPUT);
 | 
			
		||||
        glDebugMessageCallback(opengl_log, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void start_render_frame(void) {
 | 
			
		||||
    clear_draw_buffer();
 | 
			
		||||
    pipeline_last_used = PIPELINE_NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -38,10 +78,13 @@ void end_render_frame(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_use_space_pipeline(void) {
 | 
			
		||||
static void finally_use_space_pipeline(void) {
 | 
			
		||||
    if (pipeline_last_used == PIPELINE_SPACE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    depth_range_high = 1.0;
 | 
			
		||||
    depth_range_low = 0.0;
 | 
			
		||||
 | 
			
		||||
    static GLuint list = 0;
 | 
			
		||||
    if (!list) {
 | 
			
		||||
        list = glGenLists(1);
 | 
			
		||||
@@ -54,9 +97,9 @@ void finally_use_space_pipeline(void) {
 | 
			
		||||
                glDisable(GL_DEPTH_CLAMP);
 | 
			
		||||
 | 
			
		||||
            glEnable(GL_CULL_FACE);
 | 
			
		||||
            glDepthRange(0, 1);
 | 
			
		||||
            glEnable(GL_TEXTURE_2D);
 | 
			
		||||
            glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
            glEnable(GL_DEPTH_TEST);
 | 
			
		||||
 | 
			
		||||
            /* solid white, no modulation */
 | 
			
		||||
            glColor4ub(255, 255, 255, 255);
 | 
			
		||||
@@ -76,7 +119,7 @@ void finally_use_space_pipeline(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_use_2d_pipeline(void) {
 | 
			
		||||
static void finally_use_2d_pipeline(void) {
 | 
			
		||||
    if (pipeline_last_used == PIPELINE_SPACE) {
 | 
			
		||||
        glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 | 
			
		||||
        glFlush();
 | 
			
		||||
@@ -111,6 +154,7 @@ void finally_use_2d_pipeline(void) {
 | 
			
		||||
    glOrtho(0, (double)ctx.base_render_width, (double)ctx.base_render_height, 0, 0, 1);
 | 
			
		||||
 | 
			
		||||
    glMatrixMode(GL_MODELVIEW);
 | 
			
		||||
    /* TODO: 2d camera */
 | 
			
		||||
    glLoadIdentity();
 | 
			
		||||
 | 
			
		||||
    texture_mode_last_used = -1;
 | 
			
		||||
@@ -118,7 +162,7 @@ void finally_use_2d_pipeline(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_use_texture_mode(TextureMode mode) {
 | 
			
		||||
static void finally_use_texture_mode(TextureMode mode) {
 | 
			
		||||
    if (texture_mode_last_used == mode)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@@ -248,6 +292,9 @@ void finally_render_skybox(DeferredCommandDrawSkybox command) {
 | 
			
		||||
    glMatrixMode(GL_MODELVIEW);
 | 
			
		||||
    glLoadMatrixf(&camera_look_at_matrix_solipsist.row[0].x);
 | 
			
		||||
 | 
			
		||||
    glDepthRange(0.0f, 1.0f);
 | 
			
		||||
    glDisable(GL_FOG);
 | 
			
		||||
 | 
			
		||||
    glDisable(GL_TEXTURE_2D);
 | 
			
		||||
    glEnable(GL_TEXTURE_CUBE_MAP);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
 | 
			
		||||
@@ -370,38 +417,6 @@ void finally_render_skybox(DeferredCommandDrawSkybox command) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_apply_fog(DeferredCommandApplyFog command) {
 | 
			
		||||
    if (command.density < 0.0f || command.density > 1.0f)
 | 
			
		||||
        log_warn("Invalid fog density given, should be in range [0..1]");
 | 
			
		||||
 | 
			
		||||
    /* TODO: cache it for constant parameters, which is a common case */
 | 
			
		||||
 | 
			
		||||
    glEnable(GL_FOG);
 | 
			
		||||
 | 
			
		||||
    glFogf(GL_FOG_DENSITY, command.density);
 | 
			
		||||
    glFogf(GL_FOG_START, command.start);
 | 
			
		||||
    glFogf(GL_FOG_END, command.end);
 | 
			
		||||
 | 
			
		||||
    float color_conv[4];
 | 
			
		||||
    color_conv[0] = (float)command.color.r / UINT8_MAX;
 | 
			
		||||
    color_conv[1] = (float)command.color.g / UINT8_MAX;
 | 
			
		||||
    color_conv[2] = (float)command.color.b / UINT8_MAX;
 | 
			
		||||
    color_conv[3] = (float)command.color.a / UINT8_MAX;
 | 
			
		||||
 | 
			
		||||
    glFogfv(GL_FOG_COLOR, color_conv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_pop_fog(void) {
 | 
			
		||||
    glDisable(GL_FOG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_set_depth_range(DeferredCommandDepthRange command) {
 | 
			
		||||
    glDepthRange(command.low, command.high);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_clear_draw_buffer(DeferredCommandClear command) {
 | 
			
		||||
    glClearColor((1.0f / 255) * command.color.r,
 | 
			
		||||
                 (1.0f / 255) * command.color.g,
 | 
			
		||||
@@ -418,18 +433,64 @@ void finally_clear_draw_buffer(DeferredCommandClear command) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static GLsizei to_gl_type_enum(int value) {
 | 
			
		||||
    switch (value) {
 | 
			
		||||
        case TWN_FLOAT: return GL_FLOAT;
 | 
			
		||||
        case TWN_INT: return GL_INT;
 | 
			
		||||
        case TWN_SHORT: return GL_SHORT;
 | 
			
		||||
        case TWN_UNSIGNED_SHORT: return GL_UNSIGNED_SHORT;
 | 
			
		||||
        case TWN_UNSIGNED_BYTE: return GL_UNSIGNED_BYTE;
 | 
			
		||||
        case TWN_BYTE: return GL_BYTE;
 | 
			
		||||
        default:
 | 
			
		||||
            CRY("to_gl_type_enum", "Unknown primitive type");
 | 
			
		||||
            return -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void finally_draw_command(DeferredCommandDraw command) {
 | 
			
		||||
    /* TODO: don't assume a single vertex array ? */
 | 
			
		||||
    SDL_assert(command.vertices.arity != 0);
 | 
			
		||||
    SDL_assert(command.vertices.buffer);
 | 
			
		||||
    SDL_assert((command.element_buffer && command.element_count != 0) || command.primitive_count != 0);
 | 
			
		||||
 | 
			
		||||
    /* TODO: cache previous setting, don't recommit */
 | 
			
		||||
    glDepthRange(command.depth_range_low, command.depth_range_high);
 | 
			
		||||
 | 
			
		||||
    /* TODO: cache it for constant parameters, which is a common case */
 | 
			
		||||
    if (fabsf(0.0f - ctx.game_copy.fog_density) >= 0.00001f) {
 | 
			
		||||
        glEnable(GL_FOG);
 | 
			
		||||
 | 
			
		||||
        /* clamp to valid range */
 | 
			
		||||
        ctx.game_copy.fog_density = clampf(ctx.game_copy.fog_density, 0.0, 1.0);
 | 
			
		||||
 | 
			
		||||
        glFogf(GL_FOG_DENSITY, ctx.game_copy.fog_density);
 | 
			
		||||
        glFogf(GL_FOG_START, ctx.game_copy.fog_start);
 | 
			
		||||
        glFogf(GL_FOG_END, ctx.game_copy.fog_end);
 | 
			
		||||
 | 
			
		||||
        float color_conv[4];
 | 
			
		||||
        color_conv[0] = (float)ctx.game_copy.fog_color.r / UINT8_MAX;
 | 
			
		||||
        color_conv[1] = (float)ctx.game_copy.fog_color.g / UINT8_MAX;
 | 
			
		||||
        color_conv[2] = (float)ctx.game_copy.fog_color.b / UINT8_MAX;
 | 
			
		||||
        color_conv[3] = (float)ctx.game_copy.fog_color.a / UINT8_MAX;
 | 
			
		||||
 | 
			
		||||
        glFogfv(GL_FOG_COLOR, color_conv);
 | 
			
		||||
    } else
 | 
			
		||||
        glDisable(GL_FOG);
 | 
			
		||||
 | 
			
		||||
    if (command.pipeline == PIPELINE_SPACE)
 | 
			
		||||
        finally_use_space_pipeline();
 | 
			
		||||
    else
 | 
			
		||||
        finally_use_2d_pipeline();
 | 
			
		||||
 | 
			
		||||
    finally_use_texture_mode(command.texture_mode);
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
                    to_gl_type_enum(command.vertices.type),
 | 
			
		||||
                    command.vertices.stride,
 | 
			
		||||
                    (void *)command.vertices.offset);
 | 
			
		||||
 | 
			
		||||
@@ -439,7 +500,7 @@ void finally_draw_command(DeferredCommandDraw command) {
 | 
			
		||||
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
			
		||||
        glClientActiveTexture(GL_TEXTURE0);
 | 
			
		||||
        glTexCoordPointer(command.texcoords.arity,
 | 
			
		||||
                          command.texcoords.type,
 | 
			
		||||
                          to_gl_type_enum(command.texcoords.type),
 | 
			
		||||
                          command.texcoords.stride,
 | 
			
		||||
                          (void *)command.texcoords.offset);
 | 
			
		||||
    }
 | 
			
		||||
@@ -449,7 +510,7 @@ void finally_draw_command(DeferredCommandDraw command) {
 | 
			
		||||
 | 
			
		||||
        glEnableClientState(GL_COLOR_ARRAY);
 | 
			
		||||
        glColorPointer(command.colors.arity,
 | 
			
		||||
                       command.colors.type,
 | 
			
		||||
                       to_gl_type_enum(command.colors.type),
 | 
			
		||||
                       command.colors.stride,
 | 
			
		||||
                       (void *)command.colors.offset);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#include "twn_gl_any_rendering_c.h"
 | 
			
		||||
#include "twn_draw_c.h"
 | 
			
		||||
#include "twn_engine_context_c.h"
 | 
			
		||||
#include "twn_util_c.h"
 | 
			
		||||
#include "twn_draw_c.h"
 | 
			
		||||
 | 
			
		||||
#include <stb_ds.h>
 | 
			
		||||
 | 
			
		||||
@@ -120,3 +120,85 @@ GLuint get_scratch_vertex_array(void) {
 | 
			
		||||
    (*used)++;
 | 
			
		||||
    return (*current_scratch_vertex_array)[*used - 1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GPUTexture create_gpu_texture(TextureFilter filter, bool generate_mipmaps) {
 | 
			
		||||
    GLuint texture;
 | 
			
		||||
    glGenTextures(1, &texture);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, texture);
 | 
			
		||||
 | 
			
		||||
#if !defined(EMSCRIPTEN)
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
 | 
			
		||||
#else
 | 
			
		||||
    if (generate_mipmaps)
 | 
			
		||||
        glGenerateMipmap(GL_TEXTURE_2D);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (filter == TEXTURE_FILTER_NEAREAST) {
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
			
		||||
    } else if (filter == TEXTURE_FILTER_LINEAR) {
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
			
		||||
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 | 
			
		||||
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 | 
			
		||||
 | 
			
		||||
#if !defined(EMSCRIPTEN)
 | 
			
		||||
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
    return texture;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void delete_gpu_texture(GPUTexture texture) {
 | 
			
		||||
    glDeleteTextures(1, &texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void upload_gpu_texture(GPUTexture texture, void *pixels, int channels, int width, int height) {
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, texture);
 | 
			
		||||
 | 
			
		||||
    int format_internal, format;
 | 
			
		||||
    if (channels == 4) {
 | 
			
		||||
        #ifdef EMSCRIPTEN
 | 
			
		||||
        format_internal = GL_RGBA;
 | 
			
		||||
        #else
 | 
			
		||||
        format_internal = GL_RGBA8;
 | 
			
		||||
        #endif
 | 
			
		||||
        format = GL_RGBA;
 | 
			
		||||
    } else if (channels == 3) {
 | 
			
		||||
        #ifdef EMSCRIPTEN
 | 
			
		||||
        format_internal = GL_RGBA;
 | 
			
		||||
        #else
 | 
			
		||||
        format_internal = GL_RGBA8;
 | 
			
		||||
        #endif
 | 
			
		||||
        format = GL_RGB;
 | 
			
		||||
    } else if (channels == 1) {
 | 
			
		||||
        format_internal = GL_ALPHA;
 | 
			
		||||
        format = GL_ALPHA;
 | 
			
		||||
    } else {
 | 
			
		||||
        CRY("upload_gpu_texture", "Unsupported channel count");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glTexImage2D(GL_TEXTURE_2D,
 | 
			
		||||
                 0,
 | 
			
		||||
                 format_internal,
 | 
			
		||||
                 width,
 | 
			
		||||
                 height,
 | 
			
		||||
                 0,
 | 
			
		||||
                 format,
 | 
			
		||||
                 GL_UNSIGNED_BYTE,
 | 
			
		||||
                 pixels);
 | 
			
		||||
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void bind_gpu_texture(GPUTexture texture) {
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, texture);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
#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,8 +2,9 @@
 | 
			
		||||
#define TWN_GPU_TEXTURE_C_H
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
typedef GLuint GPUTexture;
 | 
			
		||||
typedef uint32_t GPUTexture;
 | 
			
		||||
 | 
			
		||||
typedef enum TextureFilter {
 | 
			
		||||
    TEXTURE_FILTER_NEAREAST,
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ void finally_render_quads(const Primitive2D primitives[],
 | 
			
		||||
{
 | 
			
		||||
    DeferredCommandDraw command = {0};
 | 
			
		||||
 | 
			
		||||
    GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;
 | 
			
		||||
    uint32_t off = 0, voff = 0, uvoff = 0, coff = 0;
 | 
			
		||||
 | 
			
		||||
    if (!batch.constant_colored && batch.textured) {
 | 
			
		||||
        off   = offsetof(ElementIndexedQuad, v1);
 | 
			
		||||
@@ -33,7 +33,7 @@ void finally_render_quads(const Primitive2D primitives[],
 | 
			
		||||
 | 
			
		||||
    command.vertices = (AttributeArrayPointer) {
 | 
			
		||||
        .arity = 2,
 | 
			
		||||
        .type = GL_FLOAT,
 | 
			
		||||
        .type = TWN_FLOAT,
 | 
			
		||||
        .stride = off,
 | 
			
		||||
        .offset = voff,
 | 
			
		||||
        .buffer = buffer
 | 
			
		||||
@@ -42,7 +42,7 @@ void finally_render_quads(const Primitive2D primitives[],
 | 
			
		||||
    if (batch.textured)
 | 
			
		||||
        command.texcoords = (AttributeArrayPointer) {
 | 
			
		||||
            .arity = 2,
 | 
			
		||||
            .type = GL_FLOAT,
 | 
			
		||||
            .type = TWN_FLOAT,
 | 
			
		||||
            .stride = off,
 | 
			
		||||
            .offset = uvoff,
 | 
			
		||||
            .buffer = buffer
 | 
			
		||||
@@ -51,7 +51,7 @@ void finally_render_quads(const Primitive2D primitives[],
 | 
			
		||||
    if (!batch.constant_colored) {
 | 
			
		||||
        command.colors = (AttributeArrayPointer) {
 | 
			
		||||
            .arity = 4,
 | 
			
		||||
            .type = GL_UNSIGNED_BYTE,
 | 
			
		||||
            .type = TWN_UNSIGNED_BYTE,
 | 
			
		||||
            .stride = off,
 | 
			
		||||
            .offset = coff,
 | 
			
		||||
            .buffer = buffer
 | 
			
		||||
@@ -68,10 +68,14 @@ void finally_render_quads(const Primitive2D primitives[],
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    command.element_buffer = get_quad_element_buffer();
 | 
			
		||||
    command.element_count = 6 * (GLsizei)batch.size;
 | 
			
		||||
    command.range_end = 6 * (GLsizei)batch.size;
 | 
			
		||||
    command.element_count = 6 * (uint32_t)batch.size;
 | 
			
		||||
    command.range_end = 6 * (uint32_t)batch.size;
 | 
			
		||||
 | 
			
		||||
    use_texture_mode(batch.mode);
 | 
			
		||||
    command.texture_mode = batch.mode;
 | 
			
		||||
    command.pipeline = PIPELINE_2D;
 | 
			
		||||
 | 
			
		||||
    command.depth_range_high = depth_range_high;
 | 
			
		||||
    command.depth_range_low = depth_range_low;
 | 
			
		||||
 | 
			
		||||
    DeferredCommand final_command = {
 | 
			
		||||
        .type = DEFERRED_COMMAND_TYPE_DRAW,
 | 
			
		||||
 
 | 
			
		||||
@@ -70,8 +70,6 @@ void render_rect_batch(const Primitive2D primitives[],
 | 
			
		||||
    /* single vertex array is used for every batch with NULL glBufferData() trick at the end */
 | 
			
		||||
    VertexBuffer const vertex_array = get_scratch_vertex_array();
 | 
			
		||||
 | 
			
		||||
    use_texture_mode(batch.mode);
 | 
			
		||||
 | 
			
		||||
    /* vertex population over a vertex buffer builder interface */
 | 
			
		||||
    {
 | 
			
		||||
        VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_quad_payload_size(batch) * batch.size);
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,6 @@ void render_skybox(void) {
 | 
			
		||||
    if (!paths_in_use)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    use_space_pipeline();
 | 
			
		||||
 | 
			
		||||
    /* note: ownership of 'paths_in_use' goes there */
 | 
			
		||||
    DeferredCommand command = {
 | 
			
		||||
        .type = DEFERRED_COMMAND_TYPE_DRAW_SKYBOX,
 | 
			
		||||
 
 | 
			
		||||
@@ -351,7 +351,7 @@ void finally_draw_text(FontData const *font_data,
 | 
			
		||||
 | 
			
		||||
    command.vertices = (AttributeArrayPointer) {
 | 
			
		||||
        .arity = 2,
 | 
			
		||||
        .type = GL_FLOAT,
 | 
			
		||||
        .type = TWN_FLOAT,
 | 
			
		||||
        .stride = offsetof(ElementIndexedQuadWithoutColor, v1),
 | 
			
		||||
        .offset = offsetof(ElementIndexedQuadWithoutColor, v0),
 | 
			
		||||
        .buffer = buffer
 | 
			
		||||
@@ -359,7 +359,7 @@ void finally_draw_text(FontData const *font_data,
 | 
			
		||||
 | 
			
		||||
    command.texcoords = (AttributeArrayPointer) {
 | 
			
		||||
        .arity = 2,
 | 
			
		||||
        .type = GL_FLOAT,
 | 
			
		||||
        .type = TWN_FLOAT,
 | 
			
		||||
        .stride = offsetof(ElementIndexedQuadWithoutColor, v1),
 | 
			
		||||
        .offset = offsetof(ElementIndexedQuadWithoutColor, uv0),
 | 
			
		||||
        .buffer = buffer
 | 
			
		||||
@@ -373,10 +373,14 @@ void finally_draw_text(FontData const *font_data,
 | 
			
		||||
    command.textured = true;
 | 
			
		||||
 | 
			
		||||
    command.element_buffer = get_quad_element_buffer();
 | 
			
		||||
    command.element_count = 6 * (GLsizei)len;
 | 
			
		||||
    command.range_end = 6 * (GLsizei)len;
 | 
			
		||||
    command.element_count = 6 * (uint32_t)len;
 | 
			
		||||
    command.range_end = 6 * (uint32_t)len;
 | 
			
		||||
 | 
			
		||||
    use_texture_mode(TEXTURE_MODE_GHOSTLY);
 | 
			
		||||
    command.texture_mode = TEXTURE_MODE_GHOSTLY;
 | 
			
		||||
    command.pipeline = PIPELINE_2D;
 | 
			
		||||
 | 
			
		||||
    command.depth_range_high = depth_range_high;
 | 
			
		||||
    command.depth_range_low = depth_range_low;
 | 
			
		||||
 | 
			
		||||
    DeferredCommand final_command = {
 | 
			
		||||
        .type = DEFERRED_COMMAND_TYPE_DRAW,
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ void finally_draw_uncolored_space_traingle_batch(const MeshBatch *batch,
 | 
			
		||||
 | 
			
		||||
    command.vertices = (AttributeArrayPointer) {
 | 
			
		||||
        .arity = 3,
 | 
			
		||||
        .type = GL_FLOAT,
 | 
			
		||||
        .type = TWN_FLOAT,
 | 
			
		||||
        .stride = offsetof(UncoloredSpaceTriangle, v1),
 | 
			
		||||
        .offset = offsetof(UncoloredSpaceTriangle, v0),
 | 
			
		||||
        .buffer = buffer
 | 
			
		||||
@@ -95,7 +95,7 @@ void finally_draw_uncolored_space_traingle_batch(const MeshBatch *batch,
 | 
			
		||||
 | 
			
		||||
    command.texcoords = (AttributeArrayPointer) {
 | 
			
		||||
        .arity = 2,
 | 
			
		||||
        .type = GL_FLOAT,
 | 
			
		||||
        .type = TWN_FLOAT,
 | 
			
		||||
        .stride = offsetof(UncoloredSpaceTriangle, v1),
 | 
			
		||||
        .offset = offsetof(UncoloredSpaceTriangle, uv0),
 | 
			
		||||
        .buffer = buffer
 | 
			
		||||
@@ -104,13 +104,18 @@ void finally_draw_uncolored_space_traingle_batch(const MeshBatch *batch,
 | 
			
		||||
    command.textured = true;
 | 
			
		||||
    command.texture_key = texture_key;
 | 
			
		||||
 | 
			
		||||
    command.primitive_count = (GLsizei)(3 * primitives_len);
 | 
			
		||||
    command.primitive_count = (uint32_t)(3 * primitives_len);
 | 
			
		||||
 | 
			
		||||
    /* TODO: support alpha blended case, with distance sort */
 | 
			
		||||
    TextureMode mode = textures_get_mode(&ctx.texture_cache, texture_key);
 | 
			
		||||
    if (mode == TEXTURE_MODE_GHOSTLY)
 | 
			
		||||
        mode = TEXTURE_MODE_SEETHROUGH;
 | 
			
		||||
    use_texture_mode(mode);
 | 
			
		||||
 | 
			
		||||
    command.texture_mode = mode;
 | 
			
		||||
    command.pipeline = PIPELINE_SPACE;
 | 
			
		||||
 | 
			
		||||
    command.depth_range_high = depth_range_high;
 | 
			
		||||
    command.depth_range_low = depth_range_low;
 | 
			
		||||
 | 
			
		||||
    DeferredCommand final_command = {
 | 
			
		||||
        .type = DEFERRED_COMMAND_TYPE_DRAW,
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@
 | 
			
		||||
 | 
			
		||||
#include "rendering/twn_circles.c"
 | 
			
		||||
#include "rendering/twn_draw.c"
 | 
			
		||||
#include "rendering/twn_fog.c"
 | 
			
		||||
#include "rendering/twn_skybox.c"
 | 
			
		||||
#include "rendering/twn_sprites.c"
 | 
			
		||||
#include "rendering/twn_rects.c"
 | 
			
		||||
 
 | 
			
		||||
@@ -12,13 +12,6 @@
 | 
			
		||||
#include <stb_ds.h>
 | 
			
		||||
#include <toml.h>
 | 
			
		||||
 | 
			
		||||
/* TODO: should not be used here directly */
 | 
			
		||||
#ifdef EMSCRIPTEN
 | 
			
		||||
#include <GLES2/gl2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
@@ -100,28 +93,6 @@ static void poll_events(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef EMSCRIPTEN
 | 
			
		||||
 | 
			
		||||
static void APIENTRY opengl_log(GLenum source,
 | 
			
		||||
                                GLenum type,
 | 
			
		||||
                                GLuint id,
 | 
			
		||||
                                GLenum severity,
 | 
			
		||||
                                GLsizei length,
 | 
			
		||||
                                const GLchar* message,
 | 
			
		||||
                                const void* userParam)
 | 
			
		||||
{
 | 
			
		||||
    (void)source;
 | 
			
		||||
    (void)type;
 | 
			
		||||
    (void)id;
 | 
			
		||||
    (void)severity;
 | 
			
		||||
    (void)userParam;
 | 
			
		||||
 | 
			
		||||
    log_info("OpenGL: %.*s\n", length, message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void preserve_persistent_ctx_fields(void) {
 | 
			
		||||
    ctx.game.udata = ctx.game_copy.udata;
 | 
			
		||||
}
 | 
			
		||||
@@ -539,25 +510,13 @@ static bool initialize(void) {
 | 
			
		||||
    if (SDL_GL_SetSwapInterval(-1))
 | 
			
		||||
        SDL_GL_SetSwapInterval(1);
 | 
			
		||||
 | 
			
		||||
#ifndef EMSCRIPTEN
 | 
			
		||||
    if (gladLoadGL() == 0) {
 | 
			
		||||
        CRY("Init", "GLAD failed");
 | 
			
		||||
    if (!render_init())
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
 | 
			
		||||
 | 
			
		||||
#ifndef EMSCRIPTEN
 | 
			
		||||
    glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
 | 
			
		||||
    glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
 | 
			
		||||
    glHint(GL_FOG_HINT, GL_FASTEST);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* might need this to have multiple windows */
 | 
			
		||||
    ctx.window_id = SDL_GetWindowID(ctx.window);
 | 
			
		||||
 | 
			
		||||
    glViewport(0, 0, (GLsizei)ctx.base_render_width, (GLsizei)ctx.base_render_height);
 | 
			
		||||
    setup_viewport(0, 0, (int)ctx.base_render_width, (int)ctx.base_render_height);
 | 
			
		||||
 | 
			
		||||
    /* TODO: */
 | 
			
		||||
    // SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h);
 | 
			
		||||
@@ -596,14 +555,6 @@ static bool initialize(void) {
 | 
			
		||||
    /* you could change this at runtime if you wanted */
 | 
			
		||||
    ctx.update_multiplicity = 1;
 | 
			
		||||
 | 
			
		||||
#ifndef EMSCRIPTEN
 | 
			
		||||
    /* hook up opengl debugging callback */
 | 
			
		||||
    if (ctx.game.debug) {
 | 
			
		||||
        glEnable(GL_DEBUG_OUTPUT);
 | 
			
		||||
        glDebugMessageCallback(opengl_log, NULL);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* random seeding */
 | 
			
		||||
    /* SDL_GetPerformanceCounter returns some platform-dependent number. */
 | 
			
		||||
    /* it should vary between game instances. i checked! random enough for me. */
 | 
			
		||||
@@ -718,6 +669,9 @@ static bool initialize(void) {
 | 
			
		||||
    ctx.render_double_buffered = true;
 | 
			
		||||
    ctx.window_mouse_resident = true;
 | 
			
		||||
 | 
			
		||||
    ctx.game.fog_color = (Color){ 255, 255, 255, 255 }; /* TODO: pick some grey? */
 | 
			
		||||
    ctx.game.fog_end = 1.0f;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
#include "twn_loop.h"
 | 
			
		||||
 | 
			
		||||
#ifndef EMSCRIPTEN
 | 
			
		||||
#define SDL_MAIN_HANDLED
 | 
			
		||||
#endif
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user