Files
korenkonder_ReDIVA/src/CRE/Glitter/render_group.cpp
T

742 lines
23 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#include "glitter.hpp"
namespace Glitter {
RenderGroup::RenderGroup() : flags(), type(), draw_type(), pivot(), z_offset(),
count(), ctrl(), disp(), texture(), mask_texture(), frame(), elements(),
buffer(), max_count(), random_ptr(), disp_type(), fog_type(), vao() {
split_u = 1;
split_v = 1;
split_uv = 1.0f;
mat = mat4_identity;
mat_rot = mat4_identity;
mat_draw = mat4_identity;
disp_type = DISP_NORMAL;
emission = 1.0f;
#if !SHARED_GLITTER_BUFFER
use_own_buffer = true;
#endif
blend_mode = PARTICLE_BLEND_TYPICAL;
mask_blend_mode = PARTICLE_BLEND_TYPICAL;
}
RenderGroup::~RenderGroup() {
}
RenderElement* RenderGroup::AddElement(RenderElement* rend_elem) {
if (!rend_elem)
rend_elem = elements;
size_t left_count = count - (rend_elem - elements);
size_t index = 0;
if (left_count < 1)
return 0;
while (rend_elem->alive) {
index++;
rend_elem++;
if (index >= left_count)
return 0;
}
rend_elem->alive = true;
ctrl++;
return rend_elem;
}
F2RenderGroup::F2RenderGroup(F2ParticleInst* ptcl_inst) : particle() {
switch (ptcl_inst->data.data.type) {
case PARTICLE_QUAD:
case PARTICLE_LINE:
case PARTICLE_LOCUS:
break;
default:
return;
}
if (ptcl_inst->data.data.count > 0)
count = ptcl_inst->data.data.count;
else
count = ptcl_inst->data.data.type == PARTICLE_LOCUS ? 30 : 250;
max_count = count * 4;
random_ptr = ptcl_inst->data.random_ptr;
particle = ptcl_inst;
elements = new RenderElement[count];
if (!elements || !ptcl_inst) {
count = 0;
max_count = 0;
return;
}
memset(elements, 0, sizeof(RenderElement) * count);
if (!max_count)
return;
bool is_quad = ptcl_inst->data.data.type == PARTICLE_QUAD;
Particle* ptcl = particle->data.particle;
if (ptcl && ptcl->buffer && !ptcl->buffer_used) {
buffer = ptcl->buffer;
max_count = ptcl->max_count;
vao = ptcl->vao;
#if !SHARED_GLITTER_BUFFER
vbo = ptcl->vbo;
ebo = ptcl->ebo;
use_own_buffer = false;
#endif
ptcl->buffer_used = true;
}
#if !SHARED_GLITTER_BUFFER
if (use_own_buffer)
CreateBuffer(max_count, is_quad, buffer, vao, vbo, ebo);
#endif
if (!is_quad)
draw_list.reserve(count);
}
F2RenderGroup::~F2RenderGroup() {
DeleteBuffers(false);
}
bool F2RenderGroup::CannotDisp() {
if (!particle)
return true;
else if (particle->data.effect)
return (particle->data.effect->flags & EFFECT_INST_EXT_ANIM_NON_INIT) != 0;
else if ((particle = particle->data.parent) && particle->data.effect)
return (particle->data.effect->flags & EFFECT_INST_EXT_ANIM_NON_INIT) != 0;
else
return true;
}
void F2RenderGroup::Copy(F2RenderGroup* dst) {
dst->flags = flags;
dst->type = type;
dst->draw_type = draw_type;
dst->blend_mode = blend_mode;
dst->mask_blend_mode = mask_blend_mode;
dst->pivot = pivot;
dst->split_u = split_u;
dst->split_v = split_v;
dst->split_uv = split_uv;
dst->z_offset = z_offset;
if (dst->count > count)
dst->count = count;
dst->ctrl = ctrl;
dst->texture = texture;
dst->mask_texture = mask_texture;
dst->frame = frame;
dst->mat = mat;
dst->mat_rot = mat_rot;
dst->mat_draw = mat_draw;
if (dst->count == count) {
memmove(dst->elements, elements, sizeof(RenderElement) * dst->count);
dst->ctrl = ctrl;
}
}
void F2RenderGroup::Ctrl(GLT, float_t delta_frame, bool copy_mats) {
if (!particle)
return;
Particle::Data* ptcl_data = &particle->data.data;
blend_mode = ptcl_data->blend_mode;
mask_blend_mode = ptcl_data->mask_blend_mode;
texture = ptcl_data->texture;
mask_texture = ptcl_data->mask_texture;
split_u = ptcl_data->split_u;
split_v = ptcl_data->split_v;
split_uv = ptcl_data->split_uv;
type = ptcl_data->type;
draw_type = ptcl_data->draw_type;
z_offset = ptcl_data->z_offset;
pivot = ptcl_data->pivot;
flags = ptcl_data->flags;
name.assign(ptcl_data->name);
if (copy_mats && particle->data.emitter) {
F2EmitterInst* emitter = particle->data.emitter;
mat = emitter->mat;
mat_rot = emitter->mat_rot;
}
for (size_t ctrl = this->ctrl, i = 0; ctrl; i++) {
if (!elements[i].alive)
continue;
CtrlParticle(GLT_VAL, &elements[i], delta_frame);
ctrl--;
}
frame += delta_frame;
}
void F2RenderGroup::CtrlParticle(GLT, Glitter::RenderElement* rend_elem, float_t delta_frame) {
if (!particle || (particle->data.data.flags & PARTICLE_LOOP
&& particle->HasEnded(false)) || rend_elem->frame >= rend_elem->life_time) {
rend_elem->alive = false;
if (rend_elem->locus_history) {
delete rend_elem->locus_history;
rend_elem->locus_history = 0;
}
ctrl--;
return;
}
particle->AccelerateParticle(GLT_VAL, rend_elem,
rend_elem->frame * (float_t)(1.0 / 60.0), delta_frame, random_ptr);
if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION)
rend_elem->rotation += rend_elem->rotation_add * delta_frame;
else
rend_elem->rotation.z += rend_elem->rotation_add.z * delta_frame;
rend_elem->uv_scroll += particle->data.data.uv_scroll_add
* (particle->data.data.uv_scroll_add_scale * delta_frame);
particle->StepUVParticle(GLT_VAL, rend_elem, delta_frame, random_ptr);
rend_elem->disp = true;
rend_elem->color = -1.0f;
bool disp = true;
if (particle->data.data.sub_flags & PARTICLE_SUB_USE_CURVE)
disp = particle->GetValue(GLT_VAL, rend_elem, rend_elem->frame, random_ptr);
if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION
|| fabsf(rend_elem->rotation.z) <= 0.000001f) {
rend_elem->rot_z_cos = 1.0f;
rend_elem->rot_z_sin = 0.0f;
}
else {
rend_elem->rot_z_cos = cosf(rend_elem->rotation.z);
rend_elem->rot_z_sin = sinf(rend_elem->rotation.z);
}
if (disp)
particle->GetColor(rend_elem);
if (particle->data.data.type == PARTICLE_LOCUS)
rend_elem->locus_history->Append(rend_elem, particle);
rend_elem->frame += delta_frame;
if (particle->data.data.flags & PARTICLE_LOOP && rend_elem->frame >= rend_elem->life_time)
rend_elem->frame -= rend_elem->life_time;
}
void F2RenderGroup::DeleteBuffers(bool free) {
Particle* ptcl = 0;
if (particle) {
ptcl = particle->data.particle;
if (!free)
particle->data.render_group = 0;
particle = 0;
}
#if SHARED_GLITTER_BUFFER
if (ptcl && ptcl->buffer)
ptcl->buffer_used = false;
#else
if (use_own_buffer)
Glitter::DeleteBuffer(buffer, vao, vbo, ebo);
else if (ptcl && ptcl->buffer)
ptcl->buffer_used = false;
#endif
if (!free && elements) {
Free();
delete[] elements;
elements = 0;
}
}
void F2RenderGroup::Emit(GPM, GLT, Particle::Data* ptcl_data,
F2EmitterInst* emit_inst, int32_t dup_count, int32_t count) {
RenderElement* element = 0;
for (int32_t i = 0; i < dup_count; i++)
for (int32_t index = 0; index < count; index++, element++) {
element = AddElement(element);
if (!element)
break;
particle->EmitParticle(GPM_VAL, GLT_VAL,
element, emit_inst, ptcl_data, index, random_ptr);
}
}
void F2RenderGroup::Free() {
if (count <= 0) {
ctrl = 0;
return;
}
RenderElement* elem = elements;
for (size_t i = count; i; i--, elem++) {
elem->alive = false;
if (elem->locus_history) {
delete elem->locus_history;
elem->locus_history = 0;
}
}
ctrl = 0;
}
void F2RenderGroup::FreeData() {
DeleteBuffers(true);
}
bool F2RenderGroup::GetExtAnimScale(vec3* ext_anim_scale, float_t* ext_scale) {
if (particle)
particle->GetExtAnimScale(ext_anim_scale, ext_scale);
return false;
}
mat4 F2RenderGroup::RotateToEmitPosition(F2RenderGroup* rend_group,
RenderElement* rend_elem, vec3* vec) {
vec3 vec2;
if (rend_group->flags & PARTICLE_EMITTER_LOCAL)
vec2 = rend_elem->translation;
else {
mat4_get_translation(&rend_group->mat, &vec2);
vec2 -= rend_elem->translation;
}
vec2 = vec3::normalize(vec2);
mat4 mat;
if (fabsf(vec2.y) >= 0.000001f) {
mat = mat4_identity;
vec3 vec1 = *vec;
vec3 axis;
float_t angle;
axis_angle_from_vectors(axis, angle, vec1, vec2);
mat4_mul_rotation(&mat, &axis, angle, &mat);
}
else
mat4_rotate_z((float_t)M_PI, &mat);
return mat;
}
mat4 F2RenderGroup::RotateToPrevPosition(F2RenderGroup* rend_group,
RenderElement* rend_elem, vec3* vec) {
vec3 vec2 = rend_elem->translation - rend_elem->translation_prev;
if (vec3::length_squared(vec2) < 0.000001f)
vec2 = vec3::normalize(rend_elem->translation);
else
vec2 = vec3::normalize(vec2);
mat4 mat;
mat4_rotate_z((float_t)M_PI, &mat);
if (fabsf(vec2.y) >= 0.000001f) {
vec3 vec1 = *vec;
vec3 axis;
float_t angle;
axis_angle_from_vectors(axis, angle, vec1, vec2);
mat4_mul_rotation(&mat, &axis, angle, &mat);
}
return mat;
}
XRenderGroup::XRenderGroup(XParticleInst* ptcl_inst) : particle(), use_culling(), use_camera() {
object_name_hash = hash_murmurhash_empty;
switch (ptcl_inst->data.data.type) {
case PARTICLE_QUAD:
if (ptcl_inst->data.data.count > 0)
count = ptcl_inst->data.data.count;
else
count = 2500;
max_count = 4 * count;
break;
case PARTICLE_LINE:
count = (size_t)ptcl_inst->data.data.locus_history_size
+ ptcl_inst->data.data.locus_history_size_random;
max_count = count;
break;
case PARTICLE_LOCUS:
count = (size_t)ptcl_inst->data.data.locus_history_size
+ ptcl_inst->data.data.locus_history_size_random;
max_count = 2 * count;
break;
case PARTICLE_MESH:
count = 1280;
max_count = 0;
break;
default:
return;
}
random_ptr = ptcl_inst->data.random_ptr;
particle = ptcl_inst;
elements = new RenderElement[count];
if (!elements || !ptcl_inst) {
count = 0;
max_count = 0;
return;
}
memset(elements, 0, sizeof(RenderElement) * count);
if (!max_count || ptcl_inst->data.data.type == PARTICLE_MESH)
return;
bool is_quad = ptcl_inst->data.data.type == PARTICLE_QUAD;
Particle* ptcl = particle->data.particle;
if (ptcl && ptcl->buffer && !ptcl->buffer_used) {
buffer = ptcl->buffer;
max_count = ptcl->max_count;
vao = ptcl->vao;
#if !SHARED_GLITTER_BUFFER
vbo = ptcl->vbo;
ebo = ptcl->ebo;
use_own_buffer = false;
#endif
ptcl->buffer_used = true;
}
#if !SHARED_GLITTER_BUFFER
if (use_own_buffer)
CreateBuffer(max_count, is_quad, buffer, vao, vbo, ebo);
#endif
if (!is_quad)
draw_list.reserve(count);
}
XRenderGroup::~XRenderGroup() {
DeleteBuffers(false);
}
bool XRenderGroup::CannotDisp() {
if (!particle)
return true;
else if (particle->data.effect)
return (particle->data.effect->flags & EFFECT_INST_EXT_ANIM_NON_INIT) != 0;
else if ((particle = particle->data.parent) && particle->data.effect)
return (particle->data.effect->flags & EFFECT_INST_EXT_ANIM_NON_INIT) != 0;
else
return true;
}
void XRenderGroup::CheckUseCamera() {
if (particle)
use_camera = particle->GetUseCamera();
else
use_camera = false;
}
void XRenderGroup::Copy(XRenderGroup* dst) {
dst->flags = flags;
dst->type = type;
dst->draw_type = draw_type;
dst->blend_mode = blend_mode;
dst->mask_blend_mode = mask_blend_mode;
dst->pivot = pivot;
dst->split_u = split_u;
dst->split_v = split_v;
dst->split_uv = split_uv;
dst->z_offset = z_offset;
if (dst->count > count)
dst->count = count;
dst->ctrl = ctrl;
dst->texture = texture;
dst->mask_texture = mask_texture;
dst->frame = frame;
dst->mat = mat;
dst->mat_rot = mat_rot;
dst->mat_draw = mat_draw;
if (dst->count == count) {
memmove(dst->elements, elements, sizeof(RenderElement) * dst->count);
dst->ctrl = ctrl;
}
}
void XRenderGroup::Ctrl(float_t delta_frame, bool copy_mats) {
if (!particle)
return;
Particle::Data* ptcl_data = &particle->data.data;
blend_mode = ptcl_data->blend_mode;
mask_blend_mode = ptcl_data->mask_blend_mode;
texture = ptcl_data->texture;
mask_texture = ptcl_data->mask_texture;
object_name_hash = ptcl_data->mesh.object_name_hash;
split_u = ptcl_data->split_u;
split_v = ptcl_data->split_v;
split_uv = ptcl_data->split_uv;
type = ptcl_data->type;
draw_type = ptcl_data->draw_type;
z_offset = ptcl_data->z_offset;
pivot = ptcl_data->pivot;
flags = ptcl_data->flags;
if (copy_mats && particle->data.emitter) {
XEmitterInst* emitter = particle->data.emitter;
mat = emitter->mat;
mat_rot = emitter->mat_rot;
}
for (size_t ctrl = this->ctrl, i = 0; ctrl; i++) {
if (!elements[i].alive)
continue;
CtrlParticle(&elements[i], delta_frame);
ctrl--;
}
frame += delta_frame;
}
void XRenderGroup::CtrlParticle(RenderElement* rend_elem, float_t delta_frame) {
random_ptr->XSetStep(rend_elem->step);
if (!particle || (particle->data.data.flags & PARTICLE_LOOP
&& particle->HasEnded(false)) || rend_elem->frame >= rend_elem->life_time) {
rend_elem->alive = false;
if (rend_elem->locus_history) {
delete rend_elem->locus_history;
rend_elem->locus_history = 0;
}
ctrl--;
return;
}
particle->AccelerateParticle(rend_elem, delta_frame, random_ptr);
if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION
|| particle->data.data.type == PARTICLE_MESH)
rend_elem->rotation += rend_elem->rotation_add * delta_frame;
else
rend_elem->rotation.z += rend_elem->rotation_add.z * delta_frame;
vec2 uv_scroll = particle->data.data.uv_scroll_add
* (particle->data.data.uv_scroll_add_scale * delta_frame);
if (uv_scroll.x != 0.0f)
rend_elem->uv_scroll.x = fmodf(rend_elem->uv_scroll.x + uv_scroll.x, 1.0f);
if (uv_scroll.y != 0.0f)
rend_elem->uv_scroll.y = fmodf(rend_elem->uv_scroll.y + uv_scroll.y, 1.0f);
if (particle->data.data.sub_flags & PARTICLE_SUB_UV_2ND_ADD) {
vec2 uv_scroll_2nd = particle->data.data.uv_scroll_2nd_add
* (particle->data.data.uv_scroll_2nd_add_scale * delta_frame);
if (uv_scroll_2nd.x != 0.0f)
rend_elem->uv_scroll_2nd.x = fmodf(rend_elem->uv_scroll_2nd.x + uv_scroll_2nd.x, 1.0f);
if (uv_scroll_2nd.y != 0.0f)
rend_elem->uv_scroll_2nd.y = fmodf(rend_elem->uv_scroll_2nd.y + uv_scroll_2nd.y, 1.0f);
}
particle->StepUVParticle(rend_elem, delta_frame, random_ptr);
rend_elem->disp = true;
rend_elem->color = -1.0f;
bool disp = true;
float_t color_scale = -1.0f;
if (particle->data.data.sub_flags & PARTICLE_SUB_USE_CURVE)
disp = particle->GetValue(rend_elem, rend_elem->frame, random_ptr, &color_scale);
if (particle->data.data.draw_type == DIRECTION_PARTICLE_ROTATION
|| fabsf(rend_elem->rotation.z) <= 0.000001f) {
rend_elem->rot_z_cos = 1.0f;
rend_elem->rot_z_sin = 0.0f;
}
else {
rend_elem->rot_z_cos = cosf(rend_elem->rotation.z);
rend_elem->rot_z_sin = sinf(rend_elem->rotation.z);
}
if (disp)
particle->GetColor(rend_elem, color_scale);
if (particle->data.data.type == PARTICLE_LOCUS)
rend_elem->locus_history->Append(rend_elem, particle);
rend_elem->frame += delta_frame;
if (particle->data.data.flags & PARTICLE_LOOP && rend_elem->frame >= rend_elem->life_time)
rend_elem->frame -= rend_elem->life_time;
}
void XRenderGroup::DeleteBuffers(bool free) {
Particle* ptcl = 0;
if (particle) {
ptcl = particle->data.particle;
if (!free)
particle->data.render_group = 0;
particle = 0;
}
#if SHARED_GLITTER_BUFFER
if (ptcl && ptcl->buffer)
ptcl->buffer_used = false;
#else
if (use_own_buffer)
Glitter::DeleteBuffer(buffer, vao, vbo, ebo);
else if (ptcl && ptcl->buffer)
ptcl->buffer_used = false;
#endif
if (!free && elements) {
Free();
delete[] elements;
elements = 0;
}
}
void XRenderGroup::Emit(Particle::Data* ptcl_data,
XEmitterInst* emit_inst, int32_t dup_count, int32_t count, float_t frame) {
RenderElement* element;
int64_t i;
int32_t index;
uint8_t step;
step = emit_inst->RandomGetStep();
random_ptr->XSetStep(1);
for (element = 0, i = 0; i < dup_count; i++)
for (index = 0; index < count; index++, element++) {
element = AddElement(element);
if (!element)
break;
emit_inst->RandomStepValue();
element->frame = frame;
particle->EmitParticle(element, emit_inst, ptcl_data, index, step, random_ptr);
}
}
void XRenderGroup::Free() {
if (count <= 0) {
ctrl = 0;
return;
}
RenderElement* elem = elements;
for (size_t i = count; i; i--, elem++) {
elem->alive = false;
if (elem->locus_history) {
delete elem->locus_history;
elem->locus_history = 0;
}
}
ctrl = 0;
}
void XRenderGroup::FreeData() {
DeleteBuffers(true);
}
bool XRenderGroup::GetEmitterScale(vec3& emitter_scale) {
if (particle) {
Glitter::EmitterInst* emit_inst = particle->data.emitter;
if (emit_inst) {
emitter_scale = emit_inst->scale * emit_inst->scale_all;
return emitter_scale.x > 0.000001f || emitter_scale.y > 0.000001f || emitter_scale.z > 0.000001f;
}
}
emitter_scale = 1.0f;
return false;
}
bool XRenderGroup::GetExtAnimScale(vec3* ext_anim_scale, float_t* ext_scale) {
if (particle)
particle->GetExtAnimScale(ext_anim_scale, ext_scale);
return false;
}
bool XRenderGroup::HasEnded() {
if (particle)
return particle->HasEnded(true);
return true;
}
mat4 XRenderGroup::RotateMeshToEmitPosition(XRenderGroup* rend_group,
RenderElement* rend_elem, vec3* vec, vec3* trans) {
vec3 vec2;
mat4_get_translation(&rend_group->mat, &vec2);
vec2 -= *trans;
if (vec3::length_squared(vec2) < 0.000001f)
vec2 = { 0.0f, 1.0f, 0.0f };
else
vec2 = vec3::normalize(vec2);
vec3 vec1 = *vec;
vec3 axis;
float_t angle;
axis_angle_from_vectors(axis, angle, vec1, vec2);
mat4 mat = mat4_identity;
mat4_mul_rotation(&mat, &axis, angle, &mat);
return mat;
}
mat4 XRenderGroup::RotateMeshToPrevPosition(XRenderGroup* rend_group,
RenderElement* rend_elem, vec3* vec, vec3* trans) {
vec3 vec2 = rend_elem->translation - rend_elem->translation_prev;
if (vec3::length_squared(vec2) < 0.000001f)
vec2 = vec3::normalize(rend_elem->base_direction);
else
vec2 = vec3::normalize(vec2);
vec3 vec1 = *vec;
vec3 axis;
float_t angle;
axis_angle_from_vectors(axis, angle, vec1, vec2);
mat4 mat = mat4_identity;
mat4_mul_rotation(&mat, &axis, angle, &mat);
return mat;
}
mat4 XRenderGroup::RotateToEmitPosition(XRenderGroup* rend_group,
RenderElement* rend_elem, vec3* vec) {
vec3 vec2;
mat4_get_translation(&rend_elem->mat, &vec2);
vec2 -= rend_elem->translation;
if (vec3::length_squared(vec2) < 0.000001f)
vec2 = { 0.0f, 1.0f, 0.0f };
else
vec3::normalize(vec2);
vec3 vec1 = *vec;
vec3 axis;
float_t angle;
axis_angle_from_vectors(axis, angle, vec1, vec2);
mat4 mat = mat4_identity;
mat4_mul_rotation(&mat, &axis, angle, &mat);
return mat;
}
mat4 XRenderGroup::RotateToPrevPosition(XRenderGroup* rend_group,
RenderElement* rend_elem, vec3* vec) {
vec3 vec2 = rend_elem->translation - rend_elem->translation_prev;
if (vec3::length_squared(vec2) < 0.000001f)
vec2 = vec3::normalize(rend_elem->base_direction);
else
vec2 = vec3::normalize(vec2);
vec3 vec1 = *vec;
vec3 axis;
float_t angle;
axis_angle_from_vectors(axis, angle, vec1, vec2);
mat4 mat = mat4_identity;
mat4_mul_rotation(&mat, &axis, angle, &mat);
return mat;
}
}