summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bonus-node.c180
-rw-r--r--src/bonus-node.h29
3 files changed, 211 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5f55d86..32bfdb0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,6 +12,8 @@ sars_SOURCES = \
baby-node.h \
bb2f.h \
bb3f.h \
+ bonus-node.c \
+ bonus-node.h \
clear-node.c \
clear-node.h \
cp437.h \
diff --git a/src/bonus-node.c b/src/bonus-node.c
new file mode 100644
index 0000000..7eb2c9e
--- /dev/null
+++ b/src/bonus-node.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 - Vito Caputo - <vcaputo@pengaru.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* Bonus nodes are for showing bonus quantities numerically which move along
+ * with an entity, and when taken get released from the entity's position and
+ * float away on their own.
+ *
+ * The current way this works is by providing a release counter pointer for
+ * triggering the release, along with a release position pointer for storing
+ * the last position when released. So the entity needs some members for saving
+ * these locations which point at members within the bonus_node_t.
+ *
+ * The release gets realised at render time by checking if the release counter
+ * is non-zero. Upon release, the render func takes over management of the
+ * position and life-cycle of the node by returning STAGE_RENDER_FUNC_RET_FREE
+ * when done.
+ *
+ * One particularly crufty aspect is the digit nodes are hung off a nested
+ * stage within the bonus_node_t that's being explicitly rendered and freed,
+ * rather than existing as direct descendants of the game stage. This results
+ * in some redundant stage_dirty()/stage_render()/stage_free() rigamarole here,
+ * and is only being done because I want to vary the alpha in the render func
+ * for fading the digits out as they decay - and the incoming stage_t on the
+ * render func is a const so we can't set the alpha directly on the outer bonus
+ * node before letting render naturally descend down to the children layers with
+ * the adjusted alpha.
+ *
+ * It's no big deal for now, but it illustrates some of the unnecessary
+ * friction remaining in the libstage API. I'm not convinced constifying these
+ * things is bringing enough value to justify these kinds of annoyances. FIXME
+ *
+ * Another crufty point is for now I threw the release decay duration in
+ * bonus-node.h so that the caller can accesss it when storing at the release
+ * pointer, while making it available here for compile-time evaluation of (1.f
+ * / BONUS_NODE_RELEASE_MS). Also the counter isn't really applied in
+ * normalized time, but is just a frame counter right now - the name lies.
+ * TODO FIXME
+ *
+ * I'm not too concerned about these things since SARS is such a
+ * silly thing, but it's a useful exercise to see how (un)usable these
+ * libraries are.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stage.h>
+
+#include "bonus-node.h"
+#include "digit-node.h"
+#include "m4f.h"
+#include "m4f-3dx.h"
+#include "v2f.h"
+
+typedef struct bonus_node_t {
+ stage_t *stage;
+ v2f_t *position;
+ float scale;
+ unsigned release;
+ v2f_t release_position;
+ unsigned n_digits;
+ m4f_t digits_x[];
+} bonus_node_t;
+
+static stage_render_func_ret_t bonus_node_render(const stage_t *stage, void *object, float alpha, void *render_ctxt)
+{
+ bonus_node_t *bonus_node = object;
+ v3f_t scale;
+
+ assert(stage);
+ assert(bonus_node);
+
+ scale.x = scale.y = scale.z = bonus_node->scale;
+
+ if (bonus_node->release) {
+ float t = 1.f - (1.f / BONUS_NODE_RELEASE_MS * (float)bonus_node->release);
+
+ bonus_node->release--;
+ if (!bonus_node->release)
+ return STAGE_RENDER_FUNC_RET_FREE;
+
+ for (int i = 0; i < bonus_node->n_digits; i++) {
+ bonus_node->digits_x[i] = m4f_translate(NULL, &(v3f_t){
+ .x = bonus_node->release_position.x + bonus_node->scale*2.f + (float)i * -bonus_node->scale*2.f + (t * sinf((float)bonus_node->release * .1f) * .1f),
+ .y = bonus_node->release_position.y + bonus_node->scale*2.f + t * .5f,
+ .z = 0.f
+ });
+ bonus_node->digits_x[i] = m4f_scale(&bonus_node->digits_x[i], &scale);
+ }
+
+ stage_set_alpha(bonus_node->stage, 1.f - t);
+ stage_dirty(bonus_node->stage);
+ stage_render(bonus_node->stage, render_ctxt);
+
+ return STAGE_RENDER_FUNC_RET_CONTINUE;
+ }
+
+ /* update tranforms for the digits before they render */
+ for (int i = 0; i < bonus_node->n_digits; i++) {
+ bonus_node->digits_x[i] = m4f_translate(NULL, &(v3f_t){
+ .x = bonus_node->position->x + bonus_node->scale * 2.f + (float)i * -bonus_node->scale * 2.f,
+ .y = bonus_node->position->y + bonus_node->scale*2.f,
+ .z = 0.f
+ });
+ bonus_node->digits_x[i] = m4f_scale(&bonus_node->digits_x[i], &scale);
+ }
+ stage_dirty(bonus_node->stage);
+ stage_render(bonus_node->stage, render_ctxt);
+
+ return STAGE_RENDER_FUNC_RET_CONTINUE;
+}
+
+
+static void bonus_node_free(const stage_t *stage, void *object)
+{
+ bonus_node_t *bonus_node = object;
+
+ assert(stage);
+ stage_free(bonus_node->stage);
+ free(bonus_node);
+}
+
+
+static const stage_ops_t bonus_node_ops = {
+ .render_func = bonus_node_render,
+ .free_func = bonus_node_free,
+};
+
+
+stage_t * bonus_node_new(stage_conf_t *conf, unsigned value, m4f_t *projection_x, v2f_t *position, float scale, unsigned **release, v2f_t **release_position)
+{
+ unsigned v = value, n_digits = 0, i = 0;
+ bonus_node_t *bonus_node;
+ stage_t *s;
+
+ assert(release);
+ assert(position);
+ assert(release_position);
+ assert(projection_x);
+
+ do {
+ n_digits++;
+ v /= 10;
+ } while (v);
+
+ bonus_node = calloc(1, sizeof(bonus_node_t) + n_digits * sizeof(bonus_node->digits_x[0]));
+ assert(bonus_node);
+ bonus_node->n_digits = n_digits;
+ bonus_node->position = position;
+ bonus_node->scale = scale;
+ bonus_node->stage = stage_new(&(stage_conf_t){.name = "bonus-container", .active = 1, .alpha = 1.f}, NULL, NULL); /* use a discrete container stage for render_func alpha control */
+ *release = &bonus_node->release;
+ *release_position = &bonus_node->release_position;
+
+ s = stage_new(conf, &bonus_node_ops, bonus_node);
+ assert(s);
+
+ v = value;
+ do {
+ /* TODO: model_x positioning of the digits */
+ (void) digit_node_new(&(stage_conf_t){ .parent = bonus_node->stage, .name = "bonus-digit", .active = 1, .alpha = 1.f },
+ v % 10, projection_x, &bonus_node->digits_x[i++]);
+ v /= 10;
+ } while (v);
+
+ return s;
+}
diff --git a/src/bonus-node.h b/src/bonus-node.h
new file mode 100644
index 0000000..c138589
--- /dev/null
+++ b/src/bonus-node.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 - Vito Caputo - <vcaputo@pengaru.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BONUS_NODE_H
+#define _BONUS_NODE_H
+
+#define BONUS_NODE_RELEASE_MS 100 /* FIXME: this needs to be actual time units, right now it's frames */
+
+typedef struct stage_conf_t stage_conf_t;
+typedef struct m4f_t m4f_t;
+typedef struct v2f_t v2f_t;
+
+stage_t * bonus_node_new(stage_conf_t *conf, unsigned value, m4f_t *projection_x, v2f_t *position, float scale, unsigned **release, v2f_t **release_position);
+
+#endif
+
© All Rights Reserved