Merge pull request #247 from kichikuou/3d

Rance Quest: Fix 3D rendering issues
This commit is contained in:
Nunuhara Cabbage
2025-06-23 18:26:36 -07:00
committed by GitHub
8 changed files with 141 additions and 23 deletions
+2
View File
@@ -195,6 +195,7 @@ struct RE_instance {
vec4 bounding_sphere;
struct RE_instance *shadow_volume_instance;
float z_from_camera;
int texture_animation_index;
};
struct RE_plugin *RE_plugin_new(enum RE_plugin_version version);
@@ -214,6 +215,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name);
bool RE_instance_load_motion(struct RE_instance *instance, const char *name);
bool RE_instance_load_next_motion(struct RE_instance *instance, const char *name);
bool RE_instance_free_next_motion(struct RE_instance *instance);
bool RE_instance_set_mesh_show(struct RE_instance *instance, const char *mesh_name, bool show);
bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z);
int RE_instance_get_bone_index(struct RE_instance *instance, const char *name);
bool RE_instance_trans_local_pos_to_world_pos_by_bone(struct RE_instance *instance, int bone, vec3 offset, vec3 out);
+2 -2
View File
@@ -177,12 +177,12 @@ void main() {
// Alpha mapping
float alpha = texel.a * color_mod.a * alpha_mod;
if (alpha_mode == ALPHA_TEST) {
if (alpha < 0.8)
if (alpha < 0.75)
discard;
} else if (alpha_mode == ALPHA_MAP_BLEND) {
alpha *= texture(alpha_texture, tex_coord).r;
} else if (alpha_mode == ALPHA_MAP_TEST) {
if (texture(alpha_texture, tex_coord).r < 0.8)
if (texture(alpha_texture, tex_coord).r < 0.1)
discard;
}
+8 -1
View File
@@ -50,8 +50,10 @@ struct model {
};
struct mesh {
char *name;
uint32_t flags;
bool is_transparent;
bool hidden;
GLuint vao;
GLuint attr_buffer;
GLuint index_buffer;
@@ -66,7 +68,8 @@ struct mesh {
struct material {
uint32_t flags;
bool is_transparent;
GLuint color_map;
int nr_color_maps;
GLuint *color_maps;
GLuint specular_map;
GLuint alpha_map;
GLuint light_map;
@@ -92,6 +95,7 @@ struct motion {
float current_frame;
float frame_begin, frame_end;
float loop_frame_begin, loop_frame_end;
int texture_index;
};
// Attribute variable locations
@@ -498,6 +502,8 @@ struct mot {
char *name;
uint32_t nr_frames;
uint32_t nr_bones;
uint32_t nr_texture_indices;
uint32_t *texture_indices; // texture index for each frame
struct mot_bone *motions[];
};
@@ -549,6 +555,7 @@ void amt_free(struct amt *amt);
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);
// collision.c
+54 -13
View File
@@ -83,7 +83,6 @@ static GLuint load_texture(struct archive *aar, const char *path, const char *na
{
struct archive_data *dfile = RE_get_aar_entry(aar, path, name, "");
if (!dfile) {
WARNING("cannot load texture %s\\%s", path, name);
return 0;
}
struct cg *cg = cg_load_data(dfile);
@@ -110,6 +109,35 @@ static GLuint load_texture(struct archive *aar, const char *path, const char *na
return texture;
}
static GLuint *load_texture_list(struct archive *aar, const char *path, const char *name, int *nr_textures_out, bool *has_alpha_out)
{
// Load the base texture (e.g. face.png)
GLuint tex = load_texture(aar, path, name, has_alpha_out);
if (!tex)
return NULL;
GLuint *textures = xmalloc(10 * sizeof(GLuint));
int nr_textures = 0;
textures[nr_textures++] = tex;
// Try to load additional textures (e.g. face[1].png, face[2].png, etc.)
const char *ext = strrchr(name, '.');
if (ext) {
for (;;) {
char next_name[100];
snprintf(next_name, sizeof(next_name), "%.*s[%d]%s", (int)(ext - name), name, nr_textures, ext);
tex = load_texture(aar, path, next_name, NULL);
if (!tex)
break;
textures[nr_textures++] = tex;
if (nr_textures % 10 == 0) {
textures = xrealloc(textures, (nr_textures + 10) * sizeof(GLuint));
}
}
}
*nr_textures_out = nr_textures;
return textures;
}
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;
@@ -118,8 +146,8 @@ static bool init_material(struct material *material, const struct pol_material *
return false;
}
bool has_alpha;
material->color_map = load_texture(aar, path, m->textures[COLOR_MAP], &has_alpha);
if (!material->color_map)
material->color_maps = load_texture_list(aar, path, m->textures[COLOR_MAP], &material->nr_color_maps, &has_alpha);
if (!material->color_maps)
return false;
if (m->textures[SPECULAR_MAP])
@@ -162,8 +190,10 @@ static bool init_material(struct material *material, const struct pol_material *
static void destroy_material(struct material *material)
{
if (material->color_map)
glDeleteTextures(1, &material->color_map);
if (material->color_maps) {
glDeleteTextures(material->nr_color_maps, material->color_maps);
free(material->color_maps);
}
if (material->specular_map)
glDeleteTextures(1, &material->specular_map);
if (material->alpha_map)
@@ -317,6 +347,7 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
}
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->name = xstrdup(m->name);
mesh->flags = m->flags;
mesh->material = material;
if (re_plugin_version == RE_REIGN_PLUGIN)
@@ -393,6 +424,7 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_
static void destroy_mesh(struct mesh *mesh)
{
free(mesh->name);
glDeleteVertexArrays(1, &mesh->vao);
glDeleteBuffers(1, &mesh->attr_buffer);
if (mesh->index_buffer)
@@ -661,8 +693,10 @@ struct model *model_create_sphere(int r, int g, int b, int a)
model->materials = xcalloc(1, sizeof(struct material));
struct material *material = &model->materials[0];
material->is_transparent = true;
glGenTextures(1, &material->color_map);
glBindTexture(GL_TEXTURE_2D, material->color_map);
material->color_maps = xmalloc(sizeof(GLuint));
material->nr_color_maps = 1;
glGenTextures(1, material->color_maps);
glBindTexture(GL_TEXTURE_2D, material->color_maps[0]);
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);
@@ -678,18 +712,18 @@ static int cmp_motions_by_bone_id(const void *lhs, const void *rhs)
static struct mot *mot_load(const char *name, struct model *model, struct archive *aar)
{
struct archive_data *dfile = RE_get_aar_entry(aar, model->path, name, ".MOT");
if (!dfile) {
struct archive_data *mot_file = RE_get_aar_entry(aar, model->path, name, ".MOT");
if (!mot_file) {
WARNING("%s\\%s.MOT: not found", model->path, name);
return NULL;
}
struct mot *mot = mot_parse(dfile->data, dfile->size, name);
struct mot *mot = mot_parse(mot_file->data, mot_file->size, name);
if (!mot) {
WARNING("%s: parse error", dfile->name);
archive_free_data(dfile);
WARNING("%s: parse error", mot_file->name);
archive_free_data(mot_file);
return NULL;
}
archive_free_data(dfile);
archive_free_data(mot_file);
if (model->nr_bones != (int)mot->nr_bones)
ERROR("%s: wrong number of bones. Expected %d but got %d", name, model->nr_bones, mot->nr_bones);
@@ -708,6 +742,13 @@ 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);
}
return mot;
}
+35 -1
View File
@@ -14,6 +14,7 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <cglm/cglm.h>
@@ -424,6 +425,9 @@ void mot_free(struct mot *mot)
free(mot->motions[i]->name);
free(mot->motions[i]);
}
if (mot->texture_indices) {
free(mot->texture_indices);
}
free(mot);
}
@@ -487,7 +491,10 @@ struct amt_material *amt_find_material(struct amt *amt, const char *name)
void opr_load(uint8_t *data, size_t size, struct pol *pol)
{
bool *selected = xcalloc(pol->nr_meshes, sizeof(bool));
bool *selected = xmalloc(pol->nr_meshes * sizeof(bool));
for (int i = 0; i < pol->nr_meshes; i++) {
selected[i] = !!pol->meshes[i];
}
while (size > 0) {
char line[200];
uint8_t *nl = memchr(data, '\n', size);
@@ -561,3 +568,30 @@ void opr_load(uint8_t *data, size_t size, struct pol *pol)
}
free(selected);
}
void txa_load(uint8_t *data, size_t size, struct mot *mot)
{
uint32_t count = 0;
uint32_t *indices = xmalloc(100 * sizeof(uint32_t));
const char *p = (const char *)data;
while (p < (const char *)data + size) {
if (isdigit(*p)) {
uint32_t n = 0;
while (p < (const char *)data + size && isdigit(*p)) {
n = n * 10 + (*p - '0');
p++;
}
indices[count++] = n;
if (count % 100 == 0) {
indices = xrealloc(indices, (count + 100) * sizeof(uint32_t));
}
} else if (isspace(*p)) {
p++;
} else {
WARNING("invalid character in txa file: '%c'", *p);
p++;
}
}
mot->nr_texture_indices = count;
mot->texture_indices = indices;
}
+21 -1
View File
@@ -131,12 +131,18 @@ static void update_motion(struct motion *m, float delta_frame)
}
break;
case RE_MOTION_STATE_LOOP:
if (m->current_frame > m->loop_frame_end)
if (m->loop_frame_begin == m->loop_frame_end)
m->current_frame = m->loop_frame_begin;
else if (m->current_frame > m->loop_frame_end)
m->current_frame = m->loop_frame_begin + fmodf(m->current_frame - m->loop_frame_begin, m->loop_frame_end - m->loop_frame_begin);
break;
default:
VM_ERROR("Invalid motion state %d", m->state);
}
uint32_t anim_frame = m->current_frame - m->frame_begin;
m->texture_index = (m->mot && anim_frame < m->mot->nr_texture_indices)
? m->mot->texture_indices[anim_frame] : 0;
}
static void calc_motion_frame(struct motion *m, int bone, struct mot_frame *out)
@@ -326,6 +332,7 @@ bool RE_build_model(struct RE_plugin *plugin, int elapsed_ms)
if (inst->type == RE_ITYPE_SKINNED)
update_bones(inst);
inst->texture_animation_index = inst->motion ? inst->motion->texture_index : 0;
}
// Update particle effects in a second pass, because it uses the results of
@@ -502,6 +509,19 @@ bool RE_instance_free_next_motion(struct RE_instance *instance)
return true;
}
bool RE_instance_set_mesh_show(struct RE_instance *instance, const char *mesh_name, bool show)
{
if (!instance || !instance->model)
return false;
for (int i = 0; i < instance->model->nr_meshes; i++) {
if (!strcmp(instance->model->meshes[i].name, mesh_name)) {
instance->model->meshes[i].hidden = !show;
return true;
}
}
return false;
}
bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z)
{
if (!instance)
+13 -3
View File
@@ -335,6 +335,12 @@ void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out)
glm_look(camera->pos, front, up, out);
}
static bool should_draw_shadow(struct mesh *mesh, struct material *material)
{
return !(mesh->flags & (MESH_ALPHA | MESH_BOTH | MESH_SPRITE))
&& !(material->flags & (MATERIAL_ALPHA | MATERIAL_SPRITE));
}
static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum draw_phase phase)
{
struct model *model = inst->model;
@@ -362,6 +368,8 @@ 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];
if (mesh->hidden)
continue;
struct material *material = &model->materials[mesh->material];
bool is_transparent = mesh->is_transparent || inst->alpha < 1.0f;
if (phase != (is_transparent ? DRAW_TRANSPARENT : DRAW_OPAQUE))
@@ -396,10 +404,12 @@ 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);
glBindTexture(GL_TEXTURE_2D, material->color_map);
int animation_index = inst->texture_animation_index < material->nr_color_maps
? inst->texture_animation_index : 0;
glBindTexture(GL_TEXTURE_2D, material->color_maps[animation_index]);
glUniform1i(r->texture, COLOR_TEXTURE_UNIT);
if (draw_shadow && !(mesh->flags & MESH_BOTH))
if (draw_shadow && should_draw_shadow(mesh, material))
glUniform1f(r->shadow_darkness, material->shadow_darkness);
else
glUniform1f(r->shadow_darkness, 0.0f);
@@ -614,7 +624,7 @@ static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *
struct material *material = &model->materials[mesh->material];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, material->color_map);
glBindTexture(GL_TEXTURE_2D, material->color_maps[0]);
glUniform1i(r->texture, 0);
glBindVertexArray(mesh->vao);
+6 -2
View File
@@ -1891,7 +1891,11 @@ static bool TapirEngine_GetInstancePathLine(int plugin, int instance, struct pag
}
//bool TapirEngine_CreateInstancePathLineList(int PluginNumber, int InstanceNumber, int PathInstanceNumber);
//bool TapirEngine_SetInstanceMeshShow(int PluginNumber, int InstanceNumber, struct string *pIMeshName, bool Show);
static bool TapirEngine_SetInstanceMeshShow(int plugin, int instance, struct string *mesh_name, bool show)
{
return RE_instance_set_mesh_show(get_instance(plugin, instance), mesh_name->text, show);
}
static bool TapirEngine_SetDrawOption(int plugin_number, int draw_option, int param)
{
@@ -2303,7 +2307,7 @@ HLL_LIBRARY(ReignEngine, REIGN_EXPORTS,
HLL_EXPORT(OptimizeInstancePathLine, TapirEngine_OptimizeInstancePathLine), \
HLL_EXPORT(GetInstancePathLine, TapirEngine_GetInstancePathLine), \
HLL_TODO_EXPORT(CreateInstancePathLineList, TapirEngine_CreateInstancePathLineList), \
HLL_TODO_EXPORT(SetInstanceMeshShow, TapirEngine_SetInstanceMeshShow), \
HLL_EXPORT(SetInstanceMeshShow, TapirEngine_SetInstanceMeshShow), \
HLL_EXPORT(SetDrawOption, TapirEngine_SetDrawOption), \
HLL_EXPORT(GetDrawOption, TapirEngine_GetDrawOption), \
HLL_TODO_EXPORT(SetDebugMode, TapirEngine_SetDebugMode), \