summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonAki <konaki@anokonaki.org>2026-10-12 13:54:29 +0800
committerKonAki <konaki@anokonaki.org>2026-10-12 13:54:29 +0800
commit9dfe3ac89d2cc6ac5fce56008e0bce1e6d6637aa (patch)
treea1d994b5beb4f4168f07153f63eaba3ad40db2f9
parente1bca003fa9ac46a1ce1b71d14d2a8feb8462dc6 (diff)
dialog example shows the effects, wire fx into the build
-rw-r--r--README.md3
-rwxr-xr-xbuild.sh6
-rw-r--r--examples/dialog.c58
3 files changed, 57 insertions, 10 deletions
diff --git a/README.md b/README.md
index cf605e9..70af8e3 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,8 @@ The engine modules are a `.h` and a `.c` pair, they depend on each other a bit,
| toml | kontoml |
| tile | tilemaps and sprite sheets |
| 2d | what any 2D game needs: a scrolling camera, frame animation, drawing frames of a sprite sheet |
-| stage | sprites on a stage for visual novels and cutscenes: slots, layers above or below your text box, fades, moves, a background that stretches, covers or fits (adds 2d) |
+| fx | whole screen effects done on the pixels: fade to a colour, flash, shake and tone (adds 2d) |
+| stage | sprites and pictures on a stage for visual novels and cutscenes: slots, layers above or below your text box, fades, moves, scale, rotation, blend modes, a background (or CG) that stretches, covers or fits and can pan and zoom (adds 2d) |
| textbox | a text box for any game: wrapped pages, typewriter, name plate, a face inside, menus, a panel that can be a colour, an image or a nine patch (adds 2d, font) |
| platformer | a box that runs and jumps through a tilemap, with coyote time and jump buffering (adds tile) |
| rpg | top-down games on tilemaps: actors that walk a tile at a time, events on tiles (talk, touch, step), directions (adds tile) |
diff --git a/build.sh b/build.sh
index f533e80..2274af2 100755
--- a/build.sh
+++ b/build.sh
@@ -12,7 +12,7 @@ developer=0
usage()
{
echo "usage: build.sh [-d] [-D] [-p platform] [-m module,...] [-o objdir] [target ...]"
- echo "modules: font toml tile pack ui debug assets image audio mic model 2d stage textbox platformer rpg 3d sector world"
+ echo "modules: font toml tile pack ui debug assets image audio mic model 2d fx stage textbox platformer rpg 3d sector world"
echo "platforms: native linux bsd windows"
echo "targets: all run clean tools pack examples"
exit 1
@@ -77,7 +77,7 @@ addobj()
for m in $modules; do
DEFS="$DEFS -DKON_MODULE_$(echo "$m" | tr 'a-z' 'A-Z')"
case $m in
- font|toml|tile|pack|ui|debug|2d|stage|textbox|platformer|rpg|3d|sector|world) addobj "kon$m" ;;
+ font|toml|tile|pack|ui|debug|2d|fx|stage|textbox|platformer|rpg|3d|sector|world) addobj "kon$m" ;;
assets) addobj konassets ;;
model) addobj konmodel; addobj konassets ;;
image) addobj stb_image ;;
@@ -107,7 +107,7 @@ case " $modules " in *" debug "*) need font; need assets ;; esac
case " $modules " in *" ui "*) need font ;; esac
case " $modules " in *" world "*) need 3d; need sector; need tile ;; esac
case " $modules " in *" platformer "*|*" rpg "*) need tile ;; esac
-case " $modules " in *" stage "*) need 2d ;; esac
+case " $modules " in *" stage "*|*" fx "*) need 2d ;; esac
case " $modules " in *" textbox "*) need 2d; need font ;; esac
case " $modules " in *" 3d "*) need tile ;; esac
case " $modules " in *" model "*) need assets ;; esac
diff --git a/examples/dialog.c b/examples/dialog.c
index 51fe369..f6ce9a7 100644
--- a/examples/dialog.c
+++ b/examples/dialog.c
@@ -1,21 +1,24 @@
/*
* dialog: a little scene with sprites on a stage, a text box in front of them and a menu of buttons in the middle
*
- * build: ./build.sh -d -m 2d,stage,textbox,font obj/dialog
+ * build: ./build.sh -d -m 2d,stage,textbox,fx,font obj/dialog
* run: obj/dialog
*
- * space, enter or a click goes on, up and down or the mouse pick in the menu, l puts Bo in front of the text box and back again
+ * space, enter or a click goes on, up and down or the mouse pick in the menu, l puts Bo in front of the text box and back again.
+ * f flashes, s shakes, t changes the tone, d fades out and in, p turns a glow picture on and off. the box stays clear of all of them
*/
#include <stdio.h>
+#include <math.h>
#include "konprogram.h"
#include "kon2d.h"
#include "konstage.h"
#include "kontextbox.h"
+#include "konfx.h"
-#if !defined(KON_MODULE_2D) || !defined(KON_MODULE_STAGE) || !defined(KON_MODULE_TEXTBOX) || !defined(KON_MODULE_FONT)
-#error "build with: ./build.sh -d -m 2d,stage,textbox,font obj/dialog"
+#if !defined(KON_MODULE_2D) || !defined(KON_MODULE_STAGE) || !defined(KON_MODULE_TEXTBOX) || !defined(KON_MODULE_FX) || !defined(KON_MODULE_FONT)
+#error "build with: ./build.sh -d -m 2d,stage,textbox,fx,font obj/dialog"
#endif
#define VIEW_WIDTH 320
@@ -35,9 +38,11 @@ typedef struct state {
kon_stage_t stage;
kon_stageSprite_t sprites[4];
kon_textbox_t box, menu;
- kon_image *back[2], *block[SPRITES];
+ kon_screenfx_t fx;
+ kon_image *back[2], *block[SPRITES], *glow;
int who[SPRITES];
int beat, background;
+ int toned, faded, glowing, glowSprite;
} state_t;
/*** pictures ***/
@@ -72,6 +77,23 @@ static kon_image *makeGradient(uint32_t top, uint32_t bottom)
return image;
}
+static kon_image *makeGlow(int size)
+{
+ kon_image *image = kon_createFramebuffer(size, size);
+ int x, y;
+
+ if (!image) return NULL;
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; x++) {
+ float dx = ((float)x + 0.5f) / (float)size * 2.0f - 1.0f, dy = ((float)y + 0.5f) / (float)size * 2.0f - 1.0f;
+ float d = sqrtf(dx * dx + dy * dy), a = d < 1.0f ? (1.0f - d) * (1.0f - d) : 0.0f;
+
+ image->data[y * size + x] = ((uint32_t)(a * 255.0f) << 24) | (COL_SAND & 0x00FFFFFFu);
+ }
+ }
+ return image;
+}
+
/*** the scene ***/
static void say(state_t *state, int who, const char *text)
@@ -162,6 +184,18 @@ static int event(kon_program_t *program, const kon_event_t *ev, void *user)
if (ev->type == KON_EVENT_KEY_DOWN) {
if (ev->key == KON_KEY_SPACE || ev->key == KON_KEY_ENTER) action(state);
else if (ev->key == KON_KEY_L && state->who[BO] >= 0) kon_stageLayer(&state->stage, state->who[BO], state->sprites[state->who[BO]].layer == KON_LAYER_BACK ? KON_LAYER_FRONT : KON_LAYER_BACK);
+ else if (ev->key == KON_KEY_F) kon_screenfxFlash(&state->fx, 0xC0FFFFFFu, 0.4f);
+ else if (ev->key == KON_KEY_S) kon_screenfxShake(&state->fx, 5.0f, 2.0f, 12.0f, 0.5f);
+ else if (ev->key == KON_KEY_T) {
+ state->toned = !state->toned;
+ kon_screenfxTone(&state->fx, state->toned ? 30 : 0, state->toned ? 10 : 0, state->toned ? -20 : 0, state->toned ? 80 : 0, 0.8f, KON_EASE_INOUT);
+ } else if (ev->key == KON_KEY_D) {
+ state->faded = !state->faded;
+ kon_screenfxFade(&state->fx, COL_BACKGROUND, state->faded ? 1.0f : 0.0f, 0.8f, KON_EASE_LINEAR);
+ } else if (ev->key == KON_KEY_P) {
+ state->glowing = !state->glowing;
+ kon_stageFade(&state->stage, state->glowSprite, state->glowing ? 0.9f : 0.0f, 0.6f, KON_EASE_LINEAR);
+ }
else if (ev->key == KON_KEY_UP) kon_textboxSelect(&state->menu, -1);
else if (ev->key == KON_KEY_DOWN) kon_textboxSelect(&state->menu, 1);
else return 0;
@@ -187,8 +221,9 @@ static void update(kon_program_t *program, double dt, void *user)
{
state_t *state = user;
- (void)program;
kon_stageUpdate(&state->stage, (float)dt);
+ kon_screenfxUpdate(&state->fx, (float)dt);
+ kon_stageRotate(&state->stage, state->glowSprite, (float)program->time * 0.3f, 0.0f, KON_EASE_LINEAR);
kon_textboxUpdate(&state->box, (float)dt);
kon_textboxUpdate(&state->menu, (float)dt);
if (state->box.state == KON_TEXTBOX_EMPTY && state->menu.state == KON_TEXTBOX_EMPTY && !kon_stageBusy(&state->stage)) beat(state);
@@ -202,6 +237,7 @@ static void draw(kon_program_t *program, kon_framebuffer_t *game, void *user)
kon_clearFramebuffer(game, COL_BACKGROUND);
kon_stageDrawBackground(&state->stage, game);
kon_stageDraw(&state->stage, game, KON_LAYER_BACK);
+ kon_screenfxApply(&state->fx, game);
kon_textboxDraw(&state->box, game);
kon_stageDraw(&state->stage, game, KON_LAYER_FRONT);
kon_textboxDraw(&state->menu, game);
@@ -219,6 +255,15 @@ static int init(kon_program_t *program, void *user)
kon_stageInit(&state->stage, state->sprites, 4, VIEW_WIDTH, VIEW_HEIGHT);
state->who[ADA] = state->who[BO] = -1;
+ kon_screenfxInit(&state->fx);
+
+ state->glow = makeGlow(160);
+ if (!state->glow) return 0;
+ state->glowSprite = kon_stageAdd(&state->stage, state->glow, NULL, KON_LAYER_BACK);
+ state->sprites[state->glowSprite].blend = KON_BLEND_ADD;
+ state->sprites[state->glowSprite].anchorX = state->sprites[state->glowSprite].anchorY = 0.5f;
+ state->sprites[state->glowSprite].z = 10;
+ kon_stageMove(&state->stage, state->glowSprite, VIEW_WIDTH * 0.5f, 60.0f, 0.0f, KON_EASE_LINEAR);
kon_textboxInit(&state->box, program->font, 12, 118, VIEW_WIDTH - 24, 52);
state->box.panel.fill = 0xA026223Au;
@@ -238,6 +283,7 @@ static void shutdown(kon_program_t *program, void *user)
(void)program;
for (i = 0; i < 2; i++) kon_freeFramebuffer(state->back[i]);
for (i = 0; i < SPRITES; i++) kon_freeFramebuffer(state->block[i]);
+ kon_freeFramebuffer(state->glow);
}
int main(void)