mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Merge pull request #205 from kichikuou/alpha
TapirEngine: Fix alpha test / alpha blend conditions
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user