tests: added sdl-joystick, an analog joystick test
authorMatthew Mondor <mmondor@pulsar-zone.net>
Tue, 7 Mar 2017 01:56:53 +0000 (01:56 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Tue, 7 Mar 2017 01:56:53 +0000 (01:56 +0000)
tests/sdl-joystick/GNUmakefile [new file with mode: 0644]
tests/sdl-joystick/src/main.c [new file with mode: 0644]

diff --git a/tests/sdl-joystick/GNUmakefile b/tests/sdl-joystick/GNUmakefile
new file mode 100644 (file)
index 0000000..7871336
--- /dev/null
@@ -0,0 +1,59 @@
+# $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
+
+# And to enable profiling
+#CFLAGS += -pg
+#LDFLAGS += -pg
+
+OBJS := $(addprefix src/,main.o)
+BIN := joystick
+
+SDL_CFLAGS := $(shell sdl-config --cflags)
+SDL_LDFLAGS := $(shell sdl-config --libs)
+SDL_LDFLAGS += -lSDL_image -lSDL_gfx
+
+# OS dependent settings follow
+OS := $(shell $(UNAME) -s)
+ifneq (,$(findstring CYGWIN,$(OS)))
+       # cygwin-mingw
+       CFLAGS += -mno-cygwin -I/usr/local/include -I/usr/include/mingw -DWIN32
+       LDFLAGS += -mwindows -mno-cygwin -L/usr/lib/mingw -L/usr/local/lib
+else
+       # unix
+       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
+endif
+
+# Architecture independent settings follow
+CFLAGS += -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234
+ifeq ($(OBJARCH),i386)
+       CFLAGS += -DBYTE_ORDER=LITTLE_ENDIAN
+else
+       CFLAGS += -DBYTE_ORDER=BIG_ENDIAN
+endif
+
+CFLAGS += $(SDL_CFLAGS)
+LDFLAGS += $(SDL_LDFLAGS)
+
+all: $(BIN)
+
+%.o: %.c
+       $(CC) -c $(CFLAGS) -o $@ $<
+
+$(BIN): $(OBJS)
+       $(CC) -o $@ $(OBJS) $(LDFLAGS)
+
+clean:
+       $(RM) -f $(BIN) $(BIN).exe $(OBJS) stdout.txt stderr.txt
diff --git a/tests/sdl-joystick/src/main.c b/tests/sdl-joystick/src/main.c
new file mode 100644 (file)
index 0000000..0ebdb7f
--- /dev/null
@@ -0,0 +1,274 @@
+/* $Id: main.c,v 1.4 2015/04/13 05:16:12 mmondor Exp $ */
+
+/*
+ * SDL-based joystick test
+ * Copyright (c) 2017, Matthew Mondor
+ */
+
+/*
+ * Analog joysticks may have different center, low and max values, as well as
+ * different resolutions for their pots.  This uses a calibration test, then
+ * displays where the cursor is on the screen according to the test and
+ * current pot values as the user moves the stick around.  May be useful to
+ * both test joystick accuracy and SDL usage of such devices.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_framerate.h>
+#include <SDL_gfxPrimitives.h>
+
+
+#define SCREEN_WIDTH   640
+#define SCREEN_HEIGHT  480
+#define SCREEN_DEPTH   32
+#define FPS            60
+#define CURSOR_RADIUS  4
+
+
+int                    main(int, char **);
+
+static void            err(const char *);
+static void            warn(const char *);
+static bool            screen_init(void);
+static void            screen_destroy(void);
+static bool            joystick_init(void);
+static void            joystick_scale(void);
+static void            joystick_destroy(void);
+
+static void            cursor_update(SDL_JoyAxisEvent *);
+static void            draw_screen(void);
+
+
+static SDL_Surface     *screen_surface = NULL;
+static SDL_Joystick    *joystick = NULL;
+
+/* Current pointer position on screen, updated by joystick events */
+int                    pos_x = SCREEN_WIDTH / 2,
+                       pos_y = SCREEN_HEIGHT / 2;
+
+/* Calibration test values */
+int                    cal_x_sensitivity = 3000, cal_y_sensitivity = 3000;
+int                    cal_center_x = 0, cal_center_y = 0,
+                       cal_min_x = -19000, cal_min_y = -22800,
+                       cal_max_x = 22800, cal_max_y = 19800;
+int                    cal_scale_left = 0, cal_scale_right = 0,
+                       cal_scale_up = 0, cal_scale_down = 0;
+
+/* Used for frame rate delay */
+static FPSmanager      fpsm;
+
+
+/* ARGSUSED */
+int
+main(int argc, char **argv)
+{
+       SDL_Event       ev;
+
+       if (!screen_init())
+               err("screen_init()");
+       if (!joystick_init())
+               err("joystick_init()");
+       /* XXX Calibration */
+       joystick_scale();
+
+       (void)SDL_EventState(SDL_JOYAXISMOTION, SDL_ENABLE);
+       (void)SDL_EventState(SDL_JOYBALLMOTION, SDL_ENABLE);
+
+       for (;;) {
+               while (SDL_PollEvent(&ev)) {
+                       switch (ev.type) {
+                       case SDL_JOYAXISMOTION:
+                               cursor_update(&ev.jaxis);
+                               break;
+                       case SDL_MOUSEBUTTONDOWN:
+                       case SDL_KEYDOWN:
+                       case SDL_QUIT:
+                               goto end;
+                               /* NOTREACHED */
+                               break;
+                       }
+               }
+               draw_screen();
+       }
+
+end:
+       exit(EXIT_SUCCESS);
+}
+
+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(void)
+{
+       const SDL_VideoInfo     *vi;
+       int                     screen_flags = 0;
+
+       if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) == -1)
+               return false;
+
+       if ((vi = SDL_GetVideoInfo()) == NULL)
+               return false;
+       screen_flags |= SDL_HWPALETTE | SDL_DOUBLEBUF;
+       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(SCREEN_WIDTH, SCREEN_HEIGHT,
+           SCREEN_DEPTH, screen_flags)) == NULL)
+               return false;
+
+       /* Initialize FPS delay */
+       SDL_initFramerate(&fpsm);
+       if (SDL_setFramerate(&fpsm, FPS) == -1)
+               return false;
+
+       (void) atexit(screen_destroy);
+       return true;
+}
+
+static void
+screen_destroy(void)
+{
+
+       SDL_Quit();
+}
+
+static bool
+joystick_init(void)
+{
+
+       /* Initialize joystick */
+       /* XXX
+        * - Present a menu of joystick choices
+        * - Maybe also axis # selection for x/y
+        * - atexit(3) handler to close
+        */
+       if (SDL_NumJoysticks > 0 &&
+           (joystick = SDL_JoystickOpen(0)) != NULL) {
+               (void) atexit(joystick_destroy);
+               return true;
+       }
+
+       return false;
+}
+
+static void
+joystick_destroy(void)
+{
+
+       if (joystick != NULL)
+               SDL_JoystickClose(joystick);
+}
+
+static void
+joystick_scale(void)
+{
+
+       cal_scale_left = (cal_center_x - cal_min_x) / (SCREEN_WIDTH / 2);
+       cal_scale_right = (cal_max_x - cal_center_x) / (SCREEN_WIDTH / 2);
+       cal_scale_up = (cal_center_y - cal_min_y) / (SCREEN_HEIGHT / 2);
+       cal_scale_down = (cal_max_y - cal_center_y) / (SCREEN_HEIGHT / 2);
+
+       /* XXX DEBUG */
+       printf("SCALING:\n");
+       printf("center: x: %d, y: %d\n",
+              cal_center_x, cal_center_y);
+       printf("limits: x-left: %d, x-right: %d, y-up: %d, y-down: %d\n",
+              cal_min_x, cal_max_x, cal_min_y, cal_max_y);
+       printf("scale: left: %d, right: %d, up: %d, down: %d\n",
+              cal_scale_left, cal_scale_right, cal_scale_up, cal_scale_down);
+}
+
+static void
+cursor_update(SDL_JoyAxisEvent *aev)
+{
+       int     x, y;
+
+       switch (aev->axis) {
+       case 0: /* X */
+               x = aev->value;
+               /* XXX Autocalibrate */
+               if (x < cal_min_x) {
+                       cal_min_x = x;
+                       joystick_scale();
+               } else if (x > cal_max_x) {
+                       cal_max_x = x;
+                       joystick_scale();
+               }
+               if (x < cal_center_x - cal_x_sensitivity)
+                       pos_x = (SCREEN_WIDTH / 2) - (abs(x) / cal_scale_left);
+               else if (x > cal_center_x + cal_x_sensitivity)
+                       pos_x = (SCREEN_WIDTH / 2) + (abs(x) / cal_scale_right);
+               else
+                       pos_x = SCREEN_WIDTH / 2;
+               break;
+       case 1: /* Y */
+               y = aev->value;
+               /* XXX Autocalibrate */
+               if (y < cal_min_y) {
+                       cal_min_y = y;
+                       joystick_scale();
+               } else if (y > cal_max_y) {
+                       cal_max_y = y;
+                       joystick_scale();
+               }
+               if (y < cal_center_y - cal_y_sensitivity)
+                       pos_y = (SCREEN_HEIGHT / 2) - (abs(y) / cal_scale_up);
+               else if (y > cal_center_y + cal_y_sensitivity)
+                       pos_y = (SCREEN_HEIGHT / 2) + (abs(y) / cal_scale_down);
+               else
+                       pos_y = SCREEN_HEIGHT / 2;
+               break;
+       }
+
+       /* XXX DEBUG */
+       /*
+       if (aev->axis == 0 || aev->axis == 1) {
+               printf("posx: %d, posy: %d\n", pos_x, pos_y);
+               printf("\t%d, %d, %d\n", aev->which, aev->axis, aev->value);
+       }
+       */
+}
+
+static void
+draw_screen(void)
+{
+
+       (void)SDL_FillRect(screen_surface, NULL, 0x00000000);
+
+       if (pos_x > - CURSOR_RADIUS && pos_x < SCREEN_WIDTH - CURSOR_RADIUS &&
+           pos_y > - CURSOR_RADIUS && pos_y < SCREEN_HEIGHT - CURSOR_RADIUS)
+               (void)filledCircleRGBA(screen_surface, pos_x, pos_y,
+                   CURSOR_RADIUS, 255, 255, 255, 255);
+
+       (void)SDL_Flip(screen_surface);
+
+       /* Delay as necessary to maintain frame rate */
+       SDL_framerateDelay(&fpsm);
+}