textures working on web, separation of vertex and index buffers (actually matters)
This commit is contained in:
parent
d76ea06470
commit
814269ab0c
@ -18,13 +18,9 @@ void game_tick(void) {
|
|||||||
struct state *state = ctx.udata;
|
struct state *state = ctx.udata;
|
||||||
++state->counter;
|
++state->counter;
|
||||||
|
|
||||||
m_sprite("nothing!",
|
m_sprite("twn.png",
|
||||||
(Rect) {
|
(Rect) { .w = 128, .h = 64, },
|
||||||
.x = 0,
|
m_opt(stretch, true)
|
||||||
.y = 0,
|
|
||||||
.w = 32,
|
|
||||||
.h = 32,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,12 +39,18 @@ enum {
|
|||||||
|
|
||||||
|
|
||||||
typedef uint32_t VertexBuffer;
|
typedef uint32_t VertexBuffer;
|
||||||
|
typedef uint32_t IndexBuffer;
|
||||||
|
|
||||||
typedef struct VertexBufferBuilder {
|
typedef struct VertexBufferBuilder {
|
||||||
size_t size;
|
size_t size;
|
||||||
void *base;
|
void *base;
|
||||||
} VertexBufferBuilder;
|
} VertexBufferBuilder;
|
||||||
|
|
||||||
|
typedef struct IndexBufferBuilder {
|
||||||
|
size_t size;
|
||||||
|
void *base;
|
||||||
|
} IndexBufferBuilder;
|
||||||
|
|
||||||
|
|
||||||
typedef struct SpritePrimitive {
|
typedef struct SpritePrimitive {
|
||||||
Rect rect;
|
Rect rect;
|
||||||
@ -268,19 +274,19 @@ void text_cache_reset_arena(TextCache *cache);
|
|||||||
/* vertex buffer */
|
/* vertex buffer */
|
||||||
|
|
||||||
VertexBuffer create_vertex_buffer(void);
|
VertexBuffer create_vertex_buffer(void);
|
||||||
|
|
||||||
void restart_scratch_vertex_arrays(void);
|
void restart_scratch_vertex_arrays(void);
|
||||||
|
|
||||||
VertexBuffer get_scratch_vertex_array(void);
|
VertexBuffer get_scratch_vertex_array(void);
|
||||||
|
|
||||||
void delete_vertex_buffer(VertexBuffer buffer);
|
void delete_vertex_buffer(VertexBuffer buffer);
|
||||||
|
|
||||||
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes);
|
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes);
|
||||||
|
|
||||||
VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes);
|
VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes);
|
||||||
|
|
||||||
void finish_vertex_builder(VertexBufferBuilder *builder);
|
void finish_vertex_builder(VertexBufferBuilder *builder);
|
||||||
|
|
||||||
|
IndexBuffer create_index_buffer(void);
|
||||||
|
void delete_index_buffer(IndexBuffer buffer);
|
||||||
|
void specify_index_buffer(IndexBuffer buffer, void const *data, size_t bytes);
|
||||||
|
IndexBufferBuilder build_index_buffer(IndexBuffer buffer, size_t bytes);
|
||||||
|
void finish_index_builder(IndexBufferBuilder *builder);
|
||||||
|
|
||||||
/* 2d */
|
/* 2d */
|
||||||
|
|
||||||
/* fills two existing arrays with the geometry data of a circle */
|
/* fills two existing arrays with the geometry data of a circle */
|
||||||
@ -304,9 +310,8 @@ struct QuadBatch collect_rect_batch(const Primitive2D primitives[], size_t len);
|
|||||||
void render_sprite_batch(const Primitive2D primitives[], struct QuadBatch batch);
|
void render_sprite_batch(const Primitive2D primitives[], struct QuadBatch batch);
|
||||||
void render_rect_batch(const Primitive2D primitives[], struct QuadBatch batch);
|
void render_rect_batch(const Primitive2D primitives[], struct QuadBatch batch);
|
||||||
|
|
||||||
VertexBuffer get_quad_element_buffer(void);
|
IndexBuffer get_quad_element_buffer(void);
|
||||||
|
IndexBuffer get_circle_element_buffer(void);
|
||||||
VertexBuffer get_circle_element_buffer(void);
|
|
||||||
|
|
||||||
void render_circle(const CirclePrimitive *circle);
|
void render_circle(const CirclePrimitive *circle);
|
||||||
|
|
||||||
|
@ -50,8 +50,9 @@ bool render_init(void) {
|
|||||||
|
|
||||||
log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
|
log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
|
||||||
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
|
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
||||||
glHint(GL_FOG_HINT, GL_FASTEST);
|
glHint(GL_FOG_HINT, GL_FASTEST);
|
||||||
|
|
||||||
@ -196,59 +197,79 @@ static void finally_use_2d_pipeline(void) {
|
|||||||
pipeline_last_used = PIPELINE_2D;
|
pipeline_last_used = PIPELINE_2D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setup_ghostly_texture_mode(void) {
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
static GLuint list = 0;
|
||||||
|
if (!list) {
|
||||||
|
list = glGenLists(1);
|
||||||
|
glNewList(list, GL_COMPILE);
|
||||||
|
#endif
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
glEndList();
|
||||||
|
}
|
||||||
|
glCallList(list);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setup_seethrough_texture_mode(void) {
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
static GLuint list = 0;
|
||||||
|
if (!list) {
|
||||||
|
list = glGenLists(1);
|
||||||
|
glNewList(list, GL_COMPILE);
|
||||||
|
#endif
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
glAlphaFunc(GL_EQUAL, 1.0f);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
glEndList();
|
||||||
|
}
|
||||||
|
glCallList(list);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setup_opaque_texture_mode(void) {
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
static GLuint list = 0;
|
||||||
|
if (!list) {
|
||||||
|
list = glGenLists(1);
|
||||||
|
glNewList(list, GL_COMPILE);
|
||||||
|
#endif
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
glEndList();
|
||||||
|
}
|
||||||
|
glCallList(list);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO: ensure we minimize depth func switching to enable Hi-Z (hierarchical depth) optimizations */
|
/* TODO: ensure we minimize depth func switching to enable Hi-Z (hierarchical depth) optimizations */
|
||||||
static void finally_use_texture_mode(TextureMode mode) {
|
static void finally_use_texture_mode(TextureMode mode) {
|
||||||
if (texture_mode_last_used == mode)
|
if (texture_mode_last_used == mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
static GLuint lists = 0;
|
|
||||||
if (!lists) {
|
|
||||||
lists = glGenLists(3);
|
|
||||||
|
|
||||||
/* ghostly */
|
|
||||||
glNewList(lists + 0, GL_COMPILE); {
|
|
||||||
#endif
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
} glEndList();
|
|
||||||
|
|
||||||
/* seethrough */
|
|
||||||
glNewList(lists + 1, GL_COMPILE); {
|
|
||||||
#endif
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glEnable(GL_ALPHA_TEST);
|
|
||||||
glAlphaFunc(GL_EQUAL, 1.0f);
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
} glEndList();
|
|
||||||
|
|
||||||
/* opaque */
|
|
||||||
glNewList(lists + 2, GL_COMPILE); {
|
|
||||||
#endif
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
} glEndList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == TEXTURE_MODE_GHOSTLY) {
|
if (mode == TEXTURE_MODE_GHOSTLY) {
|
||||||
glCallList(lists + 0);
|
setup_ghostly_texture_mode();
|
||||||
} else if (mode == TEXTURE_MODE_SEETHROUGH) {
|
} else if (mode == TEXTURE_MODE_SEETHROUGH) {
|
||||||
glCallList(lists + 1);
|
setup_seethrough_texture_mode();
|
||||||
} else {
|
} else {
|
||||||
glCallList(lists + 2);
|
setup_opaque_texture_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
texture_mode_last_used = mode;
|
texture_mode_last_used = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +308,40 @@ void finish_vertex_builder(VertexBufferBuilder *builder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IndexBufferBuilder build_index_buffer(IndexBuffer buffer, size_t bytes) {
|
||||||
|
SDL_assert(bytes != 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bytes, NULL, GL_STREAM_DRAW);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
void *mapping = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||||
|
#else
|
||||||
|
void *mapping = SDL_malloc(bytes);
|
||||||
|
#endif
|
||||||
|
if (!mapping)
|
||||||
|
CRY("build_vertex_buffer", "Error mapping a vertex array buffer");
|
||||||
|
|
||||||
|
return (IndexBufferBuilder) {
|
||||||
|
.base = mapping,
|
||||||
|
.size = bytes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void finish_index_builder(IndexBufferBuilder *builder) {
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
if (!glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER))
|
||||||
|
CRY("finish_vertex_builder", "Error unmapping a vertex array buffer");
|
||||||
|
#else
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, builder->size, builder->base, GL_STREAM_DRAW);
|
||||||
|
SDL_free(builder->base);
|
||||||
|
#endif
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
builder->base = 0;
|
||||||
|
builder->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void load_cubemap_side(const char *path, GLenum target) {
|
static void load_cubemap_side(const char *path, GLenum target) {
|
||||||
SDL_Surface *surface = textures_load_surface(path);
|
SDL_Surface *surface = textures_load_surface(path);
|
||||||
/* TODO: sanity check whether all of them have same dimensions? */
|
/* TODO: sanity check whether all of them have same dimensions? */
|
||||||
|
@ -29,6 +29,18 @@ void delete_vertex_buffer(VertexBuffer buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IndexBuffer create_index_buffer(void) {
|
||||||
|
GLuint result;
|
||||||
|
glGenBuffers(1, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void delete_index_buffer(IndexBuffer buffer) {
|
||||||
|
glDeleteBuffers(1, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes) {
|
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW);
|
||||||
@ -36,14 +48,21 @@ void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VertexBuffer get_quad_element_buffer(void) {
|
void specify_index_buffer(IndexBuffer buffer, void const *data, size_t bytes) {
|
||||||
static VertexBuffer buffer = 0;
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bytes, data, GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IndexBuffer get_quad_element_buffer(void) {
|
||||||
|
static IndexBuffer buffer = 0;
|
||||||
|
|
||||||
/* it's only generated once at runtime */
|
/* it's only generated once at runtime */
|
||||||
/* TODO: use builder interface, not direct calls (glMapBuffer isn't portable) */
|
/* TODO: use builder interface, not direct calls (glMapBuffer isn't portable) */
|
||||||
if (buffer == 0) {
|
if (buffer == 0) {
|
||||||
buffer = create_vertex_buffer();
|
buffer = create_index_buffer();
|
||||||
VertexBufferBuilder builder = build_vertex_buffer(buffer, sizeof (GLshort) * QUAD_ELEMENT_BUFFER_LENGTH * 6 );
|
IndexBufferBuilder builder = build_index_buffer(buffer, sizeof (GLshort) * QUAD_ELEMENT_BUFFER_LENGTH * 6 );
|
||||||
|
|
||||||
for (size_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) {
|
for (size_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) {
|
||||||
((GLshort *)builder.base)[i * 6 + 0] = (GLshort)(i * 4 + 0);
|
((GLshort *)builder.base)[i * 6 + 0] = (GLshort)(i * 4 + 0);
|
||||||
@ -54,7 +73,7 @@ VertexBuffer get_quad_element_buffer(void) {
|
|||||||
((GLshort *)builder.base)[i * 6 + 5] = (GLshort)(i * 4 + 0);
|
((GLshort *)builder.base)[i * 6 + 5] = (GLshort)(i * 4 + 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_vertex_builder(&builder);
|
finish_index_builder(&builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert_always(buffer);
|
SDL_assert_always(buffer);
|
||||||
@ -63,12 +82,12 @@ VertexBuffer get_quad_element_buffer(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VertexBuffer get_circle_element_buffer(void) {
|
IndexBuffer get_circle_element_buffer(void) {
|
||||||
static VertexBuffer buffer = 0;
|
static IndexBuffer buffer = 0;
|
||||||
|
|
||||||
if (buffer == 0) {
|
if (buffer == 0) {
|
||||||
buffer = create_vertex_buffer();
|
buffer = create_index_buffer();
|
||||||
VertexBufferBuilder builder = build_vertex_buffer(buffer, sizeof (GLshort) * (CIRCLE_VERTICES_MAX - 2) * 3);
|
IndexBufferBuilder builder = build_index_buffer(buffer, sizeof (GLshort) * (CIRCLE_VERTICES_MAX - 2) * 3);
|
||||||
|
|
||||||
for (size_t i = 1; i < CIRCLE_VERTICES_MAX - 1; ++i) {
|
for (size_t i = 1; i < CIRCLE_VERTICES_MAX - 1; ++i) {
|
||||||
/* first one is center point index, always zero */
|
/* first one is center point index, always zero */
|
||||||
@ -79,7 +98,7 @@ VertexBuffer get_circle_element_buffer(void) {
|
|||||||
((GLshort *)builder.base)[(i - 1) * 3 + 2] = (GLshort)i + 1;
|
((GLshort *)builder.base)[(i - 1) * 3 + 2] = (GLshort)i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_vertex_builder(&builder);
|
finish_index_builder(&builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert_always(buffer);
|
SDL_assert_always(buffer);
|
||||||
@ -128,7 +147,11 @@ GPUTexture create_gpu_texture(TextureFilter filter, bool generate_mipmaps, int c
|
|||||||
SDL_assert(width > 0 && height > 0);
|
SDL_assert(width > 0 && height > 0);
|
||||||
SDL_assert(channels > 0 && channels <= 4);
|
SDL_assert(channels > 0 && channels <= 4);
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
|
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
|
||||||
|
#else
|
||||||
|
(void)generate_mipmaps;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (filter == TEXTURE_FILTER_NEAREAST) {
|
if (filter == TEXTURE_FILTER_NEAREAST) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
@ -881,7 +881,7 @@ int enter_loop(int argc, char **argv) {
|
|||||||
profile_end("startup");
|
profile_end("startup");
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
emscripten_set_main_loop(main_loop, ctx.desired_frametime, true);
|
emscripten_set_main_loop(main_loop, 0, true);
|
||||||
#else
|
#else
|
||||||
while (ctx.is_running)
|
while (ctx.is_running)
|
||||||
main_loop();
|
main_loop();
|
||||||
|
Loading…
Reference in New Issue
Block a user