mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Merge pull request #247 from kichikuou/3d
Rance Quest: Fix 3D rendering issues
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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), \
|
||||
|
||||
Reference in New Issue
Block a user