From 728f54b0f7b471e784782c65f41c6f307a056bba Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Wed, 8 Jan 2020 20:22:36 -0800 Subject: libs/puddle: add a classic 2D raindrop sim lib These were commonish in the 90s demo days, done as a library to encourage use by different modules. You can simply render this directly onto a frame buffer like the old days, or sample it as a height map or density field for more complex compositions. --- src/libs/Makefile.am | 2 +- src/libs/puddle/Makefile.am | 3 + src/libs/puddle/puddle.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ src/libs/puddle/puddle.h | 30 ++++++++++ 4 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/libs/puddle/Makefile.am create mode 100644 src/libs/puddle/puddle.c create mode 100644 src/libs/puddle/puddle.h (limited to 'src/libs') diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am index 9f3499d..820efef 100644 --- a/src/libs/Makefile.am +++ b/src/libs/Makefile.am @@ -1 +1 @@ -SUBDIRS = ascii grid din ray txt +SUBDIRS = ascii grid din puddle ray txt diff --git a/src/libs/puddle/Makefile.am b/src/libs/puddle/Makefile.am new file mode 100644 index 0000000..faacb49 --- /dev/null +++ b/src/libs/puddle/Makefile.am @@ -0,0 +1,3 @@ +noinst_LIBRARIES = libpuddle.a +libpuddle_a_SOURCES = puddle.c puddle.h +libpuddle_a_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/puddle/puddle.c b/src/libs/puddle/puddle.c new file mode 100644 index 0000000..e5c0dd4 --- /dev/null +++ b/src/libs/puddle/puddle.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 - Vito Caputo - + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "puddle.h" + +typedef struct puddle_t { + int w, h; + float *a, *b; + float floats[]; +} puddle_t; + +typedef struct v2f_t { + float x, y; +} v2f_t; + + +puddle_t * puddle_new(int w, int h) +{ + puddle_t *puddle; + + puddle = calloc(1, sizeof(puddle_t) + sizeof(float) * w * (h + 2) * 2); + if (!puddle) + return NULL; + + puddle->w = w; + puddle->h = h; + + puddle->a = &puddle->floats[w]; + puddle->b = &puddle->floats[w * 2 + w * h + w]; + + return puddle; +} + + +void puddle_free(puddle_t *puddle) +{ + free(puddle); +} + + +/* Run the puddle simulation for a tick, using the supplied viscosity value. + * A good viscosity value is ~.01, YMMV. + */ +void puddle_tick(puddle_t *puddle, float viscosity) +{ + float *a, *b; + + assert(puddle); + + a = puddle->a; + b = puddle->b; + + for (int y = 0, i = 0; y < puddle->h; y++) { + for (int x = 0; x < puddle->w; x++, i++) { + float tmp = a[i - puddle->w] + + a[i - 1] + + a[i + 1] + + a[i + puddle->w]; + + tmp -= b[i] * 2.f; + tmp *= .5f; + tmp -= tmp * viscosity; + + b[i] = tmp; + } + } + + puddle->b = a; + puddle->a = b; +} + + +/* Set a specific cell in the puddle to the supplied value */ +void puddle_set(puddle_t *puddle, int x, int y, float value) +{ + assert(puddle); + assert(x >= 0 && x < puddle->w); + assert(y >= 0 && y < puddle->h); + + puddle->a[y * puddle->w + x] = value; +} + + +static inline float lerp(float a, float b, float t) +{ + return (1.0f - t) * a + t * b; +} + + +/* Sample the supplied puddle field at the specified coordinate. + * + * The puddle field is treated as a unit square mapped to the specified + * dimensions @ create time. the sampled value is linearly interpolated from + * the data. + */ +float puddle_sample(const puddle_t *puddle, const v2f_t *coordinate) +{ + int x0, y0, x1, y1; + float x, y, tx, ty; + + assert(puddle); + assert(coordinate); + + x = .5f + (coordinate->x * .5f + .5f) * (puddle->w - 2); + y = .5f + (coordinate->y * .5f + .5f) * (puddle->h - 2); + + x0 = floorf(x); + y0 = floorf(y); + + x1 = x0 + 1; + y1 = y0 + 1; + + tx = x - (float)x0; + ty = y - (float)y0; + + return lerp(lerp(puddle->a[y0 * puddle->w + x0], puddle->a[y0 * puddle->w + x1], tx), + lerp(puddle->a[y1 * puddle->w + x0], puddle->a[y1 * puddle->w + x1], tx), + ty); +} diff --git a/src/libs/puddle/puddle.h b/src/libs/puddle/puddle.h new file mode 100644 index 0000000..cc8988e --- /dev/null +++ b/src/libs/puddle/puddle.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 - Vito Caputo - + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _PUDDLE_H +#define _PUDDLE_H + +typedef struct puddle_t puddle_t; +typedef struct v2f_t v2f_t; + +puddle_t * puddle_new(int w, int h); +void puddle_free(puddle_t *puddle); +void puddle_tick(puddle_t *puddle, float viscosity); +void puddle_set(puddle_t *puddle, int x, int y, float v); +float puddle_sample(const puddle_t *puddle, const v2f_t *coordinate); + + +#endif -- cgit v1.2.1