aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <frankhwei536@gmail.com>2015-02-17 15:33:03 -0500
committerFranklin Wei <frankhwei536@gmail.com>2015-02-17 15:33:03 -0500
commit6030b176c2819c83c625f257ad7e8632a8245ed9 (patch)
treefd98417c4f40a3bc8479a5900920a0ccd40fedd6
parentef4cc242dc8ad04320d19af22931fcbdbf670c13 (diff)
downloadkappa-6030b176c2819c83c625f257ad7e8632a8245ed9.zip
kappa-6030b176c2819c83c625f257ad7e8632a8245ed9.tar.gz
kappa-6030b176c2819c83c625f257ad7e8632a8245ed9.tar.bz2
kappa-6030b176c2819c83c625f257ad7e8632a8245ed9.tar.xz
Emulate the Rockbox plugin API, ported xracer
Tons of changes
-rw-r--r--Makefile2
-rw-r--r--OBJ9
-rw-r--r--apps/fixedpoint.c457
-rw-r--r--apps/fixedpoint.h125
-rw-r--r--apps/plugin.c52
-rw-r--r--apps/plugin.h56
-rw-r--r--apps/xracer/compat.h37
-rw-r--r--apps/xracer/generator.c202
-rw-r--r--apps/xracer/generator.h46
-rw-r--r--apps/xracer/graphics.c237
-rw-r--r--apps/xracer/graphics.h48
-rw-r--r--apps/xracer/main.c142
-rw-r--r--apps/xracer/map.c44
-rw-r--r--apps/xracer/map.h44
-rw-r--r--apps/xracer/maps.c15
-rw-r--r--apps/xracer/maps.h3
-rw-r--r--apps/xracer/road.h48
-rw-r--r--apps/xracer/sprite.c26
-rw-r--r--apps/xracer/sprite.h42
-rw-r--r--apps/xracer/util.c161
-rw-r--r--apps/xracer/util.h66
-rw-r--r--apps/xracer/xracer.h72
-rw-r--r--boot/head.S2
-rw-r--r--drivers/gfx-as.S11
-rw-r--r--drivers/gfx.c218
-rw-r--r--drivers/gfx_font.c10
-rw-r--r--drivers/include/gfx.h26
-rw-r--r--drivers/ps2.c3
-rw-r--r--kernel/include/version.h2
-rw-r--r--kernel/main.c33
-rw-r--r--libc/include/stdlib.h4
-rw-r--r--libc/stdlib.c93
32 files changed, 2292 insertions, 44 deletions
diff --git a/Makefile b/Makefile
index 380445b..cfa96c0 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ kappa.iso: kappa.bin
@grub-mkrescue -o kappa.iso $(ISODIR) 2> /dev/null
kappa.bin: $(OBJ) $(SOURCES) Makefile
- @$(LD) -T kernel/linker.ld -o kappa.bin -melf_i386 $(OBJ)
+ @$(LD) -T kernel/linker.ld -o kappa.bin -melf_i386 $(OBJ) -L /usr/lib32 -lgcc_s -static
@echo "LD $@"
drivers/gfx.o: drivers/gfx.c Makefile
diff --git a/OBJ b/OBJ
index 81fe9b1..056e923 100644
--- a/OBJ
+++ b/OBJ
@@ -1,3 +1,12 @@
+apps/fixedpoint.o
+apps/plugin.o
+apps/xracer/graphics.o
+apps/xracer/generator.o
+apps/xracer/map.o
+apps/xracer/maps.o
+apps/xracer/sprite.o
+apps/xracer/main.o
+apps/xracer/util.o
boot/head.o
drivers/gfx.o
drivers/gfx-as.o
diff --git a/apps/fixedpoint.c b/apps/fixedpoint.c
new file mode 100644
index 0000000..ceb8b0c
--- /dev/null
+++ b/apps/fixedpoint.c
@@ -0,0 +1,457 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Jens Arnold
+ *
+ * Fixed point library for plugins
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "fixedpoint.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#ifndef BIT_N
+#define BIT_N(n) (1U << (n))
+#endif
+
+/** TAKEN FROM ORIGINAL fixedpoint.h */
+/* Inverse gain of circular cordic rotation in s0.31 format. */
+static const long cordic_circular_gain = 0xb2458939; /* 0.607252929 */
+
+/* Table of values of atan(2^-i) in 0.32 format fractions of pi where pi = 0xffffffff / 2 */
+static const unsigned long atan_table[] = {
+ 0x1fffffff, /* +0.785398163 (or pi/4) */
+ 0x12e4051d, /* +0.463647609 */
+ 0x09fb385b, /* +0.244978663 */
+ 0x051111d4, /* +0.124354995 */
+ 0x028b0d43, /* +0.062418810 */
+ 0x0145d7e1, /* +0.031239833 */
+ 0x00a2f61e, /* +0.015623729 */
+ 0x00517c55, /* +0.007812341 */
+ 0x0028be53, /* +0.003906230 */
+ 0x00145f2e, /* +0.001953123 */
+ 0x000a2f98, /* +0.000976562 */
+ 0x000517cc, /* +0.000488281 */
+ 0x00028be6, /* +0.000244141 */
+ 0x000145f3, /* +0.000122070 */
+ 0x0000a2f9, /* +0.000061035 */
+ 0x0000517c, /* +0.000030518 */
+ 0x000028be, /* +0.000015259 */
+ 0x0000145f, /* +0.000007629 */
+ 0x00000a2f, /* +0.000003815 */
+ 0x00000517, /* +0.000001907 */
+ 0x0000028b, /* +0.000000954 */
+ 0x00000145, /* +0.000000477 */
+ 0x000000a2, /* +0.000000238 */
+ 0x00000051, /* +0.000000119 */
+ 0x00000028, /* +0.000000060 */
+ 0x00000014, /* +0.000000030 */
+ 0x0000000a, /* +0.000000015 */
+ 0x00000005, /* +0.000000007 */
+ 0x00000002, /* +0.000000004 */
+ 0x00000001, /* +0.000000002 */
+ 0x00000000, /* +0.000000001 */
+ 0x00000000, /* +0.000000000 */
+};
+
+/* Precalculated sine and cosine * 16384 (2^14) (fixed point 18.14) */
+static const short sin_table[91] =
+{
+ 0, 285, 571, 857, 1142, 1427, 1712, 1996, 2280, 2563,
+ 2845, 3126, 3406, 3685, 3963, 4240, 4516, 4790, 5062, 5334,
+ 5603, 5871, 6137, 6401, 6663, 6924, 7182, 7438, 7691, 7943,
+ 8191, 8438, 8682, 8923, 9161, 9397, 9630, 9860, 10086, 10310,
+ 10531, 10748, 10963, 11173, 11381, 11585, 11785, 11982, 12175, 12365,
+ 12550, 12732, 12910, 13084, 13254, 13420, 13582, 13740, 13894, 14043,
+ 14188, 14329, 14466, 14598, 14725, 14848, 14967, 15081, 15190, 15295,
+ 15395, 15491, 15582, 15668, 15749, 15825, 15897, 15964, 16025, 16082,
+ 16135, 16182, 16224, 16261, 16294, 16321, 16344, 16361, 16374, 16381,
+ 16384
+};
+
+/**
+ * Implements sin and cos using CORDIC rotation.
+ *
+ * @param phase has range from 0 to 0xffffffff, representing 0 and
+ * 2*pi respectively.
+ * @param cos return address for cos
+ * @return sin of phase, value is a signed value from LONG_MIN to LONG_MAX,
+ * representing -1 and 1 respectively.
+ */
+long fp_sincos(unsigned long phase, long *cos)
+{
+ int32_t x, x1, y, y1;
+ unsigned long z, z1;
+ int i;
+
+ /* Setup initial vector */
+ x = cordic_circular_gain;
+ y = 0;
+ z = phase;
+
+ /* The phase has to be somewhere between 0..pi for this to work right */
+ if (z < 0xffffffff / 4) {
+ /* z in first quadrant, z += pi/2 to correct */
+ x = -x;
+ z += 0xffffffff / 4;
+ } else if (z < 3 * (0xffffffff / 4)) {
+ /* z in third quadrant, z -= pi/2 to correct */
+ z -= 0xffffffff / 4;
+ } else {
+ /* z in fourth quadrant, z -= 3pi/2 to correct */
+ x = -x;
+ z -= 3 * (0xffffffff / 4);
+ }
+
+ /* Each iteration adds roughly 1-bit of extra precision */
+ for (i = 0; i < 31; i++) {
+ x1 = x >> i;
+ y1 = y >> i;
+ z1 = atan_table[i];
+
+ /* Decided which direction to rotate vector. Pivot point is pi/2 */
+ if (z >= 0xffffffff / 4) {
+ x -= y1;
+ y += x1;
+ z -= z1;
+ } else {
+ x += y1;
+ y -= x1;
+ z += z1;
+ }
+ }
+
+ if (cos)
+ *cos = x;
+
+ return y;
+}
+
+/**
+ * Fixed point square root via Newton-Raphson.
+ * @param x square root argument.
+ * @param fracbits specifies number of fractional bits in argument.
+ * @return Square root of argument in same fixed point format as input.
+ *
+ * This routine has been modified to run longer for greater precision,
+ * but cuts calculation short if the answer is reached sooner.
+ */
+long fp_sqrt(long x, unsigned int fracbits)
+{
+ unsigned long xfp, b;
+ int n = 8; /* iteration limit (should terminate earlier) */
+
+ if (x <= 0)
+ return 0; /* no sqrt(neg), or just sqrt(0) = 0 */
+
+ /* Increase working precision by one bit */
+ xfp = x << 1;
+ fracbits++;
+
+ /* Get the midpoint between fracbits index and the highest bit index */
+ b = ((sizeof(xfp)*8-1) - __builtin_clzl(xfp) + fracbits) >> 1;
+ b = BIT_N(b);
+
+ do
+ {
+ unsigned long c = b;
+ b = (fp_div(xfp, b, fracbits) + b) >> 1;
+ if (c == b) break;
+ }
+ while (n-- > 0);
+
+ return b >> 1;
+}
+
+/* Accurate int sqrt with only elementary operations.
+ * Snagged from:
+ * http://www.devmaster.net/articles/fixed-point-optimizations/ */
+unsigned long isqrt(unsigned long x)
+{
+ /* Adding CLZ could optimize this further */
+ unsigned long g = 0;
+ int bshift = 15;
+ unsigned long b = 1ul << bshift;
+
+ do
+ {
+ unsigned long temp = (g + g + b) << bshift;
+
+ if (x > temp)
+ {
+ g += b;
+ x -= temp;
+ }
+
+ b >>= 1;
+ }
+ while (bshift--);
+
+ return g;
+}
+
+/**
+ * Fixed point sinus using a lookup table
+ * don't forget to divide the result by 16384 to get the actual sinus value
+ * @param val sinus argument in degree
+ * @return sin(val)*16384
+ */
+long fp14_sin(int val)
+{
+ val = (val+360)%360;
+ if (val < 181)
+ {
+ if (val < 91)/* phase 0-90 degree */
+ return (long)sin_table[val];
+ else/* phase 91-180 degree */
+ return (long)sin_table[180-val];
+ }
+ else
+ {
+ if (val < 271)/* phase 181-270 degree */
+ return -(long)sin_table[val-180];
+ else/* phase 270-359 degree */
+ return -(long)sin_table[360-val];
+ }
+ return 0;
+}
+
+/**
+ * Fixed point cosinus using a lookup table
+ * don't forget to divide the result by 16384 to get the actual cosinus value
+ * @param val sinus argument in degree
+ * @return cos(val)*16384
+ */
+long fp14_cos(int val)
+{
+ val = (val+360)%360;
+ if (val < 181)
+ {
+ if (val < 91)/* phase 0-90 degree */
+ return (long)sin_table[90-val];
+ else/* phase 91-180 degree */
+ return -(long)sin_table[val-90];
+ }
+ else
+ {
+ if (val < 271)/* phase 181-270 degree */
+ return -(long)sin_table[270-val];
+ else/* phase 270-359 degree */
+ return (long)sin_table[val-270];
+ }
+ return 0;
+}
+
+/**
+ * Fixed-point natural log
+ * taken from http://www.quinapalus.com/efunc.html
+ * "The code assumes integers are at least 32 bits long. The (positive)
+ * argument and the result of the function are both expressed as fixed-point
+ * values with 16 fractional bits, although intermediates are kept with 28
+ * bits of precision to avoid loss of accuracy during shifts."
+ */
+long fp16_log(int x)
+{
+ int t;
+ int y = 0xa65af;
+
+ if (x < 0x00008000) x <<=16, y -= 0xb1721;
+ if (x < 0x00800000) x <<= 8, y -= 0x58b91;
+ if (x < 0x08000000) x <<= 4, y -= 0x2c5c8;
+ if (x < 0x20000000) x <<= 2, y -= 0x162e4;
+ if (x < 0x40000000) x <<= 1, y -= 0x0b172;
+ t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd;
+ t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920;
+ t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27;
+ t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85;
+ t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1;
+ t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8;
+ t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe;
+ x = 0x80000000 - x;
+ y -= x >> 15;
+
+ return y;
+}
+
+/**
+ * Fixed-point exponential
+ * taken from http://www.quinapalus.com/efunc.html
+ * "The code assumes integers are at least 32 bits long. The (non-negative)
+ * argument and the result of the function are both expressed as fixed-point
+ * values with 16 fractional bits. Notice that after 11 steps of the
+ * algorithm the constants involved become such that the code is simply
+ * doing a multiplication: this is explained in the note below.
+ * The extension to negative arguments is left as an exercise."
+ */
+long fp16_exp(int x)
+{
+ int t;
+ int y = 0x00010000;
+
+ if (x < 0) x += 0xb1721, y >>= 16;
+ t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
+ t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
+ t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
+ t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
+ t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
+ t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
+ t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
+ t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
+ t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
+ t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
+ t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
+ y += ((y >> 8) * x) >> 8;
+
+ return y;
+}
+
+/** MODIFIED FROM replaygain.c */
+
+#define FP_MUL_FRAC(x, y) fp_mul(x, y, fracbits)
+#define FP_DIV_FRAC(x, y) fp_div(x, y, fracbits)
+
+/* constants in fixed point format, 28 fractional bits */
+#define FP28_LN2 (186065279L) /* ln(2) */
+#define FP28_LN2_INV (387270501L) /* 1/ln(2) */
+#define FP28_EXP_ZERO (44739243L) /* 1/6 */
+#define FP28_EXP_ONE (-745654L) /* -1/360 */
+#define FP28_EXP_TWO (12428L) /* 1/21600 */
+#define FP28_LN10 (618095479L) /* ln(10) */
+#define FP28_LOG10OF2 (80807124L) /* log10(2) */
+
+#define TOL_BITS 2 /* log calculation tolerance */
+
+
+/* The fpexp10 fixed point math routine is based
+ * on oMathFP by Dan Carter (http://orbisstudios.com).
+ */
+
+/** FIXED POINT EXP10
+ * Return 10^x as FP integer. Argument is FP integer.
+ */
+long fp_exp10(long x, unsigned int fracbits)
+{
+ long k;
+ long z;
+ long R;
+ long xp;
+
+ /* scale constants */
+ const long fp_one = (1 << fracbits);
+ const long fp_half = (1 << (fracbits - 1));
+ const long fp_two = (2 << fracbits);
+ const long fp_mask = (fp_one - 1);
+ const long fp_ln2_inv = (FP28_LN2_INV >> (28 - fracbits));
+ const long fp_ln2 = (FP28_LN2 >> (28 - fracbits));
+ const long fp_ln10 = (FP28_LN10 >> (28 - fracbits));
+ const long fp_exp_zero = (FP28_EXP_ZERO >> (28 - fracbits));
+ const long fp_exp_one = (FP28_EXP_ONE >> (28 - fracbits));
+ const long fp_exp_two = (FP28_EXP_TWO >> (28 - fracbits));
+
+ /* exp(0) = 1 */
+ if (x == 0)
+ {
+ return fp_one;
+ }
+
+ /* convert from base 10 to base e */
+ x = FP_MUL_FRAC(x, fp_ln10);
+
+ /* calculate exp(x) */
+ k = (FP_MUL_FRAC(abs(x), fp_ln2_inv) + fp_half) & ~fp_mask;
+
+ if (x < 0)
+ {
+ k = -k;
+ }
+
+ x -= FP_MUL_FRAC(k, fp_ln2);
+ z = FP_MUL_FRAC(x, x);
+ R = fp_two + FP_MUL_FRAC(z, fp_exp_zero + FP_MUL_FRAC(z, fp_exp_one
+ + FP_MUL_FRAC(z, fp_exp_two)));
+ xp = fp_one + FP_DIV_FRAC(FP_MUL_FRAC(fp_two, x), R - x);
+
+ if (k < 0)
+ {
+ k = fp_one >> (-k >> fracbits);
+ }
+ else
+ {
+ k = fp_one << (k >> fracbits);
+ }
+
+ return FP_MUL_FRAC(k, xp);
+}
+
+/** FIXED POINT LOG10
+ * Return log10(x) as FP integer. Argument is FP integer.
+ */
+long fp_log10(long n, unsigned int fracbits)
+{
+ /* Calculate log2 of argument */
+
+ long log2, frac;
+ const long fp_one = (1 << fracbits);
+ const long fp_two = (2 << fracbits);
+ const long tolerance = (1 << ((fracbits / 2) + 2));
+
+ if (n <=0) return FP_NEGINF;
+ log2 = 0;
+
+ /* integer part */
+ while (n < fp_one)
+ {
+ log2 -= fp_one;
+ n <<= 1;
+ }
+ while (n >= fp_two)
+ {
+ log2 += fp_one;
+ n >>= 1;
+ }
+
+ /* fractional part */
+ frac = fp_one;
+ while (frac > tolerance)
+ {
+ frac >>= 1;
+ n = FP_MUL_FRAC(n, n);
+ if (n >= fp_two)
+ {
+ n >>= 1;
+ log2 += frac;
+ }
+ }
+
+ /* convert log2 to log10 */
+ return FP_MUL_FRAC(log2, (FP28_LOG10OF2 >> (28 - fracbits)));
+}
+
+/** CONVERT FACTOR TO DECIBELS */
+long fp_decibels(unsigned long factor, unsigned int fracbits)
+{
+ /* decibels = 20 * log10(factor) */
+ return FP_MUL_FRAC((20L << fracbits), fp_log10(factor, fracbits));
+}
+
+/** CONVERT DECIBELS TO FACTOR */
+long fp_factor(long decibels, unsigned int fracbits)
+{
+ /* factor = 10 ^ (decibels / 20) */
+ return fp_exp10(FP_DIV_FRAC(decibels, (20L << fracbits)), fracbits);
+}
diff --git a/apps/fixedpoint.h b/apps/fixedpoint.h
new file mode 100644
index 0000000..4a2769b
--- /dev/null
+++ b/apps/fixedpoint.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Jens Arnold
+ *
+ * Fixed point library for plugins
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/** FIXED POINT MATH ROUTINES - USAGE
+ *
+ * - x and y arguments are fixed point integers
+ * - fracbits is the number of fractional bits in the argument(s)
+ * - functions return long fixed point integers with the specified number
+ * of fractional bits unless otherwise specified
+ *
+ * Multiply two fixed point numbers:
+ * fp_mul(x, y, fracbits)
+ *
+ * Divide two fixed point numbers:
+ * fp_div(x, y, fracbits)
+ *
+ * Calculate sin and cos of an angle:
+ * fp_sincos(phase, *cos)
+ * where phase is a 32 bit unsigned integer with 0 representing 0
+ * and 0xFFFFFFFF representing 2*pi, and *cos is the address to
+ * a long signed integer. Value returned is a long signed integer
+ * from -0x80000000 to 0x7fffffff, representing -1 to 1 respectively.
+ * That is, value is a fixed point integer with 31 fractional bits.
+ *
+ * Take square root of a fixed point number:
+ * fp_sqrt(x, fracbits)
+ *
+ * Take the square root of an integer:
+ * isqrt(x)
+ *
+ * Calculate sin or cos of an angle (very fast, from a table):
+ * fp14_sin(angle)
+ * fp14_cos(angle)
+ * where angle is a non-fixed point integer in degrees. Value
+ * returned is a fixed point integer with 14 fractional bits.
+ *
+ * Calculate the exponential of a fixed point integer
+ * fp16_exp(x)
+ * where x and the value returned are fixed point integers
+ * with 16 fractional bits.
+ *
+ * Calculate the natural log of a positive fixed point integer
+ * fp16_log(x)
+ * where x and the value returned are fixed point integers
+ * with 16 fractional bits.
+ *
+ * Calculate decibel equivalent of a gain factor:
+ * fp_decibels(factor, fracbits)
+ * where fracbits is in the range 12 to 22 (higher is better),
+ * and factor is a positive fixed point integer.
+ *
+ * Calculate factor equivalent of a decibel value:
+ * fp_factor(decibels, fracbits)
+ * where fracbits is in the range 12 to 22 (lower is better),
+ * and decibels is a fixed point integer.
+ */
+
+#ifndef FIXEDPOINT_H
+#define FIXEDPOINT_H
+
+#define fp_mul(x, y, z) (long)((((long long)(x)) * ((long long)(y))) >> (z))
+#define fp_div(x, y, z) (long)((((long)(x)) << (z)) / ((long)(y)))
+
+long fp_sincos(unsigned long phase, long *cos);
+long fp_sqrt(long a, unsigned int fracbits);
+long fp14_cos(int val);
+long fp14_sin(int val);
+long fp16_log(int x);
+long fp16_exp(int x);
+
+unsigned long isqrt(unsigned long x);
+
+/* fast unsigned multiplication (16x16bit->32bit or 32x32bit->32bit,
+ * whichever is faster for the architecture) */
+#ifdef CPU_ARM
+#define FMULU(a, b) ((uint32_t) (((uint32_t) (a)) * ((uint32_t) (b))))
+#else /* SH1, coldfire */
+#define FMULU(a, b) ((uint32_t) (((uint16_t) (a)) * ((uint16_t) (b))))
+#endif
+
+/** MODIFIED FROM replaygain.c */
+#define FP_INF (0x7fffffff)
+#define FP_NEGINF -(0x7fffffff)
+
+/** FIXED POINT EXP10
+ * Return 10^x as FP integer. Argument is FP integer.
+ */
+long fp_exp10(long x, unsigned int fracbits);
+
+/** FIXED POINT LOG10
+ * Return log10(x) as FP integer. Argument is FP integer.
+ */
+long fp_log10(long n, unsigned int fracbits);
+
+/* fracbits in range 12 - 22 work well. Higher is better for
+ * calculating dB, lower is better for calculating factor.
+ */
+
+/** CONVERT FACTOR TO DECIBELS */
+long fp_decibels(unsigned long factor, unsigned int fracbits);
+
+/** CONVERT DECIBELS TO FACTOR */
+long fp_factor(long decibels, unsigned int fracbits);
+
+#endif /* FIXEDPOINT_H */
diff --git a/apps/plugin.c b/apps/plugin.c
new file mode 100644
index 0000000..440841a
--- /dev/null
+++ b/apps/plugin.c
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+#include "plugin.h"
+#include "gfx.h"
+
+static void plugin_clear(void)
+{
+ gfx_clear();
+}
+
+static void plugin_drawpix(int x, int y)
+{
+ gfx_drawpixel(x, y);
+}
+
+static void plugin_vline(int a, int b, int c)
+{
+ gfx_vline(a, b, c);
+}
+
+static void plugin_hline(int a, int b, int c)
+{
+ gfx_hline(a, b, c);
+}
+
+static const struct plugin_api kappa_api = {
+ &plugin_clear,
+ &plugin_hline,
+ &plugin_vline,
+ &plugin_drawpix,
+ &gfx_drawline,
+ &gfx_drawrect,
+ &gfx_fillrect,
+ &gfx_set_foreground,
+ &gfx_get_foreground,
+ &gfx_set_background,
+ &gfx_get_background,
+ &srand,
+ &rand,
+ &gfx_filltriangle,
+ &gfx_drawcircle,
+ &gfx_fillcircle,
+ &gfx_update,
+ &gfx_putsxy
+};
+
+void plugin_load(enum plugin_status (*plugin)(const struct plugin_api*))
+{
+ bool status = gfx_get_doublebuffer();
+ gfx_set_doublebuffer(true);
+ plugin(&kappa_api);
+ gfx_set_doublebuffer(status);
+}
diff --git a/apps/plugin.h b/apps/plugin.h
new file mode 100644
index 0000000..5d62b93
--- /dev/null
+++ b/apps/plugin.h
@@ -0,0 +1,56 @@
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "gfx.h"
+#include "timer.h"
+
+#define LCD_WIDTH (*gfx_width)
+#define LCD_HEIGHT (*gfx_height)
+#define LCD_BLACK VGA_RGBPACK(0, 0, 0)
+#define LCD_WHITE VGA_RGBPACK(255,255,255)
+#define LCD_RGBPACK VGA_RGBPACK
+#define LOGF printf
+#define ARRAYLEN(a) (sizeof(a)/sizeof(a[0]))
+
+#define RGB_UNPACK_RED(x) ((x & 0xFF0000) >> 16)
+#define RGB_UNPACK_GREEN(x) ((x & 0xFF00) >> 8)
+#define RGB_UNPACK_BLUE(x) ((x & 0xFF) >> 0)
+
+enum plugin_status {
+ PLUGIN_OK = 0, /* PLUGIN_OK == EXIT_SUCCESS */
+ /* 1...255 reserved for exit() */
+ PLUGIN_POWEROFF,
+ PLUGIN_GOTO_WPS,
+ PLUGIN_ERROR = -1,
+};
+
+struct plugin_api {
+ void (*lcd_clear_display)(void);
+ void (*lcd_hline)(int x1, int x2, int y);
+ void (*lcd_vline)(int x, int y1, int y2);
+ void (*lcd_drawpixel)(int x, int y);
+ void (*lcd_drawline)(int x1, int y1, int x2, int y2);
+ void (*lcd_drawrect)(int x, int y, int width, int height);
+ void (*lcd_fillrect)(int x, int y, int width, int height);
+ void (*lcd_set_foreground)(unsigned foreground);
+ unsigned (*lcd_get_foreground)(void);
+ void (*lcd_set_background)(unsigned foreground);
+ unsigned (*lcd_get_background)(void);
+
+ void (*srand)(unsigned int seed);
+ unsigned int (*rand)(void);
+
+ void (*lcd_filltriangle)(int, int, int, int, int, int);
+ void (*lcd_drawcircle)(int x, int y, int r);
+ void (*lcd_fillcircle)(int x, int y, int r);
+ void (*lcd_update)(void);
+ void (*lcd_putsxy)(int x, int y, const char*);
+};
+
+/* defined by the plugin */
+extern const struct plugin_api *rb;
+
+#endif
diff --git a/apps/xracer/compat.h b/apps/xracer/compat.h
new file mode 100644
index 0000000..b37abc0
--- /dev/null
+++ b/apps/xracer/compat.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "plugin.h"
+
+/* this file contains some #defines to make this as platform-neutral as possible */
+
+/* rockbox/kappa API */
+
+#define FILL_TRI(x1, y1, x2, y2, x3, y3) rb->lcd_filltriangle(x1, y1, x2, y2, x3, y3)
+#define FILL_RECT(x, y, w, h) rb->lcd_fillrect(x, y, w, h)
+#define DRAW_HLINE(x1, x2, y) rb->lcd_hline(x1, x2, y)
+#define CLEAR_DISPLAY() rb->lcd_clear_display()
+#define SET_FOREGROUND(x) rb->lcd_set_foreground(x)
+#define SET_BACKGROUND(x) rb->lcd_set_background(x)
+#define LCD_UPDATE() rb->lcd_update()
+#define PUTSXY(x, y, s) rb->lcd_putsxy(x, y, s)
+#define YIELD()
+#define LOGF printf
diff --git a/apps/xracer/generator.c b/apps/xracer/generator.c
new file mode 100644
index 0000000..166395b
--- /dev/null
+++ b/apps/xracer/generator.c
@@ -0,0 +1,202 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "plugin.h"
+
+#include "xracer.h"
+#include "compat.h"
+#include "generator.h"
+#include "graphics.h"
+#include "road.h"
+#include "sprite.h"
+#include "util.h"
+
+
+static int last_y=0;
+
+void gen_reset(void)
+{
+ last_y = 0;
+}
+
+/* add_road(): adds a section of road segments between s and s+len,
+ each with the properties specified */
+void add_road(struct road_segment *road, unsigned int road_length, unsigned int s, unsigned int len, long curve, int hill)
+{
+ unsigned int i;
+ for(i = s; i < s+len && i < road_length; ++i)
+ {
+ struct road_segment tmp;
+ tmp.idx = i;
+ tmp.p1_z = i * SEGMENT_LENGTH;
+ tmp.p2_z = (i + 1) * SEGMENT_LENGTH;
+
+ /* change the lines below for hills */
+ tmp.p1_y = last_y;
+ tmp.p2_y = last_y+hill;
+ last_y += hill;
+
+ /* change this line for curves */
+ tmp.curve = curve;
+
+ tmp.color = (i/RUMBLE_LENGTH)%2?ROAD_COLOR1:ROAD_COLOR2;
+ tmp.border_color = (i/RUMBLE_LENGTH)%2?BORDER_COLOR1:BORDER_COLOR2;
+ tmp.lanes = (i/RUMBLE_LENGTH)%2?LANES:1;
+ tmp.lane_color = LANE_COLOR;
+ tmp.grass_color = (i/RUMBLE_LENGTH)%2?GRASS_COLOR1:GRASS_COLOR2;
+ tmp.clip = 0;
+ tmp.sprites = NULL;
+ road[i] = tmp;
+ }
+ if(i > road_length)
+ {
+ warning("road segment out of bounds (i=%d, len=%d)", i, road_length);
+ }
+}
+
+/* enter_uphill(): adds a road section with slopes 0,1...slope-1 */
+/* assumes slope is positive, for negative slopes, use *_downhill */
+static inline void enter_uphill(struct road_segment *road, unsigned int road_length, unsigned int s, int slope, long curve)
+{
+ for(int i=0; i<slope; ++i)
+ {
+ add_road(road, road_length, s + i, 1, curve, i);
+ }
+}
+
+/* exit_hill(): opposite of enter_hill, adds a road section with slopes slope-1...0 */
+/* assumes slope is positive, for negative slopes, use *_downhill */
+static inline void exit_uphill(struct road_segment *road, unsigned int road_length, unsigned int s, int slope, long curve)
+{
+ int n = slope;
+ for(int i = 0; i<n; ++i, --slope)
+ {
+ add_road(road, road_length, s + i, 1, curve, slope);
+ }
+}
+
+/* add_uphill(): currently unused */
+/* assumes slope is positive, for negative slopes, use *_downhill */
+void add_uphill(struct road_segment *road, unsigned int road_length, unsigned int s, int slope, int hold, long curve)
+{
+ enter_uphill(road, road_length, s, slope, curve);
+ add_road(road, road_length, s+slope, hold, curve, slope);
+ exit_uphill(road, road_length, s+slope+hold, slope, curve);
+}
+
+/* enter_downhill: adds a road section with slopes 0,-1,...slope+1 */
+/* assumes slope is negative, for positive slopes use *_uphill */
+static inline void enter_downhill(struct road_segment *road, unsigned int road_length, unsigned int s, int slope, long curve)
+{
+ int n = 0;
+ for(int i=0; i<-slope;++i, --n)
+ {
+ add_road(road, road_length, s + i, 1, curve, n);
+ }
+}
+
+/* adds a road section with slopes slope, slope+1,...,-1 */
+static inline void exit_downhill(struct road_segment *road, unsigned int road_length, unsigned int s, int slope, long curve)
+{
+ int n = slope;
+ for(int i=0; i<-slope; ++i, ++n)
+ {
+ add_road(road, road_length, s + i, 1, curve, n);
+ }
+}
+
+void add_downhill(struct road_segment *road, unsigned int road_length, unsigned int s, int slope, int hold, long curve)
+{
+ enter_downhill(road, road_length, s, slope, curve);
+ add_road(road, road_length, s-slope, hold, curve, slope);
+ exit_downhill(road, road_length, s-slope+hold, slope, curve);
+}
+
+/* generate_random_road(): generates a random track road_length segments long */
+
+void generate_random_road(struct road_segment *road, unsigned int road_length, bool hills, bool curves)
+{
+ gen_reset();
+ rb->srand(42);
+ int len;
+ for(unsigned int i = 0; i < road_length; i += len)
+ {
+ /* get an EVEN number */
+ len = (rb->rand()% 20 + 10) * 2;
+ if(i + len >= road_length)
+ len = road_length - i;
+
+ int r = rb->rand() % 12;
+
+ /* probability distribution */
+ /* 0, 1: uphill */
+ /* 2, 3: downhill */
+ /* 4, 5, 6, 7: straight */
+ /* 8, 9: left */
+ /* 10,11: right */
+ switch(r)
+ {
+ case 0:
+ case 1:
+ enter_uphill(road, road_length, i, 5, 0);
+ add_road(road, road_length, i+5, len-10, 0, ( hills ? 5 : 0));
+ exit_uphill(road, road_length, i+len-5, 5, 0);
+ break;
+ case 2:
+ case 3:
+ enter_downhill(road, road_length, i, -5, 0);
+ add_road(road, road_length, i+5, len-10, 0, (hills ? -5 : 0));
+ exit_downhill(road, road_length, i+len-5, -5, 0);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ add_road(road, road_length, i, len, 0, 0);
+ break;
+ case 8:
+ case 9:
+ add_road(road, road_length, i, len, (curves ? -1 << FRACBITS: 0), 0);
+ break;
+ case 10:
+ case 11:
+ add_road(road, road_length, i, len, (curves ? 1 << FRACBITS: 0), 0);
+ break;
+ }
+ }
+}
+
+void add_sprite(struct road_segment *seg, struct sprite_data_t *data)
+{
+ LOGF("adding sprite");
+ struct sprite_t *s = util_alloc(sizeof(struct sprite_t));
+ s->data = data;
+ s->next = NULL;
+ if(!seg->sprites)
+ {
+ seg->sprites = s;
+ return;
+ }
+ struct sprite_t *i = seg->sprites;
+ while(i->next)
+ i = i->next;
+ i->next = s;
+}
diff --git a/apps/xracer/generator.h b/apps/xracer/generator.h
new file mode 100644
index 0000000..306c3b9
--- /dev/null
+++ b/apps/xracer/generator.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef _GENERATOR_H_
+#define _GENERATOR_H_
+
+#include <stdbool.h>
+
+struct sprite_data_t;
+struct road_segment;
+
+void gen_reset(void);
+
+void add_road(struct road_segment *road, unsigned int road_length, unsigned int idx, unsigned int len, long curve, int hill);
+
+/* slope *must* be positive! for negative slopes, use add_downhill */
+void add_uphill(struct road_segment *road, unsigned int road_length, unsigned int idx, int slope, int hold, long curve);
+
+/* slope *must* be negative! for positive slopes, use add_uphill */
+void add_downhill(struct road_segment *road, unsigned int road_length, unsigned int idx, int slope, int hold, long curve);
+
+void generate_random_road(struct road_segment *road, unsigned int road_length, bool hills, bool curves);
+
+/* appends a sprite to the end of the linked list of sprites */
+/* data must be static! */
+void add_sprite(struct road_segment *seg, struct sprite_data_t *data);
+
+#endif
diff --git a/apps/xracer/graphics.c b/apps/xracer/graphics.c
new file mode 100644
index 0000000..e4d222d
--- /dev/null
+++ b/apps/xracer/graphics.c
@@ -0,0 +1,237 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "plugin.h"
+
+#include "fixedpoint.h"
+
+#include "xracer.h"
+#include "compat.h"
+#include "graphics.h"
+#include "road.h"
+#include "sprite.h"
+#include "util.h"
+
+/* fill poly takes 4 screenspace coordinates and fills them */
+/* order of arguments matters: */
+/* (x1, y1) (x2, y2) */
+/* (x3, y3) (x4, y4) */
+static inline void fill_poly(int x1, int y1,
+ int x2, int y2,
+ int x3, int y3,
+ int x4, int y4,
+ unsigned color)
+{
+ SET_FOREGROUND(color);
+ FILL_TRI(x1, y1, x2, y2, x3, y3);
+ FILL_TRI(x1, y1, x3, y3, x4, y4);
+}
+
+/* project(): performs 3d projection of pt_3d onto pt_2d given camera parameters */
+/* this takes arguments by value so as to allow easy changing of camera positions at render time*/
+
+static inline int project(int cam_x, int cam_y, int cam_z, int camera_depth, struct point_3d *pt_3d, struct point_2d *pt_2d, float *scale_return)
+{
+ /* calculate the coordinates relative to the camera */
+ int rel_x, rel_y, rel_z;
+ rel_x = pt_3d->x - cam_x;
+ rel_y = pt_3d->y - cam_y;
+ rel_z = pt_3d->z - cam_z;
+ float scale = (float)camera_depth / rel_z;
+ pt_2d->x = (LCD_WIDTH/2) + (scale * rel_x * (LCD_WIDTH/2));
+ pt_2d->y = (LCD_WIDTH/2) - (scale * rel_y * (LCD_HEIGHT/2));
+ pt_2d->w = scale * ROAD_WIDTH * (LCD_WIDTH/2);
+ if(scale_return)
+ *scale_return=scale;
+ return rel_z;
+}
+
+static inline int border_width(int projected_road_width, int lanes)
+{
+ return projected_road_width/MAX(6, 2*lanes);
+}
+
+static inline int lane_marker_width(int projected_road_width, int lanes)
+{
+ return projected_road_width/MAX(32, 8*lanes);
+}
+
+/* fill_gradient(): draws a gradient across the whole screen from top to bottom,
+ changing from top_color to bottom_color */
+
+static void fill_gradient(int top, unsigned top_color, int bottom, unsigned bottom_color)
+{
+ long top_r, top_g, top_b;
+ top_r = RGB_UNPACK_RED(top_color) << FRACBITS;
+ top_g = RGB_UNPACK_GREEN(top_color) << FRACBITS;
+ top_b = RGB_UNPACK_BLUE(top_color) << FRACBITS;
+
+ long bottom_r, bottom_g, bottom_b;
+ bottom_r = RGB_UNPACK_RED(bottom_color) << FRACBITS;
+ bottom_g = RGB_UNPACK_GREEN(bottom_color) << FRACBITS;
+ bottom_b = RGB_UNPACK_BLUE(bottom_color) << FRACBITS;
+
+ bottom <<= FRACBITS;
+ top <<= FRACBITS;
+ long r_step = fp_div((bottom_r-top_r), (bottom-top), FRACBITS);
+ long g_step = fp_div((bottom_g-top_g), (bottom-top), FRACBITS);
+ long b_step = fp_div((bottom_b-top_b), (bottom-top), FRACBITS);
+
+ long r = top_r;
+ long g = top_g;
+ long b = top_b;
+
+ bottom >>= FRACBITS;
+ top >>= FRACBITS;
+
+ for(int i = top; i<bottom; ++i)
+ {
+ SET_FOREGROUND(LCD_RGBPACK( ROUND(r), ROUND(g), ROUND(b) ));
+ DRAW_HLINE(0, LCD_WIDTH, i);
+ r += r_step;
+ g += g_step;
+ b += b_step;
+ }
+}
+
+/* draws a segment on screen given its 2d screen coordinates and other data */
+
+static inline void render_segment(struct point_2d *p1, struct point_2d *p2,
+ unsigned road_color, unsigned border_color,
+ int lanes, unsigned lane_color, unsigned grass_color)
+{
+ int border_1 = border_width(p1->w, lanes);
+ int border_2 = border_width(p2->w, lanes);
+
+ /* draw grass first */
+ SET_FOREGROUND(grass_color);
+ FILL_RECT(0, p2->y, LCD_WIDTH, p1->y - p2->y);
+
+ /* draw borders */
+ fill_poly(p1->x-p1->w-border_1, p1->y, p1->x-p1->w, p1->y,
+ p2->x-p2->w, p2->y, p2->x-p2->w-border_2, p2->y, border_color);
+
+ fill_poly(p1->x+p1->w+border_1, p1->y, p1->x+p1->w, p1->y,
+ p2->x+p2->w, p2->y, p2->x+p2->w+border_2, p2->y, border_color);
+
+ /* draw road */
+ fill_poly(p2->x-p2->w, p2->y, p2->x+p2->w, p2->y, p1->x+p1->w, p1->y, p1->x-p1->w, p1->y, road_color);
+
+ /* draw lanes */
+ if(lanes > 1)
+ {
+ int lane_1 = lane_marker_width(p1->w, lanes);
+ int lane_2 = lane_marker_width(p2->w, lanes);
+
+ int lane_w1, lane_w2, lane_x1, lane_x2;
+ lane_w1 = p1->w*2/lanes;
+ lane_w2 = p2->w*2/lanes;
+ lane_x1 = p1->x - p1->w + lane_w1;
+ lane_x2 = p2->x - p2->w + lane_w2;
+ for(int i=1; i<lanes; lane_x1 += lane_w1, lane_x2 += lane_w2, ++i)
+ {
+ fill_poly(lane_x1 - lane_1/2, p1->y, lane_x1 + lane_1/2, p1->y,
+ lane_x2 + lane_2/2, p2->y, lane_x2 - lane_2/2, p2->y, lane_color);
+ }
+ }
+}
+
+/* project_segment(): does the 3d calculations on a road segment */
+
+static inline bool project_segment(struct road_segment *base, struct road_segment *seg, int x, int dx,
+ struct camera_t *camera, struct point_2d *p1, struct point_2d *p2, int *maxy,
+ int road_length)
+{
+ bool looped = (seg->idx < base->idx);
+ seg->clip = *maxy;
+
+ /* future optimization: do one projection per segment because segment n's p2 is the same as segments n+1's p1*/
+
+ /* input points (3d space) */
+
+ struct point_3d p1_3d={-x, seg->p1_y, seg->p1_z};
+ struct point_3d p2_3d={-x-dx, seg->p2_y, seg->p2_z};
+
+ int camera_offset = (looped ? road_length * SEGMENT_LENGTH - camera->pos.z : 0);
+
+ /* 3d project the 2nd point FIRST because its results can be used to save some work */
+
+ int p2_cz = project(camera->pos.x, camera->pos.y, camera->pos.z - camera_offset, camera->depth, &p2_3d, p2, NULL);
+
+ /* decide whether or not to draw this segment */
+
+ if(p2_cz <= camera->depth || /* behind camera */
+ p2->y >= *maxy) /* clipped */
+ {
+ return false;
+ }
+
+ /* nothing is drawn below this */
+ *maxy = p2->y;
+
+ /* now 3d project the first point */
+
+ /* save the scale factor to draw sprites */
+ project(camera->pos.x, camera->pos.y, camera->pos.z - camera_offset, camera->depth, &p1_3d, p1, &seg->p1_scale);
+
+ if(p2->y >= p1->y) /* backface cull */
+ {
+ return false;
+ }
+ return true;
+}
+
+/* render(): The primary render driver function
+ *
+ * calculates segment coordinates and calls render_segment to draw the segment on-screen
+ * also handles the faking of curves
+ */
+
+void render(struct camera_t *camera, struct road_segment *road, unsigned int road_length, int camera_height)
+{
+ fill_gradient(0, SKY_COLOR1, LCD_HEIGHT, SKY_COLOR2);
+
+ struct road_segment *base = FIND_SEGMENT(camera->pos.z, road, road_length);
+
+ long base_percent = fp_div((camera->pos.z % SEGMENT_LENGTH) << FRACBITS, SEGMENT_LENGTH << FRACBITS, FRACBITS);
+ long dx = - fp_mul(base->curve, base_percent, FRACBITS);
+ long x = 0;
+
+ /* clipping height, nothing is drawn below this */
+ int maxy = LCD_HEIGHT;
+
+ /* move the camera to a fixed point above the road */
+ /* interpolate so as to prevent jumpy camera movement on hills */
+ camera->pos.y = INTERPOLATE(base->p1_y, base->p2_y, base_percent) + camera_height;
+
+ for(int i = 0; i < DRAW_DIST; ++i)
+ {
+ struct road_segment *seg = &road[(base->idx + i) % road_length];
+
+ if(project_segment(base, seg, ROUND(x), ROUND(dx), camera, &seg->p1, &seg->p2, &maxy, road_length))
+ {
+ render_segment(&seg->p1, &seg->p2, seg->color, seg->border_color, seg->lanes, seg->lane_color, seg->grass_color);
+ }
+ /* curve calculation */
+ x += dx;
+ dx += seg->curve; /* seg->curve is already FP */
+ }
+}
diff --git a/apps/xracer/graphics.h b/apps/xracer/graphics.h
new file mode 100644
index 0000000..aeecf0b
--- /dev/null
+++ b/apps/xracer/graphics.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef _GRAPHICS_H_
+#define _GRAPHICS_H_
+
+/* some basic types */
+
+struct point_3d {
+ int x;
+ int y;
+ int z;
+};
+
+struct camera_t {
+ struct point_3d pos;
+ int depth;
+};
+
+struct point_2d {
+ int x;
+ int y;
+ int w;
+};
+
+struct road_segment;
+
+void render(struct camera_t *camera, struct road_segment *road, unsigned int road_length, int camera_height);
+
+#endif
diff --git a/apps/xracer/main.c b/apps/xracer/main.c
new file mode 100644
index 0000000..9a51a31
--- /dev/null
+++ b/apps/xracer/main.c
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This code draws heavily on
+ * Jake Gordon's "How to build a racing game" tutorial at
+ *
+ * <http://codeincomplete.com/projects/racer/>
+ *
+ * and
+ *
+ * Louis Gorenfield's "Lou's Pseudo 3d Page" at
+ *
+ * <http://www.extentofthejam.com/pseudo/>
+ *
+ * Thanks!
+ */
+
+#include "plugin.h"
+
+#include "xracer.h"
+#include "compat.h"
+#include "generator.h"
+#include "graphics.h"
+#include "map.h"
+#include "maps.h"
+#include "road.h"
+#include "sprite.h"
+#include "util.h"
+
+#include "fixedpoint.h" /* only used for FOV computation */
+
+const struct plugin_api *rb;
+
+/* can move to audiobuf if too big... */
+struct road_segment road[MAX_ROAD_LENGTH];
+
+/* this can be changed to allow for variable-sized maps */
+unsigned int road_length=MAX_ROAD_LENGTH;
+
+int camera_height = CAMERA_HEIGHT;
+
+void generate_test_road(void)
+{
+ gen_reset();
+ add_road(road, road_length, 0, road_length, 0, 0);
+}
+
+void do_early_init(void)
+{
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ /* GIMME DAT RAW POWAH!!! */
+ rb->cpu_boost(true);
+#endif
+
+ init_alloc();
+}
+
+void do_late_init(void)
+{
+}
+
+enum plugin_status do_flythrough(void)
+{
+ struct camera_t camera;
+ camera.depth = LCD_WIDTH/CAMERA_TAN;
+
+ camera.pos.x = 0;
+ /* y is automatically calculated */
+ camera.pos.z = 0;
+
+ //generate_test_road();
+
+ //road_length = load_map(road, MAX_ROAD_LENGTH, loop_map, ARRAYLEN(loop_map));
+
+ //road_length = load_external_map(road, MAX_ROAD_LENGTH, "/output.xrm");
+
+ road_length = -1;
+
+
+ road_length = MAX_ROAD_LENGTH;
+
+ generate_random_road(road, road_length, HILLS, CURVES);
+
+ do_late_init();
+
+ long last_timestamp = *current_tick;
+
+ while(1)
+ {
+ camera.pos.z += 512;
+ /* loop the track right before going off the "end" */
+ camera.pos.z %= (road_length - DRAW_DIST) * SEGMENT_LENGTH;
+
+ render(&camera, road, road_length, camera_height);
+
+ char buf[32];
+ int dt = *current_tick - last_timestamp;
+ snprintf(buf, sizeof(buf), "DT: %d", dt);
+ SET_FOREGROUND(LCD_WHITE);
+ PUTSXY(0, 0, buf);
+
+ LCD_UPDATE();
+
+ //rb->sleep((HZ/100)-dt);
+ YIELD();
+ last_timestamp = *current_tick;
+ }
+}
+
+/* plugin_start(): plugin entry point */
+/* contains main loop */
+enum plugin_status xracer_main(const struct plugin_api *param)
+{
+ rb = param;
+
+ do_early_init();
+
+ enum plugin_status rc = do_flythrough();
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ rb->cpu_boost(false);
+#endif
+ return rc;
+}
diff --git a/apps/xracer/map.c b/apps/xracer/map.c
new file mode 100644
index 0000000..9a4f740
--- /dev/null
+++ b/apps/xracer/map.c
@@ -0,0 +1,44 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "generator.h"
+#include "map.h"
+#include "util.h"
+
+static bool add_section(struct road_segment *road, unsigned int max_road_length, unsigned int *back, struct road_section *map)
+{
+ bool ret = true;
+ switch(map->type)
+ {
+ case 0:
+ /* constant segment */
+ add_road(road, max_road_length, *back, map->len, map->curve, map->slope);
+ *back += map->len;
+ break;
+ case 1:
+ /* up-hill */
+ add_uphill(road, max_road_length, *back, map->slope, map->len, map->curve);
+ *back += map->len + 2*map->slope;
+ break;
+ case 2:
+ add_downhill(road, max_road_length, *back, map->slope, map->len, map->curve);
+ *back += map->len + 2*map->slope;
+ break;
+ default:
+ warning("invalid type id");
+ ret = false;
+ break;
+ }
+ return ret;
+}
+
+unsigned load_map(struct road_segment *road, unsigned int max_road_length, struct road_section *map, unsigned int map_length)
+{
+ gen_reset();
+ unsigned int back = 0;
+ for(unsigned int i=0;i<map_length;++i)
+ {
+ add_section(road, max_road_length, &back, &map[i]);
+ }
+ return back;
+}
diff --git a/apps/xracer/map.h b/apps/xracer/map.h
new file mode 100644
index 0000000..b7315df
--- /dev/null
+++ b/apps/xracer/map.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdint.h>
+
+#define MAP_VERSION 0x0001
+
+struct road_segment;
+
+struct road_section {
+ unsigned char type;
+ uint32_t len;
+ int32_t slope;
+
+ /* FP, 8 fracbits */
+ long curve;
+};
+
+/* takes a map in internal format and converts it to road_segment's */
+
+unsigned int load_map(struct road_segment*, unsigned max_road_length, struct road_section*, unsigned map_len);
+
+#endif
diff --git a/apps/xracer/maps.c b/apps/xracer/maps.c
new file mode 100644
index 0000000..770f3a6
--- /dev/null
+++ b/apps/xracer/maps.c
@@ -0,0 +1,15 @@
+#include "xracer.h"
+#include "maps.h"
+
+struct road_section loop_map[10] = {
+ { 0, 300, 0, 0 },
+ { 0, 100, 0, 1 << (FRACBITS) },
+ { 0, 200, 0, 0 },
+ { 0, 100, 0, 1 << (FRACBITS) },
+ { 0, 600, 0, 0 },
+ { 0, 100, 0, 1 << (FRACBITS) },
+ { 0, 200, 0, 0 },
+ { 0, 100, 0, 1 << (FRACBITS) },
+ { 0, 300, 0, 0 },
+ { 0, DRAW_DIST, 0, 0}
+};
diff --git a/apps/xracer/maps.h b/apps/xracer/maps.h
new file mode 100644
index 0000000..cab72d5
--- /dev/null
+++ b/apps/xracer/maps.h
@@ -0,0 +1,3 @@
+#include "map.h"
+
+struct road_section loop_map[10];
diff --git a/apps/xracer/road.h b/apps/xracer/road.h
new file mode 100644
index 0000000..2c1fe44
--- /dev/null
+++ b/apps/xracer/road.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef _ROAD_H_
+#define _ROAD_H_
+
+struct point_2d;
+struct sprite_t;
+
+struct road_segment {
+ int idx;
+ int p1_z;
+ int p2_z;
+ int p1_y;
+ int p2_y;
+ struct point_2d p1;
+ struct point_2d p2;
+ float p1_scale; /* slow... */
+ long curve; /* fixed-point with FRACBITS fractional bits */
+ unsigned color;
+ unsigned border_color;
+ int lanes;
+ unsigned lane_color;
+ unsigned grass_color;
+ int clip;
+ /* linked list of sprites */
+ struct sprite_t *sprites;
+};
+
+#endif
diff --git a/apps/xracer/sprite.c b/apps/xracer/sprite.c
new file mode 100644
index 0000000..1ad6ee9
--- /dev/null
+++ b/apps/xracer/sprite.c
@@ -0,0 +1,26 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "sprite.h"
+
+struct sprite_data_t sprites[] = {
+ {0, 0, 320, 240}, /* billboard 1 */
+};
diff --git a/apps/xracer/sprite.h b/apps/xracer/sprite.h
new file mode 100644
index 0000000..ae7f00e
--- /dev/null
+++ b/apps/xracer/sprite.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef _SPRITE_H_
+#define _SPRITE_H_
+
+struct sprite_data_t {
+ int x, y;
+ int w, h;
+};
+
+struct sprite_data_t sprites[1];
+
+/* the sprite_t object/struct/whatever should be as lightweight as possible */
+/* here it consists of just a pointer to the data */
+
+struct sprite_t {
+ struct sprite_t *next;
+ struct sprite_data_t *data;
+ /* offset ranges from -1 (FP) to 1 (FP) */
+ long offset;
+};
+
+#endif
diff --git a/apps/xracer/util.c b/apps/xracer/util.c
new file mode 100644
index 0000000..8f09d67
--- /dev/null
+++ b/apps/xracer/util.c
@@ -0,0 +1,161 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "plugin.h"
+#include "fixedpoint.h"
+#include "util.h"
+
+static void *plugin_buffer = NULL;
+static size_t bytes_left = -1;
+
+uint8_t allocbuf[1024 * 512];
+
+void init_alloc(void)
+{
+ if(!plugin_buffer)
+ {
+ plugin_buffer = allocbuf;
+ bytes_left = sizeof(allocbuf);
+ }
+}
+
+void *util_alloc(size_t sz)
+{
+ if(plugin_buffer)
+ {
+ void *ret = plugin_buffer;
+ plugin_buffer += sz;
+ if((signed long) bytes_left - (signed long) sz < 0)
+ {
+ error("Im all outta memoriez!!! :(");
+ return NULL;
+ }
+ bytes_left -= sz;
+ return ret;
+ }
+ else
+ {
+ warning("call to %s without init", __func__);
+ return NULL;
+ }
+}
+
+size_t util_alloc_remaining(void)
+{
+ if(plugin_buffer)
+ return bytes_left;
+ else
+ {
+ warning("call to %s without init", __func__);
+ return -1;
+ }
+}
+
+/* camera_calc_depth(): calculates the camera depth given its FOV by evaluating */
+/* LCD_WIDTH / tan(fov/2) */
+int camera_calc_depth(int fov)
+{
+ fov /= 2;
+ long fov_sin, fov_cos;
+ /* nasty (but fast) fixed-point math! */
+ fov_sin = fp14_sin(fov);
+ fov_cos = fp14_cos(fov);
+
+ long tan;
+ /* fp14_sin/cos has 14 fractional bits */
+ tan = fp_div(fov_sin, fov_cos, 14);
+
+ long width = LCD_WIDTH << 14;
+ return fp_div(width, tan, 14) >> 14;
+}
+
+void error_real(const char *msg, ...) {
+ char buf[256];
+ LOGF("ERROR: %s!", msg);
+}
+
+/* this CRC code was adapted from <http://automationwiki.com/index.php?title=CRC-16-CCITT> */
+
+static uint16_t crc_table [256] = {
+
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
+ 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
+ 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
+ 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
+ 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
+ 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
+ 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
+ 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
+ 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
+ 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
+ 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
+ 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
+ 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03,
+ 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
+ 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6,
+ 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
+ 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
+ 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1,
+ 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
+ 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
+ 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
+ 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447,
+ 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
+ 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2,
+ 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
+ 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
+ 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
+ 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0,
+ 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
+ 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
+ 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba,
+ 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
+ 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+uint16_t crc16_ccitt(unsigned char *data, size_t length, uint16_t seed, uint16_t final)
+{
+ size_t count;
+ unsigned int crc = seed;
+ unsigned int temp;
+
+ for (count = 0; count < length; ++count)
+ {
+ temp = (*data++ ^ (crc >> 8)) & 0xff;
+ crc = crc_table[temp] ^ (crc << 8);
+ }
+
+ return (uint16_t)(crc ^ final);
+}
+
+void warning_real(const char *msg, ...) {
+ LOGF("WARNING: %s!", msg);
+}
diff --git a/apps/xracer/util.h b/apps/xracer/util.h
new file mode 100644
index 0000000..2112c88
--- /dev/null
+++ b/apps/xracer/util.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <stdint.h>
+
+#include "xracer.h"
+#include "fixedpoint.h"
+
+/* finds the address of a segment corresponding to a z coordinate */
+#define FIND_SEGMENT(z, r, l) (&r[(int)((float)z/SEGMENT_LENGTH)%l])
+
+/* linearly interpolates a and b with percent having FRACBITS fractional bits */
+#define INTERPOLATE(a, b, percent) (((a << FRACBITS) + fp_mul((b<<FRACBITS)-(a<<FRACBITS), percent, FRACBITS)) >> FRACBITS)
+
+/* rounds a fixed-point number with FRACBITS fractional bits */
+/* returns an integer */
+/* adds 1/2 and truncates the fractional bits */
+#define ROUND(x) ((x+(1<<(FRACBITS-1)))>>FRACBITS)
+
+#ifdef ROCKBOX_LITTLE_ENDIAN
+#define READ_BE_UINT16(p) ((((const uint8_t*)p)[0] << 8) | ((const uint8_t*)p)[1])
+#define READ_BE_UINT32(p) ((((const uint8_t*)p)[0] << 24) | (((const uint8_t*)p)[1] << 16) | (((const uint8_t*)p)[2] << 8) | ((const uint8_t*)p)[3])
+#else
+#define READ_BE_UINT16(p) (*(const uint16_t*)p)
+#define READ_BE_UINT32(p) (*(const uint32_t*)p)
+#endif
+
+/* call this before using any alloc functions or the plugin buffer */
+void init_alloc(void);
+
+void *util_alloc(size_t);
+
+size_t util_alloc_remaining(void);
+
+/* camera_calc_depth(): calculates the camera depth given its FOV by evaluating */
+/* LCD_WIDTH / tan(fov/2) */
+int camera_calc_depth(int fov);
+
+void warning_real(const char *msg, ...);
+
+void error_real(const char *msg, ...);
+
+unsigned short crc16_ccitt(unsigned char *data, size_t length, unsigned short seed, unsigned short final);
+
+#define warning warning_real
+#define error error_real
+/*#define warning(msg, ...) warning_real("in function %s at %s:%d: %s", __func__, __FILE__, __LINE__, msg, ##__VA_ARGS__)
+ #define error(msg, ...) error_real("in function %s at %s:%d: %s", __func__, __FILE__, __LINE__, msg, ##__VA_ARGS__)*/
diff --git a/apps/xracer/xracer.h b/apps/xracer/xracer.h
new file mode 100644
index 0000000..70d2677
--- /dev/null
+++ b/apps/xracer/xracer.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 Franklin Wei
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+2 * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef _XRACER_H_
+#define _XRACER_H_
+
+/* miscellaneous #defines and data types */
+
+#include "plugin.h"
+
+/* colors */
+#define SKY_COLOR1 LCD_RGBPACK(0, 0x96, 0xff) /* top of sky gradient */
+#define SKY_COLOR2 LCD_RGBPACK(0xfe, 0xfe, 0xfe) /* bottom of sky gradient */
+#define GRASS_COLOR1 LCD_RGBPACK(0, 0xc5, 0)
+#define GRASS_COLOR2 LCD_RGBPACK(0, 0x9a, 0)
+#define ROAD_COLOR1 LCD_RGBPACK(120, 120, 120)
+#define ROAD_COLOR2 LCD_RGBPACK(80, 80, 80)
+#define BORDER_COLOR1 LCD_RGBPACK(240, 0, 0)
+#define BORDER_COLOR2 LCD_RGBPACK(240, 240, 240)
+#define LANE_COLOR LCD_RGBPACK(0xcc, 0xcc, 0xcc)
+
+/* road parameters */
+#define ROAD_WIDTH (LCD_WIDTH/2) /* actually half the road width for easier math */
+#define MAX_ROAD_LENGTH 4096
+#define SEGMENT_LENGTH (LCD_WIDTH * 12)
+
+/* road generator parameters */
+#define HILLS true
+#define CURVES true
+
+/* this specifies the length of each road and border color in segments */
+#define RUMBLE_LENGTH 3
+#define LANES 3
+
+/* camera parameters */
+#define DRAW_DIST 256
+
+/* NOTE: FOV is not used, the tangent value (see below) is */
+#define CAMERA_FOV 120 /* in degrees */
+#define CAMERA_TAN 1.732050808L
+#define CAMERA_HEIGHT 200
+
+/* game parameters */
+/* currently this is how far the camera moves per keypress */
+#define MANUAL_SPEED 50
+
+/* number of bits to use for the fractional part of fixed-point numbers */
+/* note that FOV calculation always uses 14 by default */
+#define FRACBITS 8
+
+/* the number of fractional bits to use for high-precision numbers */
+#define HIPREC_FRACBITS 24
+
+#endif
diff --git a/boot/head.S b/boot/head.S
index b74e929..8e607e0 100644
--- a/boot/head.S
+++ b/boot/head.S
@@ -17,8 +17,8 @@ multiboot_header:
.long 0
.long 0
.long 0 # 1=text mode
- .long 0 # screen height (don't care)
.long 0 # screen width (don't care)
+ .long 0 # screen height (don't care)
.long 32 # screen BPP: MUST be 32
.section .stack
diff --git a/drivers/gfx-as.S b/drivers/gfx-as.S
index 675a6d5..a58fa12 100644
--- a/drivers/gfx-as.S
+++ b/drivers/gfx-as.S
@@ -25,8 +25,10 @@ gfx_clear_packed:
popl %ebx
ret
- .global gfx_hline
-gfx_hline:
+ .global gfx_hline_fast
+
+gfx_hline_fast:
+ int $0x80
pushl %ebx
movl 8(%esp), %eax
movl 12(%esp), %ecx
@@ -54,8 +56,9 @@ gfx_hline:
popl %ebx
ret
- .global gfx_vline
-gfx_vline:
+ .global gfx_vline_fast
+
+gfx_vline_fast:
pushl %esi
pushl %ebx
movl 12(%esp), %eax
diff --git a/drivers/gfx.c b/drivers/gfx.c
index 7c56800..028a5e5 100644
--- a/drivers/gfx.c
+++ b/drivers/gfx.c
@@ -9,7 +9,10 @@
#include "panic.h"
#include "gfx.h"
+uint8_t *real_framebuffer = NULL;
+uint8_t *temp_framebuffer = NULL;
uint8_t *framebuffer = NULL;
+bool double_buffer = false;
uint16_t fb_width;
uint16_t fb_height;
@@ -28,6 +31,8 @@ uint32_t _gfx_fgcol, _gfx_bgcol;
void (*gfx_clear)(void);
void (*gfx_drawpixel)(int x, int y);
+void (*gfx_hline)(int x1, int x2, int y);
+void (*gfx_vline)(int y1, int y2, int x);
void gfx_set_background(uint32_t col)
{
@@ -58,6 +63,7 @@ void gfx_drawpixel_32bpp_checked(int x, int y)
else
panic("pixel OOB!\n");
}
+
/* implemented in assembly now */
/*
void gfx_clear(uint32_t col)
@@ -195,8 +201,7 @@ void gfx_puts(const char* str)
}
/* implemented in assembly now */
-#if 0
-void gfx_hline(int x1, int x2, int y)
+void gfx_hline_checked(int x1, int x2, int y)
{
/* make sure x1 is to the left of x2 */
if(x2 < x1)
@@ -206,19 +211,26 @@ void gfx_hline(int x1, int x2, int y)
x2 = temp;
}
- uint8_t *base = framebuffer + y * fb_stride;
+ x1 = MAX(0, x1);
+ x2 = MIN(x2, fb_width);
- uint8_t *dest = base + x1 * fb_bpp;
- uint8_t *stop = base + x2 * fb_bpp;
- const uint32_t col = _gfx_fgcol;
- while(dest < stop)
+ if(0 <= y && y < fb_height)
{
- *(uint32_t*)dest = col;
- dest += fb_bpp;
+
+ uint8_t *base = framebuffer + y * fb_stride;
+
+ uint8_t *dest = base + x1 * fb_bpp;
+ uint8_t *stop = base + x2 * fb_bpp;
+ const uint32_t col = _gfx_fgcol;
+ while(dest < stop)
+ {
+ *(uint32_t*)dest = col;
+ dest += fb_bpp;
+ }
}
}
-void gfx_vline(int y1, int y2, int x)
+void gfx_vline_checked(int y1, int y2, int x)
{
/* make sure y1 is above y2 */
if(y2 < y1)
@@ -228,17 +240,22 @@ void gfx_vline(int y1, int y2, int x)
y2 = temp;
}
- uint8_t *dest = framebuffer + y1 * fb_stride + x * fb_bpp;
- uint8_t *stop = framebuffer + y2 * fb_stride + x * fb_bpp;
- const uint32_t col = _gfx_fgcol;
- const uint16_t stride = fb_stride;
- while(dest < stop)
+ y1 = MAX(0, y1);
+ y2 = MIN(y2, fb_height);
+
+ if(0 <= x && x < fb_width)
{
- *(uint32_t*)dest = col;
- dest += stride;
+ uint8_t *dest = framebuffer + y1 * fb_stride + x * fb_bpp;
+ uint8_t *stop = framebuffer + y2 * fb_stride + x * fb_bpp;
+ const uint32_t col = _gfx_fgcol;
+ const uint16_t stride = fb_stride;
+ while(dest < stop)
+ {
+ *(uint32_t*)dest = col;
+ dest += stride;
+ }
}
}
-#endif
void gfx_fillrect(int x, int y, int w, int h)
{
@@ -328,15 +345,172 @@ void gfx_fillcircle(int cx, int cy, int r)
}
}
+/* these next two functions were taken directly from the Rockbox project's XLCD
+ * library.
+ * Copyright (C) 2005 Jens Arnold */
+
+/* sort the given coordinates by increasing x value */
+static void sort_points_by_increasing_y(int* y1, int* x1,
+ int* y2, int* x2,
+ int* y3, int* x3)
+{
+ int x, y;
+ if (*x1 > *x3)
+ {
+ if (*x2 < *x3) /* x2 < x3 < x1 */
+ {
+ x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x;
+ y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y;
+ }
+ else if (*x2 > *x1) /* x3 < x1 < x2 */
+ {
+ x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x;
+ y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y;
+ }
+ else /* x3 <= x2 <= x1 */
+ {
+ x = *x1; *x1 = *x3; *x3 = x;
+ y = *y1; *y1 = *y3; *y3 = y;
+ }
+ }
+ else
+ {
+ if (*x2 < *x1) /* x2 < x1 <= x3 */
+ {
+ x = *x1; *x1 = *x2; *x2 = x;
+ y = *y1; *y1 = *y2; *y2 = y;
+ }
+ else if (*x2 > *x3) /* x1 <= x3 < x2 */
+ {
+ x = *x2; *x2 = *x3; *x3 = x;
+ y = *y2; *y2 = *y3; *y3 = y;
+ }
+ /* else already sorted */
+ }
+}
+
+/* draw a filled triangle, using horizontal lines for speed */
+void gfx_filltriangle(int x1, int y1,
+ int x2, int y2,
+ int x3, int y3)
+{
+ long fp_x1, fp_x2, fp_dx1, fp_dx2;
+ int y;
+ sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3);
+
+ if (y1 < y3) /* draw */
+ {
+ fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
+ fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
+
+ if (y1 < y2) /* first part */
+ {
+ fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
+ fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
+ for (y = y1; y < y2; y++)
+ {
+ gfx_hline(fp_x1 >> 16, fp_x2 >> 16, y);
+ fp_x1 += fp_dx1;
+ fp_x2 += fp_dx2;
+ }
+ }
+ if (y2 < y3) /* second part */
+ {
+ fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
+ fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
+ for (y = y2; y < y3; y++)
+ {
+ gfx_hline(fp_x1 >> 16, fp_x2 >> 16, y);
+ fp_x1 += fp_dx1;
+ fp_x2 += fp_dx2;
+ }
+ }
+ }
+}
+
+static void gfx_bitmap32(int x, int y, const struct bitmap_t *bmp)
+{
+ /* SLOOW */
+ uint8_t *data = bmp->data;
+ for(unsigned int i = y; i < y + bmp->h && i < fb_height; ++i)
+ {
+ for(unsigned int j = x; j < x + bmp->w && j < fb_width; ++j)
+ {
+ uint8_t r = *data++;
+ uint8_t g = *data++;
+ uint8_t b = *data++;
+ gfx_set_foreground(VGA_RGBPACK(r, g, b));
+ gfx_drawpixel(j, i);
+ }
+ }
+}
+
+void gfx_bitmap(int x, int y, const struct bitmap_t *bmp)
+{
+ gfx_bitmap32(x, y, bmp);
+}
+
+void gfx_drawrect(int x, int y, int w, int h)
+{
+ gfx_hline(MAX(0, x), MIN(x + w, fb_width), MAX(0, y));
+ gfx_hline(MAX(0, x), MIN(x + w, fb_width), MIN(y + h, fb_height));
+ gfx_vline(MAX(0, y), MIN(y + h, fb_height),MAX(0, x));
+ gfx_vline(MAX(0, y), MIN(y + h, fb_height),MIN(x + w, fb_width));
+}
+
+void gfx_update(void)
+{
+ memcpy(real_framebuffer, framebuffer, fb_height * fb_stride);
+}
+
+void gfx_set_doublebuffer(bool yesno)
+{
+ if(yesno)
+ framebuffer = temp_framebuffer;
+ else
+ framebuffer = real_framebuffer;
+}
+
+bool gfx_get_doublebuffer(void)
+{
+ if(framebuffer == temp_framebuffer)
+ return true;
+ else
+ return false;
+}
+
+void gfx_putsxy(int x, int y, const char* str)
+{
+ while(*str)
+ {
+ gfx_drawchar(x, y, *str);
+ x += FONT_WIDTH;
+ str++;
+ }
+}
+
+void gfx_putsxy_bg(int x, int y, const char* str)
+{
+ while(*str)
+ {
+ gfx_drawchar_bg(x, y, *str);
+ x += FONT_WIDTH;
+ str++;
+ }
+}
bool gfx_init(struct vbe_info_t *vbe_mode_info)
{
- framebuffer = (uint8_t*)vbe_mode_info->physbase;
+ real_framebuffer = (uint8_t*)vbe_mode_info->physbase;
+ gfx_set_doublebuffer(false);
fb_width = vbe_mode_info->Xres;
fb_height = vbe_mode_info->Yres;
fb_bpp = vbe_mode_info->bpp / 8;
fb_stride = vbe_mode_info->pitch;
- fb_stride32 = fb_stride / 4;
+ fb_stride32 = fb_stride / sizeof(uint32_t);
+ gfx_hline = gfx_hline_checked;
+ gfx_vline = gfx_vline_checked;
+ temp_framebuffer = malloc(fb_height * fb_stride);
if(fb_bpp != 4)
{
printf("WARNING: BPP != 32, falling back to text mode...\n");
@@ -344,8 +518,8 @@ bool gfx_init(struct vbe_info_t *vbe_mode_info)
}
else
{
- //extern void gfx_drawpixel_32bpp(int, int);
- gfx_drawpixel = &gfx_drawpixel_32bpp_checked;
+ extern void gfx_drawpixel_32bpp(int, int);
+ gfx_drawpixel = &gfx_drawpixel_32bpp;
}
set_putchar(gfx_putchar);
diff --git a/drivers/gfx_font.c b/drivers/gfx_font.c
index 4515b31..6669931 100644
--- a/drivers/gfx_font.c
+++ b/drivers/gfx_font.c
@@ -1719,10 +1719,10 @@ const uint8_t gfx_font[][12] = {
b(11111000),
b(11111100),
b(11111110),
- b(11111111), /* 8 */
- b(11111000),
- b(11011000),
- b(10001100),
- b(00000110) /* 12 */
+ b(11100000), /* 8 */
+ b(11000000),
+ b(10000000),
+ b(00000000),
+ b(00000000) /* 12 */
},
};
diff --git a/drivers/include/gfx.h b/drivers/include/gfx.h
index 2abc172..5e97100 100644
--- a/drivers/include/gfx.h
+++ b/drivers/include/gfx.h
@@ -62,9 +62,9 @@ void gfx_set_background(uint32_t);
uint32_t gfx_get_background(void);
-void gfx_hline(int x1, int x2, int y);
+void (*gfx_hline)(int x1, int x2, int y);
-void gfx_vline(int y1, int y2, int x);
+void (*gfx_vline)(int y1, int y2, int x);
void gfx_fillrect(int x1, int y1, int w, int h);
@@ -75,9 +75,31 @@ void gfx_drawcircle(int cx, int cy, int rad);
void gfx_fillcircle(int cx, int cy, int rad);
+void gfx_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3);
+
extern const uint16_t *gfx_width, *gfx_height;
/* this is _BYTES_ per pixel, NOT BITS per pixel! */
extern const uint8_t *gfx_bpp;
+struct bitmap_t {
+ unsigned int w, h;
+ unsigned int bpp;
+ uint8_t *data;
+};
+
+void gfx_bitmap(int x, int y, const struct bitmap_t*);
+
+void gfx_drawrect(int x, int y, int w, int h);
+
+void gfx_set_doublebuffer(bool);
+
+bool gfx_get_doublebuffer(void);
+
+/* don't call this wo/ double buffering! */
+void gfx_update(void);
+
+void gfx_putsxy(int, int, const char*);
+
+void gfx_putsxy_bg(int, int, const char*);
#endif
diff --git a/drivers/ps2.c b/drivers/ps2.c
index c9ff30e..9da026d 100644
--- a/drivers/ps2.c
+++ b/drivers/ps2.c
@@ -4,6 +4,7 @@
#include "io.h"
#include "isr.h"
#include "ps2.h"
+#include "ps2_keymaps.h"
static void ps2_wait(void)
{
@@ -19,6 +20,8 @@ void ps2_set_leds(uint8_t status)
outb(0x60, status);
}
+static uint8_t keyboard_state[16];
+
static void key_handler(struct regs_t *regs)
{
(void) regs;
diff --git a/kernel/include/version.h b/kernel/include/version.h
new file mode 100644
index 0000000..48f36a8
--- /dev/null
+++ b/kernel/include/version.h
@@ -0,0 +1,2 @@
+#define KAPPA_KERNEL_VERSION "0.0.0-alpha"
+#define KAPPA_KERNEL_CODENAME "Ayatollah's Aqueduct"
diff --git a/kernel/main.c b/kernel/main.c
index dc0926d..0ddf4e7 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -40,6 +40,12 @@ void int80(struct regs_t *regs)
}
}
+void div0(struct regs_t *regs)
+{
+ (void) regs;
+ panic("Divide by zero!\n");
+}
+
void main(struct multiboot_info_t *hdr, uint32_t magic)
{
fpu_enable();
@@ -74,6 +80,7 @@ void main(struct multiboot_info_t *hdr, uint32_t magic)
timer_init(HZ);
ps2_init();
+ set_interrupt_handler(0, div0);
set_interrupt_handler(0xd, gpf);
set_interrupt_handler(0x80, int80);
@@ -83,17 +90,28 @@ void main(struct multiboot_info_t *hdr, uint32_t magic)
printf("Kernel version %s: \"%s\"\n", KAPPA_KERNEL_VERSION, KAPPA_KERNEL_CODENAME);
- //printf("Starting linked-in application XRacer...\n");
- printf("Running graphics benchmark...\n");
+ printf("Starting linked-in application XRacer...\n");
+ //printf("Running graphics benchmark...\n");
srand(42);
- gfx_drawcircle(100, 100, 100);
+ gfx_reset();
- gfx_fillcircle(50, 30, 20);
+ enum plugin_status;
+ struct plugin_api;
+ extern enum plugin_status xracer_main(const struct plugin_api*);
+ extern void plugin_load(enum plugin_status (*func)(const struct plugin_api*));
- while(1);
+ plugin_load(xracer_main);
- //xracer_main();
+ gfx_filltriangle(100, 100, 100, 100, 100, 100);
+
+ for(int i=0;i<200;)
+ {
+ gfx_putsxy_bg(i, 0, " ");
+ gfx_drawchar_bg(++i, 0, 131);
+ timer_delay(1);
+ }
+ while(1);
if(gfx_status)
{
@@ -180,6 +198,9 @@ void main(struct multiboot_info_t *hdr, uint32_t magic)
int y2= rand() % height;
gfx_set_foreground(rand() % 0x1000000);
gfx_drawline(x1, y1, x2, y2);
+ char buf[32];
+ snprintf(buf, 32, "Line %d", i);
+ gfx_putsxy(0, 0, buf);
}
int endline = *current_tick;
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index a6e27f2..49116df 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -1,6 +1,8 @@
#ifndef _STDLIB_H_
#define _STDLIB_H_
+#include <stddef.h>
+
/* this is by no means standards-compliant... but who cares? :P */
/* NOT reentrant! */
@@ -14,5 +16,7 @@ char* itoa(int val, int base);
unsigned int rand(void);
void srand(unsigned int);
int abs(int);
+void *malloc(size_t);
+int snprintf(char*, int, const char*, ...);
#endif
diff --git a/libc/stdlib.c b/libc/stdlib.c
index bea3b65..c6a9c3d 100644
--- a/libc/stdlib.c
+++ b/libc/stdlib.c
@@ -1,3 +1,6 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
/* adapted from <http://www.strudel.org.uk/itoa/> */
@@ -54,12 +57,96 @@ void srand(unsigned int seed)
rand_s2 = seed++;
rand_s3 = seed++;
/* "warm it up" */
- rand();
- rand();
- rand();
+ for(int i=0;i<10;++i)
+ rand();
}
int abs(int val)
{
return (val<0?-val:val);
}
+
+void *malloc(size_t sz)
+{
+ static uint8_t mallocbuf[1024*1024*16];
+ static uint8_t *next_ptr = mallocbuf;
+ static int bytes_left = sizeof(mallocbuf);
+ bytes_left -= sz;
+ if(bytes_left < 0)
+ return NULL;
+ else
+ {
+ void *ret = next_ptr;
+ next_ptr += sz;
+ return ret;
+ }
+}
+
+static inline int snputs(char *buf, int idx, int sz, const char *str)
+{
+ while(idx < sz && *str)
+ {
+ buf[idx++] = *str++;
+ }
+ return idx;
+}
+
+static char hex_table[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+static inline int snprint_hex(char *buf, int idx, int sz, unsigned int n)
+{
+ unsigned mask = 0xF0000000;
+ unsigned shift = 28;
+ while(mask && idx < sz)
+ {
+ buf[idx++] = hex_table[(n & mask) >> shift];
+ mask >>= 4;
+ shift -= 4;
+ }
+ return idx;
+}
+
+int snprintf(char *buf, int sz, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int i = 0;
+ /* leave room for the null! */
+ sz--;
+ while(*fmt && i < sz)
+ {
+ char ch = *fmt++;
+ switch(ch)
+ {
+ case '%':
+ {
+ switch(*fmt++)
+ {
+ case 'c':
+ buf[i++] = va_arg(ap, int);
+ break;
+ case 's':
+ i = snputs(buf, i, sz, va_arg(ap, const char*));
+ break;
+ case 'x':
+ i = snprint_hex(buf, i, sz, va_arg(ap, unsigned));
+ break;
+ case 'd':
+ i = snputs(buf, i, sz, itoa(va_arg(ap, unsigned), 10));
+ break;
+ default:
+ i = snputs(buf, i, sz, "snprintf: unknown format\n");
+ break;
+ }
+ break;
+ }
+ default:
+ buf[i++] = ch;
+ break;
+ }
+ }
+ buf[i] = '\0';
+ va_end(ap);
+ return 0;
+}