automatic detenction of texture mode and batching based on it
This commit is contained in:
parent
945b1d21fe
commit
3edd692771
@ -11,38 +11,31 @@ static void ingame_tick(struct state *state) {
|
||||
world_drawdef(scn->world);
|
||||
player_calc(scn->player);
|
||||
|
||||
for (size_t i = 100000; --i;)
|
||||
push_sprite_ex((t_frect){ .x = 32, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/light.png",
|
||||
.color = (t_color){255, 0, 0, 255},
|
||||
.blend = false });
|
||||
push_sprite_ex((t_frect){ .x = 32, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/light.png",
|
||||
.color = (t_color){255, 0, 0, 255}, });
|
||||
|
||||
push_sprite_ex((t_frect){ .x = 48, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/light.png",
|
||||
.color = (t_color){0, 255, 0, 255},
|
||||
.blend = true });
|
||||
.color = (t_color){0, 255, 0, 255}, });
|
||||
|
||||
push_sprite_ex((t_frect){ .x = 64, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/light.png",
|
||||
.color = (t_color){0, 0, 255, 255},
|
||||
.blend = true });
|
||||
.color = (t_color){0, 0, 255, 255}, });
|
||||
|
||||
push_sprite_ex((t_frect){ .x = 32, .y = 32, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/player/baron-walk.png",
|
||||
.color = (t_color){255, 255, 255, 255},
|
||||
.rotation = (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64,
|
||||
.blend = true });
|
||||
.rotation = (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64, });
|
||||
|
||||
push_sprite_ex((t_frect){ .x = 64, .y = 32, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/player/baron-walk.png",
|
||||
.color = (t_color){255, 255, 255, 255},
|
||||
.rotation = (float)M_PI / 64,
|
||||
.blend = true });
|
||||
.rotation = (float)M_PI / 64, });
|
||||
|
||||
push_sprite_ex((t_frect){ .x = 96, .y = 32, .w = 64, .h = 64 }, (t_push_sprite_args){
|
||||
.path = "/assets/player/baron-walk.png",
|
||||
.color = (t_color){255, 255, 255, 255},
|
||||
.blend = true });
|
||||
.color = (t_color){255, 255, 255, 255}, });
|
||||
|
||||
unfurl_triangle("/assets/big-violet.png",
|
||||
(t_fvec3){ -1, -1, 0 },
|
||||
|
@ -17,7 +17,6 @@ struct sprite_primitive {
|
||||
t_texture_key texture_key;
|
||||
bool flip_x;
|
||||
bool flip_y;
|
||||
bool blend; /* must be explicitly stated, textures having alpha channel isn't enough */
|
||||
};
|
||||
|
||||
struct rect_primitive {
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define PRIVATE_TEXTURES_H
|
||||
|
||||
#include "../util.h"
|
||||
#include "../textures/modes.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stb_rect_pack.h>
|
||||
@ -13,7 +14,8 @@ struct texture {
|
||||
t_rect srcrect; /* position in atlas */
|
||||
SDL_Surface *data; /* original image data */
|
||||
int atlas_index;
|
||||
GLuint loner_texture; /* stored directly for loners, == 0 means atlas_index should be used*/
|
||||
GLuint loner_texture; /* stored directly for loners, == 0 means atlas_index should be used */
|
||||
enum texture_mode mode;
|
||||
};
|
||||
|
||||
|
||||
|
@ -71,7 +71,6 @@ static void render_2d(void) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
const size_t render_queue_len = arrlenu(ctx.render_queue_2d);
|
||||
@ -107,11 +106,12 @@ static void render_2d(void) {
|
||||
static void render_space(void) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDepthFunc(GL_LESS);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
/* solid white, no modulation */
|
||||
|
@ -13,7 +13,6 @@ typedef struct push_sprite_args {
|
||||
float rotation;
|
||||
bool flip_x;
|
||||
bool flip_y;
|
||||
bool blend;
|
||||
} t_push_sprite_args;
|
||||
|
||||
/* clears all render queues */
|
||||
|
@ -68,7 +68,6 @@ void push_sprite(char *path, t_frect rect) {
|
||||
.texture_key = textures_get_key(&ctx.texture_cache, path),
|
||||
.flip_x = false,
|
||||
.flip_y = false,
|
||||
.blend = true,
|
||||
};
|
||||
|
||||
struct primitive_2d primitive = {
|
||||
@ -88,7 +87,6 @@ void push_sprite_ex(t_frect rect, t_push_sprite_args args) {
|
||||
.texture_key = textures_get_key(&ctx.texture_cache, args.path),
|
||||
.flip_x = args.flip_x,
|
||||
.flip_y = args.flip_y,
|
||||
.blend = args.blend,
|
||||
};
|
||||
|
||||
struct primitive_2d primitive = {
|
||||
@ -101,16 +99,16 @@ void push_sprite_ex(t_frect rect, t_push_sprite_args args) {
|
||||
|
||||
|
||||
static struct sprite_batch {
|
||||
int atlas_id;
|
||||
size_t size; /* how many primitives are in current batch */
|
||||
bool blend; /* whether it's blended or not */
|
||||
int atlas_id;
|
||||
enum texture_mode mode;
|
||||
bool constant_colored; /* whether colored batch is uniformly colored */
|
||||
} collect_sprite_batch(const struct primitive_2d *primitives, size_t len) {
|
||||
/* assumes that first primitive is already a sprite */
|
||||
struct sprite_batch batch = {
|
||||
.atlas_id =
|
||||
textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key),
|
||||
.blend = primitives[0].sprite.blend,
|
||||
.mode = textures_get_mode(&ctx.texture_cache, primitives[0].sprite.texture_key),
|
||||
.constant_colored = true,
|
||||
};
|
||||
|
||||
@ -128,7 +126,8 @@ static struct sprite_batch {
|
||||
break;
|
||||
|
||||
/* only collect the same blend modes */
|
||||
if (current->sprite.blend != batch.blend)
|
||||
const enum texture_mode mode = textures_get_mode(&ctx.texture_cache, current->sprite.texture_key);
|
||||
if (mode != batch.mode)
|
||||
break;
|
||||
|
||||
/* only collect the same texture atlases */
|
||||
@ -156,13 +155,23 @@ static void render_sprites(const struct primitive_2d primitives[],
|
||||
if (vertex_array == 0)
|
||||
glGenBuffers(1, &vertex_array);
|
||||
|
||||
if (batch.blend) {
|
||||
if (batch.mode == TEXTURE_MODE_GHOSTLY) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
} else if (batch.mode == TEXTURE_MODE_SEETHROUGH) {
|
||||
glDisable(GL_BLEND);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glDepthMask(GL_TRUE);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_EQUAL, 1.0f);
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
}
|
||||
|
||||
size_t payload_size;
|
||||
@ -186,7 +195,8 @@ static void render_sprites(const struct primitive_2d primitives[],
|
||||
void *const payload = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||
|
||||
for (size_t i = 0; i < batch.size; ++i) {
|
||||
const size_t cur = !batch.blend ? batch.size - i - 1: i; /* render opaques front to back */
|
||||
/* render opaques front to back */
|
||||
const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1;
|
||||
const struct sprite_primitive sprite = primitives[cur].sprite;
|
||||
|
||||
const t_rect srcrect =
|
||||
|
@ -293,6 +293,34 @@ void textures_dump_atlases(struct texture_cache *cache) {
|
||||
}
|
||||
|
||||
|
||||
static enum texture_mode infer_texture_mode(SDL_Surface *surface) {
|
||||
const uint32_t amask = surface->format->Amask;
|
||||
if (amask == 0)
|
||||
return TEXTURE_MODE_OPAQUE;
|
||||
|
||||
enum texture_mode result = TEXTURE_MODE_OPAQUE;
|
||||
|
||||
SDL_LockSurface(surface);
|
||||
|
||||
for (int i = 0; i < surface->w * surface->h; ++i) {
|
||||
/* TODO: don't assume 32 bit depth ? */
|
||||
t_color color;
|
||||
SDL_GetRGBA(((uint32_t *)surface->pixels)[i], surface->format, &color.r, &color.g, &color.b, &color.a);
|
||||
|
||||
if (color.a == 0)
|
||||
result = TEXTURE_MODE_SEETHROUGH;
|
||||
else if (color.a != 255) {
|
||||
result = TEXTURE_MODE_GHOSTLY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(surface);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static t_texture_key textures_load(struct texture_cache *cache, const char *path) {
|
||||
/* no need to do anything if it was loaded already */
|
||||
const ptrdiff_t i = shgeti(cache->hash, path);
|
||||
@ -300,8 +328,10 @@ static t_texture_key textures_load(struct texture_cache *cache, const char *path
|
||||
return (t_texture_key){ (uint16_t)i };
|
||||
|
||||
SDL_Surface *surface = image_to_surface(path);
|
||||
struct texture new_texture = {0};
|
||||
new_texture.data = surface;
|
||||
struct texture new_texture = {
|
||||
.data = surface,
|
||||
.mode = infer_texture_mode(surface),
|
||||
};
|
||||
|
||||
/* it's a "loner texture," it doesn't fit in an atlas so it's not in one */
|
||||
if (surface->w >= TEXTURE_ATLAS_SIZE || surface->h >= TEXTURE_ATLAS_SIZE) {
|
||||
@ -472,6 +502,17 @@ void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum
|
||||
}
|
||||
|
||||
|
||||
enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key) {
|
||||
if (m_texture_key_is_valid(key)) {
|
||||
return cache->hash[key.id].value.mode;
|
||||
} else {
|
||||
CRY("Texture binding failed.",
|
||||
"Tried to get texture that isn't loaded.");
|
||||
return TEXTURE_MODE_GHOSTLY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t textures_get_num_atlases(const struct texture_cache *cache) {
|
||||
return cache->atlas_index + 1;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define TEXTURES_H
|
||||
|
||||
#include "private/textures.h"
|
||||
#include "textures/modes.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
@ -45,6 +46,9 @@ int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key k
|
||||
/* binds atlas texture in opengl state */
|
||||
void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target);
|
||||
|
||||
/* returns helpful information about contents of alpha channel in given texture */
|
||||
enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key);
|
||||
|
||||
/* returns the number of atlases in the cache */
|
||||
size_t textures_get_num_atlases(const struct texture_cache *cache);
|
||||
|
||||
|
11
src/textures/modes.h
Normal file
11
src/textures/modes.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef TEXTURES_MODES_H
|
||||
#define TEXTURES_MODES_H
|
||||
|
||||
/* alpha channel information */
|
||||
enum texture_mode {
|
||||
TEXTURE_MODE_OPAQUE, /* all pixels are solid */
|
||||
TEXTURE_MODE_SEETHROUGH, /* some pixels are alpha zero */
|
||||
TEXTURE_MODE_GHOSTLY, /* arbitrary alpha values */
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user