summaryrefslogtreecommitdiffstats
path: root/src/pong.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pong.c')
-rw-r--r--src/pong.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/pong.c b/src/pong.c
new file mode 100644
index 0000000..aba6ae6
--- /dev/null
+++ b/src/pong.c
@@ -0,0 +1,280 @@
+#include <io.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "system.h"
+
+#include "GPU.h"
+
+#define msleep(msec) usleep(1000*msec);
+
+
+static void
+pio_write (unsigned int data)
+{
+ IOWR (PIO_0_BASE, 0, data);
+}
+
+
+static void
+gpu_write (unsigned int reg, unsigned int data)
+{
+ IOWR (GPU_0_BASE, reg << 2, data);
+}
+
+
+static void
+update_gpu (int x, int y, int bat0, int bat1)
+{
+ // set locations
+ gpu_write (GPU_REG_SPRITE_X, x + GPU_OFFSET);
+ gpu_write (GPU_REG_SPRITE_Y, y + GPU_OFFSET);
+ gpu_write (GPU_REG_BAT0_Y, bat0 + GPU_OFFSET);
+ gpu_write (GPU_REG_BAT1_Y, bat1 + GPU_OFFSET);
+
+
+ // enable video
+ gpu_write (GPU_REG_BLANK, 0);
+}
+
+
+static void
+show_score (int score)
+{
+ // int to seven segment lookup: MSB dp g f e d c b a LSB
+ const uint8_t lookup[10] =
+ { 0x3F, 0x6, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x7, 0x7F, 0x6F };
+
+ uint8_t ss = 0;
+
+ // show negative with DP
+ if (score < 0)
+ {
+ ss |= 0x80;
+ score = -score;
+ }
+
+ if (score > 9)
+ score = 9;
+
+ ss |= lookup[score];
+
+ pio_write (ss);
+}
+
+static void
+load_sprite (void)
+{
+ const uint16_t sprite[16] =
+ { 0x00C0, 0x03E0, 0x0FF8, 0x1FFE, 0x3FC7, 0x3F83, 0x3933, 0x3987, 0x3D37,
+ 0x3D37, 0x3D87, 0x3FFF, 0x1FFE, 0x07F8, 0x01E0, 0x00C0
+ };
+ const unsigned int n = sizeof (sprite) / sizeof (uint16_t);
+ unsigned int i;
+
+ gpu_write (GPU_REG_SPRITE_COLOUR, GPU_RGB(7,2,0));
+
+ // squirt the bromium logo into the sprite
+ for (i = 0; i < n; ++i)
+ gpu_write (GPU_REG_SPRITE_BASE + i, sprite[i]);
+}
+
+
+static int
+dir (int a, int b)
+{
+ if (a > b)
+ return 1;
+ if (a < b)
+ return -1;
+ return 0;
+}
+
+static void
+move_bat (int *b, int db)
+{
+ *b += dir (db, *b);
+}
+
+static int
+squish (int *v, int min, int max)
+{
+ if (*v < min)
+ {
+ *v = min;
+ return 1;
+ }
+ if (*v >= max)
+ {
+ *v = max - 1;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+find_intersection (int x, int y, int xd, int yd, int t)
+{
+
+ // super lazy - we should use the power of MATHS
+
+ while (x != t)
+ {
+ x += xd;
+ y += yd;
+
+ if (squish (&y, 0, GPU_HEIGHT))
+ yd = -yd;
+
+ if (squish (&x, 0, GPU_WIDTH))
+ xd = -xd;
+ }
+
+ return y;
+}
+
+static int
+has_missed (int y1, int y2)
+{
+ y1 = y1 - y2;
+ if (y1 < 0)
+ y1 = -y1;
+ if (y1 > 20)
+ return 1;
+ return 0;
+}
+
+static int
+x_speed (void)
+{
+ return (rand () % 10) + 1;
+}
+
+static int
+y_speed (void)
+{
+ return (rand () % 9) - 4;
+}
+
+
+int
+main (void)
+{
+ int x, y, xd, yd;
+ int bat0, dbat0;
+ int bat1, dbat1;
+ int score = 0;
+ int serve = 0;
+ int i;
+
+ printf ("Working...\n");
+
+ srand (12392184);
+
+ bat0 = GPU_HEIGHT / 2;
+ bat1 = GPU_HEIGHT / 2;
+
+ load_sprite ();
+
+ for (;;)
+ {
+ xd = x_speed ();
+ yd = y_speed ();
+
+ show_score (score);
+
+ if (!serve)
+ {
+ x = 1;
+ y = bat0;
+ dbat0 = GPU_HEIGHT / 2;
+ dbat1 = find_intersection (x + xd, y + yd, xd, yd, GPU_WIDTH - 1);
+ }
+ else
+ {
+ x = GPU_WIDTH - 2;
+ y = bat1;
+ yd = -yd;
+ dbat0 = find_intersection (x + xd, y + yd, xd, yd, 0);
+ dbat1 = GPU_HEIGHT / 2;
+ }
+ serve = !serve;
+
+ for (;;)
+ {
+ x += xd;
+ y += yd;
+
+
+ if (squish (&y, 0, GPU_HEIGHT))
+ yd = -yd;
+
+ if (squish (&x, 0, GPU_WIDTH))
+ {
+ xd = x_speed ();
+ if (x)
+ xd = -xd;
+ yd = y_speed ();
+
+ if (x)
+ {
+
+ if (has_missed (y, bat1))
+ {
+ score++;
+ break;
+ }
+ dbat0 = find_intersection (x + xd, y + yd, xd, yd, 0);
+ dbat1 = GPU_HEIGHT / 2;
+
+ }
+ else
+ {
+
+ if (has_missed (y, bat0))
+ {
+ score--;
+ break;
+ }
+ dbat0 = GPU_HEIGHT / 2;
+ dbat1 =
+ find_intersection (x + xd, y + yd, xd, yd, GPU_WIDTH - 1);
+
+ }
+ }
+
+ move_bat (&bat0, dbat0);
+ move_bat (&bat1, dbat1);
+
+ update_gpu (x, y, bat0, bat1);
+
+ msleep (2);
+ }
+
+ if (!serve)
+ {
+ dbat1 = GPU_HEIGHT / 2;
+ dbat0 = bat0;
+ }
+ else
+ {
+ dbat0 = GPU_HEIGHT / 2;
+ dbat1 = bat1;
+ }
+
+ for (i = 0; i < 200; ++i)
+ {
+ if (i == 100)
+ show_score (score);
+
+ move_bat (&bat0, dbat0);
+ move_bat (&bat1, dbat1);
+
+ update_gpu (x, y, bat0, bat1);
+ msleep (2);
+
+ }
+ }
+}