diff --git a/game_compatibility.md b/game_compatibility.md index fe06470..9d5bb78 100644 --- a/game_compatibility.md +++ b/game_compatibility.md @@ -57,7 +57,7 @@ issues, please let me know or open a pull request to update this table. | Sengoku Rance -Three for the Slash! Thrust! Burn!- (EN) | Unknown | | | AliveZ | Unknown | | | エドランゼ ~Come on!水戸姫様~ | Unknown | | -| 闘神都市III | Unsupported | | +| 闘神都市III | Supported | | | ばにしゅ!~おっぱいの消えた王国~ | Unknown | | | 僕だけの保健室 | Unknown | | | ももいろガーディアン | Unknown | | diff --git a/include/reign.h b/include/reign.h index b5424dc..a98e1f2 100644 --- a/include/reign.h +++ b/include/reign.h @@ -25,6 +25,8 @@ #include "gfx/gfx.h" #include "plugin.h" +struct hash_table; + enum RE_instance_type { RE_ITYPE_UNINITIALIZED = 0, RE_ITYPE_STATIC = 1, @@ -82,6 +84,8 @@ struct RE_plugin { int nr_instances; struct RE_instance **instances; struct archive *aar; + struct hash_table *model_cache; + struct hash_table *pae_cache; struct RE_renderer *renderer; struct RE_camera camera; mat4 proj_transform; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index ff078f0..1e156a3 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -43,6 +43,7 @@ struct model { struct bone *bones; struct hash_table *bone_map; // bone id in POL/MOT -> struct bone * struct hash_table *bone_name_map; // bone name -> (struct bone * | NULL) + struct hash_table *mot_cache; // name -> struct mot * vec3 aabb[2]; // axis-aligned bounding box bool has_transparent_material; }; @@ -82,7 +83,6 @@ struct bone { struct motion { struct RE_instance *instance; struct mot *mot; - char *name; int state; float current_frame; float frame_begin, frame_end; @@ -193,7 +193,7 @@ void RE_renderer_free(struct RE_renderer *r); bool 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); +bool RE_renderer_detect_height(struct height_detector *hd, float x, float z, float *y_out); void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out); // particle.c @@ -272,7 +272,14 @@ struct particle_position { struct particle_position_unit units[NR_PARTICLE_POSITION_UNITS]; }; -struct particle_object { +struct pae { + char *path; + struct hash_table *textures; // name -> struct billboard_texture* + int nr_objects; + struct pae_object *objects; +}; + +struct pae_object { char *name; enum particle_type type; enum particle_move_type move_type; @@ -325,9 +332,18 @@ struct particle_object { float offset_x; float offset_y; - // Runtime data struct model *model; - struct particle_instance *instances; +}; + +struct particle_effect { + struct pae *pae; + struct particle_object *objects; // pae->nr_objects elements + bool camera_quake_enabled; +}; + +struct particle_object { + struct pae_object *pae_obj; + struct particle_instance *instances; // pae_obj->nr_particles elements vec3_range pos; vec3 move_vec, move_ortho; }; @@ -340,20 +356,15 @@ struct particle_instance { float pitch_angle; }; -struct particle_effect { - char *path; - struct hash_table *textures; // name -> struct billboard_texture* - int nr_objects; - struct particle_object *objects; - bool camera_quake_enabled; -}; +struct pae *pae_load(struct archive *aar, const char *path); +void pae_free(struct pae *pae); +void pae_calc_frame_range(struct pae *pae, struct motion *motion); +float pae_object_calc_alpha(struct pae_object *po, struct particle_instance *pi, float frame); -struct particle_effect *particle_effect_load(struct archive *aar, const char *path); +struct particle_effect *particle_effect_create(struct pae *pae); void particle_effect_free(struct particle_effect *effect); -void particle_effect_calc_frame_range(struct particle_effect *effect, struct motion *motion); void particle_effect_update(struct RE_instance *inst); void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest); -float particle_object_calc_alpha(struct particle_object *po, struct particle_instance *pi, float frame); // parser.c @@ -442,6 +453,7 @@ struct pol_bone { }; struct mot { + char *name; uint32_t nr_frames; uint32_t nr_bones; struct mot_bone *motions[]; @@ -487,7 +499,7 @@ void pol_free(struct pol *pol); void pol_compute_aabb(struct pol *model, vec3 dest[2]); struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id); -struct mot *mot_parse(uint8_t *data, size_t size); +struct mot *mot_parse(uint8_t *data, size_t size, const char *name); void mot_free(struct mot *mot); struct amt *amt_parse(uint8_t *data, size_t size); diff --git a/src/3d/debug.c b/src/3d/debug.c index 0552eee..a7b9bfc 100644 --- a/src/3d/debug.c +++ b/src/3d/debug.c @@ -63,9 +63,9 @@ static void print_motion(const char *name, struct motion *m, int indent) indent_printf(indent, "%s = {state=%s, frame=%f, range=(%d,%d), loop_range=(%d,%d)},\n", name, motion_state_name(m->state), m->current_frame, (int)m->frame_begin, (int)m->frame_end, (int)m->loop_frame_begin, (int)m->loop_frame_end); - } else { + } else if (m->mot) { indent_printf(indent, "%s = {name=\"%s\", state=%s, frame=%f},\n", - name, m->name, motion_state_name(m->state), m->current_frame); + name, m->mot->name, motion_state_name(m->state), m->current_frame); } } @@ -101,7 +101,7 @@ static void print_instance(struct RE_instance *inst, int index, int indent) if (inst->motion_blend) 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, "path = \"%s\",\n", inst->effect->pae->path); indent--; indent_printf(indent, "},\n"); diff --git a/src/3d/model.c b/src/3d/model.c index 3936284..fb63fb6 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -422,6 +422,7 @@ struct model *model_load(struct archive *aar, const char *path) ERROR("%s: Too many bones (%u)", model->path, pol->nr_bones); model->bone_map = ht_create(pol->nr_bones * 3 / 2); model->bone_name_map = ht_create(pol->nr_bones * 3 / 2); + model->mot_cache = ht_create(16); model->bones = xcalloc(pol->nr_bones, sizeof(struct bone)); for (uint32_t i = 0; i < pol->nr_bones; i++) { add_bone(model, pol, &pol->bones[i]); @@ -499,6 +500,10 @@ void model_free(struct model *model) ht_free_int(model->bone_map); if (model->bone_name_map) ht_free(model->bone_name_map); + if (model->mot_cache) { + ht_foreach_value(model->mot_cache, (void(*)(void*))mot_free); + ht_free(model->mot_cache); + } free(model->path); free(model); @@ -604,18 +609,14 @@ static int cmp_motions_by_bone_id(const void *lhs, const void *rhs) return (*(struct mot_bone **)lhs)->id - (*(struct mot_bone **)rhs)->id; } -struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar) +static struct mot *mot_load(const char *name, struct model *model, struct archive *aar) { - struct model *model = instance->model; - if (!model) - return NULL; - struct archive_data *dfile = RE_get_aar_entry(aar, model->path, name, ".MOT"); if (!dfile) { WARNING("%s\\%s.MOT: not found", model->path, name); return NULL; } - struct mot *mot = mot_parse(dfile->data, dfile->size); + struct mot *mot = mot_parse(dfile->data, dfile->size, name); if (!mot) { WARNING("%s: parse error", dfile->name); archive_free_data(dfile); @@ -640,18 +641,28 @@ struct motion *motion_load(const char *name, struct RE_instance *instance, struc } qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id); + return mot; +} + +struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar) +{ + struct model *model = instance->model; + if (!model || !model->mot_cache) + return NULL; + struct mot *mot = ht_get(model->mot_cache, name, NULL); + if (!mot) { + mot = mot_load(name, model, aar); + if (!mot) + return NULL; + ht_put(model->mot_cache, name, mot); + } struct motion *motion = xcalloc(1, sizeof(struct motion)); motion->instance = instance; motion->mot = mot; - motion->name = strdup(name); return motion; } void motion_free(struct motion *motion) { - if (motion->mot) - mot_free(motion->mot); - if (motion->name) - free(motion->name); free(motion); } diff --git a/src/3d/parser.c b/src/3d/parser.c index 228853f..87383c2 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -353,7 +353,7 @@ struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id) return NULL; } -struct mot *mot_parse(uint8_t *data, size_t size) +struct mot *mot_parse(uint8_t *data, size_t size, const char *name) { struct buffer r; buffer_init(&r, data, size); @@ -369,6 +369,7 @@ struct mot *mot_parse(uint8_t *data, size_t size) uint32_t nr_bones = buffer_read_int32(&r); struct mot *mot = xcalloc(1, sizeof(struct mot) + nr_bones * sizeof(struct mot_bone *)); + mot->name = strdup(name); mot->nr_frames = nr_frames; mot->nr_bones = nr_bones; for (uint32_t i = 0; i < nr_bones; i++) { @@ -391,6 +392,7 @@ struct mot *mot_parse(uint8_t *data, size_t size) void mot_free(struct mot *mot) { + free(mot->name); for (uint32_t i = 0; i < mot->nr_bones; i++) { free(mot->motions[i]->name); free(mot->motions[i]); diff --git a/src/3d/particle.c b/src/3d/particle.c index b9ac076..723cf20 100644 --- a/src/3d/particle.c +++ b/src/3d/particle.c @@ -239,10 +239,10 @@ static struct particle_position *parse_position(char **ptext) return epos; } -static struct particle_effect *parse_pae(char *text) +static struct pae *parse_pae(char *text) { - struct particle_effect *pae = xcalloc(1, sizeof(struct particle_effect)); - struct particle_object *current_object = NULL; + struct pae *pae = xcalloc(1, sizeof(struct pae)); + struct pae_object *current_object = NULL; for (;;) { // Skip whitespaces and comments @@ -269,7 +269,7 @@ static struct particle_effect *parse_pae(char *text) if (!*text) { // EOF return pae; } else if (MATCH("オブジェクト " QUOTED_STRING " = {", string_buf)) { - pae->objects = xrealloc_array(pae->objects, pae->nr_objects, pae->nr_objects + 1, sizeof(struct particle_object)); + pae->objects = xrealloc_array(pae->objects, pae->nr_objects, pae->nr_objects + 1, sizeof(struct pae_object)); current_object = &pae->objects[pae->nr_objects++]; current_object->name = utf2sjis(string_buf, 0); // Default values. @@ -449,15 +449,15 @@ static struct particle_effect *parse_pae(char *text) } } err: - particle_effect_free(pae); + pae_free(pae); return NULL; } -static void load_textures(struct particle_effect *effect, struct archive *aar) +static void load_textures(struct pae *effect, struct archive *aar) { effect->textures = ht_create(16); for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + struct pae_object *po = &effect->objects[i]; for (int j = 0; j < po->nr_textures; j++) { const char *name = po->textures[j]; if (ht_get(effect->textures, name, NULL)) @@ -587,7 +587,7 @@ static void eval_pos_for_instance(struct particle_position *pp, vec3 dest) } } -static float eval_child_slope(struct particle_object *po) +static float eval_child_slope(struct pae_object *po) { float slope = glm_lerp(po->child_begin_slope, po->child_end_slope, randf()); if (slope > 1.0) @@ -607,29 +607,30 @@ static void interpolate_pos(vec3 begin, vec3 end, float move_curve, float t, vec static void init_particle_instances(struct particle_object *po) { - po->instances = xcalloc(po->nr_particles, sizeof(struct particle_instance)); + struct pae_object *pae_obj = po->pae_obj; + po->instances = xcalloc(pae_obj->nr_particles, sizeof(struct particle_instance)); - for (int i = 0; i < po->nr_particles; i++) { + for (int i = 0; i < pae_obj->nr_particles; i++) { struct particle_instance *pi = &po->instances[i]; - switch (po->move_type) { + switch (pae_obj->move_type) { case PARTICLE_MOVE_FIXED: case PARTICLE_MOVE_LINEAR: - pi->begin_frame = po->begin_frame; - pi->end_frame = po->end_frame; + pi->begin_frame = pae_obj->begin_frame; + pi->end_frame = pae_obj->end_frame; break; case PARTICLE_MOVE_EMITTER: - pi->begin_frame = glm_lerp(po->child_create_begin_frame, po->child_create_end_frame, (float)i / po->nr_particles); - pi->end_frame = pi->begin_frame + po->child_frame; - pi->roll_angle = eval_child_slope(po); + pi->begin_frame = glm_lerp(pae_obj->child_create_begin_frame, pae_obj->child_create_end_frame, (float)i / pae_obj->nr_particles); + pi->end_frame = pi->begin_frame + pae_obj->child_frame; + pi->roll_angle = eval_child_slope(pae_obj); pi->pitch_angle = randf() * (2.0f * GLM_PIf); break; } - eval_pos_for_instance(po->position[0], pi->random_offset.begin); - eval_pos_for_instance(po->position[1], pi->random_offset.end); + eval_pos_for_instance(pae_obj->position[0], pi->random_offset.begin); + eval_pos_for_instance(pae_obj->position[1], pi->random_offset.end); } } -struct particle_effect *particle_effect_load(struct archive *aar, const char *path) +struct pae *pae_load(struct archive *aar, const char *path) { const char *basename = strrchr(path, '\\'); basename = basename ? basename + 1 : path; @@ -653,20 +654,19 @@ struct particle_effect *particle_effect_load(struct archive *aar, const char *pa // clarity. char *text = sjis2utf(sjis_text, dfile->size); free(sjis_text); - struct particle_effect *effect = parse_pae(text); + struct pae *pae = parse_pae(text); free(text); - if (!effect) { + if (!pae) { WARNING("could not parse %s", dfile->name); archive_free_data(dfile); return NULL; } archive_free_data(dfile); - effect->path = strdup(path); - effect->camera_quake_enabled = true; - load_textures(effect, aar); - for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + pae->path = strdup(path); + load_textures(pae, aar); + for (int i = 0; i < pae->nr_objects; i++) { + struct pae_object *po = &pae->objects[i]; if (po->polygon_name && *po->polygon_name) { char *pol_path = xmalloc(strlen(path) + strlen(po->polygon_name) + 2); @@ -674,10 +674,22 @@ struct particle_effect *particle_effect_load(struct archive *aar, const char *pa po->model = model_load(aar, pol_path); free(pol_path); } - - init_particle_instances(po); } + return pae; +} + +struct particle_effect *particle_effect_create(struct pae *pae) +{ + struct particle_effect *effect = xcalloc(1, sizeof(struct particle_effect)); + effect->pae = pae; + effect->objects = xcalloc(pae->nr_objects, sizeof(struct particle_object)); + effect->camera_quake_enabled = true; + for (int i = 0; i < pae->nr_objects; i++) { + struct particle_object *po = &effect->objects[i]; + po->pae_obj = &pae->objects[i]; + init_particle_instances(po); + } return effect; } @@ -699,10 +711,10 @@ static void particle_position_free(struct particle_position *pos) free(pos); } -void particle_effect_free(struct particle_effect *effect) +void pae_free(struct pae *pae) { - for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + for (int i = 0; i < pae->nr_objects; i++) { + struct pae_object *po = &pae->objects[i]; free(po->name); for (int j = 0; j < NR_PARTICLE_POSITIONS; j++) particle_position_free(po->position[j]); @@ -719,21 +731,30 @@ void particle_effect_free(struct particle_effect *effect) free(po->damages); if (po->model) model_free(po->model); - free(po->instances); } - ht_foreach_value(effect->textures, free_billboard_texture); - ht_free(effect->textures); + ht_foreach_value(pae->textures, free_billboard_texture); + ht_free(pae->textures); + free(pae->objects); + free(pae->path); + free(pae); +} + +void particle_effect_free(struct particle_effect *effect) +{ + for (int i = 0; i < effect->pae->nr_objects; i++) { + struct particle_object *obj = &effect->objects[i]; + free(obj->instances); + } free(effect->objects); - free(effect->path); free(effect); } -void particle_effect_calc_frame_range(struct particle_effect *effect, struct motion *motion) +void pae_calc_frame_range(struct pae *pae, struct motion *motion) { int begin_frame = INT_MAX; int end_frame = INT_MIN; - for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + for (int i = 0; i < pae->nr_objects; i++) { + struct pae_object *po = &pae->objects[i]; int obj_begin = po->begin_frame; int obj_end = max(po->end_frame, po->child_create_end_frame + po->child_frame); if (begin_frame > obj_begin) @@ -745,7 +766,7 @@ void particle_effect_calc_frame_range(struct particle_effect *effect, struct mot motion->frame_end = motion->loop_frame_end = end_frame; } -static void update_camera_quake(struct RE_instance *inst, struct particle_object *po) +static void update_camera_quake(struct RE_instance *inst, struct pae_object *po) { float frame = inst->motion->current_frame - po->begin_frame; float total_frames = po->end_frame - po->begin_frame; @@ -769,19 +790,20 @@ void particle_effect_update(struct RE_instance *inst) struct particle_effect *effect = inst->effect; if (!effect) return; - for (int i = 0; i < effect->nr_objects; i++) { + for (int i = 0; i < effect->pae->nr_objects; i++) { struct particle_object *po = &effect->objects[i]; - if (po->type == PARTICLE_TYPE_CAMERA_QUAKE) { + struct pae_object *pae_obj = po->pae_obj; + if (pae_obj->type == PARTICLE_TYPE_CAMERA_QUAKE) { if (effect->camera_quake_enabled) - update_camera_quake(inst, po); + update_camera_quake(inst, pae_obj); continue; } // These cannot be precomputed, because they may depend on the target's // *current* bone matrix. - eval_pos_for_object(inst, po->position[0], po->pos.begin); - eval_pos_for_object(inst, po->position[1], po->pos.end); + eval_pos_for_object(inst, pae_obj->position[0], po->pos.begin); + eval_pos_for_object(inst, pae_obj->position[1], po->pos.end); glm_vec3_sub(po->pos.end, po->pos.begin, po->move_vec); - switch (po->dir_type) { + switch (pae_obj->dir_type) { case PARTICLE_DIR_TYPE_NORMAL: glm_vec3_normalize(po->move_vec); glm_vec3_ortho(po->move_vec, po->move_ortho); @@ -798,45 +820,47 @@ void particle_effect_update(struct RE_instance *inst) static void calc_emitter_pos(struct particle_object *po, struct particle_instance *pi, float t, vec3 dest, vec3 move_vec) { + struct pae_object *pae_obj = po->pae_obj; vec3 begin, end; glm_vec3_add(po->pos.begin, pi->random_offset.begin, begin); glm_vec3_add(po->pos.end, pi->random_offset.end, end); - interpolate_pos(begin, end, po->move_curve, t, dest); + interpolate_pos(begin, end, pae_obj->move_curve, t, dest); if (move_vec) glm_vec3_sub(end, begin, move_vec); // Orbital rotation. vec3 angle, dist; - glm_vec3_lerp(po->revolution_angle.begin, po->revolution_angle.end, t, angle); - glm_vec3_lerp(po->revolution_distance.begin, po->revolution_distance.end, t, dist); + glm_vec3_lerp(pae_obj->revolution_angle.begin, pae_obj->revolution_angle.end, t, angle); + glm_vec3_lerp(pae_obj->revolution_distance.begin, pae_obj->revolution_distance.end, t, dist); glm_vec3_scale(angle, GLM_PIf / 180.0f, angle); // deg -> rad - if (po->revolution_angle.begin[0] != 0.0f || po->revolution_angle.end[0] != 0.0f) { + if (pae_obj->revolution_angle.begin[0] != 0.0f || pae_obj->revolution_angle.end[0] != 0.0f) { dest[1] += dist[0] * sinf(angle[0]); dest[2] -= dist[0] * cosf(angle[0]); } - if (po->revolution_angle.begin[1] != 0.0f || po->revolution_angle.end[1] != 0.0f) { + if (pae_obj->revolution_angle.begin[1] != 0.0f || pae_obj->revolution_angle.end[1] != 0.0f) { dest[0] += dist[1] * sinf(angle[1]); dest[2] -= dist[1] * cosf(angle[1]); } - if (po->revolution_angle.begin[2] != 0.0f || po->revolution_angle.end[2] != 0.0f) { + if (pae_obj->revolution_angle.begin[2] != 0.0f || pae_obj->revolution_angle.end[2] != 0.0f) { dest[1] += dist[2] * sinf(angle[2]); dest[0] += dist[2] * cosf(angle[2]); } // Apply the curve. - glm_vec3_muladds(po->curve_length, 4.9f * t * (1.0f - t), dest); + glm_vec3_muladds(pae_obj->curve_length, 4.9f * t * (1.0f - t), dest); } static void calc_pos_and_up_vector(struct particle_object *po, struct particle_instance *pi, float t, vec3 pos, vec3 up_vector) { - switch (po->move_type) { + struct pae_object *pae_obj = po->pae_obj; + switch (pae_obj->move_type) { case PARTICLE_MOVE_FIXED: glm_vec3_add(po->pos.begin, pi->random_offset.begin, pos); glm_vec3_copy(GLM_YUP, up_vector); break; case PARTICLE_MOVE_LINEAR: calc_emitter_pos(po, pi, t, pos, up_vector); - switch (po->up_vector_type) { + switch (pae_obj->up_vector_type) { case PARTICLE_UP_VECTOR_Y_AXIS: case PARTICLE_UP_VECTOR_INSTANCE_MOVE: glm_vec3_copy(GLM_YUP, up_vector); @@ -852,12 +876,12 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i case PARTICLE_MOVE_EMITTER: { // Calculate the instance's initial and final position. - float t0 = glm_clamp_zo(glm_percent(po->begin_frame, po->end_frame, pi->begin_frame)); + float t0 = glm_clamp_zo(glm_percent(pae_obj->begin_frame, pae_obj->end_frame, pi->begin_frame)); vec3_range inst_pos; calc_emitter_pos(po, pi, t0, inst_pos.begin, NULL); vec3 inst_move; glm_vec3_copy(po->move_vec, inst_move); - switch (po->dir_type) { + switch (pae_obj->dir_type) { case PARTICLE_DIR_TYPE_NORMAL: glm_vec3_rotate(inst_move, pi->roll_angle, po->move_ortho); glm_vec3_rotate(inst_move, pi->pitch_angle, po->move_vec); @@ -867,12 +891,12 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i break; } glm_vec3_copy(inst_pos.begin, inst_pos.end); - switch (po->child_move_dir_type) { + switch (pae_obj->child_move_dir_type) { case PARTICLE_CHILD_MOVE_DIR_NORMAL: - glm_vec3_muladds(inst_move, po->child_length, inst_pos.end); + glm_vec3_muladds(inst_move, pae_obj->child_length, inst_pos.end); break; case PARTICLE_CHILD_MOVE_DIR_REVERSE: - glm_vec3_muladds(inst_move, po->child_length, inst_pos.begin); + glm_vec3_muladds(inst_move, pae_obj->child_length, inst_pos.begin); glm_vec3_negate(inst_move); break; } @@ -880,7 +904,7 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i glm_vec3_lerp(inst_pos.begin, inst_pos.end, t, pos); // Calculate the up vector. - switch (po->up_vector_type) { + switch (pae_obj->up_vector_type) { case PARTICLE_UP_VECTOR_Y_AXIS: glm_vec3_copy(GLM_YUP, up_vector); break; @@ -888,13 +912,13 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i glm_vec3_copy(po->move_vec, up_vector); break; case PARTICLE_UP_VECTOR_INSTANCE_MOVE: - if (po->child_length != 0.0f) + if (pae_obj->child_length != 0.0f) glm_vec3_copy(inst_move, up_vector); else glm_vec3_copy(GLM_XUP, up_vector); break; } - if (po->dir_type == PARTICLE_DIR_TYPE_XY_PLANE) { + if (pae_obj->dir_type == PARTICLE_DIR_TYPE_XY_PLANE) { mat3 rot = {{ inst_move[1], -inst_move[0], 0.0f }, { inst_move[0], inst_move[1], 0.0f }, { 0.0f, 0.0f, 1.0f }}; @@ -905,7 +929,7 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i } } -static void calc_scale(struct particle_object *po, int frame, vec3 dest) +static void calc_scale(struct pae_object *po, int frame, vec3 dest) { glm_vec3_broadcast(po->sizes2[min(frame, po->nr_sizes2 - 1)], dest); if (po->nr_sizes_x) @@ -916,6 +940,7 @@ static void calc_scale(struct particle_object *po, int frame, vec3 dest) void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest) { + struct pae_object *pae_obj = po->pae_obj; float t = glm_percent(pi->begin_frame, pi->end_frame, frame); vec3 pos, up_vector; @@ -927,7 +952,7 @@ void particle_object_calc_local_transform(struct RE_instance *inst, struct parti float step_frac = rel_frame - cur_step; glm_translate_make(dest, pos); - if (po->type == PARTICLE_TYPE_BILLBOARD) { + if (pae_obj->type == PARTICLE_TYPE_BILLBOARD) { mat4 view_mat; RE_calc_view_matrix(&inst->plugin->camera, up_vector, view_mat); mat3 rot; @@ -936,7 +961,7 @@ void particle_object_calc_local_transform(struct RE_instance *inst, struct parti } vec3 angles; - glm_vec3_lerp(po->rotation.begin, po->rotation.end, t, angles); + glm_vec3_lerp(pae_obj->rotation.begin, pae_obj->rotation.end, t, angles); angles[0] *= -GLM_PIf / 180.0f; angles[1] *= -GLM_PIf / 180.0f; angles[2] *= GLM_PIf / 180.0f; @@ -944,21 +969,21 @@ void particle_object_calc_local_transform(struct RE_instance *inst, struct parti glm_euler_zxy(angles, rotation_mat); glm_mat4_mul(dest, rotation_mat, dest); - if (po->nr_sizes2 > 0) { + if (pae_obj->nr_sizes2 > 0) { vec3 scale, scale2; - calc_scale(po, cur_step, scale); - calc_scale(po, next_step, scale2); + calc_scale(pae_obj, cur_step, scale); + calc_scale(pae_obj, next_step, scale2); glm_vec3_lerp(scale, scale2, step_frac, scale); glm_scale(dest, scale); } else { - glm_scale_uni(dest, glm_lerp(po->size[0], po->size[1], t)); + glm_scale_uni(dest, glm_lerp(pae_obj->size[0], pae_obj->size[1], t)); } - glm_translate_x(dest, -po->offset_x); - glm_translate_y(dest, -po->offset_y); + glm_translate_x(dest, -pae_obj->offset_x); + glm_translate_y(dest, -pae_obj->offset_y); } -float particle_object_calc_alpha(struct particle_object *po, struct particle_instance *pi, float frame) +float pae_object_calc_alpha(struct pae_object *po, struct particle_instance *pi, float frame) { frame -= pi->begin_frame; if (frame < po->alpha_fadein_frame) diff --git a/src/3d/reign.c b/src/3d/reign.c index a1e546f..ac56605 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -24,6 +24,7 @@ #include "system4.h" #include "system4/aar.h" #include "system4/cg.h" +#include "system4/hashtable.h" #include "system4/string.h" #include "3d_internal.h" @@ -66,7 +67,7 @@ static void unload_instance(struct RE_instance *instance) instance->next_motion = NULL; } if (instance->model) { - model_free(instance->model); + // No need to free, model is owned by plugin->model_cache. instance->model = NULL; } if (instance->effect) { @@ -137,8 +138,12 @@ static void update_motion(struct motion *m, float delta_frame) static void calc_motion_frame(struct motion *m, int bone, struct mot_frame *out) { - int cur_frame = m->current_frame; - int next_frame = ceilf(m->current_frame); + uint32_t cur_frame = m->current_frame; + uint32_t next_frame = ceilf(m->current_frame); + if (next_frame >= m->mot->nr_frames) { + *out = m->mot->motions[bone]->frames[m->mot->nr_frames - 1]; + return; + } float t = m->current_frame - cur_frame; struct mot_frame *frames = m->mot->motions[bone]->frames; interpolate_motion_frame(&frames[cur_frame], &frames[next_frame], t, out); @@ -215,6 +220,8 @@ struct RE_plugin *RE_plugin_new(void) plugin->nr_instances = 16; plugin->instances = xcalloc(plugin->nr_instances, sizeof(struct RE_instance *)); plugin->aar = aar; + plugin->model_cache = ht_create(32); + plugin->pae_cache = ht_create(32); for (int i = 0; i < RE_NR_BACK_CGS; i++) RE_back_cg_init(&plugin->back_cg[i]); plugin->fog_type = RE_FOG_NONE; @@ -232,6 +239,10 @@ void RE_plugin_free(struct RE_plugin *plugin) } free(plugin->instances); archive_free(plugin->aar); + ht_foreach_value(plugin->model_cache, (void(*)(void*))model_free); + ht_free(plugin->model_cache); + ht_foreach_value(plugin->pae_cache, (void(*)(void*))pae_free); + ht_free(plugin->pae_cache); if (plugin->renderer) RE_renderer_free(plugin->renderer); for (int i = 0; i < RE_NR_BACK_CGS; i++) @@ -372,21 +383,34 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) if (name[0] == '\0') return false; + struct pae *pae; switch (instance->type) { case RE_ITYPE_STATIC: case RE_ITYPE_SKINNED: - instance->model = model_load(instance->plugin->aar, name); + instance->model = ht_get(instance->plugin->model_cache, name, NULL); + if (!instance->model) { + instance->model = model_load(instance->plugin->aar, name); + if (instance->model) + ht_put(instance->plugin->model_cache, name, instance->model); + } if (instance->model && instance->model->nr_bones > 0) instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4)); return !!instance->model; case RE_ITYPE_PARTICLE_EFFECT: - instance->effect = particle_effect_load(instance->plugin->aar, name); + pae = ht_get(instance->plugin->pae_cache, name, NULL); + if (!pae) { + pae = pae_load(instance->plugin->aar, name); + if (!pae) + return false; + ht_put(instance->plugin->pae_cache, name, pae); + } + instance->effect = particle_effect_create(pae); if (!instance->motion) { instance->motion = xcalloc(1, sizeof(struct motion)); instance->motion->instance = instance; - particle_effect_calc_frame_range(instance->effect, instance->motion); + pae_calc_frame_range(instance->effect->pae, instance->motion); } - return !!instance->effect; + return true; default: WARNING("Invalid instance type %d", instance->type); return false; @@ -468,8 +492,19 @@ float RE_instance_calc_height(struct RE_instance *instance, float x, float z) if (!instance->height_detector) { instance->height_detector = RE_renderer_create_height_detector(instance->plugin->renderer, instance->model); } - float y = RE_renderer_detect_height(instance->height_detector, x, z); - return y; + + float y; + if (RE_renderer_detect_height(instance->height_detector, x, z, &y)) + return y; + + // Return the average of 4 neighbors. + int cnt = 0; + float total = 0.0f; + if (RE_renderer_detect_height(instance->height_detector, x - 0.5f, z, &y)) { cnt++; total += y; } + if (RE_renderer_detect_height(instance->height_detector, x + 0.5f, z, &y)) { cnt++; total += y; } + if (RE_renderer_detect_height(instance->height_detector, x, z - 0.5f, &y)) { cnt++; total += y; } + if (RE_renderer_detect_height(instance->height_detector, x, z + 0.5f, &y)) { cnt++; total += y; } + return cnt ? total / cnt : 0.0f; } bool RE_instance_set_debug_draw_shadow_volume(struct RE_instance *inst, bool draw) @@ -565,7 +600,7 @@ bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float en int RE_effect_get_num_object(struct particle_effect *effect) { - return effect ? effect->nr_objects : 0; + return effect ? effect->pae->nr_objects : 0; } bool RE_effect_get_camera_quake_flag(struct particle_effect *effect) @@ -583,47 +618,47 @@ bool RE_effect_set_camera_quake_flag(struct particle_effect *effect, bool enable struct particle_object *RE_get_effect_object(struct particle_effect *effect, unsigned object) { - if (!effect || object >= (unsigned)effect->nr_objects) + if (!effect || object >= (unsigned)effect->pae->nr_objects) return NULL; return &effect->objects[object]; } int RE_particle_get_type(struct particle_object *po) { - return po ? po->type : 0; + return po ? po->pae_obj->type : 0; } int RE_particle_get_move_type(struct particle_object *po) { - return po ? po->move_type : 0; + return po ? po->pae_obj->move_type : 0; } int RE_particle_get_up_vec_type(struct particle_object *po) { - return po ? po->up_vector_type : 0; + return po ? po->pae_obj->up_vector_type : 0; } float RE_particle_get_move_curve(struct particle_object *po) { - return po ? po->move_curve : 0.0; + return po ? po->pae_obj->move_curve : 0.0; } void RE_particle_get_frame(struct particle_object *po, int *begin_frame, int *end_frame) { if (!po) return; - *begin_frame = po->begin_frame; - *end_frame = po->end_frame; + *begin_frame = po->pae_obj->begin_frame; + *end_frame = po->pae_obj->end_frame; } int RE_particle_get_stop_frame(struct particle_object *po) { - return po ? po->stop_frame : 0; + return po ? po->pae_obj->stop_frame : 0; } const char *RE_particle_get_name(struct particle_object *po) { - return po ? po->name : NULL; + return po ? po->pae_obj->name : NULL; } int RE_particle_get_num_pos(struct particle_object *po) @@ -638,9 +673,9 @@ int RE_particle_get_num_pos_unit(struct particle_object *po, int pos) static struct particle_position_unit *get_position_unit(struct particle_object *po, int pos, int unit) { - if (!po || pos >= NR_PARTICLE_POSITIONS || !po->position[pos] || unit >= NR_PARTICLE_POSITION_UNITS) + if (!po || pos >= NR_PARTICLE_POSITIONS || !po->pae_obj->position[pos] || unit >= NR_PARTICLE_POSITION_UNITS) return NULL; - return &po->position[pos]->units[unit]; + return &po->pae_obj->position[pos]->units[unit]; } int RE_particle_get_pos_unit_type(struct particle_object *po, int pos, int unit) @@ -666,298 +701,298 @@ int RE_particle_get_pos_unit_index(struct particle_object *po, int pos, int unit int RE_particle_get_num_texture(struct particle_object *po) { - return po ? po->nr_textures : 0; + return po ? po->pae_obj->nr_textures : 0; } const char *RE_particle_get_texture(struct particle_object *po, int texture) { - if (!po || texture >= po->nr_textures) + if (!po || texture >= po->pae_obj->nr_textures) return NULL; - return po->textures[texture]; + return po->pae_obj->textures[texture]; } bool RE_particle_get_size(struct particle_object *po, float *begin_size, float *end_size) { if (!po) return false; - *begin_size = po->size[0]; - *end_size = po->size[1]; + *begin_size = po->pae_obj->size[0]; + *end_size = po->pae_obj->size[1]; return true; } bool RE_particle_get_size2(struct particle_object *po, int frame, float *size) { - if (!po || frame >= po->nr_sizes2) + if (!po || frame >= po->pae_obj->nr_sizes2) return false; - *size = po->sizes2[frame]; + *size = po->pae_obj->sizes2[frame]; return true; } bool RE_particle_get_size_x(struct particle_object *po, int frame, float *size) { - if (!po || frame >= po->nr_sizes_x) + if (!po || frame >= po->pae_obj->nr_sizes_x) return false; - *size = po->sizes_x[frame]; + *size = po->pae_obj->sizes_x[frame]; return true; } bool RE_particle_get_size_y(struct particle_object *po, int frame, float *size) { - if (!po || frame >= po->nr_sizes_y) + if (!po || frame >= po->pae_obj->nr_sizes_y) return false; - *size = po->sizes_y[frame]; + *size = po->pae_obj->sizes_y[frame]; return true; } bool RE_particle_get_size_type(struct particle_object *po, int frame, int *type) { - if (!po || frame >= po->nr_size_types) + if (!po || frame >= po->pae_obj->nr_size_types) return false; - *type = po->size_types[frame]; + *type = po->pae_obj->size_types[frame]; return true; } bool RE_particle_get_size_x_type(struct particle_object *po, int frame, int *type) { - if (!po || frame >= po->nr_size_x_types) + if (!po || frame >= po->pae_obj->nr_size_x_types) return false; - *type = po->size_x_types[frame]; + *type = po->pae_obj->size_x_types[frame]; return true; } bool RE_particle_get_size_y_type(struct particle_object *po, int frame, int *type) { - if (!po || frame >= po->nr_size_y_types) + if (!po || frame >= po->pae_obj->nr_size_y_types) return false; - *type = po->size_y_types[frame]; + *type = po->pae_obj->size_y_types[frame]; return true; } int RE_particle_get_num_size2(struct particle_object *po) { - return po ? po->nr_sizes2 : 0; + return po ? po->pae_obj->nr_sizes2 : 0; } int RE_particle_get_num_size_x(struct particle_object *po) { - return po ? po->nr_sizes_x : 0; + return po ? po->pae_obj->nr_sizes_x : 0; } int RE_particle_get_num_size_y(struct particle_object *po) { - return po ? po->nr_sizes_y : 0; + return po ? po->pae_obj->nr_sizes_y : 0; } int RE_particle_get_num_size_type(struct particle_object *po) { - return po ? po->nr_size_types : 0; + return po ? po->pae_obj->nr_size_types : 0; } int RE_particle_get_num_size_x_type(struct particle_object *po) { - return po ? po->nr_size_x_types : 0; + return po ? po->pae_obj->nr_size_x_types : 0; } int RE_particle_get_num_size_y_type(struct particle_object *po) { - return po ? po->nr_size_y_types : 0; + return po ? po->pae_obj->nr_size_y_types : 0; } int RE_particle_get_blend_type(struct particle_object *po) { - return po ? po->blend_type : 0; + return po ? po->pae_obj->blend_type : 0; } const char *RE_particle_get_polygon_name(struct particle_object *po) { - return po ? po->polygon_name : NULL; + return po ? po->pae_obj->polygon_name : NULL; } int RE_particle_get_num_particles(struct particle_object *po) { - return po ? po->nr_particles : 0; + return po ? po->pae_obj->nr_particles : 0; } int RE_particle_get_alpha_fadein_time(struct particle_object *po) { - return po ? po->alpha_fadein_time : 0; + return po ? po->pae_obj->alpha_fadein_time : 0; } int RE_particle_get_alpha_fadeout_time(struct particle_object *po) { - return po ? po->alpha_fadeout_time : 0; + return po ? po->pae_obj->alpha_fadeout_time : 0; } int RE_particle_get_texture_anime_time(struct particle_object *po) { - return po ? po->texture_anime_time : 0; + return po ? po->pae_obj->texture_anime_time : 0; } float RE_particle_get_alpha_fadein_frame(struct particle_object *po) { - return po ? po->alpha_fadein_frame : 0.0; + return po ? po->pae_obj->alpha_fadein_frame : 0.0; } float RE_particle_get_alpha_fadeout_frame(struct particle_object *po) { - return po ? po->alpha_fadeout_frame : 0.0; + return po ? po->pae_obj->alpha_fadeout_frame : 0.0; } float RE_particle_get_texture_anime_frame(struct particle_object *po) { - return po ? po->texture_anime_frame : 0.0; + return po ? po->pae_obj->texture_anime_frame : 0.0; } int RE_particle_get_frame_ref_type(struct particle_object *po) { - return po ? po->frame_ref_type : 0; + return po ? po->pae_obj->frame_ref_type : 0; } int RE_particle_get_frame_ref_param(struct particle_object *po) { - return po ? po->frame_ref_param : 0; + return po ? po->pae_obj->frame_ref_param : 0; } void RE_particle_get_x_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->rotation.begin[0]; - *end_angle = po->rotation.end[0]; + *begin_angle = po->pae_obj->rotation.begin[0]; + *end_angle = po->pae_obj->rotation.end[0]; } void RE_particle_get_y_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->rotation.begin[1]; - *end_angle = po->rotation.end[1]; + *begin_angle = po->pae_obj->rotation.begin[1]; + *end_angle = po->pae_obj->rotation.end[1]; } void RE_particle_get_z_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->rotation.begin[2]; - *end_angle = po->rotation.end[2]; + *begin_angle = po->pae_obj->rotation.begin[2]; + *end_angle = po->pae_obj->rotation.end[2]; } void RE_particle_get_x_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->revolution_angle.begin[0]; - *end_angle = po->revolution_angle.end[0]; + *begin_angle = po->pae_obj->revolution_angle.begin[0]; + *end_angle = po->pae_obj->revolution_angle.end[0]; } void RE_particle_get_x_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance) { if (!po) return; - *begin_distance = po->revolution_distance.begin[0]; - *end_distance = po->revolution_distance.end[0]; + *begin_distance = po->pae_obj->revolution_distance.begin[0]; + *end_distance = po->pae_obj->revolution_distance.end[0]; } void RE_particle_get_y_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->revolution_angle.begin[1]; - *end_angle = po->revolution_angle.end[1]; + *begin_angle = po->pae_obj->revolution_angle.begin[1]; + *end_angle = po->pae_obj->revolution_angle.end[1]; } void RE_particle_get_y_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance) { if (!po) return; - *begin_distance = po->revolution_distance.begin[1]; - *end_distance = po->revolution_distance.end[1]; + *begin_distance = po->pae_obj->revolution_distance.begin[1]; + *end_distance = po->pae_obj->revolution_distance.end[1]; } void RE_particle_get_z_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->revolution_angle.begin[2]; - *end_angle = po->revolution_angle.end[2]; + *begin_angle = po->pae_obj->revolution_angle.begin[2]; + *end_angle = po->pae_obj->revolution_angle.end[2]; } void RE_particle_get_z_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance) { if (!po) return; - *begin_distance = po->revolution_distance.begin[2]; - *end_distance = po->revolution_distance.end[2]; + *begin_distance = po->pae_obj->revolution_distance.begin[2]; + *end_distance = po->pae_obj->revolution_distance.end[2]; } bool RE_particle_get_curve_length(struct particle_object *po, vec3 out) { if (!po) return false; - glm_vec3_copy(po->curve_length, out); + glm_vec3_copy(po->pae_obj->curve_length, out); return true; } int RE_particle_get_child_frame(struct particle_object *po) { - return po ? po->child_frame : 0; + return po ? po->pae_obj->child_frame : 0; } float RE_particle_get_child_length(struct particle_object *po) { - return po ? po->child_length : 0.0; + return po ? po->pae_obj->child_length : 0.0; } float RE_particle_get_child_begin_slope(struct particle_object *po) { - return po ? po->child_begin_slope : 0.0; + return po ? po->pae_obj->child_begin_slope : 0.0; } float RE_particle_get_child_end_slope(struct particle_object *po) { - return po ? po->child_end_slope : 0.0; + return po ? po->pae_obj->child_end_slope : 0.0; } float RE_particle_get_child_create_begin_frame(struct particle_object *po) { - return po ? po->child_create_begin_frame : 0.0; + return po ? po->pae_obj->child_create_begin_frame : 0.0; } float RE_particle_get_child_create_end_frame(struct particle_object *po) { - return po ? po->child_create_end_frame : 0.0; + return po ? po->pae_obj->child_create_end_frame : 0.0; } int RE_particle_get_child_move_dir_type(struct particle_object *po) { - return po ? po->child_move_dir_type : 0; + return po ? po->pae_obj->child_move_dir_type : 0; } int RE_particle_get_dir_type(struct particle_object *po) { - return po ? po->dir_type : 0; + return po ? po->pae_obj->dir_type : 0; } int RE_particle_get_num_damage(struct particle_object *po) { - return po ? po->nr_damages : 0; + return po ? po->pae_obj->nr_damages : 0; } int RE_particle_get_damage(struct particle_object *po, int frame) { - if (!po || frame >= po->nr_damages) + if (!po || frame >= po->pae_obj->nr_damages) return 0; - return po->damages[frame]; + return po->pae_obj->damages[frame]; } float RE_particle_get_offset_x(struct particle_object *po) { - return po ? po->offset_x : 0.0; + return po ? po->pae_obj->offset_x : 0.0; } float RE_particle_get_offset_y(struct particle_object *po) { - return po ? po->offset_y : 0.0; + return po ? po->pae_obj->offset_y : 0.0; } bool RE_effect_get_frame_range(struct RE_instance *instance, int *begin_frame, int *end_frame) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index ef8974e..bf4fd5b 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -490,7 +490,8 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma static void render_billboard_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame) { - if (po->nr_textures == 0) + struct pae_object *pae_obj = po->pae_obj; + if (pae_obj->nr_textures == 0) return; glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE); @@ -500,19 +501,19 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance glUniform1i(r->texture, 0); glBindVertexArray(r->billboard_vao); - for (int index = 0; index < po->nr_particles; index++) { + for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; - if (frame < pi->begin_frame || pi->end_frame < frame) + if (frame < pi->begin_frame || pi->end_frame <= frame) continue; - int step = (int)((frame - pi->begin_frame) / po->texture_anime_frame); - struct billboard_texture *bt = ht_get(inst->effect->textures, po->textures[step % po->nr_textures], NULL); + int step = (int)((frame - pi->begin_frame) / pae_obj->texture_anime_frame); + struct billboard_texture *bt = ht_get(inst->effect->pae->textures, pae_obj->textures[step % pae_obj->nr_textures], NULL); if (!bt) continue; glBindTexture(GL_TEXTURE_2D, bt->texture); - float alpha = particle_object_calc_alpha(po, pi, frame); - if (po->blend_type == PARTICLE_BLEND_ADDITIVE && !bt->has_alpha) + float alpha = pae_object_calc_alpha(pae_obj, pi, frame); + if (pae_obj->blend_type == PARTICLE_BLEND_ADDITIVE && !bt->has_alpha) alpha *= alpha; // why... glUniform1f(r->alpha_mod, alpha); @@ -530,19 +531,20 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame) { - struct model *model = po->model; + struct pae_object *pae_obj = po->pae_obj; + struct model *model = pae_obj->model; if (!model) 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++) { + for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; - if (frame < pi->begin_frame || pi->end_frame < frame) + if (frame < pi->begin_frame || pi->end_frame <= frame) continue; - float alpha = particle_object_calc_alpha(po, pi, frame); + float alpha = pae_object_calc_alpha(pae_obj, pi, frame); glUniform1f(r->alpha_mod, alpha); mat4 local_transform; @@ -588,10 +590,10 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer glDepthMask(GL_FALSE); - for (int i = 0; i < inst->effect->nr_objects; i++) { + for (int i = 0; i < inst->effect->pae->nr_objects; i++) { struct particle_object *po = &inst->effect->objects[i]; - switch (po->blend_type) { + switch (po->pae_obj->blend_type) { case PARTICLE_BLEND_NORMAL: glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); break; @@ -600,7 +602,7 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer break; } - switch (po->type) { + switch (po->pae_obj->type) { case PARTICLE_TYPE_BILLBOARD: render_billboard_particles(r, inst, po, inst->motion->current_frame); break; @@ -968,7 +970,7 @@ void RE_renderer_free_height_detector(struct height_detector *hd) free(hd); } -float RE_renderer_detect_height(struct height_detector *hd, float x, float z) +bool RE_renderer_detect_height(struct height_detector *hd, float x, float z, float *y_out) { float minx = hd->aabb[0][0]; float maxx = hd->aabb[1][0]; @@ -977,9 +979,12 @@ float RE_renderer_detect_height(struct height_detector *hd, float x, float z) float minz = hd->aabb[0][2]; float maxz = hd->aabb[1][2]; if (x < minx || x > maxx || z < minz || z > maxz) - return 0.0; + return false; int px = glm_percent(minx, maxx, x) * SHADOW_WIDTH; int pz = glm_percent(maxz, minz, z) * SHADOW_HEIGHT; - float py = hd->buf[pz * SHADOW_WIDTH + px] / 65535.0; - return glm_lerp(maxy, miny, py); + GLushort val = hd->buf[pz * SHADOW_WIDTH + px]; + if (!val) + return false; + *y_out = glm_lerp(maxy, miny, val / 65535.0f); + return true; }