Import of 2021 KITT inspired effect prototype.
authorMatthew Mondor <mmondor@pulsar-zone.net>
Thu, 8 Jun 2023 10:49:35 +0000 (10:49 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Thu, 8 Jun 2023 10:49:35 +0000 (10:49 +0000)
tests/sdl-kitt/GNUmakefile [new file with mode: 0644]
tests/sdl-kitt/main.c [new file with mode: 0644]

diff --git a/tests/sdl-kitt/GNUmakefile b/tests/sdl-kitt/GNUmakefile
new file mode 100644 (file)
index 0000000..e9b0aba
--- /dev/null
@@ -0,0 +1,38 @@
+# $Id: GNUmakefile,v 1.1 2011/03/10 13:17:33 mmondor Exp $
+
+CC := cc
+RM := rm
+UNAME := uname
+
+CFLAGS += -Wall
+
+# Enable for verbosity/debugging
+#CFLAGS += -v -H -g
+#LDFLAGS += -v -g
+
+# And to disable assertions
+#CFLAGS += -DNDEBUG
+
+OBJS := main.o
+BIN := kitt
+
+SDL_CFLAGS := $(shell sdl-config --cflags)
+SDL_LDFLAGS := $(shell sdl-config --libs)
+SDL_LDFLAGS += -lSDL_gfx
+
+CFLAGS += -I/usr/include -I/usr/pkg/include
+LDFLAGS += -Wl,-R/usr/lib -L/usr/lib -Wl,-R/usr/pkg/lib -L/usr/pkg/lib
+
+CFLAGS += $(SDL_CFLAGS)
+LDFLAGS += $(SDL_LDFLAGS)
+
+all: $(BIN)
+
+%.o: %.c
+       $(CC) -c $(CFLAGS) -o $@ $<
+
+$(BIN): $(OBJS)
+       $(CC) -o $@ $(OBJS) $(LDFLAGS)
+
+clean:
+       $(RM) -f $(BIN) $(OBJS)
diff --git a/tests/sdl-kitt/main.c b/tests/sdl-kitt/main.c
new file mode 100644 (file)
index 0000000..3d11470
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * SDL-based Knight-Rider Kitt style effect
+ * Prototype to port to AVR+TCL.  For this reason levels are 0-4095.
+ * Copyright (c) 2021, Matthew Mondor
+ *
+ * Example usage:
+ * $ gmake (or make if your OS uses GNUMake)
+ * $ ./kitt
+ * $ ./kitt -n16 -w64 -h64 -p4 -T4 -t7 -d450
+ * $ ./kitt -n16 -w92 -h48 -p4 -t3 -T4 -t8 -d255 -l 2048 -r 0 -g 0 -b 255
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <SDL.h>
+#include <SDL_framerate.h>
+
+
+#define SCREEN_DEPTH   32
+
+#define FPS            60      /* 0 = unrestricted */
+#define SHOWFPS                false
+#define FULLSCREEN     false
+
+
+int                    main(int, char **);
+void                   usage(void);
+
+static void            err(const char *);
+static void            warn(const char *);
+static bool            screen_init(int, int);
+static void            screen_destroy(void);
+
+inline static uint8_t  color_scale(uint8_t, int);
+static void            draw_screen(void);
+static void            modulate(void);
+static void            tlc(int, int);
+
+
+static SDL_Surface     *screen_surface = NULL;
+
+/* Used for frame rate delay */
+#if (FPS > 0)
+static FPSmanager      fpsm;
+#endif
+
+/* Simulate set/getprogname(3) on GNU */
+static const char *progname = "";
+
+/* Modulator state */
+static int     *levels = NULL;
+static int     channel = 0;
+static int     direction = 1;
+
+/* Parameters */
+static int     slots = 6, slot_width = 144, slot_height = 64;
+static int     color_r = 0xff, color_g = 0x20, color_b = 0x20;
+static int     bright_min = 1024, bright_max = 4095, tail = 4, head = 2,
+               dim = 896, spause = 8;
+
+
+/* ARGSUSED */
+int
+main(int argc, char **argv)
+{
+       int ch, i, skip;
+
+       progname = strdup(argv[0]);
+       while ((ch = getopt(argc, argv, "?n:w:h:l:L:T:t:d:p:r:g:b:")) != -1) {
+               switch (ch) {
+               case 'n':
+                       slots = atoi(optarg);
+                       break;
+               case 'w':
+                       slot_width = atoi(optarg);
+                       break;
+               case 'h':
+                       slot_height = atoi(optarg);
+                       break;
+               case 'l':
+                       bright_min = atoi(optarg);
+                       break;
+               case 'L':
+                       bright_max = atoi(optarg);
+                       break;
+               case 'T':
+                       head = atoi(optarg);
+                       break;
+               case 't':
+                       tail = atoi(optarg);
+                       break;
+               case 'd':
+                       dim = atoi(optarg);
+                       break;
+               case 'p':
+                       spause = atoi(optarg);
+                       break;
+               case 'r':
+                       color_r = atoi(optarg);
+                       break;
+               case 'g':
+                       color_g = atoi(optarg);
+                       break;
+               case 'b':
+                       color_b = atoi(optarg);
+                       break;
+               case '?':       /* FALLTHROUGH */
+               default:
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (!screen_init(slot_width * slots, slot_height))
+               err("screen_init()");
+
+       /* Modulator initialization */
+       if ((levels = malloc(sizeof(int) * slots)) == NULL)
+               err("malloc()");
+       channel = slots / 2;
+       skip = spause;
+       for (i = 0; i < slots; i++)
+               tlc(i, bright_min);
+
+       for (;;) {
+               SDL_Event       ev;
+
+               if (SDL_PollEvent(&ev)) {
+                       switch (ev.type) {
+                       case SDL_MOUSEBUTTONDOWN:
+                       case SDL_KEYDOWN:
+                       case SDL_QUIT:
+                               goto end;
+                       }
+               }
+
+               draw_screen();
+               if (--skip < 1) {
+                       modulate();
+                       skip = spause;
+               }
+       }
+
+end:
+       if (levels != NULL)
+               free(levels);
+
+       exit(EXIT_SUCCESS);
+}
+
+void
+usage(void)
+{
+
+       (void) fprintf(stderr,
+           "Usage: %s [-n <slots>] [-w <slotwidth>] [-h <slotheight>] "
+           "[-L <brightmax>] [-l <brightmin>] [-T <head>] [-t <tail>] "
+           "[-d <dim>] [-r <red>] [-g <green>] [-b <blue>] "
+           "[-p <pause>]\n", progname);
+       exit(EXIT_FAILURE);
+}
+
+static void
+err(const char *str)
+{
+
+       (void) fprintf(stderr, "%s\n", str);
+       exit(EXIT_FAILURE);
+}
+
+static void
+warn(const char *str)
+{
+
+       (void) fprintf(stdout, "%s\n", str);
+}
+
+static bool
+screen_init(int width, int height)
+{
+       const SDL_VideoInfo     *vi;
+       int                     screen_flags = 0;
+
+       if (SDL_Init(SDL_INIT_VIDEO) == -1)
+               return false;
+
+       if ((vi = SDL_GetVideoInfo()) == NULL)
+               return false;
+       screen_flags |= SDL_HWPALETTE | SDL_DOUBLEBUF;
+#if (FULLSCREEN == true)
+       screen_flags |= SDL_FULLSCREEN;
+#endif
+       if (vi->hw_available)
+               screen_flags |= SDL_HWSURFACE;
+       else {
+               warn("Note: Hardware surfaces not available.");
+               screen_flags |= SDL_SWSURFACE;
+       }
+       if (vi->blit_hw)
+               screen_flags |= SDL_HWACCEL;
+       else
+               warn("Note: Hardware blitting not available.");
+
+       if ((screen_surface = SDL_SetVideoMode(width, height,
+           SCREEN_DEPTH, screen_flags)) == NULL)
+               return false;
+
+       /* Initialize FPS delay */
+#if (FPS > 0)
+       SDL_initFramerate(&fpsm);
+       if (SDL_setFramerate(&fpsm, FPS) == -1)
+               return false;
+#endif
+
+       (void) atexit(screen_destroy);
+       return true;
+}
+
+static void
+screen_destroy(void)
+{
+
+       SDL_Quit();
+}
+
+/*
+ * Level is 0-4095 vs color, 0-255 (16x)
+ */
+inline static uint8_t
+color_scale(uint8_t col, int level)
+{
+
+       if (level == 0)
+               return 0;
+       /* level / 4096 = ? / col */
+       return (level * col / 4096);
+}
+
+static void
+draw_screen(void)
+{
+       int i;
+       SDL_Rect rect;
+
+#if (SHOWFPS == true)
+       static Uint32   fps_cnt = 0, fps = 0;
+#endif
+
+       rect.x = rect.y = 0;
+       rect.w = slot_width;
+       rect.h = slot_height;
+       for (i = 0; i < slots; i++, rect.x += slot_width) {
+               uint8_t r, g, b;
+               uint32_t c;
+               int l = levels[i];
+
+               /* Scale level */
+               r = color_scale(color_r, l);
+               g = color_scale(color_g, l);
+               b = color_scale(color_b, l);
+               /* Compose RGB color */
+               c = (((r << 16) & 0x00ff0000) | ((g << 8) & 0x0000ff00) | \
+                    (b & 0x000000ff));
+
+               (void)SDL_FillRect(screen_surface, &rect, c);
+       }
+
+       (void)SDL_Flip(screen_surface);
+
+       /* Delay as necessary to maintain frame rate */
+#if (FPS > 0)
+       SDL_framerateDelay(&fpsm);
+#endif
+#if (SHOWFPS == true)
+       /* Evaluate FPS */
+       fps++;
+       {
+               Uint32  t = SDL_GetTicks();
+
+               if (t - fps_cnt >= 5000) {
+                       float   seconds = (t - fps_cnt) / 1000.0;
+                       float   fps2 = fps / seconds;
+
+                       printf("%d frames in %g seconds = %g FPS\n",
+                           fps, seconds, fps2);
+                       fps_cnt = t;
+                       fps = 0;
+               }
+       }
+#endif
+}
+
+void
+modulate(void)
+{
+       int i, c, b;
+
+       for (i = 0; i < slots; i++)
+               tlc(i, bright_min);
+
+       for (i = 0, b = bright_max, c = channel;
+            i < head;
+            i++, b -= dim, c += direction)
+               tlc(c, b);
+       for (i = 0, b = bright_max, c = channel;
+            i < tail;
+            i++, b -= dim, c -= direction)
+               tlc(c, b);
+
+       c = channel + direction;
+       if (c < 0 || c == slots)
+               direction = -direction;
+       else
+               channel = c;
+}
+
+void
+tlc(int c, int l)
+{
+       if (c < 0 || c >= slots)
+               return;
+       assert(l >= 0 && l < 4096);
+
+       levels[c] = l;
+//     printf("%02d = %04d\n", c, l);
+}