work-in-progress for 3d triangle rendering
This commit is contained in:
		@@ -24,7 +24,10 @@ typedef struct context {
 | 
			
		||||
    struct rect_primitive *render_queue_rectangles;
 | 
			
		||||
    struct circle_primitive *render_queue_circles;
 | 
			
		||||
 | 
			
		||||
    struct audio_channel_pair *audio_channels;
 | 
			
		||||
    struct mesh_batch *uncolored_mesh_batches; /* texture_cache reflected */
 | 
			
		||||
    struct mesh_batch_item *uncolored_mesh_batches_loners; /* path reflected */
 | 
			
		||||
 | 
			
		||||
    struct audio_channel_item *audio_channels;
 | 
			
		||||
    SDL_AudioDeviceID audio_device;
 | 
			
		||||
    int audio_stream_frequency;
 | 
			
		||||
    SDL_AudioFormat audio_stream_format;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,29 @@ static void ingame_tick(struct state *state) {
 | 
			
		||||
    world_drawdef(scn->world);
 | 
			
		||||
    player_calc(scn->player);
 | 
			
		||||
 | 
			
		||||
    get_audio_args("soundtrack")->volume -= 0.01f;
 | 
			
		||||
    // unfurl_triangle("/assets/title.png",
 | 
			
		||||
    //                 (t_fvec3){ 1250, 700, 0 },
 | 
			
		||||
    //                 (t_fvec3){ 0, 800, 0 },
 | 
			
		||||
    //                 (t_fvec3){ 0, 0, 0 },
 | 
			
		||||
    //                 (t_shvec2){ 0, 360 },
 | 
			
		||||
    //                 (t_shvec2){ 0, 0 },
 | 
			
		||||
    //                 (t_shvec2){ 360, 0 });
 | 
			
		||||
 | 
			
		||||
    unfurl_triangle("/assets/red.png",
 | 
			
		||||
                    (t_fvec3){ 0, 0, 0 },
 | 
			
		||||
                    (t_fvec3){ RENDER_BASE_WIDTH, 0, 0 },
 | 
			
		||||
                    (t_fvec3){ RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0 },
 | 
			
		||||
                    (t_shvec2){ 0, 0 },
 | 
			
		||||
                    (t_shvec2){ 80, 0 },
 | 
			
		||||
                    (t_shvec2){ 80, 80 });
 | 
			
		||||
 | 
			
		||||
    unfurl_triangle("/assets/red.png",
 | 
			
		||||
                    (t_fvec3){ RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0 },
 | 
			
		||||
                    (t_fvec3){ 0, RENDER_BASE_HEIGHT, 0 },
 | 
			
		||||
                    (t_fvec3){ 0, 0, 0 },
 | 
			
		||||
                    (t_shvec2){ 80, 80 },
 | 
			
		||||
                    (t_shvec2){ 0, 80 },
 | 
			
		||||
                    (t_shvec2){ 0, 0 });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								src/main.c
									
									
									
									
									
								
							@@ -44,6 +44,24 @@ static void poll_events(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void main_loop(void) {
 | 
			
		||||
    /*
 | 
			
		||||
    if (!ctx.is_running) {
 | 
			
		||||
@@ -149,6 +167,7 @@ static bool initialize(void) {
 | 
			
		||||
 | 
			
		||||
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
 | 
			
		||||
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
 | 
			
		||||
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
 | 
			
		||||
 | 
			
		||||
    /* init got far enough to create a window */
 | 
			
		||||
    ctx.window = SDL_CreateWindow("emerald",
 | 
			
		||||
@@ -178,6 +197,8 @@ static bool initialize(void) {
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
 | 
			
		||||
 | 
			
		||||
    /* might need this to have multiple windows */
 | 
			
		||||
    ctx.window_id = SDL_GetWindowID(ctx.window);
 | 
			
		||||
 | 
			
		||||
@@ -235,6 +256,12 @@ static bool initialize(void) {
 | 
			
		||||
    ctx.debug = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* hook up opengl debugging callback */
 | 
			
		||||
    if (ctx.debug) {
 | 
			
		||||
        glEnable(GL_DEBUG_OUTPUT);
 | 
			
		||||
        glDebugMessageCallback(opengl_log, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* random seeding */
 | 
			
		||||
    /* SDL_GetPerformanceCounter returns some platform-dependent number. */
 | 
			
		||||
    /* it should vary between game instances. i checked! random enough for me. */
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#include "../util.h"
 | 
			
		||||
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
@@ -31,4 +32,26 @@ struct circle_primitive {
 | 
			
		||||
    t_fvec2 position;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* batch of primitives with overlapping properties */
 | 
			
		||||
struct mesh_batch {
 | 
			
		||||
    GLuint buffer; /* server side storage */
 | 
			
		||||
    uint8_t *data; /* client side storage */
 | 
			
		||||
    // size_t buffer_len; /* element count */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mesh_batch_item {
 | 
			
		||||
    char *key;
 | 
			
		||||
    struct mesh_batch value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* is structure that is in opengl vertex array */
 | 
			
		||||
struct uncolored_space_triangle {
 | 
			
		||||
    t_fvec3 v0;
 | 
			
		||||
    t_shvec2 uv0;
 | 
			
		||||
    t_fvec3 v1;
 | 
			
		||||
    t_shvec2 uv1;
 | 
			
		||||
    t_fvec3 v2;
 | 
			
		||||
    t_shvec2 uv2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										184
									
								
								src/rendering.c
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								src/rendering.c
									
									
									
									
									
								
							@@ -6,6 +6,7 @@
 | 
			
		||||
#include <stb_ds.h>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <tgmath.h>
 | 
			
		||||
 | 
			
		||||
@@ -17,6 +18,12 @@ void render_queue_clear(void) {
 | 
			
		||||
    arrsetlen(ctx.render_queue_sprites, 0);
 | 
			
		||||
    arrsetlen(ctx.render_queue_rectangles, 0);
 | 
			
		||||
    arrsetlen(ctx.render_queue_circles, 0);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < arrlenu(ctx.uncolored_mesh_batches); ++i)
 | 
			
		||||
        arrsetlen(ctx.uncolored_mesh_batches[i].data, 0);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < shlenu(ctx.uncolored_mesh_batches_loners); ++i)
 | 
			
		||||
        arrsetlen(ctx.uncolored_mesh_batches_loners[i].value.data, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -91,6 +98,78 @@ void push_circle(t_fvec2 position, float radius, t_color color) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* TODO: automatic handling of repeating textures */
 | 
			
		||||
void unfurl_triangle(const char *path,
 | 
			
		||||
                     t_fvec3 v0,
 | 
			
		||||
                     t_fvec3 v1,
 | 
			
		||||
                     t_fvec3 v2,
 | 
			
		||||
                     t_shvec2 uv0,
 | 
			
		||||
                     t_shvec2 uv1,
 | 
			
		||||
                     t_shvec2 uv2)
 | 
			
		||||
{
 | 
			
		||||
    /* corrected atlas texture coordinates */
 | 
			
		||||
    t_shvec2 uv0c, uv1c, uv2c;
 | 
			
		||||
    struct mesh_batch *batch_p;
 | 
			
		||||
 | 
			
		||||
    textures_load(&ctx.texture_cache, path);
 | 
			
		||||
 | 
			
		||||
    const int atlas_index = textures_get_atlas_index(&ctx.texture_cache, path);
 | 
			
		||||
    if (atlas_index == -1) {
 | 
			
		||||
        /* loners span whole texture i assume */
 | 
			
		||||
        uv0c = uv0;
 | 
			
		||||
        uv1c = uv1;
 | 
			
		||||
        uv2c = uv2;
 | 
			
		||||
 | 
			
		||||
        batch_p = &shgetp(ctx.uncolored_mesh_batches_loners, path)->value;
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        const size_t old_len = arrlenu(ctx.uncolored_mesh_batches);
 | 
			
		||||
        if ((size_t)atlas_index + 1 >= old_len) {
 | 
			
		||||
            /* grow to accommodate texture cache atlases */
 | 
			
		||||
            arrsetlen(ctx.uncolored_mesh_batches, atlas_index + 1);
 | 
			
		||||
 | 
			
		||||
            /* zero initialize it all, it's a valid state */
 | 
			
		||||
            SDL_memset(&ctx.uncolored_mesh_batches[atlas_index],
 | 
			
		||||
                       0,
 | 
			
		||||
                       sizeof (struct mesh_batch) * ((atlas_index + 1) - old_len));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const SDL_Rect srcrect = ctx.texture_cache.hash[atlas_index].value.srcrect; /* TODO: does it work? */
 | 
			
		||||
 | 
			
		||||
        /* fixed point galore */
 | 
			
		||||
        const int16_t srcratx = (int16_t)srcrect.x * (INT16_MAX / TEXTURE_ATLAS_SIZE);
 | 
			
		||||
        const int16_t srcratw = (int16_t)srcrect.w * (INT16_MAX / TEXTURE_ATLAS_SIZE);
 | 
			
		||||
        const int16_t srcrath = (int16_t)srcrect.h * (INT16_MAX / TEXTURE_ATLAS_SIZE);
 | 
			
		||||
        const int16_t srcraty = (int16_t)srcrect.y * (INT16_MAX / TEXTURE_ATLAS_SIZE); /* flip? */
 | 
			
		||||
 | 
			
		||||
        uv0c.x = (int16_t)(srcratx + ((uint16_t)((uv0.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7));
 | 
			
		||||
        uv0c.y = (int16_t)(srcraty + ((uint16_t)((uv0.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7));
 | 
			
		||||
        uv1c.x = (int16_t)(srcratx + ((uint16_t)((uv1.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7));
 | 
			
		||||
        uv1c.y = (int16_t)(srcraty + ((uint16_t)((uv1.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7));
 | 
			
		||||
        uv2c.x = (int16_t)(srcratx + ((uint16_t)((uv2.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7));
 | 
			
		||||
        uv2c.y = (int16_t)(srcraty + ((uint16_t)((uv2.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7));
 | 
			
		||||
 | 
			
		||||
        batch_p = &ctx.uncolored_mesh_batches[atlas_index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct uncolored_space_triangle *data = (struct uncolored_space_triangle *)batch_p->data;
 | 
			
		||||
    struct uncolored_space_triangle pack = {
 | 
			
		||||
        .v0 = v0,
 | 
			
		||||
        // .uv0 = uv0c,
 | 
			
		||||
        .uv0 = { 0, 0 },
 | 
			
		||||
        .v1 = v1,
 | 
			
		||||
        // .uv1 = uv1c,
 | 
			
		||||
        .uv1 = { INT16_MAX, 0 },
 | 
			
		||||
        .v2 = v2,
 | 
			
		||||
        // .uv2 = uv2c,
 | 
			
		||||
        .uv2 = { INT16_MAX, INT16_MAX },
 | 
			
		||||
    };
 | 
			
		||||
    arrpush(data, pack);
 | 
			
		||||
 | 
			
		||||
    batch_p->data = (uint8_t *)data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* compare functions for the sort in render_sprites */
 | 
			
		||||
static int cmp_atlases(const void *a, const void *b) {
 | 
			
		||||
    int index_a = ((const struct sprite_primitive *)a)->atlas_index;
 | 
			
		||||
@@ -312,9 +391,6 @@ static void render_circle(struct circle_primitive *circle) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void render_sprites(void) {
 | 
			
		||||
    if (ctx.texture_cache.is_dirty)
 | 
			
		||||
        textures_update_current_atlas(&ctx.texture_cache);
 | 
			
		||||
 | 
			
		||||
    sort_sprites(ctx.render_queue_sprites);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < arrlenu(ctx.render_queue_sprites); ++i) {
 | 
			
		||||
@@ -337,36 +413,120 @@ static void render_circles(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch) {
 | 
			
		||||
    size_t data_len = arrlenu(batch->data);
 | 
			
		||||
 | 
			
		||||
    /* create vertex array object */
 | 
			
		||||
    if (batch->buffer == 0)
 | 
			
		||||
        glGenBuffers(1, &batch->buffer);
 | 
			
		||||
 | 
			
		||||
    glBindBuffer(GL_ARRAY_BUFFER, batch->buffer);
 | 
			
		||||
 | 
			
		||||
    /* TODO: try using mapped buffers while building batches instead? */
 | 
			
		||||
    /*       this way we could skip client side copy that is kept until commitment */
 | 
			
		||||
    /*       alternatively we could commit glBufferSubData based on a threshold */
 | 
			
		||||
 | 
			
		||||
    /* upload batched data */
 | 
			
		||||
    glBufferData(GL_ARRAY_BUFFER,
 | 
			
		||||
                 data_len * sizeof (struct uncolored_space_triangle),
 | 
			
		||||
                 batch->data,
 | 
			
		||||
                 GL_STREAM_DRAW);
 | 
			
		||||
 | 
			
		||||
    /* vertex specification*/
 | 
			
		||||
    glEnableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
    glVertexPointer(3,
 | 
			
		||||
                    GL_FLOAT,
 | 
			
		||||
                    offsetof(struct uncolored_space_triangle, v1),
 | 
			
		||||
                    (void *)offsetof(struct uncolored_space_triangle, v0));
 | 
			
		||||
 | 
			
		||||
    /* note: propagates further to where texture binding is done */
 | 
			
		||||
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
			
		||||
    glClientActiveTexture(GL_TEXTURE0);
 | 
			
		||||
    glTexCoordPointer(2,
 | 
			
		||||
                      GL_SHORT,
 | 
			
		||||
                      offsetof(struct uncolored_space_triangle, v1),
 | 
			
		||||
                      (void *)offsetof(struct uncolored_space_triangle, uv0));
 | 
			
		||||
 | 
			
		||||
    // for (size_t i = 0; i < data_len; ++i) {
 | 
			
		||||
    //     struct uncolored_space_triangle t = ((struct uncolored_space_triangle *)batch->data)[i];
 | 
			
		||||
    //     log_info("{%i, %i, %i, %i, %i, %i}\n", t.uv0.x, t.uv0.y, t.uv1.x, t.uv1.y, t.uv2.x, t.uv2.y);
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    /* commit for drawing */
 | 
			
		||||
    glDrawArrays(GL_TRIANGLES, 0, 3 * (int)data_len);
 | 
			
		||||
 | 
			
		||||
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
			
		||||
    glDisableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
 | 
			
		||||
    /* invalidate the buffer immediately */
 | 
			
		||||
    glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
 | 
			
		||||
    glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void render_space(void) {
 | 
			
		||||
    glMatrixMode(GL_PROJECTION);
 | 
			
		||||
    glPushMatrix();
 | 
			
		||||
    glLoadIdentity();
 | 
			
		||||
    glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
 | 
			
		||||
 | 
			
		||||
    glBegin(GL_TRIANGLES);
 | 
			
		||||
    glColor4f(0.0, 1.0, 1.0, 1.0);
 | 
			
		||||
    glVertex2f(300.0,210.0);
 | 
			
		||||
    glVertex2f(340.0,215.0);
 | 
			
		||||
    glVertex2f(320.0,250.0);
 | 
			
		||||
    glEnd();
 | 
			
		||||
    glUseProgramObjectARB(0);
 | 
			
		||||
    glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
 | 
			
		||||
    /* solid white, no modulation */
 | 
			
		||||
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < arrlenu(ctx.uncolored_mesh_batches); ++i) {
 | 
			
		||||
        if (arrlenu(&ctx.uncolored_mesh_batches[i].data) > 0) {
 | 
			
		||||
            SDL_Texture *const atlas = textures_get_atlas(&ctx.texture_cache, (int)i);
 | 
			
		||||
            SDL_GL_BindTexture(atlas, NULL, NULL);
 | 
			
		||||
            draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i]);
 | 
			
		||||
            SDL_GL_UnbindTexture(atlas);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < shlenu(ctx.uncolored_mesh_batches_loners); ++i) {
 | 
			
		||||
        if (arrlenu(&ctx.uncolored_mesh_batches_loners[i].value.data) > 0) {
 | 
			
		||||
            SDL_Texture *const atlas = textures_get_loner(&ctx.texture_cache,
 | 
			
		||||
                                                          ctx.uncolored_mesh_batches_loners[i].key);
 | 
			
		||||
            SDL_GL_BindTexture(atlas, NULL, NULL);
 | 
			
		||||
            draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches_loners[i].value);
 | 
			
		||||
            SDL_GL_UnbindTexture(atlas);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glPopMatrix();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void render(void) {
 | 
			
		||||
    if (ctx.texture_cache.is_dirty)
 | 
			
		||||
        textures_update_current_atlas(&ctx.texture_cache);
 | 
			
		||||
 | 
			
		||||
    glClearColor((1.0f / 255) * 230,
 | 
			
		||||
                 (1.0f / 255) * 230,
 | 
			
		||||
                 (1.0f / 255) * 230, 1);
 | 
			
		||||
 | 
			
		||||
    glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
    glClear(GL_COLOR_BUFFER_BIT |
 | 
			
		||||
            GL_DEPTH_BUFFER_BIT |
 | 
			
		||||
            GL_STENCIL_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
    render_space();
 | 
			
		||||
    // glDisable(GL_CULL_FACE);
 | 
			
		||||
    // glDisable(GL_DEPTH_TEST);
 | 
			
		||||
    glEnable(GL_BLEND);
 | 
			
		||||
 | 
			
		||||
    /* TODO: write with no depth test, just fill it in */
 | 
			
		||||
    render_sprites();
 | 
			
		||||
    render_rectangles();
 | 
			
		||||
    render_circles();
 | 
			
		||||
 | 
			
		||||
    // SDL_RenderPresent(ctx.renderer);
 | 
			
		||||
    // glEnable(GL_CULL_FACE);
 | 
			
		||||
    // glEnable(GL_DEPTH_TEST);
 | 
			
		||||
    glDisable(GL_BLEND);
 | 
			
		||||
 | 
			
		||||
    /* TODO: use depth test to optimize gui regions away */
 | 
			
		||||
    render_space();
 | 
			
		||||
 | 
			
		||||
    SDL_RenderFlush(ctx.renderer);
 | 
			
		||||
    SDL_GL_SwapWindow(ctx.window);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,34 @@ void push_rectangle(t_frect rect, t_color color);
 | 
			
		||||
/* pushes a filled circle onto the circle render queue */
 | 
			
		||||
void push_circle(t_fvec2 position, float radius, t_color color);
 | 
			
		||||
 | 
			
		||||
/* pushes a textured 3d triangle onto the render queue */
 | 
			
		||||
/* vertices are in absolute coordinates, relative to world origin */
 | 
			
		||||
/* texture coordinates are in pixels */
 | 
			
		||||
void unfurl_triangle(const char *path,
 | 
			
		||||
                     /* */
 | 
			
		||||
                     t_fvec3 v0,
 | 
			
		||||
                     t_fvec3 v1,
 | 
			
		||||
                     t_fvec3 v2,
 | 
			
		||||
                     t_shvec2 uv0,
 | 
			
		||||
                     t_shvec2 uv1,
 | 
			
		||||
                     t_shvec2 uv2);
 | 
			
		||||
 | 
			
		||||
/* TODO: */
 | 
			
		||||
/* pushes a colored textured 3d triangle onto the render queue */
 | 
			
		||||
// void unfurl_colored_triangle(const char *path,
 | 
			
		||||
//                              t_fvec3 v0,
 | 
			
		||||
//                              t_fvec3 v1,
 | 
			
		||||
//                              t_fvec3 v2,
 | 
			
		||||
//                              t_shvec2 uv0,
 | 
			
		||||
//                              t_shvec2 uv1,
 | 
			
		||||
//                              t_shvec2 uv2,
 | 
			
		||||
//                              t_color c0,
 | 
			
		||||
//                              t_color c1,
 | 
			
		||||
//                              t_color c2);
 | 
			
		||||
 | 
			
		||||
/* TODO: billboarding */
 | 
			
		||||
// http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat2
 | 
			
		||||
 | 
			
		||||
/* renders the background, then the primitives in all render queues */
 | 
			
		||||
void render(void);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static SDL_Surface *image_to_surface(char *path) {
 | 
			
		||||
static SDL_Surface *image_to_surface(const char *path) {
 | 
			
		||||
    SDL_RWops *handle = PHYSFSRWOPS_openRead(path);
 | 
			
		||||
    if (handle == NULL)
 | 
			
		||||
        goto fail;
 | 
			
		||||
@@ -236,7 +236,7 @@ void textures_dump_atlases(struct texture_cache *cache) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void textures_load(struct texture_cache *cache, char *path) {
 | 
			
		||||
void textures_load(struct texture_cache *cache, const char *path) {
 | 
			
		||||
    /* no need to do anything if it was loaded already */
 | 
			
		||||
    if (shgeti(cache->hash, path) >= 0 || shgeti(cache->loner_hash, path) >= 0)
 | 
			
		||||
        return;
 | 
			
		||||
@@ -300,18 +300,19 @@ void textures_update_current_atlas(struct texture_cache *cache) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SDL_Rect textures_get_srcrect(struct texture_cache *cache, char *path) {
 | 
			
		||||
SDL_Rect textures_get_srcrect(struct texture_cache *cache, const char *path) {
 | 
			
		||||
    struct texture_cache_item *texture = shgetp_null(cache->hash, path);
 | 
			
		||||
    if (texture == NULL) {
 | 
			
		||||
        CRY("Texture lookup failed.",
 | 
			
		||||
            "Tried to get texture that isn't loaded.");
 | 
			
		||||
        return (SDL_Rect){ 0, 0, 0, 0 };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return texture->value.srcrect;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int textures_get_atlas_index(struct texture_cache *cache, char *path) {
 | 
			
		||||
int textures_get_atlas_index(struct texture_cache *cache, const char *path) {
 | 
			
		||||
    struct texture_cache_item *texture = shgetp_null(cache->hash, path);
 | 
			
		||||
 | 
			
		||||
    /* it might be a loner texture */
 | 
			
		||||
@@ -339,7 +340,7 @@ SDL_Texture *textures_get_atlas(struct texture_cache *cache, int index) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SDL_Texture *textures_get_loner(struct texture_cache *cache, char *path) {
 | 
			
		||||
SDL_Texture *textures_get_loner(struct texture_cache *cache, const char *path) {
 | 
			
		||||
    struct texture_cache_item *texture = shgetp_null(cache->loner_hash, path);
 | 
			
		||||
 | 
			
		||||
    if (texture == NULL) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,25 +51,25 @@ void textures_dump_atlases(struct texture_cache *cache);
 | 
			
		||||
/* loads an image if it isn't in the cache, otherwise a no-op. */
 | 
			
		||||
/* can be called from anywhere at any time after init, useful if you want to */
 | 
			
		||||
/* preload textures you know will definitely be used */
 | 
			
		||||
void textures_load(struct texture_cache *cache, char *path);
 | 
			
		||||
void textures_load(struct texture_cache *cache, const char *path);
 | 
			
		||||
 | 
			
		||||
/* repacks the current texture atlas based on the texture cache */
 | 
			
		||||
void textures_update_current_atlas(struct texture_cache *cache);
 | 
			
		||||
 | 
			
		||||
/* returns a rect in a texture cache atlas based on a path, for drawing */
 | 
			
		||||
/* if the texture is not found, returns a zero-filled rect (so check w or h) */
 | 
			
		||||
SDL_Rect textures_get_srcrect(struct texture_cache *cache, char *path);
 | 
			
		||||
SDL_Rect textures_get_srcrect(struct texture_cache *cache, const char *path);
 | 
			
		||||
 | 
			
		||||
/* returns which atlas the texture in the path is in, starting from 0 */
 | 
			
		||||
/* if the texture is not found, returns INT_MIN */
 | 
			
		||||
int textures_get_atlas_index(struct texture_cache *cache, char *path);
 | 
			
		||||
int textures_get_atlas_index(struct texture_cache *cache, const char *path);
 | 
			
		||||
 | 
			
		||||
/* returns a pointer to the atlas at `index` */
 | 
			
		||||
/* if the index is out of bounds, returns NULL. */
 | 
			
		||||
/* you can get the index via texture_get_atlas_index */
 | 
			
		||||
SDL_Texture *textures_get_atlas(struct texture_cache *cache, int index);
 | 
			
		||||
 | 
			
		||||
SDL_Texture *textures_get_loner(struct texture_cache *cache, char *path);
 | 
			
		||||
SDL_Texture *textures_get_loner(struct texture_cache *cache, const char *path);
 | 
			
		||||
 | 
			
		||||
/* returns the number of atlases in the cache */
 | 
			
		||||
size_t textures_get_num_atlases(struct texture_cache *cache);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								src/util.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/util.h
									
									
									
									
									
								
							@@ -109,6 +109,19 @@ typedef struct fvec2 {
 | 
			
		||||
} t_fvec2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* a point in some three dimension space (floating point) */
 | 
			
		||||
/* y goes up, x goes to the right */
 | 
			
		||||
typedef struct fvec3 {
 | 
			
		||||
    float x, y, z;
 | 
			
		||||
} t_fvec3;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* a point in some space (short) */
 | 
			
		||||
typedef struct shvec2 {
 | 
			
		||||
    short x, y;
 | 
			
		||||
} t_shvec2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* decrements an lvalue (which should be an int), stopping at 0 */
 | 
			
		||||
/* meant for tick-based timers in game logic */
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user