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;
|
||||
++state->counter;
|
||||
|
||||
m_sprite("nothing!",
|
||||
(Rect) {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.w = 32,
|
||||
.h = 32,
|
||||
}
|
||||
m_sprite("twn.png",
|
||||
(Rect) { .w = 128, .h = 64, },
|
||||
m_opt(stretch, true)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,12 +39,18 @@ enum {
|
||||
|
||||
|
||||
typedef uint32_t VertexBuffer;
|
||||
typedef uint32_t IndexBuffer;
|
||||
|
||||
typedef struct VertexBufferBuilder {
|
||||
size_t size;
|
||||
void *base;
|
||||
} VertexBufferBuilder;
|
||||
|
||||
typedef struct IndexBufferBuilder {
|
||||
size_t size;
|
||||
void *base;
|
||||
} IndexBufferBuilder;
|
||||
|
||||
|
||||
typedef struct SpritePrimitive {
|
||||
Rect rect;
|
||||
@ -268,19 +274,19 @@ void text_cache_reset_arena(TextCache *cache);
|
||||
/* vertex buffer */
|
||||
|
||||
VertexBuffer create_vertex_buffer(void);
|
||||
|
||||
void restart_scratch_vertex_arrays(void);
|
||||
|
||||
VertexBuffer get_scratch_vertex_array(void);
|
||||
|
||||
void delete_vertex_buffer(VertexBuffer buffer);
|
||||
|
||||
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes);
|
||||
|
||||
VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes);
|
||||
|
||||
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 */
|
||||
|
||||
/* 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_rect_batch(const Primitive2D primitives[], struct QuadBatch batch);
|
||||
|
||||
VertexBuffer get_quad_element_buffer(void);
|
||||
|
||||
VertexBuffer get_circle_element_buffer(void);
|
||||
IndexBuffer get_quad_element_buffer(void);
|
||||
IndexBuffer get_circle_element_buffer(void);
|
||||
|
||||
void render_circle(const CirclePrimitive *circle);
|
||||
|
||||
|
@ -50,8 +50,9 @@ bool render_init(void) {
|
||||
|
||||
log_info("OpenGL context: %s\n", glGetString(GL_VERSION));
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
||||
glHint(GL_FOG_HINT, GL_FASTEST);
|
||||
|
||||
@ -196,59 +197,79 @@ static void finally_use_2d_pipeline(void) {
|
||||
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 */
|
||||
static void finally_use_texture_mode(TextureMode mode) {
|
||||
if (texture_mode_last_used == mode)
|
||||
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) {
|
||||
glCallList(lists + 0);
|
||||
setup_ghostly_texture_mode();
|
||||
} else if (mode == TEXTURE_MODE_SEETHROUGH) {
|
||||
glCallList(lists + 1);
|
||||
setup_seethrough_texture_mode();
|
||||
} else {
|
||||
glCallList(lists + 2);
|
||||
setup_opaque_texture_mode();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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) {
|
||||
SDL_Surface *surface = textures_load_surface(path);
|
||||
/* 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) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
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) {
|
||||
static VertexBuffer buffer = 0;
|
||||
void specify_index_buffer(IndexBuffer buffer, void const *data, size_t bytes) {
|
||||
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 */
|
||||
/* TODO: use builder interface, not direct calls (glMapBuffer isn't portable) */
|
||||
if (buffer == 0) {
|
||||
buffer = create_vertex_buffer();
|
||||
VertexBufferBuilder builder = build_vertex_buffer(buffer, sizeof (GLshort) * QUAD_ELEMENT_BUFFER_LENGTH * 6 );
|
||||
buffer = create_index_buffer();
|
||||
IndexBufferBuilder builder = build_index_buffer(buffer, sizeof (GLshort) * QUAD_ELEMENT_BUFFER_LENGTH * 6 );
|
||||
|
||||
for (size_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) {
|
||||
((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);
|
||||
}
|
||||
|
||||
finish_vertex_builder(&builder);
|
||||
finish_index_builder(&builder);
|
||||
}
|
||||
|
||||
SDL_assert_always(buffer);
|
||||
@ -63,12 +82,12 @@ VertexBuffer get_quad_element_buffer(void) {
|
||||
}
|
||||
|
||||
|
||||
VertexBuffer get_circle_element_buffer(void) {
|
||||
static VertexBuffer buffer = 0;
|
||||
IndexBuffer get_circle_element_buffer(void) {
|
||||
static IndexBuffer buffer = 0;
|
||||
|
||||
if (buffer == 0) {
|
||||
buffer = create_vertex_buffer();
|
||||
VertexBufferBuilder builder = build_vertex_buffer(buffer, sizeof (GLshort) * (CIRCLE_VERTICES_MAX - 2) * 3);
|
||||
buffer = create_index_buffer();
|
||||
IndexBufferBuilder builder = build_index_buffer(buffer, sizeof (GLshort) * (CIRCLE_VERTICES_MAX - 2) * 3);
|
||||
|
||||
for (size_t i = 1; i < CIRCLE_VERTICES_MAX - 1; ++i) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
finish_vertex_builder(&builder);
|
||||
finish_index_builder(&builder);
|
||||
}
|
||||
|
||||
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(channels > 0 && channels <= 4);
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
|
||||
#else
|
||||
(void)generate_mipmaps;
|
||||
#endif
|
||||
|
||||
if (filter == TEXTURE_FILTER_NEAREAST) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
@ -881,7 +881,7 @@ int enter_loop(int argc, char **argv) {
|
||||
profile_end("startup");
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop(main_loop, ctx.desired_frametime, true);
|
||||
emscripten_set_main_loop(main_loop, 0, true);
|
||||
#else
|
||||
while (ctx.is_running)
|
||||
main_loop();
|
||||
|
Loading…
Reference in New Issue
Block a user