changeset 7:fbb7101b7bd8

core: implement animations, closes #2439
author David Demelier <markand@malikania.fr>
date Mon, 06 Jan 2020 21:39:16 +0100
parents 3054723e53d7
children 106620648160
files Makefile src/animation.c src/animation.h src/main.c src/sprite.c src/sprite.h src/window.c
diffstat 7 files changed, 249 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Jan 06 21:27:45 2020 +0100
+++ b/Makefile	Mon Jan 06 21:39:16 2020 +0100
@@ -21,7 +21,8 @@
 CC=             clang
 CFLAGS=         -O3 -DNDEBUG -std=c99 -Wall -Wextra
 CPPFLAGS=       -MMD
-SRCS=           src/clock.c \
+SRCS=           src/animation.c \
+                src/clock.c \
                 src/image.c \
                 src/main.c \
                 src/sprite.c \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/animation.c	Mon Jan 06 21:39:16 2020 +0100
@@ -0,0 +1,82 @@
+/*
+ * animation.c -- basic animations
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "animation.h"
+#include "sprite.h"
+
+void
+animation_init(struct animation *an, struct sprite *sprite, uint16_t delay)
+{
+	assert(an);
+	assert(sprite);
+
+	an->sprite = sprite;
+	an->row = 0;
+	an->column = 0;
+	an->delay = delay;
+	an->elapsed = 0;
+}
+
+bool
+animation_is_complete(const struct animation *an)
+{
+	assert(an);
+
+	return an->row == an->sprite->nrows &&
+	       an->column == an->sprite->ncols &&
+	       an->elapsed >= an->delay;
+}
+
+void
+animation_start(struct animation *an)
+{
+	assert(an);
+
+	an->row = 0;
+	an->column = 0;
+	an->elapsed = 0;
+}
+
+void
+animation_update(struct animation *an, unsigned ticks)
+{
+	assert(an);
+
+	an->elapsed += ticks;
+
+	if (an->elapsed < an->delay)
+		return;
+
+	an->elapsed = 0;
+	an->column += 1;
+
+	if (an->column >= an->sprite->ncols) {
+		an->column = 0;
+
+		if (++an->row >= an->sprite->nrows)
+			an->row = 0;
+	}
+}
+
+void
+animation_draw(struct animation *an, int x, int y)
+{
+	sprite_draw(an->sprite, an->row, an->column, x, y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/animation.h	Mon Jan 06 21:39:16 2020 +0100
@@ -0,0 +1,101 @@
+/*
+ * animation.h -- basic animations
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_ANIMATION_H
+#define MOLKO_ANIMATION_H
+
+/**
+ * \file animation.h
+ * \brief Basic animations.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct sprite;
+
+/**
+ * \brief Animation object
+ */
+struct animation {
+	struct sprite *sprite;  /* Sprite to use (RW) */
+	uint16_t row;           /* current row (RO) */
+	uint16_t column;        /* current column (RO) */
+	uint16_t delay;         /* delay between frames (RW) */
+	uint16_t elapsed;       /* elapsed time since last frame (RO) */
+};
+
+/**
+ * Initialize the animation.
+ *
+ * The animation does not take sprite ownership, it must be valid until
+ * animation is no longer used.
+ *
+ * \pre an != NULL
+ * \pre sprite != NULL
+ * \param an the animation
+ * \param sprite the sprite to use
+ * \param delay the delay between frames in milliseconds
+ */
+void
+animation_init(struct animation *an, struct sprite *sprite, uint16_t delay);
+
+/**
+ * Tells if the animation is complete.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ * \return true if the animation has completed
+ */
+bool
+animation_is_complete(const struct animation *an);
+
+/**
+ * Start an animation.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ */
+void
+animation_start(struct animation *an);
+
+/**
+ * Update the animation.
+ *
+ * You must call this function at each loop iteration to update the animation
+ * frame depending on its delay.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ * \param ticks the elapsed ticks since the last call
+ */
+void
+animation_update(struct animation *an, unsigned ticks);
+
+/**
+ * Draw the animation.
+ *
+ * \pre an != NULL
+ * \param an the animation
+ * \param x the X coordinate
+ * \param y the Y coordinate
+ */
+void
+animation_draw(struct animation *an, int x, int y);
+
+#endif /* !MOLKO_ANIMATION_H */
--- a/src/main.c	Mon Jan 06 21:27:45 2020 +0100
+++ b/src/main.c	Mon Jan 06 21:39:16 2020 +0100
@@ -18,10 +18,12 @@
 
 #include <stdio.h>
 
-#include "window.h"
+#include "animation.h"
+#include "clock.h"
 #include "image.h"
+#include "sprite.h"
 #include "texture.h"
-#include "sprite.h"
+#include "window.h"
 
 #include <SDL.h>
 
@@ -33,10 +35,46 @@
 
 	struct texture *logo;
 	struct sprite sprite;
+	struct clock clock;
+	struct animation animation;
 
 	window_init("Molko's Adventure", 640, 480);
 	window_set_color(0x667788ff);
