mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Merge pull request #71 from kichikuou/particle
ReignEngine: Implement particle rendering
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#define SYSTEM4_REIGN_H
|
||||
|
||||
#define RE_NR_BACK_CGS 16
|
||||
#define RE_NR_INSTANCE_TARGETS 2
|
||||
|
||||
#include <cglm/types.h>
|
||||
|
||||
@@ -124,6 +125,7 @@ struct RE_instance {
|
||||
struct height_detector *height_detector;
|
||||
|
||||
enum RE_instance_type type;
|
||||
int target[RE_NR_INSTANCE_TARGETS];
|
||||
vec3 pos;
|
||||
float pitch, roll, yaw; // in degrees
|
||||
vec3 scale;
|
||||
@@ -137,6 +139,10 @@ struct RE_instance {
|
||||
bool motion_blend;
|
||||
float motion_blend_rate;
|
||||
vec3 ambient;
|
||||
vec3 column_pos;
|
||||
float column_height;
|
||||
float column_radius;
|
||||
float column_angle; // around the Y axis, in degrees
|
||||
|
||||
// Lights
|
||||
vec3 vec;
|
||||
@@ -237,6 +243,7 @@ int RE_particle_get_num_damage(struct particle_object *po);
|
||||
int RE_particle_get_damage(struct particle_object *po, int frame);
|
||||
float RE_particle_get_offset_x(struct particle_object *po);
|
||||
float RE_particle_get_offset_y(struct particle_object *po);
|
||||
bool RE_effect_get_frame_range(struct RE_instance *instance, int *begin_frame, int *end_frame);
|
||||
|
||||
bool RE_back_cg_set(struct RE_back_cg *bcg, int no);
|
||||
bool RE_back_cg_set_name(struct RE_back_cg *bcg, struct string *name, struct archive *aar);
|
||||
|
||||
+19
-10
@@ -15,6 +15,11 @@
|
||||
*/
|
||||
|
||||
#define NR_DIR_LIGHTS 3
|
||||
|
||||
#define DIFFUSE_EMISSIVE 0
|
||||
#define DIFFUSE_NORMAL 1
|
||||
#define DIFFUSE_LIGHT_MAP 2
|
||||
|
||||
#define FOG_LINEAR 1
|
||||
#define FOG_LIGHT_SCATTERING 2
|
||||
|
||||
@@ -40,7 +45,7 @@ uniform float specular_shininess;
|
||||
uniform bool use_specular_map;
|
||||
uniform float rim_exponent;
|
||||
uniform vec3 rim_color;
|
||||
uniform bool use_light_map;
|
||||
uniform int diffuse_type;
|
||||
uniform bool use_shadow_map;
|
||||
uniform float shadow_bias;
|
||||
uniform int fog_type;
|
||||
@@ -74,16 +79,20 @@ void main() {
|
||||
vec3 frag_rgb = ambient;
|
||||
|
||||
// Diffuse lighting
|
||||
vec3 diffuse = vec3(0.0);
|
||||
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
|
||||
float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5;
|
||||
diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
|
||||
}
|
||||
if (use_light_map) {
|
||||
diffuse *= texture(light_texture, light_tex_coord).rgb;
|
||||
}
|
||||
vec4 texel = texture(tex, tex_coord);
|
||||
frag_rgb += texel.rgb * diffuse;
|
||||
if (diffuse_type == DIFFUSE_EMISSIVE) {
|
||||
frag_rgb = texel.rgb;
|
||||
} else {
|
||||
vec3 diffuse = vec3(0.0);
|
||||
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
|
||||
float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5;
|
||||
diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
|
||||
}
|
||||
if (diffuse_type == DIFFUSE_LIGHT_MAP) {
|
||||
diffuse *= texture(light_texture, light_tex_coord).rgb;
|
||||
}
|
||||
frag_rgb += texel.rgb * diffuse;
|
||||
}
|
||||
|
||||
// Specular lighting
|
||||
if (specular_strength > 0.0) {
|
||||
|
||||
+59
-12
@@ -23,10 +23,16 @@
|
||||
|
||||
#include "gfx/gl.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "reign.h"
|
||||
|
||||
#define NR_DIR_LIGHTS 3
|
||||
#define MAX_BONES 211 // Maximum in TT3
|
||||
|
||||
typedef struct vec3_range {
|
||||
vec3 begin;
|
||||
vec3 end;
|
||||
} vec3_range;
|
||||
|
||||
struct model {
|
||||
char *path;
|
||||
int nr_meshes;
|
||||
@@ -127,7 +133,7 @@ struct RE_renderer {
|
||||
GLint rim_exponent;
|
||||
GLint rim_color;
|
||||
GLint camera_pos;
|
||||
GLint use_light_map;
|
||||
GLint diffuse_type;
|
||||
GLint light_texture;
|
||||
GLint use_normal_map;
|
||||
GLint normal_texture;
|
||||
@@ -151,6 +157,7 @@ struct RE_renderer {
|
||||
|
||||
struct billboard_texture {
|
||||
GLuint texture;
|
||||
bool has_alpha;
|
||||
};
|
||||
|
||||
// reign.c
|
||||
@@ -175,6 +182,7 @@ 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);
|
||||
void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out);
|
||||
|
||||
// particle.c
|
||||
|
||||
@@ -191,6 +199,13 @@ enum particle_move_type {
|
||||
PARTICLE_MOVE_EMITTER = 2,
|
||||
};
|
||||
|
||||
enum particle_up_vector_type {
|
||||
PARTICLE_UP_VECTOR_Y_AXIS = 0,
|
||||
PARTICLE_UP_VECTOR_OBJECT_MOVE = 1,
|
||||
PARTICLE_UP_VECTOR_INSTANCE_MOVE = 2,
|
||||
PARTICLE_UP_VECTOR_TYPE_MAX = PARTICLE_UP_VECTOR_INSTANCE_MOVE
|
||||
};
|
||||
|
||||
enum particle_blend_type {
|
||||
PARTICLE_BLEND_NORMAL = 0,
|
||||
PARTICLE_BLEND_ADDITIVE = 1,
|
||||
@@ -201,6 +216,18 @@ enum particle_frame_ref_type {
|
||||
PARTICLE_FRAME_REF_TARGET = 1,
|
||||
};
|
||||
|
||||
enum particle_child_move_dir_type {
|
||||
PARTICLE_CHILD_MOVE_DIR_NORMAL = 0,
|
||||
PARTICLE_CHILD_MOVE_DIR_REVERSE = 1,
|
||||
PARTICLE_CHILD_MOVE_DIR_TYPE_MAX = PARTICLE_CHILD_MOVE_DIR_REVERSE
|
||||
};
|
||||
|
||||
enum particle_dir_type {
|
||||
PARTICLE_DIR_TYPE_NORMAL = 0,
|
||||
PARTICLE_DIR_TYPE_XY_PLANE = 1,
|
||||
PARTICLE_DIR_TYPE_MAX = PARTICLE_DIR_TYPE_XY_PLANE
|
||||
};
|
||||
|
||||
struct particle_position_unit {
|
||||
enum {
|
||||
PARTICLE_POS_UNIT_NONE = 0,
|
||||
@@ -212,13 +239,13 @@ struct particle_position_unit {
|
||||
} type;
|
||||
union {
|
||||
struct {
|
||||
int n;
|
||||
vec3 pos;
|
||||
int index;
|
||||
vec3 offset;
|
||||
} target;
|
||||
struct {
|
||||
int n;
|
||||
// char *name;
|
||||
vec3 pos;
|
||||
int target_index;
|
||||
char *name;
|
||||
vec3 offset;
|
||||
} bone;
|
||||
struct {
|
||||
float f;
|
||||
@@ -237,7 +264,7 @@ struct particle_object {
|
||||
char *name;
|
||||
enum particle_type type;
|
||||
enum particle_move_type move_type;
|
||||
int up_vector_type;
|
||||
enum particle_up_vector_type up_vector_type;
|
||||
float move_curve;
|
||||
struct particle_position *position[NR_PARTICLE_POSITIONS];
|
||||
float size[2];
|
||||
@@ -269,9 +296,9 @@ struct particle_object {
|
||||
int alpha_fadein_time;
|
||||
float alpha_fadeout_frame;
|
||||
int alpha_fadeout_time;
|
||||
vec3 rotation[2];
|
||||
vec3 revolution_angle[2];
|
||||
vec3 revolution_distance[2];
|
||||
vec3_range rotation;
|
||||
vec3_range revolution_angle;
|
||||
vec3_range revolution_distance;
|
||||
vec3 curve_length;
|
||||
int child_frame;
|
||||
float child_length;
|
||||
@@ -279,22 +306,42 @@ struct particle_object {
|
||||
float child_end_slope;
|
||||
float child_create_begin_frame;
|
||||
float child_create_end_frame;
|
||||
int child_move_dir_type;
|
||||
int dir_type;
|
||||
enum particle_child_move_dir_type child_move_dir_type;
|
||||
enum particle_dir_type dir_type;
|
||||
int nr_damages;
|
||||
int *damages;
|
||||
float offset_x;
|
||||
float offset_y;
|
||||
|
||||
// Runtime data
|
||||
struct model *model;
|
||||
struct particle_instance *instances;
|
||||
vec3_range pos;
|
||||
vec3 move_vec, move_ortho;
|
||||
};
|
||||
|
||||
struct particle_instance {
|
||||
float begin_frame;
|
||||
float end_frame;
|
||||
vec3_range random_offset;
|
||||
float roll_angle;
|
||||
float pitch_angle;
|
||||
};
|
||||
|
||||
struct particle_effect {
|
||||
char *path;
|
||||
struct hash_table *textures; // name -> struct billboard_texture*
|
||||
|
||||
int nr_objects;
|
||||
struct particle_object *objects;
|
||||
};
|
||||
|
||||
struct particle_effect *particle_effect_load(struct archive *aar, const char *path);
|
||||
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
|
||||
|
||||
|
||||
+505
-49
@@ -14,12 +14,22 @@
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <cglm/cglm.h>
|
||||
|
||||
#include "system4.h"
|
||||
#include "system4/aar.h"
|
||||
#include "system4/cg.h"
|
||||
#include "system4/hashtable.h"
|
||||
#include "system4/utfsjis.h"
|
||||
|
||||
#include "3d_internal.h"
|
||||
|
||||
static inline float randf(void)
|
||||
{
|
||||
return rand() / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
static void parse_error(const char *msg, char *input)
|
||||
{
|
||||
char *eol = strchr(input, '\n');
|
||||
@@ -69,7 +79,7 @@ static enum particle_frame_ref_type parse_particle_frame_ref_type(const char *s,
|
||||
return PARTICLE_FRAME_REF_EFFECT;
|
||||
else if (sscanf(s, "ターゲット[%d]", param) == 1)
|
||||
return PARTICLE_FRAME_REF_TARGET;
|
||||
WARNING("unknown blend type \"%s\"", s);
|
||||
WARNING("unknown frame ref type \"%s\"", s);
|
||||
return (enum particle_frame_ref_type)-1;
|
||||
}
|
||||
|
||||
@@ -148,7 +158,7 @@ static int *parse_int_list(char **ptext, int *nr)
|
||||
return ints;
|
||||
}
|
||||
|
||||
static char **parse_qstr_list(char **ptext, int *nr)
|
||||
static char **parse_qstr_list(char **ptext, int *nr, bool ignore_empty)
|
||||
{
|
||||
char *text = *ptext;
|
||||
int len;
|
||||
@@ -161,14 +171,17 @@ static char **parse_qstr_list(char **ptext, int *nr)
|
||||
cap *= 2;
|
||||
strs = xrealloc(strs, cap * sizeof(char *));
|
||||
}
|
||||
strs[*nr] = parse_quoted_string(&text);
|
||||
if (!strs[*nr]) {
|
||||
char *s = parse_quoted_string(&text);
|
||||
if (!s) {
|
||||
for (int i = 0; i < *nr; i++)
|
||||
free(strs[i]);
|
||||
free(strs);
|
||||
return NULL;
|
||||
}
|
||||
(*nr)++;
|
||||
if (s[0] == '\0' && ignore_empty)
|
||||
free(s);
|
||||
else
|
||||
strs[(*nr)++] = s;
|
||||
} while (MATCH(" , "));
|
||||
*ptext = text;
|
||||
return strs;
|
||||
@@ -196,17 +209,17 @@ static struct particle_position *parse_position(char **ptext)
|
||||
} else if (MATCH("ボーン[ %d , "QUOTED_STRING" , %f , %f , %f ]", &n, string_buf, &x, &y, &z) ||
|
||||
MATCH("ボーン[ %d , \"\" , %f , %f , %f ]", &n, &x, &y, &z)) {
|
||||
unit->type = PARTICLE_POS_UNIT_BONE;
|
||||
unit->bone.n = n;
|
||||
// unit->bone.name = utf2sjis(string_buf, 0);
|
||||
unit->bone.pos[0] = x;
|
||||
unit->bone.pos[1] = y;
|
||||
unit->bone.pos[2] = -z;
|
||||
unit->bone.target_index = n;
|
||||
unit->bone.name = utf2sjis(string_buf, 0);
|
||||
unit->bone.offset[0] = x;
|
||||
unit->bone.offset[1] = y;
|
||||
unit->bone.offset[2] = -z;
|
||||
} else if (MATCH("ターゲット[ %d , %f , %f , %f ]", &n, &x, &y, &z)) {
|
||||
unit->type = PARTICLE_POS_UNIT_TARGET;
|
||||
unit->target.n = n;
|
||||
unit->target.pos[0] = x;
|
||||
unit->target.pos[1] = y;
|
||||
unit->target.pos[2] = -z;
|
||||
unit->target.index = n;
|
||||
unit->target.offset[0] = x;
|
||||
unit->target.offset[1] = y;
|
||||
unit->target.offset[2] = -z;
|
||||
} else if (MATCH("ランダム方向( %f )", &x)) {
|
||||
unit->type = PARTICLE_POS_UNIT_RAND;
|
||||
unit->rand.f = x;
|
||||
@@ -261,6 +274,8 @@ static struct particle_effect *parse_pae(char *text)
|
||||
current_object->name = utf2sjis(string_buf, 0);
|
||||
// Default values.
|
||||
current_object->move_type = PARTICLE_MOVE_LINEAR;
|
||||
current_object->texture_anime_frame = 1.0;
|
||||
current_object->child_end_slope = 1.0;
|
||||
} else {
|
||||
parse_error("unknown toplevel.", text);
|
||||
goto err;
|
||||
@@ -281,6 +296,10 @@ static struct particle_effect *parse_pae(char *text)
|
||||
if (current_object->move_type < 0)
|
||||
goto err;
|
||||
} else if (MATCH("アップベクトルタイプ = %d", &n)) {
|
||||
if (n > PARTICLE_UP_VECTOR_TYPE_MAX) {
|
||||
WARNING("unknown up vector type %d", n);
|
||||
n = PARTICLE_UP_VECTOR_TYPE_MAX;
|
||||
}
|
||||
current_object->up_vector_type = n;
|
||||
} else if (MATCH("移動カーブ = %f", &f)) {
|
||||
current_object->move_curve = f;
|
||||
@@ -324,7 +343,7 @@ static struct particle_effect *parse_pae(char *text)
|
||||
if (!current_object->size_y_types)
|
||||
goto err;
|
||||
} else if (MATCH("テクスチャ = ")) {
|
||||
current_object->textures = parse_qstr_list(&text, ¤t_object->nr_textures);
|
||||
current_object->textures = parse_qstr_list(&text, ¤t_object->nr_textures, true);
|
||||
if (!current_object->textures)
|
||||
goto err;
|
||||
} else if (MATCH("ブレンドタイプ = " KEYWORD, string_buf)) {
|
||||
@@ -359,38 +378,38 @@ static struct particle_effect *parse_pae(char *text)
|
||||
} else if (MATCH("アルファフェードアウト時間 = %d", &n)) {
|
||||
current_object->alpha_fadeout_time = n;
|
||||
} else if (MATCH("X軸自転角度 = %f , %f", &f, &f2)) {
|
||||
current_object->rotation[0][0] = f;
|
||||
current_object->rotation[1][0] = f2;
|
||||
current_object->rotation.begin[0] = f;
|
||||
current_object->rotation.end[0] = f2;
|
||||
} else if (MATCH("Y軸自転角度 = %f , %f", &f, &f2)) {
|
||||
current_object->rotation[0][1] = f;
|
||||
current_object->rotation[1][1] = f2;
|
||||
current_object->rotation.begin[1] = f;
|
||||
current_object->rotation.end[1] = f2;
|
||||
} else if (MATCH("Z軸自転角度 = %f , %f", &f, &f2)) {
|
||||
current_object->rotation[0][2] = f;
|
||||
current_object->rotation[1][2] = f2;
|
||||
current_object->rotation.begin[2] = f;
|
||||
current_object->rotation.end[2] = f2;
|
||||
} else if (MATCH("X軸公転角度 = %f , %f", &f, &f2)) {
|
||||
current_object->revolution_angle[0][0] = f;
|
||||
current_object->revolution_angle[1][0] = f2;
|
||||
current_object->revolution_angle.begin[0] = f;
|
||||
current_object->revolution_angle.end[0] = f2;
|
||||
} else if (MATCH("Y軸公転角度 = %f , %f", &f, &f2)) {
|
||||
current_object->revolution_angle[0][1] = f;
|
||||
current_object->revolution_angle[1][1] = f2;
|
||||
current_object->revolution_angle.begin[1] = f;
|
||||
current_object->revolution_angle.end[1] = f2;
|
||||
} else if (MATCH("Z軸公転角度 = %f , %f", &f, &f2)) {
|
||||
current_object->revolution_angle[0][2] = f;
|
||||
current_object->revolution_angle[1][2] = f2;
|
||||
current_object->revolution_angle.begin[2] = f;
|
||||
current_object->revolution_angle.end[2] = f2;
|
||||
} else if (MATCH("X軸公転距離 = %f , %f", &f, &f2)) {
|
||||
current_object->revolution_distance[0][0] = f;
|
||||
current_object->revolution_distance[1][0] = f2;
|
||||
current_object->revolution_distance.begin[0] = f;
|
||||
current_object->revolution_distance.end[0] = f2;
|
||||
} else if (MATCH("Y軸公転距離 = %f , %f", &f, &f2)) {
|
||||
current_object->revolution_distance[0][1] = f;
|
||||
current_object->revolution_distance[1][1] = f2;
|
||||
current_object->revolution_distance.begin[1] = f;
|
||||
current_object->revolution_distance.end[1] = f2;
|
||||
} else if (MATCH("Z軸公転距離 = %f , %f", &f, &f2)) {
|
||||
current_object->revolution_distance[0][2] = f;
|
||||
current_object->revolution_distance[1][2] = f2;
|
||||
current_object->revolution_distance.begin[2] = f;
|
||||
current_object->revolution_distance.end[2] = f2;
|
||||
} else if (MATCH("カーブX距離 = %f", &f)) {
|
||||
current_object->curve_length[0] = f;
|
||||
} else if (MATCH("カーブY距離 = %f", &f)) {
|
||||
current_object->curve_length[1] = f;
|
||||
} else if (MATCH("カーブZ距離 = %f", &f)) {
|
||||
current_object->curve_length[2] = f;
|
||||
current_object->curve_length[2] = -f;
|
||||
} else if (MATCH("子フレーム = %d", &n)) {
|
||||
current_object->child_frame = n;
|
||||
} else if (MATCH("子距離 = %f", &f)) {
|
||||
@@ -404,8 +423,16 @@ static struct particle_effect *parse_pae(char *text)
|
||||
} else if (MATCH("子生成終了フレーム = %f", &f)) {
|
||||
current_object->child_create_end_frame = f;
|
||||
} else if (MATCH("子移動方向タイプ = %d", &n)) {
|
||||
if (n > PARTICLE_CHILD_MOVE_DIR_TYPE_MAX) {
|
||||
WARNING("unknown child move dir type %d", n);
|
||||
n = PARTICLE_CHILD_MOVE_DIR_TYPE_MAX;
|
||||
}
|
||||
current_object->child_move_dir_type = n;
|
||||
} else if (MATCH("方向タイプ = %d", &n)) {
|
||||
if (n > PARTICLE_DIR_TYPE_MAX) {
|
||||
WARNING("unknown dir type %d", n);
|
||||
n = PARTICLE_DIR_TYPE_MAX;
|
||||
}
|
||||
current_object->dir_type = n;
|
||||
} else if (MATCH("ダメージ = ")) {
|
||||
current_object->damages = parse_int_list(&text, ¤t_object->nr_damages);
|
||||
@@ -426,6 +453,182 @@ static struct particle_effect *parse_pae(char *text)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void load_textures(struct particle_effect *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];
|
||||
for (int j = 0; j < po->nr_textures; j++) {
|
||||
const char *name = po->textures[j];
|
||||
if (ht_get(effect->textures, name, NULL))
|
||||
continue; // already loaded.
|
||||
|
||||
struct archive_data *dfile = RE_get_aar_entry(aar, effect->path, name, ".bmp");
|
||||
if (!dfile)
|
||||
dfile = RE_get_aar_entry(aar, effect->path, name, ".tga");
|
||||
if (!dfile) {
|
||||
WARNING("cannot load texture %s\\%s", effect->path, name);
|
||||
continue;
|
||||
}
|
||||
struct cg *cg = cg_load_data(dfile);
|
||||
if (!cg) {
|
||||
WARNING("cg_load_data failed: %s", dfile->name);
|
||||
archive_free_data(dfile);
|
||||
continue;
|
||||
}
|
||||
archive_free_data(dfile);
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
struct billboard_texture *bt = xcalloc(1, sizeof(struct billboard_texture));
|
||||
bt->texture = texture;
|
||||
bt->has_alpha = cg->metrics.has_alpha;
|
||||
ht_put(effect->textures, name, bt);
|
||||
cg_free(cg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct RE_instance *get_target(struct RE_instance *inst, int index)
|
||||
{
|
||||
int target_id = inst->target[index];
|
||||
if (target_id < 0 || target_id >= inst->plugin->nr_instances)
|
||||
return NULL;
|
||||
return inst->plugin->instances[target_id];
|
||||
}
|
||||
|
||||
static void eval_pos_for_object(struct RE_instance *inst, struct particle_position *pp, vec3 dest)
|
||||
{
|
||||
glm_vec3_zero(dest);
|
||||
if (!pp)
|
||||
return;
|
||||
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
|
||||
struct particle_position_unit *unit = &pp->units[i];
|
||||
switch (unit->type) {
|
||||
case PARTICLE_POS_UNIT_NONE:
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_RAND:
|
||||
case PARTICLE_POS_UNIT_RAND_POSITIVE_Y:
|
||||
// These are computed per instance, in eval_pos_for_instance().
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_ABSOLUTE:
|
||||
glm_vec3_add(dest, unit->absolute, dest);
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_BONE:
|
||||
{
|
||||
struct RE_instance *target = get_target(inst, unit->bone.target_index);
|
||||
int bone = RE_instance_get_bone_index(target, unit->bone.name);
|
||||
vec3 target_pos;
|
||||
if (RE_instance_trans_local_pos_to_world_pos_by_bone(target, bone, unit->bone.offset, target_pos))
|
||||
glm_vec3_add(dest, target_pos, dest);
|
||||
else
|
||||
glm_vec3_add(dest, unit->bone.offset, dest);
|
||||
}
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_TARGET:
|
||||
{
|
||||
struct RE_instance *target = get_target(inst, unit->target.index);
|
||||
if (!target)
|
||||
break;
|
||||
vec3 scale = {
|
||||
target->column_radius,
|
||||
target->column_height,
|
||||
target->column_radius
|
||||
};
|
||||
mat4 transform;
|
||||
glm_scale_make(transform, scale);
|
||||
glm_rotate_y(transform, -glm_rad(target->column_angle), transform);
|
||||
vec3 target_pos;
|
||||
glm_mat4_mulv3(transform, unit->target.offset, 1.0f, target_pos);
|
||||
|
||||
glm_vec3_addadd(target->pos, target->column_pos, target_pos);
|
||||
glm_vec3_add(dest, target_pos, dest);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eval_pos_for_instance(struct particle_position *pp, vec3 dest)
|
||||
{
|
||||
glm_vec3_zero(dest);
|
||||
if (!pp)
|
||||
return;
|
||||
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
|
||||
struct particle_position_unit *unit = &pp->units[i];
|
||||
switch (unit->type) {
|
||||
case PARTICLE_POS_UNIT_NONE:
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_ABSOLUTE:
|
||||
case PARTICLE_POS_UNIT_BONE:
|
||||
case PARTICLE_POS_UNIT_TARGET:
|
||||
// These are computed per object, in eval_pos_for_object().
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_RAND:
|
||||
dest[0] += (randf() * 2.0 - 1.0) * unit->rand.f;
|
||||
dest[1] += (randf() * 2.0 - 1.0) * unit->rand.f;
|
||||
dest[2] += (randf() * 2.0 - 1.0) * unit->rand.f;
|
||||
break;
|
||||
case PARTICLE_POS_UNIT_RAND_POSITIVE_Y:
|
||||
dest[0] += (randf() * 2.0 - 1.0) * unit->rand.f;
|
||||
dest[1] += randf() * unit->rand.f;
|
||||
dest[2] += (randf() * 2.0 - 1.0) * unit->rand.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float eval_child_slope(struct particle_object *po)
|
||||
{
|
||||
float slope = glm_lerp(po->child_begin_slope, po->child_end_slope, randf());
|
||||
if (slope > 1.0)
|
||||
slope = 0.5 + 0.5 / slope; // ???
|
||||
return (1.0 + slope) * GLM_PI_2;
|
||||
}
|
||||
|
||||
static void interpolate_pos(vec3 begin, vec3 end, float move_curve, float t, vec3 dest)
|
||||
{
|
||||
if (move_curve == 0.0f) {
|
||||
glm_vec3_copy(end, dest);
|
||||
return;
|
||||
}
|
||||
float x = move_curve > 0.0f ? powf(t, move_curve) : 1.0f - powf(1.0f - t, -move_curve);
|
||||
glm_vec3_lerp(begin, end, x, dest);
|
||||
}
|
||||
|
||||
static void init_particle_instances(struct particle_object *po)
|
||||
{
|
||||
po->instances = xcalloc(po->nr_particles, sizeof(struct particle_instance));
|
||||
|
||||
for (int i = 0; i < po->nr_particles; i++) {
|
||||
struct particle_instance *pi = &po->instances[i];
|
||||
switch (po->move_type) {
|
||||
case PARTICLE_MOVE_FIXED:
|
||||
case PARTICLE_MOVE_LINEAR:
|
||||
pi->begin_frame = po->begin_frame;
|
||||
pi->end_frame = po->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->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);
|
||||
}
|
||||
}
|
||||
|
||||
struct particle_effect *particle_effect_load(struct archive *aar, const char *path)
|
||||
{
|
||||
const char *basename = strrchr(path, '\\');
|
||||
@@ -460,30 +663,283 @@ struct particle_effect *particle_effect_load(struct archive *aar, const char *pa
|
||||
archive_free_data(dfile);
|
||||
|
||||
effect->path = strdup(path);
|
||||
load_textures(effect, aar);
|
||||
for (int i = 0; i < effect->nr_objects; i++) {
|
||||
struct particle_object *po = &effect->objects[i];
|
||||
|
||||
if (po->polygon_name && *po->polygon_name) {
|
||||
char *pol_path = xmalloc(strlen(path) + strlen(po->polygon_name) + 2);
|
||||
sprintf(pol_path, "%s\\%s", path, po->polygon_name);
|
||||
po->model = model_load(aar, pol_path);
|
||||
free(pol_path);
|
||||
}
|
||||
|
||||
init_particle_instances(po);
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static void free_billboard_texture(void *value)
|
||||
{
|
||||
struct billboard_texture *bt = value;
|
||||
glDeleteTextures(1, &bt->texture);
|
||||
free(bt);
|
||||
}
|
||||
|
||||
static void particle_position_free(struct particle_position *pos)
|
||||
{
|
||||
if (!pos)
|
||||
return;
|
||||
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
|
||||
if (pos->units[i].type == PARTICLE_POS_UNIT_BONE)
|
||||
free(pos->units[i].bone.name);
|
||||
}
|
||||
free(pos);
|
||||
}
|
||||
|
||||
void particle_effect_free(struct particle_effect *effect)
|
||||
{
|
||||
for (int i = 0; i < effect->nr_objects; i++) {
|
||||
struct particle_object *obj = &effect->objects[i];
|
||||
free(obj->name);
|
||||
free(obj->position[0]);
|
||||
free(obj->position[1]);
|
||||
free(obj->sizes2);
|
||||
free(obj->sizes_x);
|
||||
free(obj->sizes_y);
|
||||
free(obj->size_types);
|
||||
free(obj->size_x_types);
|
||||
free(obj->size_y_types);
|
||||
for (int j = 0; j < obj->nr_textures; j++)
|
||||
free(obj->textures[j]);
|
||||
free(obj->textures);
|
||||
free(obj->polygon_name);
|
||||
free(obj->damages);
|
||||
struct particle_object *po = &effect->objects[i];
|
||||
free(po->name);
|
||||
for (int j = 0; j < NR_PARTICLE_POSITIONS; j++)
|
||||
particle_position_free(po->position[j]);
|
||||
free(po->sizes2);
|
||||
free(po->sizes_x);
|
||||
free(po->sizes_y);
|
||||
free(po->size_types);
|
||||
free(po->size_x_types);
|
||||
free(po->size_y_types);
|
||||
for (int j = 0; j < po->nr_textures; j++)
|
||||
free(po->textures[j]);
|
||||
free(po->textures);
|
||||
free(po->polygon_name);
|
||||
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);
|
||||
free(effect->objects);
|
||||
free(effect->path);
|
||||
free(effect);
|
||||
}
|
||||
|
||||
void particle_effect_calc_frame_range(struct particle_effect *effect, 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];
|
||||
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)
|
||||
begin_frame = obj_begin;
|
||||
if (end_frame < obj_end)
|
||||
end_frame = obj_end;
|
||||
}
|
||||
motion->frame_begin = begin_frame;
|
||||
motion->frame_end = end_frame;
|
||||
}
|
||||
|
||||
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++) {
|
||||
struct particle_object *po = &effect->objects[i];
|
||||
// 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);
|
||||
glm_vec3_sub(po->pos.end, po->pos.begin, po->move_vec);
|
||||
switch (po->dir_type) {
|
||||
case PARTICLE_DIR_TYPE_NORMAL:
|
||||
glm_vec3_normalize(po->move_vec);
|
||||
glm_vec3_ortho(po->move_vec, po->move_ortho);
|
||||
glm_vec3_normalize(po->move_ortho);
|
||||
break;
|
||||
case PARTICLE_DIR_TYPE_XY_PLANE:
|
||||
po->move_vec[2] = 0.0f;
|
||||
glm_vec3_normalize(po->move_vec);
|
||||
glm_vec3_copy(GLM_ZUP, po->move_ortho);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_emitter_pos(struct particle_object *po, struct particle_instance *pi, float t, vec3 dest, vec3 move_vec)
|
||||
{
|
||||
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);
|
||||
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_scale(angle, GLM_PIf / 180.0f, angle); // deg -> rad
|
||||
if (po->revolution_angle.begin[0] != 0.0f || po->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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
case PARTICLE_UP_VECTOR_Y_AXIS:
|
||||
case PARTICLE_UP_VECTOR_INSTANCE_MOVE:
|
||||
glm_vec3_copy(GLM_YUP, up_vector);
|
||||
break;
|
||||
case PARTICLE_UP_VECTOR_OBJECT_MOVE:
|
||||
if (glm_vec3_norm2(up_vector) == 0.0f)
|
||||
glm_vec3_copy(GLM_XUP, up_vector);
|
||||
else
|
||||
glm_vec3_normalize(up_vector);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
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));
|
||||
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) {
|
||||
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);
|
||||
break;
|
||||
case PARTICLE_DIR_TYPE_XY_PLANE:
|
||||
glm_vec3_rotate(inst_move, (pi->pitch_angle < GLM_PIf ? -1.0f : 1.0f) * pi->roll_angle, po->move_ortho);
|
||||
break;
|
||||
}
|
||||
glm_vec3_copy(inst_pos.begin, inst_pos.end);
|
||||
switch (po->child_move_dir_type) {
|
||||
case PARTICLE_CHILD_MOVE_DIR_NORMAL:
|
||||
glm_vec3_muladds(inst_move, po->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_negate(inst_move);
|
||||
break;
|
||||
}
|
||||
// Current position of the instance.
|
||||
glm_vec3_lerp(inst_pos.begin, inst_pos.end, t, pos);
|
||||
|
||||
// Calculate the up vector.
|
||||
switch (po->up_vector_type) {
|
||||
case PARTICLE_UP_VECTOR_Y_AXIS:
|
||||
glm_vec3_copy(GLM_YUP, up_vector);
|
||||
break;
|
||||
case PARTICLE_UP_VECTOR_OBJECT_MOVE:
|
||||
glm_vec3_copy(po->move_vec, up_vector);
|
||||
break;
|
||||
case PARTICLE_UP_VECTOR_INSTANCE_MOVE:
|
||||
if (po->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) {
|
||||
mat3 rot = {{ inst_move[1], -inst_move[0], 0.0f },
|
||||
{ inst_move[0], inst_move[1], 0.0f },
|
||||
{ 0.0f, 0.0f, 1.0f }};
|
||||
glm_mat3_mulv(rot, up_vector, up_vector);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_scale(struct particle_object *po, int frame, vec3 dest)
|
||||
{
|
||||
glm_vec3_broadcast(po->sizes2[min(frame, po->nr_sizes2 - 1)], dest);
|
||||
if (po->nr_sizes_x)
|
||||
dest[0] *= po->sizes_x[min(frame, po->nr_sizes_x - 1)];
|
||||
if (po->nr_sizes_y)
|
||||
dest[1] *= po->sizes_y[min(frame, po->nr_sizes_y - 1)];
|
||||
}
|
||||
|
||||
void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest)
|
||||
{
|
||||
float t = glm_percent(pi->begin_frame, pi->end_frame, frame);
|
||||
|
||||
vec3 pos, up_vector;
|
||||
calc_pos_and_up_vector(po, pi, t, pos, up_vector);
|
||||
|
||||
float rel_frame = frame - pi->begin_frame;
|
||||
int cur_step = rel_frame;
|
||||
int next_step = ceilf(rel_frame);
|
||||
float step_frac = rel_frame - cur_step;
|
||||
|
||||
glm_translate_make(dest, pos);
|
||||
if (po->type == PARTICLE_TYPE_BILLBOARD) {
|
||||
mat4 view_mat;
|
||||
RE_calc_view_matrix(&inst->plugin->camera, up_vector, view_mat);
|
||||
mat3 rot;
|
||||
glm_mat4_pick3t(view_mat, rot);
|
||||
glm_mat4_ins3(rot, dest);
|
||||
}
|
||||
|
||||
vec3 angles;
|
||||
glm_vec3_lerp(po->rotation.begin, po->rotation.end, t, angles);
|
||||
angles[0] *= -GLM_PIf / 180.0f;
|
||||
angles[1] *= -GLM_PIf / 180.0f;
|
||||
angles[2] *= GLM_PIf / 180.0f;
|
||||
mat4 rotation_mat;
|
||||
glm_euler_zxy(angles, rotation_mat);
|
||||
glm_mat4_mul(dest, rotation_mat, dest);
|
||||
|
||||
if (po->nr_sizes2 > 0) {
|
||||
vec3 scale, scale2;
|
||||
calc_scale(po, cur_step, scale);
|
||||
calc_scale(po, 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_translate_x(dest, -po->offset_x);
|
||||
glm_translate_y(dest, -po->offset_y);
|
||||
}
|
||||
|
||||
float particle_object_calc_alpha(struct particle_object *po, struct particle_instance *pi, float frame)
|
||||
{
|
||||
frame -= pi->begin_frame;
|
||||
if (frame < po->alpha_fadein_frame)
|
||||
return glm_clamp_zo(frame / po->alpha_fadein_frame);
|
||||
float total_frames = pi->end_frame - pi->begin_frame;
|
||||
if (total_frames - po->alpha_fadeout_frame < frame)
|
||||
return glm_clamp_zo((total_frames - frame) / po->alpha_fadeout_frame);
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
+60
-28
@@ -37,12 +37,16 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin)
|
||||
{
|
||||
struct RE_instance *instance = xcalloc(1, sizeof(struct RE_instance));
|
||||
instance->plugin = plugin;
|
||||
for (int i = 0; i < RE_NR_INSTANCE_TARGETS; i++)
|
||||
instance->target[i] = -1;
|
||||
instance->scale[0] = 1.0;
|
||||
instance->scale[1] = 1.0;
|
||||
instance->scale[2] = 1.0;
|
||||
instance->alpha = 1.0;
|
||||
instance->draw_bump = true;
|
||||
instance->fps = 30.0;
|
||||
instance->column_height = 1.0;
|
||||
instance->column_radius = 1.0;
|
||||
glm_mat4_identity(instance->local_transform);
|
||||
glm_mat3_identity(instance->normal_transform);
|
||||
return instance;
|
||||
@@ -106,6 +110,8 @@ static void update_motion(struct motion *m, float delta_frame)
|
||||
if (!m || m->state == RE_MOTION_STATE_STOP)
|
||||
return;
|
||||
m->current_frame += delta_frame;
|
||||
if (m->current_frame < m->frame_begin)
|
||||
m->current_frame = m->frame_begin;
|
||||
switch (m->state) {
|
||||
case RE_MOTION_STATE_NOLOOP:
|
||||
if (m->current_frame > m->frame_end) {
|
||||
@@ -131,13 +137,9 @@ static void calc_motion_frame(struct motion *m, int bone, struct mot_frame *out)
|
||||
interpolate_motion_frame(&frames[cur_frame], &frames[next_frame], t, out);
|
||||
}
|
||||
|
||||
static void animate(struct RE_instance *inst, int elapsed_ms)
|
||||
static void update_bones(struct RE_instance *inst)
|
||||
{
|
||||
float delta_frame = inst->fps * elapsed_ms / 1000.0;
|
||||
update_motion(inst->motion, delta_frame);
|
||||
update_motion(inst->next_motion, delta_frame);
|
||||
|
||||
if (inst->type != RE_ITYPE_SKINNED || !inst->motion)
|
||||
if (!inst->motion)
|
||||
return;
|
||||
|
||||
mat4 parent_transforms[MAX_BONES];
|
||||
@@ -235,8 +237,24 @@ bool RE_build_model(struct RE_plugin *plugin, int elapsed_ms)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < plugin->nr_instances; i++) {
|
||||
if (plugin->instances[i])
|
||||
animate(plugin->instances[i], elapsed_ms);
|
||||
struct RE_instance *inst = plugin->instances[i];
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
float delta_frame = inst->fps * elapsed_ms / 1000.0;
|
||||
update_motion(inst->motion, delta_frame);
|
||||
update_motion(inst->next_motion, delta_frame);
|
||||
|
||||
if (inst->type == RE_ITYPE_SKINNED)
|
||||
update_bones(inst);
|
||||
}
|
||||
|
||||
// Update particle effects in a second pass, because it uses the results of
|
||||
// update_bones().
|
||||
for (int i = 0; i < plugin->nr_instances; i++) {
|
||||
struct RE_instance *inst = plugin->instances[i];
|
||||
if (inst && inst->type == RE_ITYPE_PARTICLE_EFFECT)
|
||||
particle_effect_update(inst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -329,6 +347,11 @@ bool RE_instance_load(struct RE_instance *instance, const char *name)
|
||||
return !!instance->model;
|
||||
case RE_ITYPE_PARTICLE_EFFECT:
|
||||
instance->effect = particle_effect_load(instance->plugin->aar, name);
|
||||
if (!instance->motion) {
|
||||
instance->motion = xcalloc(1, sizeof(struct motion));
|
||||
instance->motion->instance = instance;
|
||||
particle_effect_calc_frame_range(instance->effect, instance->motion);
|
||||
}
|
||||
return !!instance->effect;
|
||||
default:
|
||||
WARNING("Invalid instance type %d", instance->type);
|
||||
@@ -573,9 +596,9 @@ int RE_particle_get_pos_unit_index(struct particle_object *po, int pos, int unit
|
||||
return 0;
|
||||
switch (u->type) {
|
||||
case PARTICLE_POS_UNIT_BONE:
|
||||
return u->bone.n;
|
||||
return u->bone.target_index;
|
||||
case PARTICLE_POS_UNIT_TARGET:
|
||||
return u->target.n;
|
||||
return u->target.index;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -739,72 +762,72 @@ void RE_particle_get_x_rotation_angle(struct particle_object *po, float *begin_a
|
||||
{
|
||||
if (!po)
|
||||
return;
|
||||
*begin_angle = po->rotation[0][0];
|
||||
*end_angle = po->rotation[1][0];
|
||||
*begin_angle = po->rotation.begin[0];
|
||||
*end_angle = po->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[0][1];
|
||||
*end_angle = po->rotation[1][1];
|
||||
*begin_angle = po->rotation.begin[1];
|
||||
*end_angle = po->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[0][2];
|
||||
*end_angle = po->rotation[1][2];
|
||||
*begin_angle = po->rotation.begin[2];
|
||||
*end_angle = po->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[0][0];
|
||||
*end_angle = po->revolution_angle[1][0];
|
||||
*begin_angle = po->revolution_angle.begin[0];
|
||||
*end_angle = po->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[0][0];
|
||||
*end_distance = po->revolution_distance[1][0];
|
||||
*begin_distance = po->revolution_distance.begin[0];
|
||||
*end_distance = po->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[0][1];
|
||||
*end_angle = po->revolution_angle[1][1];
|
||||
*begin_angle = po->revolution_angle.begin[1];
|
||||
*end_angle = po->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[0][1];
|
||||
*end_distance = po->revolution_distance[1][1];
|
||||
*begin_distance = po->revolution_distance.begin[1];
|
||||
*end_distance = po->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[0][2];
|
||||
*end_angle = po->revolution_angle[1][2];
|
||||
*begin_angle = po->revolution_angle.begin[2];
|
||||
*end_angle = po->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[0][2];
|
||||
*end_distance = po->revolution_distance[1][2];
|
||||
*begin_distance = po->revolution_distance.begin[2];
|
||||
*end_distance = po->revolution_distance.end[2];
|
||||
}
|
||||
|
||||
bool RE_particle_get_curve_length(struct particle_object *po, vec3 out)
|
||||
@@ -877,6 +900,15 @@ float RE_particle_get_offset_y(struct particle_object *po)
|
||||
return po ? po->offset_y : 0.0;
|
||||
}
|
||||
|
||||
bool RE_effect_get_frame_range(struct RE_instance *instance, int *begin_frame, int *end_frame)
|
||||
{
|
||||
if (!instance || !instance->effect || !instance->motion)
|
||||
return false;
|
||||
*begin_frame = instance->motion->frame_begin;
|
||||
*end_frame = instance->motion->frame_end;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RE_back_cg_set(struct RE_back_cg *bcg, int no)
|
||||
{
|
||||
if (!bcg)
|
||||
|
||||
+157
-12
@@ -37,6 +37,12 @@ enum {
|
||||
SHADOW_TEXTURE_UNIT,
|
||||
};
|
||||
|
||||
enum {
|
||||
DIFFUSE_EMISSIVE = 0,
|
||||
DIFFUSE_NORMAL = 1,
|
||||
DIFFUSE_LIGHT_MAP = 2,
|
||||
};
|
||||
|
||||
static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path)
|
||||
{
|
||||
GLuint program = glCreateProgram();
|
||||
@@ -108,10 +114,10 @@ static void init_billboard_mesh(struct RE_renderer *r)
|
||||
{
|
||||
static const GLfloat vertices[] = {
|
||||
// x, y, z, u, v
|
||||
-1.0, 2.0, 0.0, 0.0, 0.0,
|
||||
-1.0, 0.0, 0.0, 0.0, 1.0,
|
||||
1.0, 2.0, 0.0, 1.0, 0.0,
|
||||
1.0, 0.0, 0.0, 1.0, 1.0,
|
||||
-1.0, 1.0, 0.0, 0.0, 0.0,
|
||||
-1.0, -1.0, 0.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0, 0.0,
|
||||
1.0, -1.0, 0.0, 1.0, 1.0,
|
||||
};
|
||||
glGenVertexArrays(1, &r->billboard_vao);
|
||||
glBindVertexArray(r->billboard_vao);
|
||||
@@ -177,7 +183,7 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
|
||||
r->rim_exponent = glGetUniformLocation(r->program, "rim_exponent");
|
||||
r->rim_color = glGetUniformLocation(r->program, "rim_color");
|
||||
r->camera_pos = glGetUniformLocation(r->program, "camera_pos");
|
||||
r->use_light_map = glGetUniformLocation(r->program, "use_light_map");
|
||||
r->diffuse_type = glGetUniformLocation(r->program, "diffuse_type");
|
||||
r->light_texture = glGetUniformLocation(r->program, "light_texture");
|
||||
r->use_normal_map = glGetUniformLocation(r->program, "use_normal_map");
|
||||
r->normal_texture = glGetUniformLocation(r->program, "normal_texture");
|
||||
@@ -224,6 +230,7 @@ bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
bt->has_alpha = cg->metrics.has_alpha;
|
||||
|
||||
cg_free(cg);
|
||||
ht_put_int(r->billboard_textures, cg_no, bt);
|
||||
@@ -248,7 +255,7 @@ void RE_renderer_free(struct RE_renderer *r)
|
||||
free(r);
|
||||
}
|
||||
|
||||
static void calc_view_matrix(struct RE_camera *camera, mat4 out)
|
||||
void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out)
|
||||
{
|
||||
vec3 front = { 0.0, 0.0, -1.0 };
|
||||
vec3 euler = {
|
||||
@@ -259,7 +266,6 @@ static void calc_view_matrix(struct RE_camera *camera, mat4 out)
|
||||
mat4 rot;
|
||||
glm_euler(euler, rot);
|
||||
glm_mat4_mulv3(rot, front, 0.0, front);
|
||||
vec3 up = {0.0, 1.0, 0.0};
|
||||
glm_look(camera->pos, front, up, out);
|
||||
}
|
||||
|
||||
@@ -316,12 +322,12 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
|
||||
glUniform1i(r->texture, COLOR_TEXTURE_UNIT);
|
||||
|
||||
if (material->light_map && inst->plugin->light_map_mode) {
|
||||
glUniform1i(r->use_light_map, GL_TRUE);
|
||||
glUniform1i(r->diffuse_type, DIFFUSE_LIGHT_MAP);
|
||||
glActiveTexture(GL_TEXTURE0 + LIGHT_TEXTURE_UNIT);
|
||||
glBindTexture(GL_TEXTURE_2D, material->light_map);
|
||||
glUniform1i(r->light_texture, LIGHT_TEXTURE_UNIT);
|
||||
} else {
|
||||
glUniform1i(r->use_light_map, GL_FALSE);
|
||||
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
|
||||
}
|
||||
|
||||
if (material->normal_map && inst->draw_bump && inst->plugin->bump_mode) {
|
||||
@@ -342,12 +348,16 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
|
||||
|
||||
static void render_static_model(struct RE_instance *inst, struct RE_renderer *r)
|
||||
{
|
||||
if (!inst->draw)
|
||||
return;
|
||||
glUniform1i(r->has_bones, GL_FALSE);
|
||||
render_model(inst, r);
|
||||
}
|
||||
|
||||
static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r)
|
||||
{
|
||||
if (!inst->draw)
|
||||
return;
|
||||
struct model *model = inst->model;
|
||||
if (!model)
|
||||
return;
|
||||
@@ -363,6 +373,8 @@ static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r
|
||||
|
||||
static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat)
|
||||
{
|
||||
if (!inst->draw)
|
||||
return;
|
||||
int cg_no = inst->motion->current_frame;
|
||||
struct billboard_texture *bt = ht_get_int(r->billboard_textures, cg_no, NULL);
|
||||
if (!bt)
|
||||
@@ -374,6 +386,8 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
|
||||
glm_mat4_pick3t(view_mat, rot);
|
||||
glm_mat4_ins3(rot, local_transform);
|
||||
glm_scale(local_transform, inst->scale);
|
||||
// Billboard instances are bottomed at y=0.
|
||||
glm_translate_y(local_transform, 1.0);
|
||||
mat3 normal_transform;
|
||||
// This should be safe because billboards do not have non-uniform scaling.
|
||||
glm_mat4_pick3(local_transform, normal_transform);
|
||||
@@ -390,8 +404,9 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
|
||||
glUniform1f(r->specular_shininess, 0.0);
|
||||
glUniform1i(r->use_specular_map, GL_FALSE);
|
||||
glUniform1f(r->rim_exponent, 0.0);
|
||||
glUniform1i(r->use_light_map, GL_FALSE);
|
||||
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
|
||||
glUniform1i(r->use_normal_map, GL_FALSE);
|
||||
glUniform1i(r->use_shadow_map, GL_FALSE);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, bt->texture);
|
||||
@@ -404,6 +419,133 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
static void render_billboard_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame)
|
||||
{
|
||||
if (po->nr_textures == 0)
|
||||
return;
|
||||
|
||||
glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE);
|
||||
glUniform1i(r->fog_type, 0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(r->texture, 0);
|
||||
glBindVertexArray(r->billboard_vao);
|
||||
|
||||
for (int index = 0; index < po->nr_particles; index++) {
|
||||
struct particle_instance *pi = &po->instances[index];
|
||||
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);
|
||||
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)
|
||||
alpha *= alpha; // why...
|
||||
glUniform1f(r->alpha_mod, alpha);
|
||||
|
||||
mat4 local_transform;
|
||||
particle_object_calc_local_transform(inst, po, pi, frame, local_transform);
|
||||
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
|
||||
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, local_transform[0]);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glUniform1i(r->fog_type, inst->plugin->fog_type);
|
||||
}
|
||||
|
||||
static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame)
|
||||
{
|
||||
struct model *model = po->model;
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
|
||||
|
||||
for (int index = 0; index < po->nr_particles; index++) {
|
||||
struct particle_instance *pi = &po->instances[index];
|
||||
if (frame < pi->begin_frame || pi->end_frame < frame)
|
||||
continue;
|
||||
|
||||
float alpha = particle_object_calc_alpha(po, pi, frame);
|
||||
glUniform1f(r->alpha_mod, alpha);
|
||||
|
||||
mat4 local_transform;
|
||||
particle_object_calc_local_transform(inst, po, pi, frame, local_transform);
|
||||
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
|
||||
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, local_transform[0]);
|
||||
|
||||
for (int i = 0; i < model->nr_meshes; i++) {
|
||||
struct mesh *mesh = &model->meshes[i];
|
||||
struct material *material = &model->materials[mesh->material];
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, material->color_map);
|
||||
glUniform1i(r->texture, 0);
|
||||
|
||||
glBindVertexArray(mesh->vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void render_particle_effect(struct RE_instance *inst, struct RE_renderer *r)
|
||||
{
|
||||
// NOTE: inst->draw flag has no effect for particle effects.
|
||||
if (!inst->effect)
|
||||
return;
|
||||
|
||||
vec3 ambient;
|
||||
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
|
||||
glUniform3fv(r->ambient, 1, ambient);
|
||||
|
||||
glUniform1i(r->has_bones, GL_FALSE);
|
||||
glUniform1f(r->specular_strength, 0.0);
|
||||
glUniform1f(r->specular_shininess, 0.0);
|
||||
glUniform1i(r->use_specular_map, GL_FALSE);
|
||||
glUniform1f(r->rim_exponent, 0.0);
|
||||
glUniform1i(r->use_normal_map, GL_FALSE);
|
||||
glUniform1i(r->use_shadow_map, GL_FALSE);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
for (int i = 0; i < inst->effect->nr_objects; i++) {
|
||||
struct particle_object *po = &inst->effect->objects[i];
|
||||
|
||||
switch (po->blend_type) {
|
||||
case PARTICLE_BLEND_NORMAL:
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
case PARTICLE_BLEND_ADDITIVE:
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (po->type) {
|
||||
case PARTICLE_TYPE_BILLBOARD:
|
||||
render_billboard_particles(r, inst, po, inst->motion->current_frame);
|
||||
break;
|
||||
case PARTICLE_TYPE_POLYGON_OBJECT:
|
||||
render_polygon_particles(r, inst, po, inst->motion->current_frame);
|
||||
break;
|
||||
case PARTICLE_TYPE_SWORD_BLUR: // unused
|
||||
break;
|
||||
}
|
||||
}
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
static bool calc_shadow_light_transform(struct RE_plugin *plugin, mat4 dest)
|
||||
{
|
||||
// Compute AABB of shadow casters.
|
||||
@@ -579,7 +721,7 @@ void RE_render(struct sact_sprite *sp)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
mat4 view_transform;
|
||||
calc_view_matrix(&plugin->camera, view_transform);
|
||||
RE_calc_view_matrix(&plugin->camera, GLM_YUP, view_transform);
|
||||
|
||||
// Tweak the projection transform so that the rendering result is vertically
|
||||
// flipped. If we render the scene normally, the resulting image will be
|
||||
@@ -621,7 +763,7 @@ void RE_render(struct sact_sprite *sp)
|
||||
|
||||
for (int i = 0; i < plugin->nr_instances; i++) {
|
||||
struct RE_instance *inst = plugin->instances[i];
|
||||
if (!inst || !inst->draw)
|
||||
if (!inst)
|
||||
continue;
|
||||
switch (inst->type) {
|
||||
case RE_ITYPE_STATIC:
|
||||
@@ -633,6 +775,9 @@ void RE_render(struct sact_sprite *sp)
|
||||
case RE_ITYPE_BILLBOARD:
|
||||
render_billboard(inst, r, view_transform);
|
||||
break;
|
||||
case RE_ITYPE_PARTICLE_EFFECT:
|
||||
render_particle_effect(inst, r);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+95
-16
@@ -482,22 +482,97 @@ static bool ReignEngine_FreeInstanceNextMotion(int plugin, int instance)
|
||||
//bool ReignEngine_SaveInstanceAddMaterialData(int plugin, int instance);
|
||||
//bool ReignEngine_SetInstancePointPos(int plugin, int instance, int index, float x, float y, float z);
|
||||
//bool ReignEngine_GetInstancePointPos(int plugin, int instance, int index, float *pfX, float *pfY, float *pfZ);
|
||||
//bool ReignEngine_GetInstanceColumnPos(int plugin, int instance, float *fX, float *fY, float *fZ);
|
||||
//float ReignEngine_GetInstanceColumnHeight(int plugin, int instance);
|
||||
//float ReignEngine_GetInstanceColumnRadius(int plugin, int instance);
|
||||
//float ReignEngine_GetInstanceColumnAngle(int plugin, int instance);
|
||||
static bool ReignEngine_GetInstanceColumnPos(int plugin, int instance, float *x, float *y, float *z)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri)
|
||||
return false;
|
||||
*x = ri->column_pos[0];
|
||||
*y = ri->column_pos[1];
|
||||
*z = -ri->column_pos[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
static float ReignEngine_GetInstanceColumnHeight(int plugin, int instance)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
return ri ? ri->column_height : 0.0;
|
||||
}
|
||||
|
||||
static float ReignEngine_GetInstanceColumnRadius(int plugin, int instance)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
return ri ? ri->column_radius : 0.0;
|
||||
}
|
||||
|
||||
static float ReignEngine_GetInstanceColumnAngle(int plugin, int instance)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
return ri ? ri->column_angle : 0.0;
|
||||
}
|
||||
|
||||
//float ReignEngine_GetInstanceColumnAngleP(int plugin, int instance);
|
||||
//float ReignEngine_GetInstanceColumnAngleB(int plugin, int instance);
|
||||
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceColumnPos, int plugin, int instance, float x, float y, float z);
|
||||
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceColumnHeight, int plugin, int instance, float height);
|
||||
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceColumnRadius, int plugin, int instance, float radius);
|
||||
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceColumnAngle, int plugin, int instance, float angle);
|
||||
|
||||
static bool ReignEngine_SetInstanceColumnPos(int plugin, int instance, float x, float y, float z)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri)
|
||||
return false;
|
||||
ri->column_pos[0] = x;
|
||||
ri->column_pos[1] = y;
|
||||
ri->column_pos[2] = -z;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReignEngine_SetInstanceColumnHeight(int plugin, int instance, float height)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri)
|
||||
return false;
|
||||
ri->column_height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReignEngine_SetInstanceColumnRadius(int plugin, int instance, float radius)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri)
|
||||
return false;
|
||||
ri->column_radius = radius;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReignEngine_SetInstanceColumnAngle(int plugin, int instance, float angle)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri)
|
||||
return false;
|
||||
ri->column_angle = angle;
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool ReignEngine_SetInstanceColumnAngleP(int plugin, int instance, float fAngleP);
|
||||
//bool ReignEngine_SetInstanceColumnAngleB(int plugin, int instance, float fAngleB);
|
||||
//bool ReignEngine_GetInstanceDrawColumn(int plugin, int instance);
|
||||
//bool ReignEngine_SetInstanceDrawColumn(int plugin, int instance, bool bDraw);
|
||||
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceTarget, int plugin, int instance, int index, int target);
|
||||
//int ReignEngine_GetInstanceTarget(int plugin, int instance, int index);
|
||||
|
||||
static bool ReignEngine_SetInstanceTarget(int plugin, int instance, int index, int target)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri || index < 0 || index >= RE_NR_INSTANCE_TARGETS)
|
||||
return false;
|
||||
ri->target[index] = target;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ReignEngine_GetInstanceTarget(int plugin, int instance, int index)
|
||||
{
|
||||
struct RE_instance *ri = get_instance(plugin, instance);
|
||||
if (!ri || index < 0 || index >= RE_NR_INSTANCE_TARGETS)
|
||||
return -1;
|
||||
return ri->target[index];
|
||||
}
|
||||
|
||||
static float ReignEngine_GetInstanceFPS(int plugin, int instance)
|
||||
{
|
||||
@@ -561,7 +636,11 @@ static bool ReignEngine_SetInstanceShadowVolumeBoneRadius(int plugin, int instan
|
||||
//bool ReignEngine_GetInstanceDebugDrawShadowVolume(int plugin, int instance);
|
||||
//bool ReignEngine_SetInstanceDebugDrawShadowVolume(int plugin, int instance, bool flag);
|
||||
//bool ReignEngine_SaveEffect(int plugin, int instance);
|
||||
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, GetEffectFrameRange, int plugin, int instance, int *begin_frame, int *end_frame);
|
||||
|
||||
static bool ReignEngine_GetEffectFrameRange(int plugin, int instance, int *begin_frame, int *end_frame)
|
||||
{
|
||||
return RE_effect_get_frame_range(get_instance(plugin, instance), begin_frame, end_frame);
|
||||
}
|
||||
|
||||
static int ReignEngine_GetEffectObjectType(int plugin, int instance, int object)
|
||||
{
|
||||
@@ -1765,10 +1844,10 @@ HLL_LIBRARY(ReignEngine,
|
||||
HLL_TODO_EXPORT(SaveInstanceAddMaterialData, ReignEngine_SaveInstanceAddMaterialData),
|
||||
HLL_TODO_EXPORT(SetInstancePointPos, ReignEngine_SetInstancePointPos),
|
||||
HLL_TODO_EXPORT(GetInstancePointPos, ReignEngine_GetInstancePointPos),
|
||||
HLL_TODO_EXPORT(GetInstanceColumnPos, ReignEngine_GetInstanceColumnPos),
|
||||
HLL_TODO_EXPORT(GetInstanceColumnHeight, ReignEngine_GetInstanceColumnHeight),
|
||||
HLL_TODO_EXPORT(GetInstanceColumnRadius, ReignEngine_GetInstanceColumnRadius),
|
||||
HLL_TODO_EXPORT(GetInstanceColumnAngle, ReignEngine_GetInstanceColumnAngle),
|
||||
HLL_EXPORT(GetInstanceColumnPos, ReignEngine_GetInstanceColumnPos),
|
||||
HLL_EXPORT(GetInstanceColumnHeight, ReignEngine_GetInstanceColumnHeight),
|
||||
HLL_EXPORT(GetInstanceColumnRadius, ReignEngine_GetInstanceColumnRadius),
|
||||
HLL_EXPORT(GetInstanceColumnAngle, ReignEngine_GetInstanceColumnAngle),
|
||||
HLL_TODO_EXPORT(GetInstanceColumnAngleP, ReignEngine_GetInstanceColumnAngleP),
|
||||
HLL_TODO_EXPORT(GetInstanceColumnAngleB, ReignEngine_GetInstanceColumnAngleB),
|
||||
HLL_EXPORT(SetInstanceColumnPos, ReignEngine_SetInstanceColumnPos),
|
||||
@@ -1780,7 +1859,7 @@ HLL_LIBRARY(ReignEngine,
|
||||
HLL_TODO_EXPORT(GetInstanceDrawColumn, ReignEngine_GetInstanceDrawColumn),
|
||||
HLL_TODO_EXPORT(SetInstanceDrawColumn, ReignEngine_SetInstanceDrawColumn),
|
||||
HLL_EXPORT(SetInstanceTarget, ReignEngine_SetInstanceTarget),
|
||||
HLL_TODO_EXPORT(GetInstanceTarget, ReignEngine_GetInstanceTarget),
|
||||
HLL_EXPORT(GetInstanceTarget, ReignEngine_GetInstanceTarget),
|
||||
HLL_EXPORT(GetInstanceFPS, ReignEngine_GetInstanceFPS),
|
||||
HLL_EXPORT(SetInstanceFPS, ReignEngine_SetInstanceFPS),
|
||||
HLL_EXPORT(GetInstanceBoneIndex, ReignEngine_GetInstanceBoneIndex),
|
||||
|
||||
Reference in New Issue
Block a user