mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-12 09:08:11 +03:00
1163 lines
38 KiB
C++
1163 lines
38 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "glitter.hpp"
|
|
#include "../../KKdLib/str_utils.hpp"
|
|
#include "../rob/rob.hpp"
|
|
#include "../auth_3d.hpp"
|
|
|
|
namespace Glitter {
|
|
EffectInst::EffectInst(GPM, GLT, Effect* eff,
|
|
size_t id, float_t emission, bool appear_now) : data(GLT_VAL) {
|
|
effect = eff;
|
|
data = eff->data;
|
|
color = vec4_identity;
|
|
scale_all = 1.0f;
|
|
this->id = id;
|
|
translation = eff->translation;
|
|
rotation = eff->rotation;
|
|
scale = eff->scale;
|
|
frame0 = 0.0f;
|
|
frame1 = 0.0f;
|
|
mat = mat4_identity;
|
|
flags = (EffectInstFlag)0;
|
|
random = 0;
|
|
min_color = vec4_null;
|
|
ext_anim_scale = vec3_null;
|
|
some_scale = -1.0f;
|
|
|
|
if (appear_now)
|
|
data.appear_time = 0;
|
|
else
|
|
frame0 = -(float_t)data.appear_time;
|
|
}
|
|
|
|
EffectInst::~EffectInst() {
|
|
|
|
}
|
|
|
|
F2EffectInst::ExtAnim::ExtAnim() {
|
|
object_index = -1;
|
|
mesh_index = -1;
|
|
a3da_id = -1;
|
|
object_is_hrc = false;
|
|
mesh_name = 0;
|
|
mat = mat4_identity;
|
|
translation = vec3_null;
|
|
}
|
|
|
|
F2EffectInst::ExtAnim::~ExtAnim() {
|
|
|
|
}
|
|
|
|
F2EffectInst::F2EffectInst(GPM, GLT, Effect* eff,
|
|
size_t id, float_t emission, bool appear_now)
|
|
: EffectInst(GPM_VAL, GLT_VAL, eff, id, emission, appear_now) {
|
|
random_ptr = &GPM_VAL->random;
|
|
ext_anim = 0;
|
|
|
|
if (~eff->data.flags & EFFECT_LOCAL && data.ext_anim) {
|
|
F2EffectInst::ExtAnim* inst_ext_anim = new F2EffectInst::ExtAnim;
|
|
if (inst_ext_anim) {
|
|
Effect::ExtAnim* ext_anim = data.ext_anim;
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_SET_ONCE)
|
|
enum_or(flags, EFFECT_INST_SET_EXT_ANIM_ONCE);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_TRANS_ONLY)
|
|
enum_or(flags, EFFECT_INST_EXT_ANIM_TRANS_ONLY);
|
|
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM) {
|
|
inst_ext_anim->chara_index = ext_anim->chara_index;
|
|
inst_ext_anim->bone_index = GetExtAnimBoneIndex(ext_anim->node_index);
|
|
enum_or(flags, EFFECT_INST_CHARA_ANIM);
|
|
inst_ext_anim->mesh_name = 0;
|
|
}
|
|
else {
|
|
inst_ext_anim->object = ext_anim->object;
|
|
|
|
if (ext_anim->mesh_name[0])
|
|
inst_ext_anim->mesh_name = ext_anim->mesh_name;
|
|
else
|
|
inst_ext_anim->mesh_name = 0;
|
|
}
|
|
}
|
|
ext_anim = inst_ext_anim;
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM);
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
enum_or(flags, EFFECT_INST_GET_EXT_ANIM_MAT);
|
|
}
|
|
|
|
random_ptr->SetValue(GLT_VAL == Glitter::FT ? (uint32_t)data.name_hash : 0);
|
|
random = random_ptr->GetValue();
|
|
|
|
emitters.reserve(eff->emitters.size());
|
|
for (Emitter*& i : eff->emitters) {
|
|
if (!i)
|
|
continue;
|
|
|
|
F2EmitterInst* emitter = new F2EmitterInst(i, this, emission);
|
|
if (emitter)
|
|
emitters.push_back(emitter);
|
|
}
|
|
CtrlInit(GPM_VAL, GLT_VAL, emission);
|
|
}
|
|
|
|
F2EffectInst::~F2EffectInst() {
|
|
for (F2EmitterInst*& i : emitters)
|
|
delete i;
|
|
|
|
delete ext_anim;
|
|
}
|
|
|
|
void F2EffectInst::Copy(EffectInst* dst, float_t emission) {
|
|
dst->frame0 = frame0;
|
|
dst->frame1 = frame1;
|
|
dst->color = color;
|
|
dst->translation = translation;
|
|
dst->rotation = rotation;
|
|
dst->scale = scale;
|
|
dst->mat = mat;
|
|
dst->random = random;
|
|
|
|
F2EffectInst* f2_dst = dynamic_cast<F2EffectInst*>(dst);
|
|
if (f2_dst && emitters.size() == f2_dst->emitters.size()) {
|
|
size_t count = emitters.size();
|
|
for (size_t i = 0; i < count; i++)
|
|
emitters.data()[i]->Copy(f2_dst->emitters.data()[i], emission);
|
|
}
|
|
}
|
|
|
|
void F2EffectInst::Ctrl(GPM, GLT, float_t delta_frame, float_t emission) {
|
|
GetExtAnim();
|
|
GetValue(GLT_VAL);
|
|
|
|
mat4 mat;
|
|
if (GetExtAnimMat(&mat)) {
|
|
vec3 trans = translation;
|
|
mat4_translate_mult(&mat, trans.x, trans.y, trans.z, &mat);
|
|
}
|
|
else {
|
|
vec3 trans = translation;
|
|
mat4_translate(trans.x, trans.y, trans.z, &mat);
|
|
}
|
|
|
|
vec3 rot = rotation;
|
|
vec3 scale;
|
|
vec3_mult_scalar(this->scale, scale_all, scale);
|
|
|
|
mat4_rot(&mat, rot.x, rot.y, rot.z, &mat);
|
|
mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &this->mat);
|
|
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Ctrl(GPM_VAL, GLT_VAL, this, delta_frame);
|
|
|
|
if (frame0 >= 0.0f)
|
|
if (frame0 < (float_t)data.life_time) {
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Emit(GPM_VAL, GLT_VAL, delta_frame, emission);
|
|
}
|
|
else if (data.flags & EFFECT_LOOP)
|
|
frame0 -= (float_t)data.life_time;
|
|
else
|
|
Free(GPM_VAL, GLT_VAL, emission, false);
|
|
|
|
render_scene.Ctrl(GLT_VAL, delta_frame);
|
|
frame0 += delta_frame;
|
|
}
|
|
|
|
void F2EffectInst::Disp(GPM, DispType disp_type) {
|
|
render_scene.Disp(GPM_VAL, disp_type);
|
|
}
|
|
|
|
void F2EffectInst::Free(GPM, GLT, float_t emission, bool free) {
|
|
enum_or(flags, EFFECT_INST_FREE);
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Free(GPM_VAL, GLT_VAL, emission, free);
|
|
}
|
|
|
|
size_t F2EffectInst::GetCtrlCount(ParticleType type) {
|
|
return render_scene.GetCtrlCount(type);
|
|
}
|
|
|
|
size_t F2EffectInst::GetDispCount(ParticleType type) {
|
|
return render_scene.GetDispCount(type);
|
|
}
|
|
|
|
bool F2EffectInst::HasEnded(bool a2) {
|
|
if (~flags & EFFECT_INST_FREE)
|
|
return false;
|
|
else if (!a2)
|
|
return true;
|
|
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i && !i->HasEnded(a2))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void F2EffectInst::Reset(GPM, GLT, float_t emission) {
|
|
frame0 = -(float_t)data.appear_time;
|
|
frame1 = 0.0;
|
|
|
|
flags = (EffectInstFlag)0;
|
|
if (~data.flags & EFFECT_LOCAL && data.ext_anim) {
|
|
if (ext_anim) {
|
|
Effect::ExtAnim* ext_anim = data.ext_anim;
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_SET_ONCE)
|
|
enum_or(flags, EFFECT_INST_SET_EXT_ANIM_ONCE);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_TRANS_ONLY)
|
|
enum_or(flags, EFFECT_INST_EXT_ANIM_TRANS_ONLY);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM)
|
|
enum_or(flags, EFFECT_INST_CHARA_ANIM);
|
|
}
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM);
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
enum_or(flags, EFFECT_INST_GET_EXT_ANIM_MAT);
|
|
}
|
|
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Reset();
|
|
|
|
CtrlInit(GPM_VAL, GLT_VAL, emission);
|
|
}
|
|
|
|
void F2EffectInst::CtrlInit(GPM, GLT, float_t emission) {
|
|
if (data.start_time < 1)
|
|
return;
|
|
|
|
float_t delta_frame = 2.0f;
|
|
float_t start_time = (float_t)data.start_time - frame1;
|
|
while (start_time > 0.0f) {
|
|
enum_or(flags, EFFECT_INST_JUST_INIT);
|
|
if (start_time < delta_frame)
|
|
delta_frame -= start_time;
|
|
|
|
if (frame0 >= 0.0f) {
|
|
GetValue(GLT_VAL);
|
|
|
|
mat4 mat;
|
|
vec3 trans = translation;
|
|
mat4_translate(trans.x, trans.y, trans.z, &mat);
|
|
|
|
vec3 rot = rotation;
|
|
vec3 scale;
|
|
vec3_mult_scalar(this->scale, scale_all, scale);
|
|
|
|
mat4_rot(&mat, rot.x, rot.y, rot.z, &mat);
|
|
mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &mat);
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->CtrlInit(GPM_VAL, GLT_VAL, this, delta_frame);
|
|
|
|
if (frame0 < (float_t)data.life_time) {
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Emit(GPM_VAL, GLT_VAL, delta_frame, emission);
|
|
}
|
|
else if (data.flags & EFFECT_LOOP)
|
|
frame0 -= (float_t)data.life_time;
|
|
else
|
|
Free(GPM_VAL, GLT_VAL, emission, false);
|
|
|
|
render_scene.Ctrl(GLT_VAL, delta_frame);
|
|
}
|
|
|
|
frame0 += delta_frame;
|
|
frame1 += delta_frame;
|
|
start_time -= delta_frame;
|
|
}
|
|
|
|
CtrlMat(GPM_VAL, GLT_VAL);
|
|
}
|
|
|
|
void F2EffectInst::CtrlMat(GPM, GLT) {
|
|
if (~flags & EFFECT_INST_JUST_INIT)
|
|
return;
|
|
|
|
vec3 trans = translation;
|
|
vec3 rot = rotation;
|
|
vec3 scale;
|
|
vec3_mult_scalar(this->scale, scale_all, scale);
|
|
|
|
mat4 mat;
|
|
mat4_translate(trans.x, trans.y, trans.z, &mat);
|
|
mat4_rot(&mat, rot.x, rot.y, rot.z, &mat);
|
|
mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &mat);
|
|
this->mat = mat;
|
|
|
|
for (F2EmitterInst*& i : emitters)
|
|
if (i)
|
|
i->CtrlMat(GPM_VAL, GLT_VAL, this);
|
|
|
|
enum_and(flags, ~EFFECT_INST_JUST_INIT);
|
|
}
|
|
|
|
DispType F2EffectInst::GetDispType() {
|
|
if (data.flags & EFFECT_ALPHA)
|
|
return DISP_ALPHA;
|
|
return DISP_NORMAL;
|
|
}
|
|
|
|
void F2EffectInst::GetExtAnim() {
|
|
if (!ext_anim || !data.ext_anim)
|
|
return;
|
|
|
|
if (~flags & EFFECT_INST_HAS_EXT_ANIM || (flags & EFFECT_INST_SET_EXT_ANIM_ONCE
|
|
&& flags & EFFECT_INST_HAS_EXT_ANIM_TRANS))
|
|
return;
|
|
|
|
mat4* obj_mat = 0;
|
|
mat4 temp;
|
|
mat4 mat;
|
|
int32_t chara_id;
|
|
|
|
if (flags & EFFECT_INST_CHARA_ANIM) {
|
|
rob_chara* rob_chr = rob_chara_array_get(ext_anim->chara_index);
|
|
if (!rob_chr)
|
|
return;
|
|
|
|
mat4& mat = rob_chr->data.adjust_data.mat;
|
|
|
|
vec3 scale;
|
|
mat4_get_scale(&mat, &scale);
|
|
vec3_sub_scalar(scale, 1.0f, ext_anim_scale);
|
|
ext_anim_scale.z = 0.0f;
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE);
|
|
|
|
int32_t bone_index = ext_anim->bone_index;
|
|
if (bone_index != -1) {
|
|
mat4* bone_mat = rob_chr->get_bone_data_mat(bone_index);
|
|
if (!bone_mat)
|
|
return;
|
|
|
|
mat4_mult(bone_mat, &mat, &mat);
|
|
}
|
|
|
|
if (flags & EFFECT_INST_EXT_ANIM_TRANS_ONLY) {
|
|
ext_anim->mat = mat4_identity;
|
|
mat4_get_translation(&mat, &ext_anim->translation);
|
|
}
|
|
else
|
|
ext_anim->mat = mat;
|
|
goto SetFlags;
|
|
}
|
|
|
|
if (~flags & EFFECT_INST_GET_EXT_ANIM_MAT) {
|
|
if (ext_anim->mesh_index == -1) {
|
|
if (!ext_anim->mesh_name)
|
|
return;
|
|
|
|
ext_anim->mesh_index = object_storage_get_obj_mesh_index(
|
|
ext_anim->object, ext_anim->mesh_name);
|
|
}
|
|
|
|
if (ext_anim->mesh_index != -1) {
|
|
obj_mesh* mesh = object_storage_get_obj_mesh_by_index(ext_anim->object,
|
|
ext_anim->mesh_index);
|
|
if (mesh) {
|
|
ext_anim->translation = mesh->bounding_sphere.center;
|
|
goto SetFlags;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (ext_anim->a3da_id != -1)
|
|
obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id,
|
|
ext_anim->object_index, ext_anim->object_is_hrc, &temp);
|
|
|
|
if (!obj_mat) {
|
|
ext_anim->a3da_id = auth_3d_data_get_auth_3d_id(ext_anim->object,
|
|
&ext_anim->object_index, &ext_anim->object_is_hrc, 0);
|
|
if (ext_anim->a3da_id == -1)
|
|
return;
|
|
|
|
ext_anim->mesh_index = -1;
|
|
obj_mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id,
|
|
ext_anim->object_index, ext_anim->object_is_hrc, &temp);
|
|
if (!obj_mat)
|
|
return;
|
|
}
|
|
|
|
mat = mat4_identity;
|
|
chara_id = auth_3d_data_get_chara_id(ext_anim->a3da_id);
|
|
if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT) {
|
|
rob_chara* rob_chr = rob_chara_array_get(chara_id);
|
|
if (rob_chr) {
|
|
mat = rob_chr->data.adjust_data.mat;
|
|
|
|
vec3 scale;
|
|
mat4_get_scale(&mat, &scale);
|
|
vec3_sub_scalar(scale, 1.0f, ext_anim_scale);
|
|
ext_anim_scale.z = 0.0f;
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE);
|
|
}
|
|
}
|
|
|
|
if (ext_anim->mesh_name) {
|
|
if (ext_anim->mesh_index == -1)
|
|
ext_anim->mesh_index = object_storage_get_obj_mesh_index(
|
|
ext_anim->object, ext_anim->mesh_name);
|
|
|
|
if (ext_anim->mesh_index != -1) {
|
|
obj_mesh* mesh = object_storage_get_obj_mesh_by_index(
|
|
ext_anim->object, ext_anim->mesh_index);
|
|
if (mesh) {
|
|
mat4_mult(obj_mat, &mat, &mat);
|
|
ext_anim->mat = mat;
|
|
ext_anim->translation = mesh->bounding_sphere.center;
|
|
goto SetFlags;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
mat4_mult(obj_mat, &mat, &mat);
|
|
if (flags & EFFECT_INST_EXT_ANIM_TRANS_ONLY) {
|
|
ext_anim->mat = mat4_identity;
|
|
mat4_get_translation(&mat, &ext_anim->translation);
|
|
}
|
|
else
|
|
ext_anim->mat = mat;
|
|
goto SetFlags;
|
|
}
|
|
return;
|
|
|
|
SetFlags:
|
|
if (flags & EFFECT_INST_HAS_EXT_ANIM_NON_INIT) {
|
|
enum_and(flags, ~EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_TRANS);
|
|
}
|
|
}
|
|
|
|
bool F2EffectInst::GetExtAnimMat(mat4* mat) {
|
|
if (~flags & EFFECT_INST_HAS_EXT_ANIM_TRANS || !ext_anim)
|
|
return false;
|
|
|
|
vec3 trans = ext_anim->translation;
|
|
mat4_translate_mult(&ext_anim->mat, trans.x, trans.y, trans.z, mat);
|
|
return true;
|
|
}
|
|
|
|
FogType F2EffectInst::GetFog() {
|
|
if (data.flags & EFFECT_FOG)
|
|
return Glitter::FOG_DEPTH;
|
|
else if (data.flags & EFFECT_FOG_HEIGHT)
|
|
return Glitter::FOG_HEIGHT;
|
|
return Glitter::FOG_NONE;
|
|
}
|
|
|
|
void F2EffectInst::GetValue(GLT) {
|
|
Animation* anim = &effect->animation;
|
|
size_t length = anim->curves.size();
|
|
for (int32_t i = 0; i < length; i++) {
|
|
Curve* curve = anim->curves.data()[i];
|
|
float_t value;
|
|
if (!curve->F2GetValue(GLT_VAL, frame0,
|
|
&value, random + i, random_ptr))
|
|
continue;
|
|
|
|
switch (curve->type) {
|
|
case CURVE_TRANSLATION_X:
|
|
translation.x = value;
|
|
break;
|
|
case CURVE_TRANSLATION_Y:
|
|
translation.y = value;
|
|
break;
|
|
case CURVE_TRANSLATION_Z:
|
|
translation.z = value;
|
|
break;
|
|
case CURVE_ROTATION_X:
|
|
rotation.x = value;
|
|
break;
|
|
case CURVE_ROTATION_Y:
|
|
rotation.y = value;
|
|
break;
|
|
case CURVE_ROTATION_Z:
|
|
rotation.z = value;
|
|
break;
|
|
case CURVE_SCALE_X:
|
|
scale.x = value;
|
|
break;
|
|
case CURVE_SCALE_Y:
|
|
scale.y = value;
|
|
break;
|
|
case CURVE_SCALE_Z:
|
|
scale.z = value;
|
|
break;
|
|
case CURVE_SCALE_ALL:
|
|
scale_all = value;
|
|
break;
|
|
//case CURVE_COLOR_R:
|
|
// color.x = value;
|
|
// break;
|
|
//case CURVE_COLOR_G:
|
|
// color.y = value;
|
|
// break;
|
|
//case CURVE_COLOR_B:
|
|
// color.z = value;
|
|
// break;
|
|
//case CURVE_COLOR_A:
|
|
// color.w = value;
|
|
// break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void F2EffectInst::SetMinColor(float_t& r, float_t& g, float_t& b, float_t& a) {
|
|
if (~flags & EFFECT_INST_SET_ADD_MIN_COLOR)
|
|
return;
|
|
|
|
if (flags & EFFECT_INST_SET_MIN_COLOR) {
|
|
if (min_color.x >= 0.0f)
|
|
r = min_color.x;
|
|
if (min_color.y >= 0.0f)
|
|
g = min_color.y;
|
|
if (min_color.z >= 0.0f)
|
|
b = min_color.z;
|
|
if (min_color.w >= 0.0f)
|
|
a = min_color.w;
|
|
}
|
|
else {
|
|
r = min_color.x + r;
|
|
g = min_color.y + g;
|
|
b = min_color.z + b;
|
|
a = min_color.w + a;
|
|
}
|
|
|
|
if (r < 0.0f)
|
|
r = 0.0f;
|
|
if (g < 0.0f)
|
|
g = 0.0f;
|
|
if (b < 0.0f)
|
|
b = 0.0f;
|
|
if (a < 0.0f)
|
|
a = 0.0f;
|
|
}
|
|
|
|
int32_t EffectInst::GetExtAnimBoneIndex(EffectExtAnimCharaNode node) {
|
|
if (node < EFFECT_EXT_ANIM_CHARA_HEAD || node > EFFECT_EXT_ANIM_CHARA_RIGHT_TOE)
|
|
return -1;
|
|
|
|
bone_database* bone_data = (bone_database*)GPM_VAL.bone_data;
|
|
std::vector<std::string>* motion_bone_names = 0;
|
|
if (!bone_data || bone_data->skeleton.size() < 1
|
|
|| !bone_data->get_skeleton_motion_bones(
|
|
bone_database_skeleton_type_to_string(BONE_DATABASE_SKELETON_COMMON), &motion_bone_names))
|
|
return -1;
|
|
|
|
static const char* bone_names[] = {
|
|
"face_root",
|
|
"n_kuti_u",
|
|
"n_hara_cp",
|
|
"e_mune_cp",
|
|
"c_kata_l",
|
|
"j_ude_l_wj",
|
|
"e_ude_l_cp",
|
|
"n_naka_l_ex",
|
|
"c_kata_r",
|
|
"j_ude_r_wj",
|
|
"e_ude_r_cp",
|
|
"n_naka_r_ex",
|
|
"n_momo_c_l_wj_ex",
|
|
"n_hiza_l_wj_ex",
|
|
"kl_toe_l_wj",
|
|
"n_momo_c_r_wj_ex",
|
|
"n_hiza_r_wj_ex",
|
|
"kl_toe_r_wj"
|
|
};
|
|
|
|
uint64_t bone_name_hash = hash_utf8_fnv1a64m(bone_names[node]);
|
|
for (std::string& i : *motion_bone_names)
|
|
if (bone_name_hash == hash_string_fnv1a64m(i))
|
|
return (int32_t)(&i - motion_bone_names->data());
|
|
return -1;
|
|
}
|
|
|
|
XEffectInst::ExtAnim::ExtAnim() {
|
|
object_index = -1;
|
|
mesh_index = -1;
|
|
a3da_id = -1;
|
|
object_is_hrc = false;
|
|
file_name_hash = hash_murmurhash_empty;
|
|
object_hash = hash_murmurhash_empty;
|
|
instance_id = 0;
|
|
mesh_name = 0;
|
|
mat = mat4_identity;
|
|
translation = vec3_null;
|
|
}
|
|
|
|
XEffectInst::ExtAnim::~ExtAnim() {
|
|
|
|
}
|
|
|
|
XEffectInst::XEffectInst(GPM, Effect* eff,
|
|
size_t id, float_t emission, bool appear_now)
|
|
: EffectInst(GPM_VAL, Glitter::X, eff, id, emission, appear_now) {
|
|
mat_rot = mat4_identity;
|
|
mat_rot_eff_rot = mat4_identity;
|
|
random_shared.XReset();
|
|
ext_anim = 0;
|
|
render_scene = {};
|
|
|
|
if (data.flags & EFFECT_USE_SEED)
|
|
random = data.seed;
|
|
else
|
|
random = GPM_VAL->CounterGet();
|
|
random_shared.value = random;
|
|
|
|
if (~eff->data.flags & EFFECT_LOCAL && data.ext_anim_x) {
|
|
XEffectInst::ExtAnim* inst_ext_anim = new XEffectInst::ExtAnim;
|
|
if (inst_ext_anim) {
|
|
Effect::ExtAnimX* ext_anim = data.ext_anim_x;
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_SET_ONCE)
|
|
enum_or(flags, EFFECT_INST_SET_EXT_ANIM_ONCE);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_TRANS_ONLY)
|
|
enum_or(flags, EFFECT_INST_EXT_ANIM_TRANS_ONLY);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_NO_TRANS_X)
|
|
enum_or(flags, EFFECT_INST_NO_EXT_ANIM_TRANS_X);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_NO_TRANS_Y)
|
|
enum_or(flags, EFFECT_INST_NO_EXT_ANIM_TRANS_Y);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_NO_TRANS_Z)
|
|
enum_or(flags, EFFECT_INST_NO_EXT_ANIM_TRANS_Z);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_GET_THEN_UPDATE)
|
|
enum_or(flags, EFFECT_INST_GET_EXT_ANIM_THEN_UPDATE);
|
|
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM) {
|
|
inst_ext_anim->chara_index = ext_anim->chara_index;
|
|
inst_ext_anim->bone_index = GetExtAnimBoneIndex(ext_anim->node_index);
|
|
enum_or(flags, EFFECT_INST_CHARA_ANIM);
|
|
}
|
|
else {
|
|
inst_ext_anim->object_hash = ext_anim->object_hash;
|
|
inst_ext_anim->file_name_hash = ext_anim->file_name_hash;
|
|
inst_ext_anim->instance_id = ext_anim->instance_id;
|
|
}
|
|
|
|
if (ext_anim->mesh_name[0])
|
|
inst_ext_anim->mesh_name = ext_anim->mesh_name;
|
|
else
|
|
inst_ext_anim->mesh_name = 0;
|
|
}
|
|
ext_anim = inst_ext_anim;
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM);
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
enum_or(flags, EFFECT_INST_GET_EXT_ANIM_MAT);
|
|
}
|
|
|
|
emitters.reserve(eff->emitters.size());
|
|
for (Emitter*& i : eff->emitters) {
|
|
if (!i)
|
|
continue;
|
|
|
|
XEmitterInst* emitter = new XEmitterInst(i, this, emission);
|
|
if (emitter)
|
|
emitters.push_back(emitter);
|
|
}
|
|
|
|
CtrlInit(GPM_VAL, emission);
|
|
}
|
|
|
|
XEffectInst::~XEffectInst() {
|
|
for (XEmitterInst*& i : emitters)
|
|
delete i;
|
|
|
|
delete ext_anim;
|
|
}
|
|
|
|
void XEffectInst::Copy(EffectInst* dst, float_t emission) {
|
|
dst->frame0 = frame0;
|
|
dst->frame1 = frame1;
|
|
dst->color = color;
|
|
dst->translation = translation;
|
|
dst->rotation = rotation;
|
|
dst->scale = scale;
|
|
dst->mat = mat;
|
|
dst->mat = mat_rot;
|
|
dst->random = random;
|
|
|
|
XEffectInst* x_dst = dynamic_cast<XEffectInst*>(dst);
|
|
if (x_dst && emitters.size() == x_dst->emitters.size()) {
|
|
x_dst->mat_rot_eff_rot = mat_rot_eff_rot;
|
|
|
|
size_t count = emitters.size();
|
|
for (size_t i = 0; i < count; i++)
|
|
emitters.data()[i]->Copy(x_dst->emitters.data()[i], emission);
|
|
}
|
|
}
|
|
|
|
void XEffectInst::Ctrl(GPM, GLT, float_t delta_frame, float_t emission) {
|
|
GetExtAnim();
|
|
if (flags & EFFECT_INST_GET_EXT_ANIM_THEN_UPDATE && !GPM_VAL->draw_all)
|
|
return;
|
|
|
|
GetValue();
|
|
|
|
vec3 rot = rotation;
|
|
|
|
mat4 mat;
|
|
if (GetExtAnimMat(&mat)) {
|
|
mat4_normalize_rotation(&mat, &mat_rot);
|
|
mat4_clear_trans(&mat_rot, &mat_rot);
|
|
mat4_rotate_mult(&mat_rot, rot.x, rot.y, rot.z, &mat_rot_eff_rot);
|
|
|
|
vec3 trans = translation;
|
|
mat4_translate_mult(&mat, trans.x, trans.y, trans.z, &mat);
|
|
}
|
|
else {
|
|
mat_rot = mat4_identity;
|
|
mat4_rotate(rot.x, rot.y, rot.z, &mat_rot_eff_rot);
|
|
|
|
vec3 trans = translation;
|
|
mat4_translate(trans.x, trans.y, trans.z, &mat);
|
|
}
|
|
|
|
vec3 scale;
|
|
vec3_mult_scalar(this->scale, scale_all, scale);
|
|
|
|
mat4_rot(&mat, rot.x, rot.y, rot.z, &mat);
|
|
mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &this->mat);
|
|
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Ctrl(GPM_VAL, this, delta_frame);
|
|
|
|
if (frame0 >= 0.0f)
|
|
if (frame0 < (float_t)data.life_time) {
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Emit(delta_frame, emission);
|
|
}
|
|
else if (data.flags & EFFECT_LOOP)
|
|
frame0 -= (float_t)data.life_time;
|
|
else
|
|
Free(GPM_VAL, GLT_VAL, emission, false);
|
|
|
|
render_scene.Ctrl(delta_frame, true);
|
|
frame0 += delta_frame;
|
|
}
|
|
|
|
void XEffectInst::Disp(GPM, DispType disp_type) {
|
|
render_scene.Disp(GPM_VAL, disp_type);
|
|
}
|
|
|
|
void XEffectInst::Free(GPM, GLT, float_t emission, bool free) {
|
|
enum_or(flags, EFFECT_INST_FREE);
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Free(emission, free);
|
|
}
|
|
|
|
size_t XEffectInst::GetCtrlCount(ParticleType type) {
|
|
return render_scene.GetCtrlCount(type);
|
|
}
|
|
|
|
size_t XEffectInst::GetDispCount(ParticleType type) {
|
|
return render_scene.GetDispCount(type);
|
|
}
|
|
|
|
bool XEffectInst::HasEnded(bool a2) {
|
|
if (~flags & EFFECT_INST_FREE)
|
|
return false;
|
|
else if (!a2)
|
|
return true;
|
|
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i && !i->HasEnded(a2))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void XEffectInst::Reset(GPM, GLT, float_t emission) {
|
|
frame0 = -(float_t)data.appear_time;
|
|
frame1 = 0.0;
|
|
|
|
flags = (EffectInstFlag)0;
|
|
if (~data.flags & EFFECT_LOCAL && data.ext_anim_x) {
|
|
if (ext_anim) {
|
|
Effect::ExtAnimX* ext_anim = data.ext_anim_x;
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_SET_ONCE)
|
|
enum_or(flags, EFFECT_INST_SET_EXT_ANIM_ONCE);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_TRANS_ONLY)
|
|
enum_or(flags, EFFECT_INST_EXT_ANIM_TRANS_ONLY);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_NO_TRANS_X)
|
|
enum_or(flags, EFFECT_INST_NO_EXT_ANIM_TRANS_X);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_NO_TRANS_Y)
|
|
enum_or(flags, EFFECT_INST_NO_EXT_ANIM_TRANS_Y);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_NO_TRANS_Z)
|
|
enum_or(flags, EFFECT_INST_NO_EXT_ANIM_TRANS_Z);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_GET_THEN_UPDATE)
|
|
enum_or(flags, EFFECT_INST_GET_EXT_ANIM_THEN_UPDATE);
|
|
if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM)
|
|
enum_or(flags, EFFECT_INST_CHARA_ANIM);
|
|
}
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM);
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
enum_or(flags, EFFECT_INST_GET_EXT_ANIM_MAT);
|
|
}
|
|
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Reset();
|
|
|
|
CtrlInit(GPM_VAL, emission);
|
|
}
|
|
|
|
void XEffectInst::CalcDisp(GPM) {
|
|
render_scene.CalcDisp(GPM_VAL);
|
|
}
|
|
|
|
void XEffectInst::CtrlInit(GPM, float_t emission) {
|
|
if (data.start_time < 1)
|
|
return;
|
|
|
|
float_t delta_frame = 2.0f;
|
|
float_t start_time = (float_t)data.start_time - frame1;
|
|
while (start_time > 0.0f) {
|
|
enum_or(flags, EFFECT_INST_JUST_INIT);
|
|
if (start_time < delta_frame)
|
|
delta_frame -= start_time;
|
|
|
|
if (frame0 >= 0.0f) {
|
|
GetValue();
|
|
|
|
vec3 trans = translation;
|
|
vec3 rot = rotation;
|
|
vec3 scale;
|
|
vec3_mult_scalar(this->scale, scale_all, scale);
|
|
|
|
mat4 mat;
|
|
mat4_translate(trans.x, trans.y, trans.z, &mat);
|
|
mat4_rot(&mat, rot.x, rot.y, rot.z, &mat);
|
|
mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &mat);
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->CtrlInit(this, delta_frame);
|
|
|
|
if (frame0 < (float_t)data.life_time) {
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Emit(delta_frame, emission);
|
|
}
|
|
else if (data.flags & EFFECT_LOOP)
|
|
frame0 -= (float_t)data.life_time;
|
|
else {
|
|
enum_or(flags, EFFECT_INST_FREE);
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->Emit(emission, false);
|
|
}
|
|
|
|
render_scene.Ctrl(delta_frame, false);
|
|
}
|
|
|
|
frame0 += delta_frame;
|
|
frame1 += delta_frame;
|
|
start_time -= delta_frame;
|
|
}
|
|
|
|
CtrlMat(GPM_VAL);
|
|
}
|
|
|
|
void XEffectInst::CtrlMat(GPM) {
|
|
if (~flags & EFFECT_INST_JUST_INIT)
|
|
return;
|
|
|
|
vec3 trans = translation;
|
|
vec3 rot = rotation;
|
|
vec3 scale;
|
|
vec3_mult_scalar(this->scale, scale_all, scale);
|
|
|
|
mat4 mat;
|
|
mat4_translate(trans.x, trans.y, trans.z, &mat);
|
|
mat4_rot(&mat, rot.x, rot.y, rot.z, &mat);
|
|
mat4_scale_rot(&mat, scale.x, scale.y, scale.z, &mat);
|
|
this->mat = mat;
|
|
|
|
for (XEmitterInst*& i : emitters)
|
|
if (i)
|
|
i->CtrlMat(GPM_VAL, this);
|
|
|
|
enum_and(flags, ~EFFECT_INST_JUST_INIT);
|
|
}
|
|
|
|
DispType XEffectInst::GetDispType() {
|
|
if (data.flags & EFFECT_ALPHA)
|
|
return DISP_ALPHA;
|
|
return DISP_NORMAL;
|
|
}
|
|
|
|
void XEffectInst::GetExtAnim() {
|
|
if (!ext_anim || !data.ext_anim_x)
|
|
return;
|
|
|
|
if (~flags & EFFECT_INST_HAS_EXT_ANIM || (flags & EFFECT_INST_SET_EXT_ANIM_ONCE
|
|
&& flags & EFFECT_INST_HAS_EXT_ANIM_TRANS))
|
|
return;
|
|
|
|
bool set_flags = false;
|
|
|
|
if (data.ext_anim_x->flags & EFFECT_INST_CHARA_ANIM)
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
|
|
if (flags & EFFECT_INST_CHARA_ANIM) {
|
|
rob_chara* rob_chr = rob_chara_array_get(ext_anim->chara_index);
|
|
if (!rob_chr)
|
|
return;
|
|
|
|
mat4& mat = rob_chr->data.adjust_data.mat;
|
|
|
|
vec3 scale;
|
|
mat4_get_scale(&rob_chr->data.adjust_data.mat, &scale);
|
|
vec3_sub_scalar(scale, 1.0f, ext_anim_scale);
|
|
ext_anim_scale.z = 0.0f;
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE);
|
|
|
|
if (rob_chr->data.field_0 & 0x01 || ~data.ext_anim_x->flags & EFFECT_EXT_ANIM_NO_DRAW_IF_NO_DATA)
|
|
set_flags = true;
|
|
else
|
|
set_flags = false;
|
|
|
|
int32_t bone_index = ext_anim->bone_index;
|
|
if (bone_index != -1) {
|
|
mat4* bone_mat = rob_chr->get_bone_data_mat(bone_index);
|
|
if (bone_mat)
|
|
SetExtAnim(&mat, bone_mat, 0, set_flags);
|
|
}
|
|
else
|
|
SetExtAnim(&mat, 0, 0, set_flags);
|
|
}
|
|
else if (flags & EFFECT_INST_GET_EXT_ANIM_MAT) {
|
|
mat4 m = mat4_identity;
|
|
mat4 temp;
|
|
mat4* mat = 0;
|
|
if (ext_anim->a3da_id != -1)
|
|
mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id,
|
|
ext_anim->object_index, ext_anim->object_is_hrc, &temp);
|
|
|
|
if (!mat) {
|
|
ext_anim->a3da_id = auth_3d_data_get_auth_3d_id(
|
|
ext_anim->file_name_hash, ext_anim->object_hash,
|
|
&ext_anim->object_index, &ext_anim->object_is_hrc, ext_anim->instance_id);
|
|
if (ext_anim->a3da_id == -1)
|
|
return;
|
|
|
|
ext_anim->mesh_index = -1;
|
|
mat = auth_3d_data_get_auth_3d_object_mat(ext_anim->a3da_id,
|
|
ext_anim->object_index, ext_anim->object_is_hrc, &temp);
|
|
if (!mat)
|
|
return;
|
|
}
|
|
|
|
int32_t chara_id = auth_3d_data_get_chara_id(ext_anim->a3da_id);
|
|
if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT) {
|
|
rob_chara* rob_chr = rob_chara_array_get(chara_id);
|
|
if (rob_chr) {
|
|
vec3 trans = rob_chr->data.adjust_data.trans;
|
|
mat4_translate(trans.x, trans.y, trans.z, &m);
|
|
|
|
vec3 scale;
|
|
mat4_get_scale(&rob_chr->data.adjust_data.mat, &scale);
|
|
vec3_sub_scalar(scale, 1.0f, ext_anim_scale);
|
|
ext_anim_scale.z = 0.0f;
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_SCALE);
|
|
}
|
|
}
|
|
|
|
if (ext_anim->mesh_name) {
|
|
if (ext_anim->mesh_index == -1)
|
|
ext_anim->mesh_index = object_storage_get_obj_mesh_index_by_hash(
|
|
ext_anim->object_hash, ext_anim->mesh_name);
|
|
|
|
if (ext_anim->mesh_index != -1) {
|
|
obj_mesh* mesh = object_storage_get_obj_mesh_by_object_hash_index(
|
|
ext_anim->object_hash, ext_anim->mesh_index);
|
|
if (mesh) {
|
|
vec3* trans = &mesh->bounding_sphere.center;
|
|
SetExtAnim(&m, mat, trans, true);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
SetExtAnim(&m, mat, 0, true);
|
|
|
|
}
|
|
else if (ext_anim->object_hash != hash_murmurhash_empty) {
|
|
if (ext_anim->mesh_index == -1) {
|
|
if (!ext_anim->mesh_name)
|
|
return;
|
|
|
|
ext_anim->mesh_index = object_storage_get_obj_mesh_index_by_hash(
|
|
ext_anim->object_hash, ext_anim->mesh_name);
|
|
}
|
|
|
|
if (ext_anim->mesh_index != -1) {
|
|
obj_mesh* mesh = object_storage_get_obj_mesh_by_object_hash_index(
|
|
ext_anim->object_hash, ext_anim->mesh_index);
|
|
if (mesh) {
|
|
vec3* trans = &mesh->bounding_sphere.center;
|
|
SetExtAnim(0, 0, trans, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool XEffectInst::GetExtAnimMat(mat4* mat) {
|
|
if (~flags & EFFECT_INST_HAS_EXT_ANIM_TRANS || !ext_anim)
|
|
return false;
|
|
|
|
vec3 trans = ext_anim->translation;
|
|
mat4_translate_mult(&ext_anim->mat, trans.x, trans.y, trans.z, mat);
|
|
return true;
|
|
}
|
|
|
|
FogType XEffectInst::GetFog() {
|
|
if (data.flags & EFFECT_FOG)
|
|
return Glitter::FOG_DEPTH;
|
|
else if (data.flags & EFFECT_FOG_HEIGHT)
|
|
return Glitter::FOG_HEIGHT;
|
|
return Glitter::FOG_NONE;
|
|
}
|
|
|
|
void XEffectInst::GetValue() {
|
|
Animation* anim = &effect->animation;
|
|
size_t length = anim->curves.size();
|
|
for (int32_t i = 0; i < length; i++) {
|
|
Curve* curve = anim->curves.data()[i];
|
|
float_t value;
|
|
if (!curve->XGetValue(frame0, &value, random + i, &random_shared))
|
|
continue;
|
|
|
|
switch (curve->type) {
|
|
case CURVE_TRANSLATION_X:
|
|
translation.x = value;
|
|
break;
|
|
case CURVE_TRANSLATION_Y:
|
|
translation.y = value;
|
|
break;
|
|
case CURVE_TRANSLATION_Z:
|
|
translation.z = value;
|
|
break;
|
|
case CURVE_ROTATION_X:
|
|
rotation.x = value;
|
|
break;
|
|
case CURVE_ROTATION_Y:
|
|
rotation.y = value;
|
|
break;
|
|
case CURVE_ROTATION_Z:
|
|
rotation.z = value;
|
|
break;
|
|
case CURVE_SCALE_X:
|
|
scale.x = value;
|
|
break;
|
|
case CURVE_SCALE_Y:
|
|
scale.y = value;
|
|
break;
|
|
case CURVE_SCALE_Z:
|
|
scale.z = value;
|
|
break;
|
|
case CURVE_SCALE_ALL:
|
|
scale_all = value;
|
|
break;
|
|
//case CURVE_COLOR_R:
|
|
// color.x = value;
|
|
// break;
|
|
//case CURVE_COLOR_G:
|
|
// color.y = value;
|
|
// break;
|
|
//case CURVE_COLOR_B:
|
|
// color.z = value;
|
|
// break;
|
|
//case CURVE_COLOR_A:
|
|
// color.w = value;
|
|
// break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void XEffectInst::SetExtAnim(mat4* a2, mat4* a3, vec3* trans, bool set_flags) {
|
|
EffectInstFlag flags = this->flags;
|
|
if (a2) {
|
|
mat4 mat = *a2;
|
|
if (a3)
|
|
mat4_mult(a3, &mat, &mat);
|
|
|
|
if (flags & EFFECT_INST_EXT_ANIM_TRANS_ONLY) {
|
|
ext_anim->mat = mat4_identity;
|
|
mat4_get_translation(&mat, &ext_anim->translation);
|
|
}
|
|
else
|
|
ext_anim->mat = mat;
|
|
}
|
|
|
|
if (flags & EFFECT_INST_NO_EXT_ANIM_TRANS_X) {
|
|
ext_anim->mat.row3.x = 0.0f;
|
|
ext_anim->translation.x = 0.0f;
|
|
}
|
|
else if (trans)
|
|
ext_anim->translation.x = trans->x;
|
|
|
|
if (flags & EFFECT_INST_NO_EXT_ANIM_TRANS_Y) {
|
|
ext_anim->mat.row3.y = 0.0f;
|
|
ext_anim->translation.y = 0.0f;
|
|
}
|
|
else if (trans)
|
|
ext_anim->translation.y = trans->y;
|
|
|
|
if (flags & EFFECT_INST_NO_EXT_ANIM_TRANS_Z) {
|
|
ext_anim->mat.row3.z = 0.0f;
|
|
ext_anim->translation.z = 0.0f;
|
|
}
|
|
else if (trans)
|
|
ext_anim->translation.z = trans->z;
|
|
|
|
if (set_flags) {
|
|
if (flags & EFFECT_INST_GET_EXT_ANIM_THEN_UPDATE)
|
|
enum_and(flags, ~EFFECT_INST_GET_EXT_ANIM_THEN_UPDATE);
|
|
if (flags & EFFECT_INST_HAS_EXT_ANIM_NON_INIT)
|
|
enum_and(flags, ~EFFECT_INST_HAS_EXT_ANIM_NON_INIT);
|
|
}
|
|
enum_or(flags, EFFECT_INST_HAS_EXT_ANIM_TRANS);
|
|
this->flags = flags;
|
|
}
|
|
|
|
void XEffectInst::SetMinColor(float_t& r, float_t& g, float_t& b, float_t& a) {
|
|
if (~flags & EFFECT_INST_SET_ADD_MIN_COLOR)
|
|
return;
|
|
|
|
if (flags & EFFECT_INST_SET_MIN_COLOR) {
|
|
if (min_color.x >= 0.0f)
|
|
r = min_color.x;
|
|
if (min_color.y >= 0.0f)
|
|
g = min_color.y;
|
|
if (min_color.z >= 0.0f)
|
|
b = min_color.z;
|
|
if (min_color.w >= 0.0f)
|
|
a = min_color.w;
|
|
}
|
|
else {
|
|
if (min_color.x >= 0.0f)
|
|
r *= min_color.x;
|
|
if (min_color.y >= 0.0f)
|
|
g *= min_color.y;
|
|
if (min_color.z >= 0.0f)
|
|
b *= min_color.z;
|
|
if (min_color.w >= 0.0f)
|
|
a *= min_color.w;
|
|
}
|
|
|
|
if (r < 0.0f)
|
|
r = 0.0f;
|
|
if (g < 0.0f)
|
|
g = 0.0f;
|
|
if (b < 0.0f)
|
|
b = 0.0f;
|
|
if (a < 0.0f)
|
|
a = 0.0f;
|
|
}
|
|
}
|