Merge pull request #205 from kichikuou/alpha

TapirEngine: Fix alpha test / alpha blend conditions
This commit is contained in:
Nunuhara Cabbage
2024-10-25 19:00:27 -07:00
committed by GitHub
6 changed files with 55 additions and 30 deletions
-1
View File
@@ -98,7 +98,6 @@ struct RE_back_cg {
struct RE_plugin {
struct draw_plugin plugin;
enum RE_plugin_version version;
int sprite;
int nr_instances;
struct RE_instance **instances;
+7 -2
View File
@@ -46,11 +46,12 @@ struct model {
struct hash_table *mot_cache; // name -> struct mot *
struct collider *collider;
vec3 aabb[2]; // axis-aligned bounding box
bool has_transparent_material;
bool has_transparent_mesh;
};
struct mesh {
uint32_t flags;
bool is_transparent;
GLuint vao;
GLuint attr_buffer;
GLuint index_buffer;
@@ -193,6 +194,8 @@ struct billboard_texture {
// reign.c
extern enum RE_plugin_version re_plugin_version;
void RE_instance_update_local_transform(struct RE_instance *inst);
// model.c
@@ -208,7 +211,7 @@ struct archive_data *RE_get_aar_entry(struct archive *aar, const char *dir, cons
// renderer.c
struct RE_renderer *RE_renderer_new(enum RE_plugin_version version);
struct RE_renderer *RE_renderer_new(void);
void RE_renderer_free(struct RE_renderer *r);
void RE_renderer_set_viewport_size(struct RE_renderer *r, int width, int height);
bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no);
@@ -410,6 +413,7 @@ enum pol_texture_type {
enum material_flags {
MATERIAL_SPRITE = 1 << 0,
MATERIAL_ALPHA = 1 << 1,
};
struct pol_material {
@@ -433,6 +437,7 @@ enum mesh_flags {
MESH_BLEND_ADDITIVE = 1 << 5,
MESH_NO_EDGE = 1 << 6,
MESH_NO_HEIGHT_DETECTION = 1 << 7,
MESH_ALPHA = 1 << 8,
};
struct pol_mesh {
+24 -8
View File
@@ -54,6 +54,22 @@ struct vertex_bones {
GLfloat bone_weight[NR_WEIGHTS];
};
static bool is_transparent_mesh(const struct pol_mesh *mesh)
{
if (re_plugin_version == RE_REIGN_PLUGIN)
return !(mesh->flags & MESH_SPRITE);
else
return mesh->flags & MESH_ALPHA;
}
static bool is_transparent_material(const struct pol_material *material)
{
if (re_plugin_version == RE_REIGN_PLUGIN)
return !(material->flags & MATERIAL_SPRITE);
else
return material->flags & MATERIAL_ALPHA;
}
struct archive_data *RE_get_aar_entry(struct archive *aar, const char *dir, const char *name, const char *ext)
{
char *path = xmalloc(strlen(dir) + strlen(name) + strlen(ext) + 2);
@@ -120,7 +136,7 @@ static bool init_material(struct material *material, const struct pol_material *
if (m->textures[NORMAL_MAP])
material->normal_map = load_texture(aar, path, m->textures[NORMAL_MAP], NULL);
material->is_transparent = (has_alpha || material->alpha_map) && !(material->flags & MATERIAL_SPRITE);
material->is_transparent = (has_alpha || material->alpha_map) && is_transparent_material(m);
material->shadow_darkness = 1.0f;
struct amt_material *amt_m = amt ? amt_find_material(amt, m->name) : NULL;
@@ -303,6 +319,12 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
struct mesh *mesh = &model->meshes[model->nr_meshes++];
mesh->flags = m->flags;
mesh->material = material;
if (re_plugin_version == RE_REIGN_PLUGIN)
mesh->is_transparent = model->materials[material].is_transparent && is_transparent_mesh(m);
else
mesh->is_transparent = model->materials[material].is_transparent || is_transparent_mesh(m);
if (mesh->is_transparent)
model->has_transparent_mesh = true;
mesh->outline_color[0] = m->edge_color.r / 255.f;
mesh->outline_color[1] = m->edge_color.g / 255.f;
mesh->outline_color[2] = m->edge_color.b / 255.f;
@@ -493,12 +515,6 @@ struct model *model_load(struct archive *aar, const char *path)
&pol->materials[i].children[j], amt, aar, path);
}
}
for (int i = 0; i < model->nr_materials; i++) {
if (model->materials[i].is_transparent) {
model->has_transparent_material = true;
break;
}
}
// Meshes
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
@@ -650,7 +666,7 @@ struct model *model_create_sphere(int r, int g, int b, int a)
uint8_t pixel[4] = {r, g, b, a};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
glBindTexture(GL_TEXTURE_2D, 0);
model->has_transparent_material = true;
model->has_transparent_mesh = true;
return model;
}
+4
View File
@@ -64,6 +64,8 @@ static uint32_t parse_material_attributes(const char *name)
uint32_t flags = 0;
if (strstr(name, "(sprite)"))
flags |= MATERIAL_SPRITE;
if (strstr(name, "(alpha)"))
flags |= MATERIAL_ALPHA;
return flags;
}
@@ -179,6 +181,8 @@ static uint32_t parse_mesh_attributes(const char *name)
flags |= MESH_BOTH;
if (strstr(name, "(sprite)"))
flags |= MESH_SPRITE;
if (strstr(name, "(alpha)"))
flags |= MESH_ALPHA;
return flags;
}
+5 -2
View File
@@ -34,6 +34,8 @@
#include "vm.h"
#include "xsystem4.h"
enum RE_plugin_version re_plugin_version;
static struct RE_instance *create_instance(struct RE_plugin *plugin)
{
struct RE_instance *instance = xcalloc(1, sizeof(struct RE_instance));
@@ -207,6 +209,8 @@ static void update_bones(struct RE_instance *inst)
struct RE_plugin *RE_plugin_new(enum RE_plugin_version version)
{
re_plugin_version = version;
char *aar_path = gamedir_path("Data/ReignData.red");
int error = ARCHIVE_SUCCESS;
struct archive *aar = (struct archive *)aar_open(aar_path, MMAP_IF_64BIT, &error);
@@ -220,7 +224,6 @@ struct RE_plugin *RE_plugin_new(enum RE_plugin_version version)
return NULL;
struct RE_plugin *plugin = xcalloc(1, sizeof(struct RE_plugin));
plugin->version = version;
plugin->plugin.name = "ReignEngine";
plugin->plugin.update = RE_render;
plugin->plugin.to_json = RE_to_json;
@@ -262,7 +265,7 @@ bool RE_plugin_bind(struct RE_plugin *plugin, int sprite)
struct sact_sprite *sp = sact_try_get_sprite(sprite);
if (!sp)
return false;
plugin->renderer = RE_renderer_new(plugin->version);
plugin->renderer = RE_renderer_new();
plugin->sprite = sprite;
sprite_bind_plugin(sp, &plugin->plugin);
struct texture *texture = sprite_get_texture(sp);
+15 -17
View File
@@ -59,7 +59,7 @@ enum draw_phase {
DRAW_TRANSPARENT,
};
static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path, enum RE_plugin_version version)
static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path)
{
char defines[256];
snprintf(defines, sizeof(defines),
@@ -68,7 +68,7 @@ static GLuint load_shader(const char *vertex_shader_path, const char *fragment_s
"#define ENGINE %d",
RE_REIGN_PLUGIN,
RE_TAPIR_PLUGIN,
version);
re_plugin_version);
GLuint program = glCreateProgram();
GLuint vertex_shader = gfx_load_shader_file(vertex_shader_path, GL_VERTEX_SHADER, defines);
GLuint fragment_shader = gfx_load_shader_file(fragment_shader_path, GL_FRAGMENT_SHADER, defines);
@@ -101,12 +101,12 @@ static GLuint load_shader(const char *vertex_shader_path, const char *fragment_s
return program;
}
static void init_shadow_renderer(struct shadow_renderer *sr, enum RE_plugin_version version)
static void init_shadow_renderer(struct shadow_renderer *sr)
{
GLint orig_fbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_fbo);
sr->program = load_shader("shaders/reign_shadow.v.glsl", "shaders/reign_shadow.f.glsl", version);
sr->program = load_shader("shaders/reign_shadow.v.glsl", "shaders/reign_shadow.f.glsl");
sr->local_transform = glGetUniformLocation(sr->program, "local_transform");
sr->view_transform = glGetUniformLocation(sr->program, "view_transform");
sr->has_bones = glGetUniformLocation(sr->program, "has_bones");
@@ -136,13 +136,13 @@ static void destroy_shadow_renderer(struct shadow_renderer *sr)
glDeleteProgram(sr->program);
}
static void init_outline_renderer(struct outline_renderer *or, enum RE_plugin_version version)
static void init_outline_renderer(struct outline_renderer *or)
{
if (version < RE_TAPIR_PLUGIN) {
if (re_plugin_version < RE_TAPIR_PLUGIN) {
or->program = 0;
return;
}
or->program = load_shader("shaders/reign_outline.v.glsl", "shaders/reign_outline.f.glsl", version);
or->program = load_shader("shaders/reign_outline.v.glsl", "shaders/reign_outline.f.glsl");
or->local_transform = glGetUniformLocation(or->program, "local_transform");
or->view_transform = glGetUniformLocation(or->program, "view_transform");
or->proj_transform = glGetUniformLocation(or->program, "proj_transform");
@@ -203,11 +203,11 @@ static void destroy_billboard_mesh(struct RE_renderer *r)
glDeleteBuffers(1, &r->billboard_attr_buffer);
}
struct RE_renderer *RE_renderer_new(enum RE_plugin_version version)
struct RE_renderer *RE_renderer_new(void)
{
struct RE_renderer *r = xcalloc(1, sizeof(struct RE_renderer));
r->program = load_shader("shaders/reign.v.glsl", "shaders/reign.f.glsl", version);
r->program = load_shader("shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->view_transform = glGetUniformLocation(r->program, "view_transform");
r->texture = glGetUniformLocation(r->program, "tex");
r->local_transform = glGetUniformLocation(r->program, "local_transform");
@@ -258,8 +258,8 @@ struct RE_renderer *RE_renderer_new(enum RE_plugin_version version)
glGenRenderbuffers(1, &r->depth_buffer);
init_shadow_renderer(&r->shadow, version);
init_outline_renderer(&r->outline, version);
init_shadow_renderer(&r->shadow);
init_outline_renderer(&r->outline);
init_billboard_mesh(r);
r->billboard_textures = ht_create(256);
r->last_frame_timestamp = SDL_GetTicks();
@@ -338,7 +338,7 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
if (!inst->model)
return;
bool all_transparent = inst->alpha < 1.0f;
bool all_opaque = !model->has_transparent_material && inst->alpha >= 1.0f;
bool all_opaque = !model->has_transparent_mesh && inst->alpha >= 1.0f;
if ((phase == DRAW_OPAQUE && all_transparent) || (phase == DRAW_TRANSPARENT && all_opaque))
return;
@@ -362,7 +362,7 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
struct material *material = &model->materials[mesh->material];
bool is_transparent = (material->is_transparent && !(mesh->flags & MESH_SPRITE)) || inst->alpha < 1.0f;
bool is_transparent = mesh->is_transparent || inst->alpha < 1.0f;
if (phase != (is_transparent ? DRAW_TRANSPARENT : DRAW_OPAQUE))
continue;
@@ -424,10 +424,8 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
glActiveTexture(GL_TEXTURE0 + ALPHA_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->alpha_map);
glUniform1i(r->alpha_texture, ALPHA_TEXTURE_UNIT);
} else if (material->flags & MATERIAL_SPRITE || mesh->flags & MESH_SPRITE) {
glUniform1i(r->alpha_mode, ALPHA_TEST);
} else {
glUniform1i(r->alpha_mode, ALPHA_BLEND);
glUniform1i(r->alpha_mode, mesh->is_transparent ? ALPHA_BLEND : ALPHA_TEST);
}
vec2 uv_scroll;
@@ -913,7 +911,7 @@ void RE_render(struct sact_sprite *sp)
if (!r || plugin->suspended)
return;
if (plugin->version == RE_TAPIR_PLUGIN) {
if (re_plugin_version == RE_TAPIR_PLUGIN) {
uint32_t timestamp = SDL_GetTicks();
RE_build_model(plugin, timestamp - r->last_frame_timestamp);
r->last_frame_timestamp = timestamp;