diff options
| author | Franklin Wei <frankhwei536@gmail.com> | 2015-02-17 15:33:03 -0500 |
|---|---|---|
| committer | Franklin Wei <frankhwei536@gmail.com> | 2015-02-17 15:33:03 -0500 |
| commit | 6030b176c2819c83c625f257ad7e8632a8245ed9 (patch) | |
| tree | fd98417c4f40a3bc8479a5900920a0ccd40fedd6 | |
| parent | ef4cc242dc8ad04320d19af22931fcbdbf670c13 (diff) | |
| download | kappa-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-- | Makefile | 2 | ||||
| -rw-r--r-- | OBJ | 9 | ||||
| -rw-r--r-- | apps/fixedpoint.c | 457 | ||||
| -rw-r--r-- | apps/fixedpoint.h | 125 | ||||
| -rw-r--r-- | apps/plugin.c | 52 | ||||
| -rw-r--r-- | apps/plugin.h | 56 | ||||
| -rw-r--r-- | apps/xracer/compat.h | 37 | ||||
| -rw-r--r-- | apps/xracer/generator.c | 202 | ||||
| -rw-r--r-- | apps/xracer/generator.h | 46 | ||||
| -rw-r--r-- | apps/xracer/graphics.c | 237 | ||||
| -rw-r--r-- | apps/xracer/graphics.h | 48 | ||||
| -rw-r--r-- | apps/xracer/main.c | 142 | ||||
| -rw-r--r-- | apps/xracer/map.c | 44 | ||||
| -rw-r--r-- | apps/xracer/map.h | 44 | ||||
| -rw-r--r-- | apps/xracer/maps.c | 15 | ||||
| -rw-r--r-- | apps/xracer/maps.h | 3 | ||||
| -rw-r--r-- | apps/xracer/road.h | 48 | ||||
| -rw-r--r-- | apps/xracer/sprite.c | 26 | ||||
| -rw-r--r-- | apps/xracer/sprite.h | 42 | ||||
| -rw-r--r-- | apps/xracer/util.c | 161 | ||||
| -rw-r--r-- | apps/xracer/util.h | 66 | ||||
| -rw-r--r-- | apps/xracer/xracer.h | 72 | ||||
| -rw-r--r-- | boot/head.S | 2 | ||||
| -rw-r--r-- | drivers/gfx-as.S | 11 | ||||
| -rw-r--r-- | drivers/gfx.c | 218 | ||||
| -rw-r--r-- | drivers/gfx_font.c | 10 | ||||
| -rw-r--r-- | drivers/include/gfx.h | 26 | ||||
| -rw-r--r-- | drivers/ps2.c | 3 | ||||
| -rw-r--r-- | kernel/include/version.h | 2 | ||||
| -rw-r--r-- | kernel/main.c | 33 | ||||
| -rw-r--r-- | libc/include/stdlib.h | 4 | ||||
| -rw-r--r-- | libc/stdlib.c | 93 |
32 files changed, 2292 insertions, 44 deletions
@@ -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 @@ -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; +} |