156 lines
5.0 KiB
C
156 lines
5.0 KiB
C
|
|
#include "../global.h"
|
|
|
|
void util_particle_init_mesh() {
|
|
if (g_context->paint_body != NULL) {
|
|
return;
|
|
}
|
|
if (g_context->merged_object == NULL) {
|
|
util_mesh_merge(NULL);
|
|
}
|
|
|
|
g_context->paint_body = physics_body_create();
|
|
g_context->paint_body->shape = PHYSICS_SHAPE_MESH;
|
|
physics_body_init(g_context->paint_body, g_context->merged_object->base);
|
|
}
|
|
|
|
void util_particle_init_physics() {
|
|
if (physics_world_active == NULL) {
|
|
physics_world_create();
|
|
}
|
|
util_particle_init_mesh();
|
|
}
|
|
|
|
void util_particle_update() {
|
|
if (g_context->tool != TOOL_TYPE_PARTICLE) {
|
|
return;
|
|
}
|
|
|
|
util_particle_init_physics();
|
|
make_particle_get_bullet_material();
|
|
physics_world_t *world = physics_world_active;
|
|
physics_world_update(world);
|
|
|
|
for (i32 i = 0; i < 32; ++i) {
|
|
if (g_context->particles[i].timer != NULL && g_context->particles[i].timer->delay <= 0) {
|
|
physics_body_remove(g_context->particles[i].body);
|
|
mesh_object_remove((mesh_object_t *)g_context->particles[i].bullet->ext);
|
|
memset(&g_context->particles[i], 0, sizeof(g_context->particles[i]));
|
|
}
|
|
}
|
|
|
|
bool any_active = false;
|
|
for (i32 i = 0; i < 32; ++i) {
|
|
if (g_context->particles[i].timer != NULL) {
|
|
any_active = true;
|
|
break;
|
|
}
|
|
}
|
|
if (any_active) {
|
|
g_context->ddirty = 2;
|
|
g_context->rdirty = 2;
|
|
iron_delay_idle_sleep();
|
|
}
|
|
|
|
static f64 particle_last_spawn_time = 0.0;
|
|
bool particle_just_fired = false;
|
|
if (mouse_down("left") && context_in_paint_area() && !g_context->paint2d && (mouse_started("left") || sys_time() - particle_last_spawn_time >= 0.2)) {
|
|
particle_last_spawn_time = sys_time();
|
|
|
|
i32 slot = -1;
|
|
for (i32 i = 0; i < 32; ++i) {
|
|
if (g_context->particles[i].timer == NULL) {
|
|
slot = i;
|
|
break;
|
|
}
|
|
}
|
|
if (slot >= 0) {
|
|
if (mouse_started("left")) {
|
|
history_push_undo = true;
|
|
g_context->brush_blend_dirty = true;
|
|
}
|
|
|
|
object_t *o = scene_spawn_object(".Sphere", NULL, true);
|
|
mesh_object_t *mo = o->ext;
|
|
mo->base->name = ".Bullet";
|
|
mo->base->visible = true;
|
|
mo->material = make_particle_get_bullet_material();
|
|
|
|
util_render_pick_pos_nor_tex();
|
|
f32 nx = g_context->norx_picked;
|
|
f32 ny = g_context->nory_picked;
|
|
f32 nz = g_context->norz_picked;
|
|
f32 sphere_radius = g_context->brush_radius * 0.1f;
|
|
f32 spawn_h = -(sphere_radius + g_context->particle_spawn_distance) + 0.01;
|
|
mo->base->transform->loc =
|
|
(vec4_t){g_context->posx_picked + nx * spawn_h, g_context->posy_picked + ny * spawn_h, g_context->posz_picked + nz * spawn_h, 1.0};
|
|
mo->base->transform->scale = (vec4_t){g_context->brush_radius * 0.2, g_context->brush_radius * 0.2, g_context->brush_radius * 0.2, 1.0};
|
|
transform_build_matrix(mo->base->transform);
|
|
|
|
physics_body_t *body = physics_body_create();
|
|
body->shape = PHYSICS_SHAPE_SPHERE;
|
|
body->mass = g_context->particle_mass;
|
|
physics_body_init(body, mo->base);
|
|
|
|
// Random direction
|
|
f32 rx = math_random() * 2.0f - 1.0f;
|
|
f32 ry = math_random() * 2.0f - 1.0f;
|
|
f32 rz = math_random() * 2.0f - 1.0f;
|
|
f32 rlen = sqrtf(rx * rx + ry * ry + rz * rz);
|
|
if (rlen < 0.0001f)
|
|
rlen = 0.0001f;
|
|
rx /= rlen;
|
|
ry /= rlen;
|
|
rz /= rlen;
|
|
if (rx * nx + ry * ny + rz * nz < 0.0f) {
|
|
rx = -rx;
|
|
ry = -ry;
|
|
rz = -rz;
|
|
}
|
|
f32 r = g_context->particle_random;
|
|
f32 dx = nx + (rx - nx) * r;
|
|
f32 dy = ny + (ry - ny) * r;
|
|
f32 dz = nz + (rz - nz) * r;
|
|
f32 impulse = g_context->particle_spawn_distance * 30.0f;
|
|
physics_body_apply_impulse(body, (vec4_t){dx * impulse, dy * impulse, dz * impulse, 0.0});
|
|
|
|
g_context->particles[slot].body = body;
|
|
g_context->particles[slot].bullet = mo->base;
|
|
g_context->particles[slot].timer = tween_timer(g_context->particle_lifetime, NULL, NULL);
|
|
particle_just_fired = true;
|
|
}
|
|
}
|
|
|
|
if (mouse_released("left")) {
|
|
g_context->layer_preview_dirty = true;
|
|
}
|
|
|
|
#ifdef WITH_PHYSICS
|
|
if (!particle_just_fired) {
|
|
for (i32 i = 0; i < 32; ++i) {
|
|
if (g_context->particles[i].timer == NULL) {
|
|
continue;
|
|
}
|
|
physics_pair_t_array_t *pairs = physics_world_get_contact_pairs(world, g_context->particles[i].body);
|
|
if (pairs != NULL && pairs->length > 0) {
|
|
physics_pair_t *p = pairs->buffer[0];
|
|
g_context->particles[i].hit_last_x = g_context->particles[i].hit_x != 0 ? g_context->particles[i].hit_x : p->pos_a_x;
|
|
g_context->particles[i].hit_last_y = g_context->particles[i].hit_y != 0 ? g_context->particles[i].hit_y : p->pos_a_y;
|
|
g_context->particles[i].hit_last_z = g_context->particles[i].hit_z != 0 ? g_context->particles[i].hit_z : p->pos_a_z;
|
|
g_context->particles[i].hit_x = p->pos_a_x;
|
|
g_context->particles[i].hit_y = p->pos_a_y;
|
|
g_context->particles[i].hit_z = p->pos_a_z;
|
|
g_context->particles[i].hit_nor_x = p->nor_x;
|
|
g_context->particles[i].hit_nor_y = p->nor_y;
|
|
g_context->particles[i].hit_nor_z = p->nor_z;
|
|
g_context->particles[i].contact_time += sys_delta();
|
|
g_context->pdirty = 1;
|
|
}
|
|
else {
|
|
g_context->particles[i].hit_x = 0.0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|