Nimbin[12]?Games / Entropie / entropie/src/world/chips.c

Entropie git · main

Entropie festival game; first steps

sdl c game entropie cmake · first commit 2026-10-10 · last commit 2026-11-02 (18 hours ago) · synced 10 hours ago

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.gz
entropie/src/world/chips.c 5.6 KB · 134 lines 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);
    }
}