work-in-progress for 3d triangle rendering
This commit is contained in:
parent
e2ed4b2c2d
commit
b280243d30
@ -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 */
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user