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 rect_primitive *render_queue_rectangles;
 | 
				
			||||||
    struct circle_primitive *render_queue_circles;
 | 
					    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;
 | 
					    SDL_AudioDeviceID audio_device;
 | 
				
			||||||
    int audio_stream_frequency;
 | 
					    int audio_stream_frequency;
 | 
				
			||||||
    SDL_AudioFormat audio_stream_format;
 | 
					    SDL_AudioFormat audio_stream_format;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,29 @@ static void ingame_tick(struct state *state) {
 | 
				
			|||||||
    world_drawdef(scn->world);
 | 
					    world_drawdef(scn->world);
 | 
				
			||||||
    player_calc(scn->player);
 | 
					    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) {
 | 
					void main_loop(void) {
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
    if (!ctx.is_running) {
 | 
					    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_MAJOR_VERSION, 1);
 | 
				
			||||||
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
 | 
					    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 */
 | 
					    /* init got far enough to create a window */
 | 
				
			||||||
    ctx.window = SDL_CreateWindow("emerald",
 | 
					    ctx.window = SDL_CreateWindow("emerald",
 | 
				
			||||||
@@ -178,6 +197,8 @@ static bool initialize(void) {
 | 
				
			|||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* might need this to have multiple windows */
 | 
					    /* might need this to have multiple windows */
 | 
				
			||||||
    ctx.window_id = SDL_GetWindowID(ctx.window);
 | 
					    ctx.window_id = SDL_GetWindowID(ctx.window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -235,6 +256,12 @@ static bool initialize(void) {
 | 
				
			|||||||
    ctx.debug = false;
 | 
					    ctx.debug = false;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* hook up opengl debugging callback */
 | 
				
			||||||
 | 
					    if (ctx.debug) {
 | 
				
			||||||
 | 
					        glEnable(GL_DEBUG_OUTPUT);
 | 
				
			||||||
 | 
					        glDebugMessageCallback(opengl_log, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* random seeding */
 | 
					    /* random seeding */
 | 
				
			||||||
    /* SDL_GetPerformanceCounter returns some platform-dependent number. */
 | 
					    /* SDL_GetPerformanceCounter returns some platform-dependent number. */
 | 
				
			||||||
    /* it should vary between game instances. i checked! random enough for me. */
 | 
					    /* it should vary between game instances. i checked! random enough for me. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
#include "../util.h"
 | 
					#include "../util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <SDL2/SDL.h>
 | 
					#include <SDL2/SDL.h>
 | 
				
			||||||
 | 
					#include <glad/glad.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,4 +32,26 @@ struct circle_primitive {
 | 
				
			|||||||
    t_fvec2 position;
 | 
					    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
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										184
									
								
								src/rendering.c
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								src/rendering.c
									
									
									
									
									
								
							@@ -6,6 +6,7 @@
 | 
				
			|||||||
#include <stb_ds.h>
 | 
					#include <stb_ds.h>
 | 
				
			||||||
#include <glad/glad.h>
 | 
					#include <glad/glad.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <tgmath.h>
 | 
					#include <tgmath.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,6 +18,12 @@ void render_queue_clear(void) {
 | 
				
			|||||||
    arrsetlen(ctx.render_queue_sprites, 0);
 | 
					    arrsetlen(ctx.render_queue_sprites, 0);
 | 
				
			||||||
    arrsetlen(ctx.render_queue_rectangles, 0);
 | 
					    arrsetlen(ctx.render_queue_rectangles, 0);
 | 
				
			||||||
    arrsetlen(ctx.render_queue_circles, 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 */
 | 
					/* compare functions for the sort in render_sprites */
 | 
				
			||||||
static int cmp_atlases(const void *a, const void *b) {
 | 
					static int cmp_atlases(const void *a, const void *b) {
 | 
				
			||||||
    int index_a = ((const struct sprite_primitive *)a)->atlas_index;
 | 
					    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) {
 | 
					static void render_sprites(void) {
 | 
				
			||||||
    if (ctx.texture_cache.is_dirty)
 | 
					 | 
				
			||||||
        textures_update_current_atlas(&ctx.texture_cache);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sort_sprites(ctx.render_queue_sprites);
 | 
					    sort_sprites(ctx.render_queue_sprites);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (size_t i = 0; i < arrlenu(ctx.render_queue_sprites); ++i) {
 | 
					    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) {
 | 
					static void render_space(void) {
 | 
				
			||||||
    glMatrixMode(GL_PROJECTION);
 | 
					    glMatrixMode(GL_PROJECTION);
 | 
				
			||||||
    glPushMatrix();
 | 
					    glPushMatrix();
 | 
				
			||||||
    glLoadIdentity();
 | 
					    glLoadIdentity();
 | 
				
			||||||
    glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
 | 
					    glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    glBegin(GL_TRIANGLES);
 | 
					    glUseProgramObjectARB(0);
 | 
				
			||||||
    glColor4f(0.0, 1.0, 1.0, 1.0);
 | 
					    glActiveTexture(GL_TEXTURE0);
 | 
				
			||||||
    glVertex2f(300.0,210.0);
 | 
					
 | 
				
			||||||
    glVertex2f(340.0,215.0);
 | 
					    /* solid white, no modulation */
 | 
				
			||||||
    glVertex2f(320.0,250.0);
 | 
					    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 | 
				
			||||||
    glEnd();
 | 
					
 | 
				
			||||||
 | 
					    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();
 | 
					    glPopMatrix();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void render(void) {
 | 
					void render(void) {
 | 
				
			||||||
 | 
					    if (ctx.texture_cache.is_dirty)
 | 
				
			||||||
 | 
					        textures_update_current_atlas(&ctx.texture_cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    glClearColor((1.0f / 255) * 230,
 | 
					    glClearColor((1.0f / 255) * 230,
 | 
				
			||||||
                 (1.0f / 255) * 230,
 | 
					                 (1.0f / 255) * 230,
 | 
				
			||||||
                 (1.0f / 255) * 230, 1);
 | 
					                 (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_sprites();
 | 
				
			||||||
    render_rectangles();
 | 
					    render_rectangles();
 | 
				
			||||||
    render_circles();
 | 
					    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_RenderFlush(ctx.renderer);
 | 
				
			||||||
    SDL_GL_SwapWindow(ctx.window);
 | 
					    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 */
 | 
					/* pushes a filled circle onto the circle render queue */
 | 
				
			||||||
void push_circle(t_fvec2 position, float radius, t_color color);
 | 
					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 */
 | 
					/* renders the background, then the primitives in all render queues */
 | 
				
			||||||
void render(void);
 | 
					void render(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
#include <stdio.h>
 | 
					#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);
 | 
					    SDL_RWops *handle = PHYSFSRWOPS_openRead(path);
 | 
				
			||||||
    if (handle == NULL)
 | 
					    if (handle == NULL)
 | 
				
			||||||
        goto fail;
 | 
					        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 */
 | 
					    /* no need to do anything if it was loaded already */
 | 
				
			||||||
    if (shgeti(cache->hash, path) >= 0 || shgeti(cache->loner_hash, path) >= 0)
 | 
					    if (shgeti(cache->hash, path) >= 0 || shgeti(cache->loner_hash, path) >= 0)
 | 
				
			||||||
        return;
 | 
					        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);
 | 
					    struct texture_cache_item *texture = shgetp_null(cache->hash, path);
 | 
				
			||||||
    if (texture == NULL) {
 | 
					    if (texture == NULL) {
 | 
				
			||||||
        CRY("Texture lookup failed.",
 | 
					        CRY("Texture lookup failed.",
 | 
				
			||||||
            "Tried to get texture that isn't loaded.");
 | 
					            "Tried to get texture that isn't loaded.");
 | 
				
			||||||
        return (SDL_Rect){ 0, 0, 0, 0 };
 | 
					        return (SDL_Rect){ 0, 0, 0, 0 };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return texture->value.srcrect;
 | 
					    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);
 | 
					    struct texture_cache_item *texture = shgetp_null(cache->hash, path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* it might be a loner texture */
 | 
					    /* 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);
 | 
					    struct texture_cache_item *texture = shgetp_null(cache->loner_hash, path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (texture == NULL) {
 | 
					    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. */
 | 
					/* 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 */
 | 
					/* can be called from anywhere at any time after init, useful if you want to */
 | 
				
			||||||
/* preload textures you know will definitely be used */
 | 
					/* 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 */
 | 
					/* repacks the current texture atlas based on the texture cache */
 | 
				
			||||||
void textures_update_current_atlas(struct texture_cache *cache);
 | 
					void textures_update_current_atlas(struct texture_cache *cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* returns a rect in a texture cache atlas based on a path, for drawing */
 | 
					/* 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) */
 | 
					/* 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 */
 | 
					/* returns which atlas the texture in the path is in, starting from 0 */
 | 
				
			||||||
/* if the texture is not found, returns INT_MIN */
 | 
					/* 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` */
 | 
					/* returns a pointer to the atlas at `index` */
 | 
				
			||||||
/* if the index is out of bounds, returns NULL. */
 | 
					/* if the index is out of bounds, returns NULL. */
 | 
				
			||||||
/* you can get the index via texture_get_atlas_index */
 | 
					/* 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_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 */
 | 
					/* returns the number of atlases in the cache */
 | 
				
			||||||
size_t textures_get_num_atlases(struct texture_cache *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;
 | 
					} 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 */
 | 
					/* decrements an lvalue (which should be an int), stopping at 0 */
 | 
				
			||||||
/* meant for tick-based timers in game logic */
 | 
					/* meant for tick-based timers in game logic */
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user