Merge pull request #77 from kichikuou/tt3

ReignEngine improvements
This commit is contained in:
Nunuhara Cabbage
2022-11-09 16:37:53 -08:00
committed by GitHub
10 changed files with 182 additions and 59 deletions
+2
View File
@@ -42,6 +42,7 @@ enum RE_motion_state {
};
enum RE_fog_type {
RE_FOG_NONE = 0,
RE_FOG_LINEAR = 1,
RE_FOG_LIGHT_SCATTERING = 2,
};
@@ -151,6 +152,7 @@ struct RE_instance {
vec3 globe_diffuse;
// Private
bool is_transparent;
bool local_transform_needs_update;
mat4 local_transform;
mat3 normal_transform;
+28 -13
View File
@@ -19,10 +19,15 @@
#define DIFFUSE_EMISSIVE 0
#define DIFFUSE_NORMAL 1
#define DIFFUSE_LIGHT_MAP 2
#define DIFFUSE_ENV_MAP 3
#define FOG_LINEAR 1
#define FOG_LIGHT_SCATTERING 2
#define ALPHA_BLEND 0
#define ALPHA_TEST 1
#define ALPHA_MAP_BLEND 2
struct dir_light {
vec3 dir;
vec3 diffuse;
@@ -53,7 +58,7 @@ uniform int fog_type;
uniform float fog_near;
uniform float fog_far;
uniform vec3 fog_color;
uniform bool use_alpha_map;
uniform int alpha_mode;
in vec2 tex_coord;
in vec2 light_tex_coord;
@@ -81,19 +86,25 @@ void main() {
vec3 frag_rgb = ambient;
// Diffuse lighting
vec4 texel = texture(tex, tex_coord);
if (diffuse_type == DIFFUSE_EMISSIVE) {
vec4 texel;
if (diffuse_type == DIFFUSE_ENV_MAP) {
texel = texture(tex, (vec2(normal.x, -normal.y) + 1.0) / 2.0);
frag_rgb = texel.rgb;
} else {
vec3 diffuse = vec3(0.0);
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5;
diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
texel = texture(tex, tex_coord);
if (diffuse_type == DIFFUSE_EMISSIVE) {
frag_rgb = texel.rgb;
} else {
vec3 diffuse = vec3(0.0);
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5;
diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
}
if (diffuse_type == DIFFUSE_LIGHT_MAP) {
diffuse *= texture(light_texture, light_tex_coord).rgb;
}
frag_rgb += texel.rgb * diffuse;
}
if (diffuse_type == DIFFUSE_LIGHT_MAP) {
diffuse *= texture(light_texture, light_tex_coord).rgb;
}
frag_rgb += texel.rgb * diffuse;
}
// Specular lighting
@@ -109,7 +120,8 @@ void main() {
// Rim lighting
if (rim_exponent > 0.0) {
// Normal map is not used here.
frag_rgb += pow(1.0 - max(dot(normalize(normal), view_dir), 0.0), rim_exponent) * rim_color;
vec3 n = use_normal_map ? vec3(0.0, 0.0, 1.0) : normalize(normal);
frag_rgb += pow(1.0 - max(dot(n, view_dir), 0.0), rim_exponent) * rim_color;
}
// Fog
@@ -139,7 +151,10 @@ void main() {
// Alpha mapping
float alpha = texel.a * alpha_mod;
if (use_alpha_map) {
if (alpha_mode == ALPHA_TEST) {
if (alpha < 1.0)
discard;
} else if (alpha_mode == ALPHA_MAP_BLEND) {
alpha *= texture(alpha_texture, tex_coord).r;
}
-2
View File
@@ -89,8 +89,6 @@ void main() {
vec3 tangent = normal_bone_transform * vertex_tangent.xyz;
vec3 bitangent = cross(normal, tangent) * vertex_tangent.w;
TBN = transpose(mat3(tangent, bitangent, normal));
// Tangent-space normal vector.
normal = vec3(0.0, 0.0, 1.0);
}
vec4 world_pos = local_bone_transform * vec4(vertex_pos, 1.0);
+16 -2
View File
@@ -44,9 +44,11 @@ struct model {
struct hash_table *bone_map; // bone id in POL/MOT -> struct bone *
struct hash_table *bone_name_map; // bone name -> (struct bone * | NULL)
vec3 aabb[2]; // axis-aligned bounding box
bool is_transparent;
};
struct mesh {
uint32_t flags;
GLuint vao;
GLuint attr_buffer;
int nr_vertices;
@@ -54,6 +56,7 @@ struct mesh {
};
struct material {
uint32_t flags;
GLuint color_map;
GLuint specular_map;
GLuint alpha_map;
@@ -151,7 +154,7 @@ struct RE_renderer {
GLint ls_light_dir;
GLint ls_light_color;
GLint ls_sun_color;
GLint use_alpha_map;
GLint alpha_mode;
GLint alpha_texture;
GLuint billboard_vao;
@@ -182,7 +185,7 @@ struct archive_data *RE_get_aar_entry(struct archive *aar, const char *dir, cons
struct RE_renderer *RE_renderer_new(struct texture *texture);
void RE_renderer_free(struct RE_renderer *r);
bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no);
struct billboard_texture *RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no);
struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r, struct model *model);
void RE_renderer_free_height_detector(struct height_detector *hd);
float RE_renderer_detect_height(struct height_detector *hd, float x, float z);
@@ -368,8 +371,13 @@ enum pol_texture_type {
MAX_TEXTURE_TYPE
};
enum material_flags {
MATERIAL_SPRITE = 1 << 0,
};
struct pol_material {
char *name;
uint32_t flags;
char *textures[MAX_TEXTURE_TYPE];
};
@@ -379,8 +387,14 @@ struct pol_material_group {
struct pol_material *children;
};
enum mesh_flags {
MESH_NOLIGHTING = 1 << 0,
MESH_ENVMAP = 1 << 1,
};
struct pol_mesh {
char *name;
uint32_t flags;
uint32_t material;
uint32_t nr_vertices;
struct pol_vertex *vertices;
+4
View File
@@ -50,6 +50,7 @@ static const char *motion_state_name(enum RE_motion_state state)
static const char *fog_type_name(enum RE_fog_type type)
{
switch (type) {
case RE_FOG_NONE: return "NONE";
case RE_FOG_LINEAR: return "LINEAR";
case RE_FOG_LIGHT_SCATTERING: return "LIGHT_SCATTERING";
}
@@ -98,6 +99,7 @@ static void print_instance(struct RE_instance *inst, int index, int indent)
indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
if (inst->effect)
indent_printf(indent, "path = \"%s\",\n", inst->effect->path);
indent_printf(indent, "is_transparent = %d,\n", inst->is_transparent);
indent--;
indent_printf(indent, "},\n");
@@ -135,6 +137,8 @@ void RE_debug_print(struct sact_sprite *sp, int indent)
indent_printf(indent, "fog_type = %s,\n", fog_type_name(p->fog_type));
switch (p->fog_type) {
case RE_FOG_NONE:
break;
case RE_FOG_LINEAR:
indent_printf(indent, "fog_near = %f, fog_far = %f,\n", p->fog_near, p->fog_far);
indent_printf(indent, "fog_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->fog_color));
+8
View File
@@ -89,6 +89,7 @@ static GLuint load_texture(struct archive *aar, const char *path, const char *na
static bool init_material(struct material *material, const struct pol_material *m, struct amt *amt, struct archive *aar, const char *path)
{
material->flags = m->flags;
if (!m->textures[COLOR_MAP]) {
WARNING("No color texture");
return false;
@@ -271,6 +272,7 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index
}
model->meshes = xrealloc_array(model->meshes, model->nr_meshes, model->nr_meshes + 1, sizeof(struct mesh));
struct mesh *mesh = &model->meshes[model->nr_meshes++];
mesh->flags = m->flags;
mesh->material = material;
mesh->nr_vertices = nr_vertices;
@@ -439,6 +441,12 @@ 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].alpha_map) {
model->is_transparent = true;
break;
}
}
// Meshes
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
+20
View File
@@ -59,9 +59,18 @@ static void read_quaternion(struct buffer *r, versor q)
glm_quat_normalize(q);
}
static uint32_t parse_material_attributes(const char *name)
{
uint32_t flags = 0;
if (strstr(name, "(sprite)"))
flags |= MATERIAL_SPRITE;
return flags;
}
static void parse_material(struct buffer *r, struct pol_material *m)
{
m->name = read_cstring(r);
m->flags = parse_material_attributes(m->name);
int nr_textures = buffer_read_int32(r);
for (int i = 0; i < nr_textures; i++) {
@@ -148,6 +157,16 @@ static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle
t->material = buffer_read_int32(r);
}
static uint32_t parse_mesh_attributes(const char *name)
{
uint32_t flags = 0;
if (strstr(name, "(nolighting)"))
flags |= MESH_NOLIGHTING;
if (strstr(name, "(env)"))
flags |= MESH_ENVMAP;
return flags;
}
static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version)
{
int type = buffer_read_int32(r);
@@ -158,6 +177,7 @@ static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version)
}
struct pol_mesh *mesh = xcalloc(1, sizeof(struct pol_mesh));
mesh->name = read_cstring(r);
mesh->flags = parse_mesh_attributes(mesh->name);
mesh->material = buffer_read_int32(r);
mesh->nr_vertices = buffer_read_int32(r);
+2 -2
View File
@@ -741,8 +741,8 @@ void particle_effect_calc_frame_range(struct particle_effect *effect, struct mot
if (end_frame < obj_end)
end_frame = obj_end;
}
motion->frame_begin = begin_frame;
motion->frame_end = end_frame;
motion->frame_begin = motion->loop_frame_begin = begin_frame;
motion->frame_end = motion->loop_frame_end = end_frame;
}
static void update_camera_quake(struct RE_instance *inst, struct particle_object *po)
+14 -3
View File
@@ -188,7 +188,10 @@ struct RE_plugin *RE_plugin_new(void)
plugin->aar = aar;
for (int i = 0; i < RE_NR_BACK_CGS; i++)
RE_back_cg_init(&plugin->back_cg[i]);
plugin->fog_type = RE_FOG_LINEAR;
plugin->fog_type = RE_FOG_NONE;
plugin->fog_near = 1.0;
plugin->fog_far = 10.0;
glm_vec3_one(plugin->fog_color);
return plugin;
}
@@ -346,6 +349,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name)
instance->model = model_load(instance->plugin->aar, name);
if (instance->model && instance->model->nr_bones > 0)
instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4));
instance->is_transparent = instance->model->is_transparent;
return !!instance->model;
case RE_ITYPE_PARTICLE_EFFECT:
instance->effect = particle_effect_load(instance->plugin->aar, name);
@@ -354,6 +358,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name)
instance->motion->instance = instance;
particle_effect_calc_frame_range(instance->effect, instance->motion);
}
instance->is_transparent = true;
return !!instance->effect;
default:
WARNING("Invalid instance type %d", instance->type);
@@ -496,8 +501,11 @@ bool RE_motion_set_frame_range(struct motion *motion, float begin, float end)
motion->frame_end = end;
if (motion->instance->type == RE_ITYPE_BILLBOARD) {
for (int i = begin; i < end; i++) {
if (!RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i))
struct billboard_texture *bt = RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i);
if (!bt)
return false;
if (bt->has_alpha)
motion->instance->is_transparent = true;
}
}
return true;
@@ -511,8 +519,11 @@ bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float en
motion->loop_frame_end = end;
if (motion->instance->type == RE_ITYPE_BILLBOARD) {
for (int i = begin; i < end; i++) {
if (!RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i))
struct billboard_texture *bt = RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i);
if (!bt)
return false;
if (bt->has_alpha)
motion->instance->is_transparent = true;
}
}
return true;
+88 -37
View File
@@ -14,6 +14,7 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <limits.h>
#include <cglm/cglm.h>
#include "system4.h"
@@ -42,6 +43,13 @@ enum {
DIFFUSE_EMISSIVE = 0,
DIFFUSE_NORMAL = 1,
DIFFUSE_LIGHT_MAP = 2,
DIFFUSE_ENV_MAP = 3,
};
enum {
ALPHA_BLEND = 0,
ALPHA_TEST = 1,
ALPHA_MAP_BLEND = 2,
};
static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path)
@@ -200,7 +208,7 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
r->ls_light_dir = glGetUniformLocation(r->program, "ls_light_dir");
r->ls_light_color = glGetUniformLocation(r->program, "ls_light_color");
r->ls_sun_color = glGetUniformLocation(r->program, "ls_sun_color");
r->use_alpha_map = glGetUniformLocation(r->program, "use_alpha_map");
r->alpha_mode = glGetUniformLocation(r->program, "alpha_mode");
r->alpha_texture = glGetUniformLocation(r->program, "alpha_texture");
glGenRenderbuffers(1, &r->depth_buffer);
@@ -214,16 +222,17 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
return r;
}
bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no)
struct billboard_texture *RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no)
{
if (ht_get_int(r->billboard_textures, cg_no, NULL))
return true;
struct billboard_texture *bt = ht_get_int(r->billboard_textures, cg_no, NULL);
if (bt)
return bt;
struct cg *cg = asset_cg_load(cg_no);
if (!cg)
return false;
return NULL;
struct billboard_texture *bt = xcalloc(1, sizeof(struct billboard_texture));
bt = xcalloc(1, sizeof(struct billboard_texture));
glGenTextures(1, &bt->texture);
glBindTexture(GL_TEXTURE_2D, bt->texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
@@ -237,7 +246,7 @@ bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no)
cg_free(cg);
ht_put_int(r->billboard_textures, cg_no, bt);
return true;
return bt;
}
static void free_billboard_texture(void *value)
@@ -301,8 +310,11 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
struct mesh *mesh = &model->meshes[i];
struct material *material = &model->materials[mesh->material];
glUniform1i(r->fog_type, (inst->plugin->fog_mode && !(mesh->flags & MESH_NOLIGHTING))
? inst->plugin->fog_type : 0);
GLboolean use_specular_map = GL_FALSE;
if (inst->plugin->specular_mode) {
if (inst->plugin->specular_mode && !(mesh->flags & MESH_NOLIGHTING)) {
glUniform1f(r->specular_strength, material->specular_strength);
glUniform1f(r->specular_shininess, material->specular_shininess);
if (material->specular_map) {
@@ -324,7 +336,11 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
glBindTexture(GL_TEXTURE_2D, material->color_map);
glUniform1i(r->texture, COLOR_TEXTURE_UNIT);
if (material->light_map && inst->plugin->light_map_mode) {
if (mesh->flags & MESH_ENVMAP) {
glUniform1i(r->diffuse_type, DIFFUSE_ENV_MAP);
} else if (mesh->flags & MESH_NOLIGHTING) {
glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE);
} else if (material->light_map && inst->plugin->light_map_mode) {
glUniform1i(r->diffuse_type, DIFFUSE_LIGHT_MAP);
glActiveTexture(GL_TEXTURE0 + LIGHT_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->light_map);
@@ -343,12 +359,14 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
}
if (material->alpha_map) {
glUniform1i(r->use_alpha_map, GL_TRUE);
glUniform1i(r->alpha_mode, ALPHA_MAP_BLEND);
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) {
glUniform1i(r->alpha_mode, ALPHA_TEST);
} else {
glUniform1i(r->use_alpha_map, GL_FALSE);
glUniform1i(r->alpha_mode, ALPHA_BLEND);
}
glBindVertexArray(mesh->vao);
@@ -419,7 +437,8 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
glUniform1i(r->use_normal_map, GL_FALSE);
glUniform1i(r->use_shadow_map, GL_FALSE);
glUniform1i(r->use_alpha_map, GL_FALSE);
glUniform1i(r->alpha_mode, ALPHA_BLEND);
glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bt->texture);
@@ -470,8 +489,6 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glUniform1i(r->fog_type, inst->plugin->fog_type);
}
static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame)
@@ -481,6 +498,7 @@ static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *
return;
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0);
for (int index = 0; index < po->nr_particles; index++) {
struct particle_instance *pi = &po->instances[index];
@@ -529,7 +547,7 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer
glUniform1f(r->rim_exponent, 0.0);
glUniform1i(r->use_normal_map, GL_FALSE);
glUniform1i(r->use_shadow_map, GL_FALSE);
glUniform1i(r->use_alpha_map, GL_FALSE);
glUniform1i(r->alpha_mode, ALPHA_BLEND);
glDepthMask(GL_FALSE);
@@ -561,6 +579,26 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer
glDepthMask(GL_TRUE);
}
static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat)
{
switch (inst->type) {
case RE_ITYPE_STATIC:
render_static_model(inst, r);
break;
case RE_ITYPE_SKINNED:
render_skinned_model(inst, r);
break;
case RE_ITYPE_BILLBOARD:
render_billboard(inst, r, view_mat);
break;
case RE_ITYPE_PARTICLE_EFFECT:
render_particle_effect(inst, r);
break;
default:
break;
}
}
static bool calc_shadow_light_transform(struct RE_plugin *plugin, mat4 dest)
{
// Compute AABB of shadow casters.
@@ -704,6 +742,20 @@ static void setup_lights(struct RE_plugin *plugin)
}
}
static int cmp_instances_by_z(const void *lhs, const void *rhs)
{
struct RE_instance *l = *(struct RE_instance **)lhs;
struct RE_instance *r = *(struct RE_instance **)rhs;
float lz = l ? l->pos[2] : FLT_MAX;
float rz = r ? r->pos[2] : FLT_MAX;
return (lz > rz) - (lz < rz); // ascending order.
}
static bool is_transparent(struct RE_instance *inst)
{
return inst->is_transparent || inst->alpha < 1.0f;
}
void RE_render(struct sact_sprite *sp)
{
struct RE_plugin *plugin = (struct RE_plugin *)sp->plugin;
@@ -753,8 +805,9 @@ void RE_render(struct sact_sprite *sp)
glUniformMatrix4fv(r->shadow_transform, 1, GL_FALSE, shadow_transform[0]);
glUniform1f(r->shadow_bias, plugin->shadow_bias);
if (plugin->fog_mode) {
glUniform1i(r->fog_type, plugin->fog_type);
switch (plugin->fog_type) {
case RE_FOG_NONE:
break;
case RE_FOG_LINEAR:
glUniform1f(r->fog_near, plugin->fog_near);
glUniform1f(r->fog_far, plugin->fog_far);
@@ -767,8 +820,6 @@ void RE_render(struct sact_sprite *sp)
glUniform3fv(r->ls_sun_color, 1, plugin->ls_sun_color);
break;
}
} else {
glUniform1i(r->fog_type, 0);
}
glEnable(GL_BLEND);
@@ -776,27 +827,27 @@ void RE_render(struct sact_sprite *sp)
setup_lights(plugin);
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst)
// Sort instances by z-order.
struct RE_instance **sorted_instances = xmalloc(plugin->nr_instances * sizeof(struct RE_instance *));
memcpy(sorted_instances, plugin->instances, plugin->nr_instances * sizeof(struct RE_instance *));
qsort(sorted_instances, plugin->nr_instances, sizeof(struct RE_instance *), cmp_instances_by_z);
// Render opaque instances, from nearest to farthest.
for (int i = plugin->nr_instances - 1; i >= 0; i--) {
struct RE_instance *inst = sorted_instances[i];
if (!inst || is_transparent(inst))
continue;
switch (inst->type) {
case RE_ITYPE_STATIC:
render_static_model(inst, r);
break;
case RE_ITYPE_SKINNED:
render_skinned_model(inst, r);
break;
case RE_ITYPE_BILLBOARD:
render_billboard(inst, r, view_transform);
break;
case RE_ITYPE_PARTICLE_EFFECT:
render_particle_effect(inst, r);
break;
default:
break;
}
render_instance(inst, r, view_transform);
}
// Render transparent instances, from nearest to farthest.
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = sorted_instances[i];
if (!inst || !is_transparent(inst))
continue;
render_instance(inst, r, view_transform);
}
free(sorted_instances);
plugin->proj_transform[1][1] *= -1;
glFrontFace(GL_CCW);