mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user