diff --git a/include/reign.h b/include/reign.h index 7b91d40..2717d25 100644 --- a/include/reign.h +++ b/include/reign.h @@ -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; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 4aeab24..a7c1677 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -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 { diff --git a/src/3d/model.c b/src/3d/model.c index 0767630..c53c57a 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -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; } diff --git a/src/3d/parser.c b/src/3d/parser.c index 4d9a687..cec10a4 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -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; } diff --git a/src/3d/reign.c b/src/3d/reign.c index c34cbe7..db1a712 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -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); diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 1c09af9..750d9ad 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -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;