Entropie git · main
Entropie festival game; first steps
C 88.5% Markdown 9.1% GLSL 2.3%git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gzentropie/src/world/chips.c raw
/*
* Chips and sawdust: a fixed ring of little blocks, thrown, falling, lying.
*/
#include "world/chips.h"
#include <math.h>
#include <string.h>
#include "render/shapes.h"
#define CHIP_LIE 7.0f /* seconds a chip lies on the ground */
#define DUST_LIFE 1.3f /* seconds sawdust is in the air */
#define GRAVITY_C 9.81f
static float rnd(Chips *c) {
c->rng = c->rng * 1664525u + 1013904223u;
return (float)((c->rng >> 8) & 0xFFFFu) / 65535.0f;
}
void Chips_init(Chips *c) {
memset(c, 0, sizeof(*c));
c->rng = 0x51f15eedu;
c->mesh = Shapes_chip();
c->puff = Shapes_puff();
}
void Chips_destroy(Chips *c) {
Mesh_destroy(&c->mesh);
Mesh_destroy(&c->puff);
memset(c, 0, sizeof(*c));
}
void Chips_spray(Chips *c, Vec3 at, Vec3 dir, int n, bool dust) {
float len = vec3_length(dir);
dir = len > 1e-4f ? vec3_scale(dir, 1.0f / len) : vec3(0.0f, 1.0f, 0.0f);
for (int k = 0; k < n; k++) {
Chip *ch = &c->chips[c->next];
c->next = (c->next + 1) % CHIP_MAX;
Vec3 jitter = vec3(rnd(c) - 0.5f, rnd(c) - 0.5f, rnd(c) - 0.5f);
float speed = dust ? 1.8f + 1.6f * rnd(c) : 1.8f + 2.4f * rnd(c);
Vec3 d = vec3_normalize(vec3_add(dir, vec3_scale(jitter, dust ? 0.9f : 1.3f)));
*ch = (Chip){
.p = vec3_add(at, vec3_scale(jitter, 0.04f)),
.v = vec3_add(vec3_scale(d, speed), vec3(0.0f, dust ? 0.3f : 1.2f + rnd(c), 0.0f)),
.life = dust ? DUST_LIFE * (0.6f + 0.6f * rnd(c)) : CHIP_LIE + 3.0f * rnd(c),
.size = dust ? 0.014f + 0.012f * rnd(c) : 0.04f + 0.04f * rnd(c),
.angle = 6.28f * rnd(c),
.spin = (rnd(c) - 0.5f) * 30.0f,
.color = dust ? vec3(0.95f, 0.86f, 0.64f) : vec3_scale(vec3(0.93f, 0.78f, 0.52f), 0.85f + 0.2f * rnd(c)),
.dust = dust,
};
}
}
#define SMOKE_LIFE 1.8f
void Chips_puff(Chips *c, Vec3 at, Vec3 dir, bool small) {
Chip *ch = &c->chips[c->next];
c->next = (c->next + 1) % CHIP_MAX;
Vec3 jitter = vec3(rnd(c) - 0.5f, rnd(c) - 0.5f, rnd(c) - 0.5f);
*ch = (Chip){
.p = vec3_add(at, vec3_scale(jitter, 0.01f)),
.v = vec3_add(vec3_scale(dir, small ? 0.05f : 0.6f + 0.3f * rnd(c)), vec3_add(vec3_scale(jitter, 0.1f), vec3(0.0f, 0.1f, 0.0f))),
.life = (small ? 0.6f : 1.0f) * SMOKE_LIFE * (0.7f + 0.5f * rnd(c)),
.size = small ? 0.006f : 0.012f,
.angle = 6.28f * rnd(c),
.spin = (rnd(c) - 0.5f) * 2.0f,
.color = vec3_scale(vec3(0.86f, 0.87f, 0.9f), 0.9f + 0.1f * rnd(c)),
.smoke = true,
};
}
void Chips_smoke(Chips *c, Vec3 at) {
Chip *ch = &c->chips[c->next];
c->next = (c->next + 1) % CHIP_MAX;
Vec3 jitter = vec3(rnd(c) - 0.5f, 0.0f, rnd(c) - 0.5f);
float grey = 0.78f + 0.12f * rnd(c);
*ch = (Chip){
.p = vec3_add(at, vec3_scale(jitter, 0.4f)),
.v = vec3_add(vec3_scale(jitter, 0.2f), vec3(0.0f, 0.7f + 0.3f * rnd(c), 0.0f)),
.life = 3.5f + 1.5f * rnd(c),
.size = 0.25f + 0.12f * rnd(c),
.angle = 6.28f * rnd(c),
.spin = (rnd(c) - 0.5f) * 0.8f,
.color = vec3(grey, grey, grey * 1.04f),
.smoke = true,
};
}
void Chips_update(Chips *c, const Terrain *terrain, Vec3 wind, float dt) {
for (int i = 0; i < CHIP_MAX; i++) {
Chip *ch = &c->chips[i];
if (ch->life <= 0.0f) continue;
ch->life -= dt;
if (ch->smoke) { /* slows down to the wind's speed, rises, spreads */
float k = expf(-2.5f * dt), up = ch->v.y * k;
ch->v = vec3_add(vec3_scale(ch->v, k), vec3_scale(wind, 0.8f * (1.0f - k)));
ch->v.y = up + (ch->size > 0.05f ? 0.9f : 0.35f) * dt; /* (a fire's smoke: warm, rising more) */
ch->p = vec3_add(ch->p, vec3_scale(ch->v, dt));
ch->size += (ch->size > 0.05f ? 0.22f : 0.03f) * dt; /* (a fire's smoke spreads more) */
ch->angle += ch->spin * dt;
continue;
}
if (ch->down) continue;
float drag = ch->dust ? 3.5f : 0.6f, k = expf(-drag * dt), fall = ch->v.y * k;
ch->v = vec3_add(vec3_scale(ch->v, k), ch->dust ? vec3_scale(wind, 0.7f * (1.0f - k)) : vec3_zero());
ch->v.y = fall;
ch->v.y -= GRAVITY_C * (ch->dust ? 0.25f : 1.0f) * dt;
ch->p = vec3_add(ch->p, vec3_scale(ch->v, dt));
ch->angle += ch->spin * dt;
float ground = Terrain_height(terrain, ch->p.x, ch->p.z) + ch->size * 0.3f;
if (ch->p.y < ground) {
ch->p.y = ground;
if (ch->dust) ch->life = fminf(ch->life, 0.3f); /* (sawdust settles and is gone) */
ch->down = true;
ch->v = vec3_zero();
}
}
}
#define SMOKE_ALPHA 0.5f /* how thick a puff of smoke is (see-through) */
void Chips_draw(const Chips *c, Renderer *renderer) {
for (int i = 0; i < CHIP_MAX; i++) {
const Chip *ch = &c->chips[i];
if (ch->life <= 0.0f) continue;
float shrink = fminf(1.0f, ch->life / (ch->smoke ? 0.5f : ch->dust ? 0.3f : 1.5f)); /* (fading away at the end) */
float s = ch->size * (ch->smoke && ch->size > 0.05f ? 1.0f : shrink); /* (a fire's smoke: thinning out instead) */
Mat4 m = mat4_mul(mat4_translate(ch->p), mat4_mul(mat4_rotate_yxz(vec3(ch->down ? 0.0f : ch->angle, ch->angle * 0.7f, 0.0f)),
mat4_scale(vec3(s, s * (ch->dust || ch->smoke ? 1.0f : 0.35f), s * (ch->dust || ch->smoke ? 1.0f : 0.7f)))));
if (ch->smoke) Renderer_drawPuff(renderer, &c->puff, m, ch->color, SMOKE_ALPHA * fminf(1.0f, ch->life / 0.8f)); /* (thinning out at the end) */
else Renderer_drawMeshTinted(renderer, &c->mesh, m, ch->color, 0.0f);
}
}