mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
SealEngine: Add .mpr (motion material keyframes) support
.mpr is an optional sidecar to .mot used by SealEngine, replacing .txa
used in ReignEngine / TapirEngine. While .mot drives bone poses, .mpr
drives material properties on a per-frame timeline.
Supported keys, all keyed by frame number:
Object{MulAlpha,MulDiffuse,AddAmbient} : applied to the whole model
Mesh{MulAlpha,MulDiffuse,AddAmbient} : applied per named mesh
MeshTextureAnime : swap diffuse texture index
Colors and alpha use linear interpolation between keys. Out-of-range
frames hold the nearest endpoint.
Mesh* tracks act as per-mesh tints and do not leak to other meshes
that happen to share a material. MeshTextureAnime is the exception:
it rewrites the shared material's diffuse slot, so all meshes using
that material animate in sync (e.g. in Rance 9, hanny_black_move.mpr
lists only hibana_R but hibana_L animates together).
This commit is contained in:
@@ -79,6 +79,7 @@ target_sources(xsystem4 PRIVATE
|
||||
src/3d/collision.c
|
||||
src/3d/debug.c
|
||||
src/3d/model.c
|
||||
src/3d/mpr.c
|
||||
src/3d/parser.c
|
||||
src/3d/particle.c
|
||||
src/3d/reign.c
|
||||
|
||||
@@ -87,6 +87,7 @@ uniform bool use_normal_map;
|
||||
uniform sampler2D normal_texture;
|
||||
|
||||
uniform vec3 instance_ambient;
|
||||
uniform vec3 diffuse_mod;
|
||||
uniform int diffuse_type;
|
||||
uniform float shadow_darkness;
|
||||
uniform float shadow_bias;
|
||||
@@ -120,20 +121,20 @@ void main() {
|
||||
vec4 texel;
|
||||
if (diffuse_type == DIFFUSE_ENV_MAP) {
|
||||
texel = texture(tex, (vec2(normal.x, -normal.y) + 1.0) / 2.0);
|
||||
frag_rgb = texel.rgb;
|
||||
frag_rgb = texel.rgb * diffuse_mod;
|
||||
} else {
|
||||
texel = texture(tex, tex_coord);
|
||||
if (use_blend_texture) {
|
||||
texel = mix(texel, texture(blend_tex, blend_tex_coord), blend_weight);
|
||||
}
|
||||
if (diffuse_type == DIFFUSE_EMISSIVE) {
|
||||
frag_rgb = texel.rgb;
|
||||
frag_rgb = texel.rgb * diffuse_mod;
|
||||
} else {
|
||||
vec3 diffuse = dir_lights_diffuse(norm);
|
||||
if (diffuse_type == DIFFUSE_LIGHT_MAP) {
|
||||
diffuse *= texture(light_texture, light_tex_coord).rgb;
|
||||
}
|
||||
frag_rgb += texel.rgb * diffuse * color_mod.rgb;
|
||||
frag_rgb += texel.rgb * diffuse * color_mod.rgb * diffuse_mod;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ struct RE_renderer {
|
||||
GLint has_bones;
|
||||
GLint global_ambient;
|
||||
GLint instance_ambient;
|
||||
GLint diffuse_mod;
|
||||
struct {
|
||||
GLint dir;
|
||||
GLint diffuse;
|
||||
@@ -515,6 +516,7 @@ struct mot {
|
||||
uint32_t nr_bones;
|
||||
uint32_t nr_texture_indices;
|
||||
uint32_t *texture_indices; // texture index for each frame
|
||||
struct mpr *mpr; // optional
|
||||
struct mot_bone *motions[];
|
||||
};
|
||||
|
||||
@@ -568,6 +570,46 @@ struct amt_material *amt_find_material(struct amt *amt, const char *name);
|
||||
void opr_load(uint8_t *data, size_t size, struct pol *pol);
|
||||
void txa_load(uint8_t *data, size_t size, struct mot *mot);
|
||||
|
||||
// mpr.c
|
||||
|
||||
struct mpr_float_key { int frame; float v; };
|
||||
struct mpr_vec3_key { int frame; vec3 v; };
|
||||
struct mpr_int_key { int frame; int v; };
|
||||
|
||||
struct mpr_track_set {
|
||||
int nr_mul_alpha;
|
||||
struct mpr_float_key *mul_alpha;
|
||||
int nr_mul_diffuse;
|
||||
struct mpr_vec3_key *mul_diffuse;
|
||||
int nr_add_ambient;
|
||||
struct mpr_vec3_key *add_ambient;
|
||||
int nr_texture_anime;
|
||||
struct mpr_int_key *texture_anime; // mesh-scope only
|
||||
};
|
||||
|
||||
struct mpr {
|
||||
int nr_meshes; // == model->nr_meshes
|
||||
struct mpr_track_set **mesh_tracks; // sparse: indexed by mesh index, NULL if absent
|
||||
struct mpr_track_set object;
|
||||
bool has_mesh_alpha; // any mesh_tracks[i]->nr_mul_alpha > 0
|
||||
};
|
||||
|
||||
// Per-draw material modulation.
|
||||
struct mpr_modulation {
|
||||
float alpha;
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
};
|
||||
|
||||
struct mpr *mpr_load(uint8_t *data, size_t size, struct model *model);
|
||||
void mpr_free(struct mpr *mpr);
|
||||
void mpr_evaluate_object(const struct mpr *mpr, float frame,
|
||||
const struct RE_instance *inst, struct mpr_modulation *out);
|
||||
void mpr_evaluate_mesh(const struct mpr_track_set *mt, float frame,
|
||||
const struct mpr_modulation *obj, struct mpr_modulation *out);
|
||||
void mpr_build_mat_tex_index(const struct model *model, const struct RE_instance *inst,
|
||||
const struct mpr *mpr, float frame, int *mat_tex_index);
|
||||
|
||||
// collision.c
|
||||
|
||||
struct collider_triangle;
|
||||
|
||||
+13
-5
@@ -783,11 +783,19 @@ static struct mot *mot_load(const char *name, struct model *model, struct archiv
|
||||
}
|
||||
qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id);
|
||||
|
||||
// Load optional .txa file.
|
||||
struct archive_data *txa_file = RE_get_aar_entry(aar, model->path, name, ".txa");
|
||||
if (txa_file) {
|
||||
txa_load(txa_file->data, txa_file->size, mot);
|
||||
archive_free_data(txa_file);
|
||||
// Load optional sidecar file.
|
||||
if (re_plugin_version <= RE_TAPIR_PLUGIN) {
|
||||
struct archive_data *txa_file = RE_get_aar_entry(aar, model->path, name, ".txa");
|
||||
if (txa_file) {
|
||||
txa_load(txa_file->data, txa_file->size, mot);
|
||||
archive_free_data(txa_file);
|
||||
}
|
||||
} else {
|
||||
struct archive_data *mpr_file = RE_get_aar_entry(aar, model->path, name, ".mpr");
|
||||
if (mpr_file) {
|
||||
mot->mpr = mpr_load(mpr_file->data, mpr_file->size, model);
|
||||
archive_free_data(mpr_file);
|
||||
}
|
||||
}
|
||||
|
||||
return mot;
|
||||
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
/* Copyright (C) 2026 kichikuou <KichikuouChrome@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cglm/cglm.h>
|
||||
|
||||
#include "system4.h"
|
||||
|
||||
#include "3d_internal.h"
|
||||
|
||||
// .mpr parser.
|
||||
|
||||
static int resolve_mesh_index(struct model *model, const char *name)
|
||||
{
|
||||
for (int i = 0; i < model->nr_meshes; i++) {
|
||||
if (!strcmp(model->meshes[i].name, name))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void append_float_key(struct mpr_track_set *ts, int frame, float v)
|
||||
{
|
||||
ts->mul_alpha = xrealloc(ts->mul_alpha, (ts->nr_mul_alpha + 1) * sizeof(struct mpr_float_key));
|
||||
ts->mul_alpha[ts->nr_mul_alpha].frame = frame;
|
||||
ts->mul_alpha[ts->nr_mul_alpha].v = v;
|
||||
ts->nr_mul_alpha++;
|
||||
}
|
||||
|
||||
static void append_vec3_key(struct mpr_vec3_key **arr, int *nr, int frame, float r, float g, float b)
|
||||
{
|
||||
*arr = xrealloc(*arr, (*nr + 1) * sizeof(struct mpr_vec3_key));
|
||||
(*arr)[*nr].frame = frame;
|
||||
(*arr)[*nr].v[0] = r;
|
||||
(*arr)[*nr].v[1] = g;
|
||||
(*arr)[*nr].v[2] = b;
|
||||
(*nr)++;
|
||||
}
|
||||
|
||||
static void append_int_key(struct mpr_int_key **arr, int *nr, int frame, int v)
|
||||
{
|
||||
*arr = xrealloc(*arr, (*nr + 1) * sizeof(struct mpr_int_key));
|
||||
(*arr)[*nr].frame = frame;
|
||||
(*arr)[*nr].v = v;
|
||||
(*nr)++;
|
||||
}
|
||||
|
||||
// All mpr_*_key structs have `int frame` as their first field.
|
||||
static int cmp_key_by_frame(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
||||
}
|
||||
|
||||
static void sort_track_set(struct mpr_track_set *ts)
|
||||
{
|
||||
if (ts->nr_mul_alpha)
|
||||
qsort(ts->mul_alpha, ts->nr_mul_alpha, sizeof(struct mpr_float_key), cmp_key_by_frame);
|
||||
if (ts->nr_mul_diffuse)
|
||||
qsort(ts->mul_diffuse, ts->nr_mul_diffuse, sizeof(struct mpr_vec3_key), cmp_key_by_frame);
|
||||
if (ts->nr_add_ambient)
|
||||
qsort(ts->add_ambient, ts->nr_add_ambient, sizeof(struct mpr_vec3_key), cmp_key_by_frame);
|
||||
if (ts->nr_texture_anime)
|
||||
qsort(ts->texture_anime, ts->nr_texture_anime, sizeof(struct mpr_int_key), cmp_key_by_frame);
|
||||
}
|
||||
|
||||
struct mpr *mpr_load(uint8_t *data, size_t size, struct model *model)
|
||||
{
|
||||
struct mpr *mpr = xcalloc(1, sizeof(struct mpr));
|
||||
mpr->nr_meshes = model->nr_meshes;
|
||||
mpr->mesh_tracks = xcalloc(model->nr_meshes, sizeof(struct mpr_track_set *));
|
||||
struct mpr_track_set *current = NULL; // current Mesh-scope track set
|
||||
|
||||
while (size > 0) {
|
||||
char line[200];
|
||||
uint8_t *nl = memchr(data, '\n', size);
|
||||
if (nl)
|
||||
nl++;
|
||||
else
|
||||
nl = data + size;
|
||||
int copylen = min(nl - data, sizeof(line) - 1);
|
||||
memcpy(line, (char *)data, copylen);
|
||||
line[copylen] = '\0';
|
||||
size -= nl - data;
|
||||
data = nl;
|
||||
|
||||
char s[200];
|
||||
int frame, ti;
|
||||
float a, r, g, b;
|
||||
if (sscanf(line, "Mesh = \"%[^\"]\"", s) == 1) {
|
||||
int mi = resolve_mesh_index(model, s);
|
||||
if (mi < 0) {
|
||||
WARNING("mpr: unknown mesh \"%s\"", s);
|
||||
current = NULL;
|
||||
} else {
|
||||
if (!mpr->mesh_tracks[mi])
|
||||
mpr->mesh_tracks[mi] = xcalloc(1, sizeof(struct mpr_track_set));
|
||||
current = mpr->mesh_tracks[mi];
|
||||
}
|
||||
} else if (sscanf(line, "MeshMulAlpha = ( %d , %f )", &frame, &a) == 2) {
|
||||
if (current)
|
||||
append_float_key(current, frame, a);
|
||||
else
|
||||
WARNING("mpr: MeshMulAlpha outside Mesh scope");
|
||||
} else if (sscanf(line, "MeshMulDiffuse = ( %d , %f , %f , %f )", &frame, &r, &g, &b) == 4) {
|
||||
if (current)
|
||||
append_vec3_key(¤t->mul_diffuse, ¤t->nr_mul_diffuse, frame, r, g, b);
|
||||
else
|
||||
WARNING("mpr: MeshMulDiffuse outside Mesh scope");
|
||||
} else if (sscanf(line, "MeshAddAmbient = ( %d , %f , %f , %f )", &frame, &r, &g, &b) == 4) {
|
||||
if (current)
|
||||
append_vec3_key(¤t->add_ambient, ¤t->nr_add_ambient, frame, r, g, b);
|
||||
else
|
||||
WARNING("mpr: MeshAddAmbient outside Mesh scope");
|
||||
} else if (sscanf(line, "MeshTextureAnime = ( %d , %d )", &frame, &ti) == 2) {
|
||||
if (current)
|
||||
append_int_key(¤t->texture_anime, ¤t->nr_texture_anime, frame, ti);
|
||||
else
|
||||
WARNING("mpr: MeshTextureAnime outside Mesh scope");
|
||||
} else if (sscanf(line, "ObjectMulAlpha = ( %d , %f )", &frame, &a) == 2) {
|
||||
append_float_key(&mpr->object, frame, a);
|
||||
} else if (sscanf(line, "ObjectMulDiffuse = ( %d , %f , %f , %f )", &frame, &r, &g, &b) == 4) {
|
||||
append_vec3_key(&mpr->object.mul_diffuse, &mpr->object.nr_mul_diffuse, frame, r, g, b);
|
||||
} else if (sscanf(line, "ObjectAddAmbient = ( %d , %f , %f , %f )", &frame, &r, &g, &b) == 4) {
|
||||
append_vec3_key(&mpr->object.add_ambient, &mpr->object.nr_add_ambient, frame, r, g, b);
|
||||
} else if (strchr(line, '=')) {
|
||||
WARNING("mpr: unknown field: %s", line);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mpr->nr_meshes; i++) {
|
||||
if (!mpr->mesh_tracks[i])
|
||||
continue;
|
||||
sort_track_set(mpr->mesh_tracks[i]);
|
||||
if (mpr->mesh_tracks[i]->nr_mul_alpha > 0)
|
||||
mpr->has_mesh_alpha = true;
|
||||
}
|
||||
sort_track_set(&mpr->object);
|
||||
return mpr;
|
||||
}
|
||||
|
||||
static void destroy_track_set(struct mpr_track_set *ts)
|
||||
{
|
||||
free(ts->mul_alpha);
|
||||
free(ts->mul_diffuse);
|
||||
free(ts->add_ambient);
|
||||
free(ts->texture_anime);
|
||||
}
|
||||
|
||||
void mpr_free(struct mpr *mpr)
|
||||
{
|
||||
if (!mpr)
|
||||
return;
|
||||
for (int i = 0; i < mpr->nr_meshes; i++) {
|
||||
if (mpr->mesh_tracks[i]) {
|
||||
destroy_track_set(mpr->mesh_tracks[i]);
|
||||
free(mpr->mesh_tracks[i]);
|
||||
}
|
||||
}
|
||||
free(mpr->mesh_tracks);
|
||||
destroy_track_set(&mpr->object);
|
||||
free(mpr);
|
||||
}
|
||||
|
||||
// Keyframe evaluation.
|
||||
|
||||
// Returns the largest index i with keys[i].frame <= frame.
|
||||
// Returns -1 if frame < keys[0].frame.
|
||||
#define DEFINE_FIND_KEY(NAME, KEY_TYPE) \
|
||||
static int NAME(const KEY_TYPE *keys, int nr, float frame) \
|
||||
{ \
|
||||
if (frame < (float)keys[0].frame) \
|
||||
return -1; \
|
||||
int lo = 0, hi = nr - 1; \
|
||||
while (lo < hi) { \
|
||||
int mid = (lo + hi + 1) / 2; \
|
||||
if ((float)keys[mid].frame <= frame) \
|
||||
lo = mid; \
|
||||
else \
|
||||
hi = mid - 1; \
|
||||
} \
|
||||
return lo; \
|
||||
}
|
||||
|
||||
DEFINE_FIND_KEY(find_float_key, struct mpr_float_key)
|
||||
DEFINE_FIND_KEY(find_vec3_key, struct mpr_vec3_key)
|
||||
DEFINE_FIND_KEY(find_int_key, struct mpr_int_key)
|
||||
|
||||
static float eval_float(const struct mpr_float_key *keys, int nr, float frame, float fallback)
|
||||
{
|
||||
if (nr == 0)
|
||||
return fallback;
|
||||
int i = find_float_key(keys, nr, frame);
|
||||
if (i < 0)
|
||||
return keys[0].v;
|
||||
if (i >= nr - 1)
|
||||
return keys[nr - 1].v;
|
||||
float t = (frame - keys[i].frame) / (float)(keys[i + 1].frame - keys[i].frame);
|
||||
return glm_lerp(keys[i].v, keys[i + 1].v, t);
|
||||
}
|
||||
|
||||
static void eval_vec3(const struct mpr_vec3_key *keys, int nr, float frame, const vec3 fallback, vec3 out)
|
||||
{
|
||||
if (nr == 0) {
|
||||
glm_vec3_copy((float *)fallback, out);
|
||||
return;
|
||||
}
|
||||
int i = find_vec3_key(keys, nr, frame);
|
||||
if (i < 0) {
|
||||
glm_vec3_copy((float *)keys[0].v, out);
|
||||
return;
|
||||
}
|
||||
if (i >= nr - 1) {
|
||||
glm_vec3_copy((float *)keys[nr - 1].v, out);
|
||||
return;
|
||||
}
|
||||
float t = (frame - keys[i].frame) / (float)(keys[i + 1].frame - keys[i].frame);
|
||||
glm_vec3_lerp((float *)keys[i].v, (float *)keys[i + 1].v, t, out);
|
||||
}
|
||||
|
||||
static int eval_int(const struct mpr_int_key *keys, int nr, float frame, int fallback)
|
||||
{
|
||||
if (nr == 0)
|
||||
return fallback;
|
||||
int i = find_int_key(keys, nr, frame);
|
||||
if (i < 0)
|
||||
return keys[0].v;
|
||||
return keys[i].v; // step
|
||||
}
|
||||
|
||||
// Combine inst defaults with .mpr Object-scope keyframes.
|
||||
void mpr_evaluate_object(const struct mpr *mpr, float frame,
|
||||
const struct RE_instance *inst, struct mpr_modulation *out)
|
||||
{
|
||||
out->alpha = inst->alpha;
|
||||
glm_vec3_copy((float *)inst->ambient, out->ambient);
|
||||
glm_vec3_one(out->diffuse);
|
||||
if (!mpr)
|
||||
return;
|
||||
out->alpha *= eval_float(mpr->object.mul_alpha, mpr->object.nr_mul_alpha, frame, 1.f);
|
||||
vec3 add;
|
||||
eval_vec3(mpr->object.add_ambient, mpr->object.nr_add_ambient, frame, (vec3){0,0,0}, add);
|
||||
glm_vec3_add(out->ambient, add, out->ambient);
|
||||
eval_vec3(mpr->object.mul_diffuse, mpr->object.nr_mul_diffuse, frame, (vec3){1,1,1}, out->diffuse);
|
||||
}
|
||||
|
||||
// Combine the object-scope values with .mpr Mesh-scope keyframes for one mesh.
|
||||
void mpr_evaluate_mesh(const struct mpr_track_set *mt, float frame,
|
||||
const struct mpr_modulation *obj, struct mpr_modulation *out)
|
||||
{
|
||||
*out = *obj;
|
||||
if (!mt)
|
||||
return;
|
||||
out->alpha *= eval_float(mt->mul_alpha, mt->nr_mul_alpha, frame, 1.f);
|
||||
vec3 add;
|
||||
eval_vec3(mt->add_ambient, mt->nr_add_ambient, frame, (vec3){0,0,0}, add);
|
||||
glm_vec3_add(out->ambient, add, out->ambient);
|
||||
vec3 mul;
|
||||
eval_vec3(mt->mul_diffuse, mt->nr_mul_diffuse, frame, (vec3){1,1,1}, mul);
|
||||
glm_vec3_mul(out->diffuse, mul, out->diffuse);
|
||||
}
|
||||
|
||||
// MeshTextureAnime writes to the shared material slot, so all meshes
|
||||
// referencing the same material pick up the animation even if .mpr only names
|
||||
// one of them. Caller supplies the output buffer sized to model->nr_materials.
|
||||
void mpr_build_mat_tex_index(const struct model *model, const struct RE_instance *inst,
|
||||
const struct mpr *mpr, float frame, int *mat_tex_index)
|
||||
{
|
||||
for (int m = 0; m < model->nr_materials; m++)
|
||||
mat_tex_index[m] = inst->texture_animation_index;
|
||||
if (!mpr)
|
||||
return;
|
||||
for (int i = 0; i < mpr->nr_meshes; i++) {
|
||||
const struct mpr_track_set *t = mpr->mesh_tracks[i];
|
||||
if (!t || t->nr_texture_anime == 0)
|
||||
continue;
|
||||
int mat = model->meshes[i].material;
|
||||
mat_tex_index[mat] = eval_int(t->texture_anime, t->nr_texture_anime, frame, mat_tex_index[mat]);
|
||||
}
|
||||
}
|
||||
@@ -491,6 +491,7 @@ void mot_free(struct mot *mot)
|
||||
if (mot->texture_indices) {
|
||||
free(mot->texture_indices);
|
||||
}
|
||||
mpr_free(mot->mpr);
|
||||
free(mot);
|
||||
}
|
||||
|
||||
|
||||
+32
-9
@@ -225,6 +225,7 @@ struct RE_renderer *RE_renderer_new(void)
|
||||
glUniformBlockBinding(r->program, bone_transforms, BONE_TRANSFORMS_BINDING);
|
||||
r->global_ambient = glGetUniformLocation(r->program, "global_ambient");
|
||||
r->instance_ambient = glGetUniformLocation(r->program, "instance_ambient");
|
||||
r->diffuse_mod = glGetUniformLocation(r->program, "diffuse_mod");
|
||||
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
|
||||
char buf[64];
|
||||
sprintf(buf, "dir_lights[%d].dir", i);
|
||||
@@ -353,18 +354,27 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
|
||||
struct model *model = inst->model;
|
||||
if (!inst->model)
|
||||
return;
|
||||
bool all_transparent = inst->alpha < 1.0f;
|
||||
bool all_opaque = !model->has_transparent_mesh && inst->alpha >= 1.0f;
|
||||
|
||||
// NOTE: next_motion's .mpr is not sampled.
|
||||
const struct mpr *mpr = (inst->motion && inst->motion->mot) ? inst->motion->mot->mpr : NULL;
|
||||
float frame = inst->motion ? inst->motion->current_frame : 0.f;
|
||||
struct mpr_modulation obj_mod;
|
||||
mpr_evaluate_object(mpr, frame, inst, &obj_mod);
|
||||
|
||||
bool all_transparent = obj_mod.alpha < 1.0f;
|
||||
bool all_opaque = !model->has_transparent_mesh && obj_mod.alpha >= 1.0f
|
||||
&& !(mpr && mpr->has_mesh_alpha);
|
||||
if ((phase == DRAW_OPAQUE && all_transparent) || (phase == DRAW_TRANSPARENT && all_opaque))
|
||||
return;
|
||||
|
||||
int mat_tex_index[model->nr_materials];
|
||||
mpr_build_mat_tex_index(model, inst, mpr, frame, mat_tex_index);
|
||||
|
||||
if (inst->local_transform_needs_update)
|
||||
RE_instance_update_local_transform(inst);
|
||||
|
||||
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, inst->local_transform[0]);
|
||||
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, inst->normal_transform[0]);
|
||||
glUniform1f(r->alpha_mod, inst->alpha);
|
||||
glUniform3fv(r->instance_ambient, 1, inst->ambient);
|
||||
|
||||
bool draw_shadow = inst->draw_shadow && inst->plugin->shadow_mode;
|
||||
if (draw_shadow) {
|
||||
@@ -378,10 +388,21 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
|
||||
if (mesh->hidden)
|
||||
continue;
|
||||
struct material *material = &model->materials[mesh->material];
|
||||
bool is_transparent = mesh->is_transparent || inst->alpha < 1.0f;
|
||||
|
||||
const struct mpr_track_set *mt = mpr ? mpr->mesh_tracks[i] : NULL;
|
||||
struct mpr_modulation mesh_mod;
|
||||
mpr_evaluate_mesh(mt, frame, &obj_mod, &mesh_mod);
|
||||
if (mesh_mod.alpha <= 0.0f)
|
||||
continue;
|
||||
|
||||
bool is_transparent = mesh->is_transparent || mesh_mod.alpha < 1.0f;
|
||||
if (phase != (is_transparent ? DRAW_TRANSPARENT : DRAW_OPAQUE))
|
||||
continue;
|
||||
|
||||
glUniform1f(r->alpha_mod, mesh_mod.alpha);
|
||||
glUniform3fv(r->instance_ambient, 1, mesh_mod.ambient);
|
||||
glUniform3fv(r->diffuse_mod, 1, mesh_mod.diffuse);
|
||||
|
||||
if (mesh->flags & MESH_BLEND_ADDITIVE) {
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
|
||||
} else {
|
||||
@@ -411,8 +432,8 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
|
||||
glUniform3fv(r->rim_color, 1, material->rim_color);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + COLOR_TEXTURE_UNIT);
|
||||
int animation_index = inst->texture_animation_index < material->nr_color_maps
|
||||
? inst->texture_animation_index : 0;
|
||||
int tex_index = mat_tex_index[mesh->material];
|
||||
int animation_index = tex_index < material->nr_color_maps ? tex_index : 0;
|
||||
glBindTexture(GL_TEXTURE_2D, material->color_maps[animation_index]);
|
||||
glUniform1i(r->texture, COLOR_TEXTURE_UNIT);
|
||||
|
||||
@@ -444,12 +465,12 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d
|
||||
}
|
||||
|
||||
if (material->alpha_map) {
|
||||
glUniform1i(r->alpha_mode, mesh->is_transparent ? ALPHA_MAP_BLEND : ALPHA_MAP_TEST);
|
||||
glUniform1i(r->alpha_mode, is_transparent ? ALPHA_MAP_BLEND : ALPHA_MAP_TEST);
|
||||
glActiveTexture(GL_TEXTURE0 + ALPHA_TEXTURE_UNIT);
|
||||
glBindTexture(GL_TEXTURE_2D, material->alpha_map);
|
||||
glUniform1i(r->alpha_texture, ALPHA_TEXTURE_UNIT);
|
||||
} else {
|
||||
glUniform1i(r->alpha_mode, mesh->is_transparent ? ALPHA_BLEND : ALPHA_TEST);
|
||||
glUniform1i(r->alpha_mode, is_transparent ? ALPHA_BLEND : ALPHA_TEST);
|
||||
}
|
||||
|
||||
if (material->blend_texture) {
|
||||
@@ -535,6 +556,7 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
|
||||
glm_mat4_pick3(local_transform, normal_transform);
|
||||
|
||||
glUniform3fv(r->instance_ambient, 1, inst->ambient);
|
||||
glUniform3f(r->diffuse_mod, 1.f, 1.f, 1.f);
|
||||
|
||||
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
|
||||
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, normal_transform[0]);
|
||||
@@ -659,6 +681,7 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer
|
||||
return;
|
||||
|
||||
glUniform3fv(r->instance_ambient, 1, inst->ambient);
|
||||
glUniform3f(r->diffuse_mod, 1.f, 1.f, 1.f);
|
||||
|
||||
glUniform1i(r->has_bones, GL_FALSE);
|
||||
glUniform1f(r->specular_strength, 0.0);
|
||||
|
||||
@@ -40,6 +40,7 @@ xsystem4 = [version_h,
|
||||
'3d/collision.c',
|
||||
'3d/debug.c',
|
||||
'3d/model.c',
|
||||
'3d/mpr.c',
|
||||
'3d/parser.c',
|
||||
'3d/particle.c',
|
||||
'3d/reign.c',
|
||||
|
||||
Reference in New Issue
Block a user