From 44f637979c79a69fe71e708b5f654d276c066893 Mon Sep 17 00:00:00 2001
From: P. J. McDermott <pjm@nac.net>
Date: Mon, 04 Mar 2013 04:30:31 -0500
Subject: Make palette cycling a real part of the engine.

---
diff --git a/src/Makefile.am b/src/Makefile.am
index 65ae0ab..25a3c12 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,4 +9,5 @@ src_SOURCES = \
               src/compression.h src/compression.c \
               src/viewport.h    src/viewport.c \
               src/area.h        src/area.c \
+              src/palettes.h    src/palettes.c \
               $(src_resources_SOURCES)
diff --git a/src/main.c b/src/main.c
index c0b26a4..abfbf8d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,3 @@
-#include <math.h>
 #include <SDL.h>
 #include "init.h"
 #include "logging.h"
@@ -6,57 +5,7 @@
 #include "resources/map.h"
 #include "viewport.h"
 #include "area.h"
-
-#define CYCLE_LINEAR(t_max, r1, g1, b1, r2, g2, b2)                            \
-	do {                                                                   \
-		x = (double) t / (double) t_max;                               \
-		y_end = (i % 8) * 36;                                          \
-		y_start = y_end * r1;                                          \
-		y_end = y_end * r2;                                            \
-		colors[i].r = x * (y_end - y_start) + y_start;                 \
-		y_end = (i % 64 / 8) * 36;                                     \
-		y_start = y_end * g1;                                          \
-		y_end = y_end * g2;                                            \
-		colors[i].g = x * (y_end - y_start) + y_start;                 \
-		y_end = (i / 64) * 85;                                         \
-		y_start = y_end * b1;                                          \
-		y_end = y_end * b2;                                            \
-		colors[i].b = x * (y_end - y_start) + y_start;                 \
-	} while (0)
-#define CYCLE_COS(t_max, r1, g1, b1, r2, g2, b2)                               \
-	do {                                                                   \
-		/*                                                             \
-		 * t = t                                                       \
-		 * t_max = t_max                                               \
-		 * x = (t / t_max) * π                                         \
-		 * for y in {r, g, b}:                                         \
-		 *     m = y_end - y_start                                     \
-		 *     x = x                                                   \
-		 *     b = y_start                                             \
-		 *     y = m * ((cos(x) / 2) + 0.5) + b                        \
-		 */                                                            \
-		/*                                                             \
-		 * cos(x)         => [-1 .. 1]                                 \
-		 * (cos(x)/2)+0.5 => [0 .. 1]                                  \
-		 * y              => [y_start .. y_end]                        \
-		 */                                                            \
-		x = (double) t / (double) t_max * 3.14159;                     \
-		y_end = (i % 8) * 36;                                          \
-		y_start = y_end * r2;                                          \
-		y_end = y_end * r1;                                            \
-		colors[i].r = ((cos(x) / 2) + 0.5) *                           \
-			(y_end - y_start) + y_start;                           \
-		y_end = (i % 64 / 8) * 36;                                     \
-		y_start = y_end * g2;                                          \
-		y_end = y_end * g1;                                            \
-		colors[i].g = ((cos(x) / 2) + 0.5) *                           \
-			(y_end - y_start) + y_start;                           \
-		y_end = (i / 64) * 85;                                         \
-		y_start = y_end * b2;                                          \
-		y_end = y_end * b1;                                            \
-		colors[i].b = ((cos(x) / 2) + 0.5) *                           \
-			(y_end - y_start) + y_start;                           \
-	} while (0)
+#include "palettes.h"
 
 #define DEMO()                                                                 \
 	do {                                                                   \
@@ -74,7 +23,7 @@ main(void)
 	struct viewport *vp;
 	struct map *map;
 	struct area *a;
-	SDL_Color colors[256];
+	SDL_Palette *pal;
 	int i;
 	struct map_exit *e;
 
@@ -88,12 +37,9 @@ main(void)
 	if (map == NULL) {
 		err(1, "Where's the map, George?");
 	}
-	for (i = 0; i < 256; ++i) {
-		colors[i].r = (i % 8) * 36;
-		colors[i].g = (i % 64 / 8) * 36;
-		colors[i].b = (i / 64) * 85;
-	}
-	if (!SDL_SetPalette(vp->screen, SDL_LOGPAL, colors, 0, 256)) {
+	pal = map->palettes[MAP_PALETTE_DAY].palette->palette;
+	if (!SDL_SetPalette(vp->screen, SDL_LOGPAL, pal->colors,
+				0, pal->ncolors)) {
 		warn("Failed to set palette");
 	}
 	a = area_new(map, vp);
@@ -111,65 +57,84 @@ main(void)
 	render_area_to_viewport(a, vp);
 	{
 		Uint32 d, t;
-		double x;
-		int y_start, y_end;
+
+		pal = malloc(sizeof(*pal));
+		pal->colors = calloc(58, sizeof(*pal->colors));
+		pal->ncolors = 58;
 
 		for (d = 0; d < 4; ++d) {
+			t = 0;
+			debug("Day %d morn", d);
 			/* morn -> day */
-			for (t = 0; t < 360; t += 1) {
-				for (i = 0; i < 256; ++i) {
-					CYCLE_COS(360,
-							1.000, 0.875, 0.625,
-							1.000, 1.000, 1.000
-							);
+			for (; t < 360; t += 1) {
+				if (cycle_palettes_cosine(t, 360,
+						map->palettes[MAP_PALETTE_MORN]
+							.palette->palette,
+						map->palettes[MAP_PALETTE_DAY]
+							.palette->palette,
+						pal) == NULL) {
+					warn("Failed to cycle palettes");
 				}
 				if (!SDL_SetPalette(vp->screen, SDL_LOGPAL,
-							colors, 0, 256)) {
+							pal->colors,
+							0, pal->ncolors)) {
 					warn("Failed to set palette");
 				}
 				SDL_Flip(vp->screen);
 				SDL_Delay(10);
 			}
+			debug("Day %d day", d);
 			/* day -> eve */
-			for (t = 0; t < 360; t += 1) {
-				for (i = 0; i < 256; ++i) {
-					CYCLE_COS(360,
-							1.000, 1.000, 1.000,
-							0.875, 0.625, 0.625
-							);
+			for (; t < 720; t += 1) {
+				if (cycle_palettes_cosine(t, 360,
+						map->palettes[MAP_PALETTE_DAY]
+							.palette->palette,
+						map->palettes[MAP_PALETTE_EVE]
+							.palette->palette,
+						pal) == NULL) {
+					warn("Failed to cycle palettes");
 				}
 				if (!SDL_SetPalette(vp->screen, SDL_LOGPAL,
-							colors, 0, 256)) {
+							pal->colors,
+							0, pal->ncolors)) {
 					warn("Failed to set palette");
 				}
 				SDL_Flip(vp->screen);
 				SDL_Delay(10);
 			}
+			debug("Day %d eve", d);
 			/* eve -> night */
-			for (t = 0; t < 360; t += 1) {
-				for (i = 0; i < 256; ++i) {
-					CYCLE_COS(360,
-							0.875, 0.625, 0.625,
-							0.250, 0.250, 0.500
-							);
+			for (; t < 1080; t += 1) {
+				if (cycle_palettes_cosine(t, 360,
+						map->palettes[MAP_PALETTE_EVE]
+							.palette->palette,
+						map->palettes[MAP_PALETTE_NIGHT]
+							.palette->palette,
+						pal) == NULL) {
+					warn("Failed to cycle palettes");
 				}
 				if (!SDL_SetPalette(vp->screen, SDL_LOGPAL,
-							colors, 0, 256)) {
+							pal->colors,
+							0, pal->ncolors)) {
 					warn("Failed to set palette");
 				}
 				SDL_Flip(vp->screen);
 				SDL_Delay(10);
 			}
+			debug("Day %d night", d);
 			/* night -> morn */
-			for (t = 0; t < 360; t += 1) {
-				for (i = 0; i < 256; ++i) {
-					CYCLE_COS(360,
-							0.250, 0.250, 0.500,
-							1.000, 0.875, 0.625
-							);
+			for (; t < 1440; t += 1) {
+				if (cycle_palettes_cosine(t, 360,
+						map->palettes[MAP_PALETTE_NIGHT]
+							.palette->palette,
+						map->palettes[MAP_PALETTE_MORN]
+							.palette->palette,
+						pal) == NULL) {
+					warn("Failed to cycle palettes");
 				}
 				if (!SDL_SetPalette(vp->screen, SDL_LOGPAL,
-							colors, 0, 256)) {
+							pal->colors,
+							0, pal->ncolors)) {
 					warn("Failed to set palette");
 				}
 				SDL_Flip(vp->screen);
@@ -180,12 +145,9 @@ main(void)
 	quit(0);
 
 	/* Demo */
-	for (i = 0; i < 256; ++i) {
-		colors[i].r = (i % 8) * 36;
-		colors[i].g = (i % 64 / 8) * 36;
-		colors[i].b = (i / 64) * 85;
-	}
-	if (!SDL_SetPalette(vp->screen, SDL_LOGPAL, colors, 0, 256)) {
+	pal = map->palettes[MAP_PALETTE_DAY].palette->palette;
+	if (!SDL_SetPalette(vp->screen, SDL_LOGPAL, pal->colors,
+				0, pal->ncolors)) {
 		warn("Failed to set palette");
 	}
 
diff --git a/src/palettes.c b/src/palettes.c
new file mode 100644
index 0000000..19a41bf
--- /dev/null
+++ b/src/palettes.c
@@ -0,0 +1,109 @@
+#include <math.h>
+#include <SDL.h>
+#include "palettes.h"
+#include "logging.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+static inline Uint8 cycle_palettes_cosine_channel(Uint8, Uint8, double);
+static inline Uint8 cycle_palettes_linear_channel(Uint8, Uint8, double);
+
+SDL_Palette *
+cycle_palettes_cosine(Uint32 t, Uint32 t_max,
+		SDL_Palette *pal_start, SDL_Palette *pal_end,
+		SDL_Palette *pal_step)
+{
+	double x;
+	int col_i;
+
+	if (pal_start->ncolors != pal_end->ncolors) {
+		return NULL;
+	}
+	if (pal_start->ncolors != pal_step->ncolors) {
+		return NULL;
+	}
+
+	x = (double) (t % t_max) / (double) t_max * M_PI;
+
+	for (col_i = 0; col_i < pal_step->ncolors; ++col_i) {
+		pal_step->colors[col_i].r = cycle_palettes_cosine_channel(
+				pal_start->colors[col_i].r,
+				pal_end->colors[col_i].r,
+				x);
+		pal_step->colors[col_i].g = cycle_palettes_cosine_channel(
+				pal_start->colors[col_i].g,
+				pal_end->colors[col_i].g,
+				x);
+		pal_step->colors[col_i].b = cycle_palettes_cosine_channel(
+				pal_start->colors[col_i].b,
+				pal_end->colors[col_i].b,
+				x);
+	}
+
+	return pal_step;
+}
+
+SDL_Palette *
+cycle_palettes_linear(Uint32 t, Uint32 t_max,
+		SDL_Palette *pal_start, SDL_Palette *pal_end,
+		SDL_Palette *pal_step)
+{
+	double x;
+	int col_i;
+
+	if (pal_start->ncolors != pal_end->ncolors) {
+		return NULL;
+	}
+	if (pal_start->ncolors != pal_step->ncolors) {
+		return NULL;
+	}
+
+	x = (double) (t % t_max) / (double) t_max;
+
+	for (col_i = 0; col_i < pal_step->ncolors; ++col_i) {
+		pal_step->colors[col_i].r = cycle_palettes_linear_channel(
+				pal_start->colors[col_i].r,
+				pal_end->colors[col_i].r,
+				x);
+		pal_step->colors[col_i].g = cycle_palettes_linear_channel(
+				pal_start->colors[col_i].g,
+				pal_end->colors[col_i].g,
+				x);
+		pal_step->colors[col_i].b = cycle_palettes_linear_channel(
+				pal_start->colors[col_i].b,
+				pal_end->colors[col_i].b,
+				x);
+	}
+
+	return pal_step;
+}
+
+static inline Uint8
+cycle_palettes_cosine_channel(Uint8 y_start, Uint8 y_end, double x)
+{
+	double m;
+	Uint8 b;
+	Uint8 y;
+
+	m = y_end - y_start;
+	b = y_start;
+	y = m * ((cos(x) / -2.0) + 0.5) + b;
+
+	return y;
+}
+
+static inline Uint8
+cycle_palettes_linear_channel(Uint8 y_start, Uint8 y_end, double x)
+{
+	double m;
+	Uint8 b;
+	Uint8 y;
+
+	m = y_end - y_start;
+	b = y_start;
+	y = m * x + b;
+
+	return y;
+}
diff --git a/src/palettes.h b/src/palettes.h
new file mode 100644
index 0000000..c5f007a
--- /dev/null
+++ b/src/palettes.h
@@ -0,0 +1,13 @@
+#ifndef PALETTES_H
+#define PALETTES_H
+
+#include <SDL.h>
+
+SDL_Palette *cycle_palettes_cosine(Uint32 t, Uint32 t_max,
+		SDL_Palette *pal_start, SDL_Palette *pal_end,
+		SDL_Palette *pal_step);
+SDL_Palette *cycle_palettes_linear(Uint32 t, Uint32 t_max,
+		SDL_Palette *pal_start, SDL_Palette *pal_end,
+		SDL_Palette *pal_step);
+
+#endif
--
cgit v0.9.1