-	window_clear();
+
+	clock_start(&clock);
+
+	logo = image_openf("E:\\dev\\molko\\explosion.png");
+
+	if (!logo)
+		exit(1);
+
+	sprite_init(&sprite, logo, 256, 256);
+	animation_init(&animation, &sprite, 20);
+	setvbuf(stdout, NULL, _IONBF, 0);
+
+	for (;;) {
+		uint64_t ticks = clock_elapsed(&clock);
+
+		clock_start(&clock);
+
+		SDL_Event ev;
+		while (SDL_PollEvent(&ev)) {
+			switch (ev.type) {
+			case SDL_QUIT:
+				return 0;
+			}
+		}
+
+		//animation_update(&animation, ticks);
+		window_clear();
+		sprite_draw(&sprite, 4, 0, 10, 10);
+		//animation_draw(&animation, 10, 10);
+		window_present();
+		printf("%llu\n", ticks);
+		SDL_Delay(50);
+	}
+
+#if 0
 	window_set_color(0xffffffff);
 	window_draw_line(50, 50, 100, 100);
 	window_draw_point(60, 60);
@@ -44,9 +82,7 @@
 	logo = image_openf("E:\\Charactervector.png");
 	sprite_init(&sprite, logo, 65, 100);
 	sprite_draw(&sprite, 1, 2, 400, 400);
-
-	window_present();
-	SDL_Delay(5000);
+#endif
 
 	return 0;
 }
--- a/src/sprite.c	Mon Jan 06 21:27:45 2020 +0100
+++ b/src/sprite.c	Mon Jan 06 21:39:16 2020 +0100
@@ -23,25 +23,32 @@
 #include "texture.h"
 
 void
-sprite_init(struct sprite *sprite, struct texture *tex, uint8_t cellw, uint8_t cellh)
+sprite_init(struct sprite *sprite, struct texture *tex, uint16_t cellw, uint16_t cellh)
 {
+	int w = 0;
+	int h = 0;
+
 	assert(sprite);
 	assert(tex);
 
+	SDL_QueryTexture(tex->handle, NULL, NULL, &w, &h);
+
 	sprite->texture = tex;
 	sprite->cellw = cellw;
 	sprite->cellh = cellh;
+	sprite->nrows = h / cellh;
+	sprite->ncols = w / cellw;
 }
 
 void
-sprite_draw(struct sprite *sprite, unsigned r, unsigned c, int x, int y)
+sprite_draw(struct sprite *sprite, uint16_t r, uint16_t c, int x, int y)
 {
 	assert(sprite);
 
 	texture_draw_ex(
 		sprite->texture,
-		r * sprite->cellw,      /* src x */
-		c * sprite->cellh,      /* src y */
+		c * sprite->cellw,      /* src y */
+		r * sprite->cellh,      /* src x */
 		sprite->cellw,          /* src width */
 		sprite->cellh,          /* src height */
 		x,                      /* dst x */
--- a/src/sprite.h	Mon Jan 06 21:27:45 2020 +0100
+++ b/src/sprite.h	Mon Jan 06 21:39:16 2020 +0100
@@ -33,8 +33,11 @@
  */
 struct sprite {
 	struct texture *texture;        /* Texture to access (RO) */
-	uint8_t cellw;                  /* Width per cell (RW) */
-	uint8_t cellh;                  /* Hieight per cell (RW) */
+	uint16_t cellw;                 /* Width per cell (RW) */
+	uint16_t cellh;                 /* Height per cell (RW) */
+	uint16_t nrows;                 /* Number of rows (RW) */
+	uint16_t ncols;                 /* Number of columns (RW) */
+
 };
 
 /**
@@ -46,6 +49,9 @@
  * This function is only provided as convenience, user may initialize the
  * sprite by itself if wanted.
  *
+ * The fields `nrows' and `ncols' will be determined automatically from the
+ * texture size.
+ *
  * \pre sprite != NULL
  * \pre tex != NULL
  * \param sprite the sprite to initialize
@@ -56,8 +62,8 @@
 void
 sprite_init(struct sprite *sprite,
             struct texture *tex,
-            uint8_t cellw,
-            uint8_t cellh);
+            uint16_t cellw,
+            uint16_t cellh);
 
 /**
  * Draw the sprite component from row `r' and column `c'.
@@ -70,6 +76,6 @@
  * \warning No bounds checking
  */
 void
-sprite_draw(struct sprite *sprite, unsigned r, unsigned c, int x, int y);
+sprite_draw(struct sprite *sprite, uint16_t r, uint16_t c, int x, int y);
 
 #endif /* !MOLKO_SPRITE_H */
--- a/src/window.c	Mon Jan 06 21:27:45 2020 +0100
+++ b/src/window.c	Mon Jan 06 21:39:16 2020 +0100
@@ -86,8 +86,6 @@
 		.y = y
 	};
 
-	assert(w);
-
 	if (fill)
 		SDL_RenderFillRect(win.renderer, &rect);
 	else