diff options
| author | Franklin Wei <frankhwei536@gmail.com> | 2015-01-07 16:40:33 -0500 |
|---|---|---|
| committer | Franklin Wei <franklin@fwei.ml> | 2015-06-13 19:44:59 -0400 |
| commit | b9fb85845715d81f50d8fd6bf523982b339d26e7 (patch) | |
| tree | 032516d8ef26dcb67beee3b6c5a8459ebee941eb /apps | |
| parent | 8aa72f07f4bf38e9b898fb8d8042239861b9a423 (diff) | |
| download | rockbox-xracer.zip rockbox-xracer.tar.gz rockbox-xracer.tar.bz2 rockbox-xracer.tar.xz | |
[WIP] XRacer - a racing gamexracer
Plan:
-----
A simple racing game like Pole Position or Enduro.
Status:
-------
- Currently generates a random road and scrolls through it
- Random road generation (curves and hills)
- Supports loading of maps from a file ("/output.xrm")
- Sample map at http://a.pomf.se/ynhlwq.xrm
Todo:
-----
- Convert to fixed-point math in all places (only one place left!)
- Improve/fix track looping
- Improve random road generation to start and end at the same height
- Finish sprite code
- Make sprites
- Game-ify!
What's new:
-----------
- NEW: uses greylib on low-depth targets!
- Loadable maps implemented, UNTESTED!
- Sprites in progress (see render() in graphics.c)
Change-Id: Ia2ff60b3c43d9f2e3a4f63e0ad90d2cb571c605e
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
| -rw-r--r-- | apps/plugins/SUBDIRS | 2 | ||||
| -rw-r--r-- | apps/plugins/bitmaps/native/SOURCES | 4 | ||||
| -rw-r--r-- | apps/plugins/bitmaps/native/xracer_sprites.bmp | bin | 0 -> 230522 bytes | |||
| -rw-r--r-- | apps/plugins/xracer/README | 79 | ||||
| -rw-r--r-- | apps/plugins/xracer/SOURCES | 7 | ||||
| -rw-r--r-- | apps/plugins/xracer/compat.h | 61 | ||||
| -rw-r--r-- | apps/plugins/xracer/generator.c | 202 | ||||
| -rw-r--r-- | apps/plugins/xracer/generator.h | 46 | ||||
| -rw-r--r-- | apps/plugins/xracer/graphics.c | 275 | ||||
| -rw-r--r-- | apps/plugins/xracer/graphics.h | 48 | ||||
| -rw-r--r-- | apps/plugins/xracer/main.c | 200 | ||||
| -rw-r--r-- | apps/plugins/xracer/map.c | 130 | ||||
| -rw-r--r-- | apps/plugins/xracer/map.h | 47 | ||||
| -rw-r--r-- | apps/plugins/xracer/maps.c | 15 | ||||
| -rw-r--r-- | apps/plugins/xracer/maps.h | 3 | ||||
| -rw-r--r-- | apps/plugins/xracer/road.h | 48 | ||||
| -rw-r--r-- | apps/plugins/xracer/sprite.c | 26 | ||||
| -rw-r--r-- | apps/plugins/xracer/sprite.h | 42 | ||||
| -rw-r--r-- | apps/plugins/xracer/util.c | 170 | ||||
| -rw-r--r-- | apps/plugins/xracer/util.h | 66 | ||||
| -rw-r--r-- | apps/plugins/xracer/xracer.h | 69 | ||||
| -rw-r--r-- | apps/plugins/xracer/xracer.make | 27 |
23 files changed, 1568 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index fd7a49a..57a95b6 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -134,5 +134,6 @@ wavrecord,apps wavview,viewers wormlet,games xobox,games +xracer,games xworld,games zxbox,viewers diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index d02073e..6213242 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS @@ -12,6 +12,8 @@ clock /* For all targets with a bitmap display */ #ifdef HAVE_LCD_BITMAP +xracer + /* XWorld only supports color horizontal stride LCDs /for now/ ;) */ #if defined(HAVE_LCD_COLOR) && \ (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE)) diff --git a/apps/plugins/bitmaps/native/SOURCES b/apps/plugins/bitmaps/native/SOURCES index 90376d8..91a2e01 100644 --- a/apps/plugins/bitmaps/native/SOURCES +++ b/apps/plugins/bitmaps/native/SOURCES @@ -991,4 +991,8 @@ resistor.128x128x16.bmp resistor.68x20x16.bmp #endif +/* XRacer */ +/* these sprites are one-size-fits-all */ +xracer_sprites.bmp + #endif /* HAVE_LCD_BITMAP */ diff --git a/apps/plugins/bitmaps/native/xracer_sprites.bmp b/apps/plugins/bitmaps/native/xracer_sprites.bmp Binary files differnew file mode 100644 index 0000000..a88eca6 --- /dev/null +++ b/apps/plugins/bitmaps/native/xracer_sprites.bmp diff --git a/apps/plugins/xracer/README b/apps/plugins/xracer/README new file mode 100644 index 0000000..8b6312c --- /dev/null +++ b/apps/plugins/xracer/README @@ -0,0 +1,79 @@ +This file contains some quick notes about this plugin. +====================================================== + +Some useful links: +------------------ + +<http://codeincomplete.com/projects/racer/> - a very good tutorial on building a similar game in Javascript + +<http://www.extentofthejam.com/pseudo/> - excellent page on pseudo-3d + +Terminology: +------------ + +In the code, a "fixed-point" number is one that has a nonzero number of fractional bits. +When dealing with these numbers, you must be careful to convert all operands to fixed-point, and use the correct function/macro to replace the operators. +In the code, I've tried to make all fixed-point numbers of type 'long.' +An "integer" is a number with zero fractional bits. + +(NOTE: I'm not sure if this "proper" terminology) + +Code structure: +--------------- + +generator.c: random map generator + +graphics.c: this is where almost all of the rendering takes place + +main.c: main loop + +sprite.c: static sprite data (offsets, dimensions) + +util.c miscellaneous functions, also contains FOV calculation code + +Proposed map formats: +--------------------- + +There will be two map formats: one that can be compiled into the executable ("Internal format"), and one that can be loaded from a file ("Interchange format"). + +Internal format: +---------------- + +This format is represented as a series of struct road_section's. + +struct road_section { + uchar type; + uint32 len; + int slope; + long curve; // <<< this is fixed-point with 8 fracbits +}; + +'type' can be any of the following: + 0: constant segment - all 3 parameters used + 1: up-hill - an up hill is added. actual length is len + 2*slope due to enters and exits + 2: down-hill - a down hill is added. actual length is len + 2*slope due to enters and exits + +Endianness is platform-dependent in the Internal format. + +Interchange format: +------------------- + +NOTE: all numbers are BIG-ENDIAN unless otherwise specified! + +This format is essentially the Internal format serialized into a file, but with some minor differences. + +File extension: .xrm + +Current format version number: 0x0000 + +- File header - 8 bytes + - 0x00-0x04: 'XMaP' + - 0x05-0x06: version number (see above) + - 0x07-0x08: 0xFF padding +- Data blocks - 15 bytes each (corresponds to the "sections" of the Internal format) + - 0x00 : type + - 0x01-0x04: length + - 0x05-0x08: slope (signed two's complement) + - 0x09-0x0C: curve (signed two's complement, fixed-point with 8 fractional bits) + - 0x0D-0x0E: CRC16-CCITT of data from 0x0-0xC + - 0x0F : CRC high byte XOR CRC low byte diff --git a/apps/plugins/xracer/SOURCES b/apps/plugins/xracer/SOURCES new file mode 100644 index 0000000..4f08451 --- /dev/null +++ b/apps/plugins/xracer/SOURCES @@ -0,0 +1,7 @@ +main.c +generator.c +graphics.h +map.c +maps.c +sprite.c +util.c diff --git a/apps/plugins/xracer/compat.h b/apps/plugins/xracer/compat.h new file mode 100644 index 0000000..f4507d5 --- /dev/null +++ b/apps/plugins/xracer/compat.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ***************************************************************************/ + +#if (LCD_DEPTH < 4) +#include "lib/grey.h" +#else +#include "lib/xlcd.h" +#endif + +/* this file contains some #defines to make this as platform-neutral as possible */ +#if (LCD_DEPTH < 4) +/* greylib API */ + +#define FILL_TRI(x1, y1, x2, y2, x3, y3) grey_filltriangle(x1, y1, x2, y2, x3, y3) +#define FILL_RECT(x, y, w, h) grey_fillrect(x, y, w, h) +#define DRAW_HLINE(x1, x2, y) grey_hline(x1, x2, y) +#define LCD_RGBPACK(r, g, b) GREY_BRIGHTNESS(((r+g+b)/3)) +#define CLEAR_DISPLAY() grey_clear_display() +#define SET_FOREGROUND(x) grey_set_foreground(x) +#define SET_BACKGROUND(x) grey_set_background(x) +#undef LCD_BLACK +#undef LCD_WHITE +#define LCD_BLACK GREY_BLACK +#define LCD_WHITE GREY_WHITE +#define LCD_UPDATE() grey_update() +#define PUTSXY(x, y, s) grey_putsxy(x, y, s) +#define RGB_UNPACK_RED(x) (x) +#define RGB_UNPACK_GREEN(x) (x) +#define RGB_UNPACK_BLUE(x) (x) + +#else +/* rockbox API */ + +#define FILL_TRI(x1, y1, x2, y2, x3, y3) xlcd_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) + +#endif diff --git a/apps/plugins/xracer/generator.c b/apps/plugins/xracer/generator.c new file mode 100644 index 0000000..d62594b --- /dev/null +++ b/apps/plugins/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(*rb->current_tick); + 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/plugins/xracer/generator.h b/apps/plugins/xracer/generator.h new file mode 100644 index 0000000..306c3b9 --- /dev/null +++ b/apps/plugins/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/plugins/xracer/graphics.c b/apps/plugins/xracer/graphics.c new file mode 100644 index 0000000..c1c5f92 --- /dev/null +++ b/apps/plugins/xracer/graphics.c @@ -0,0 +1,275 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "lib/pluginlib_bmp.h" + +#include "pluginbitmaps/xracer_sprites.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) +{ + CLEAR_DISPLAY(); + + 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 */ + } + /* draw sprites */ + unsigned char scale_buffer[LCD_WIDTH * LCD_HEIGHT * sizeof(fb_data)]; +#if (LCD_DEPTH >= 4) + for(int i = DRAW_DIST - 1; i > 0; --i) + { + struct road_segment *seg = &road[(base->idx + i) % road_length]; + struct sprite_t *iter = seg->sprites; + while(iter) + { + struct sprite_data_t *sprite = iter->data; + float scale = seg->p1_scale; + if(seg->p1.x && seg->p1.y) + { + struct bitmap in = { + .height = sprite->h, + .width = sprite->w, + .data = (unsigned char*)(xracer_sprites + STRIDE(SCREEN_MAIN, BMPWIDTH_xracer_sprites, BMPHEIGHT_xracer_sprites) * sprite->y + sprite->x) + }; + struct bitmap out = { + .height = sprite->h * scale, + .width = sprite->w * scale, + .data = scale_buffer + }; + if(sprite->h * scale > 1 && sprite->w * scale > 1) + { + simple_resize_bitmap(&in, &out); + rb->lcd_bitmap_transparent((fb_data*)scale_buffer, + seg->p1.x - LCD_WIDTH/2, seg->p1.y - LCD_WIDTH/2, + sprite->w * scale, sprite->h * scale); + } + } + iter = iter->next; + } + } +#endif +} diff --git a/apps/plugins/xracer/graphics.h b/apps/plugins/xracer/graphics.h new file mode 100644 index 0000000..aeecf0b --- /dev/null +++ b/apps/plugins/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/plugins/xracer/main.c b/apps/plugins/xracer/main.c new file mode 100644 index 0000000..b0127be --- /dev/null +++ b/apps/plugins/xracer/main.c @@ -0,0 +1,200 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "lib/helper.h" +#include "lib/pluginlib_actions.h" +#include "lib/pluginlib_exit.h" + +#include "fixedpoint.h" /* only used for FOV computation */ + +/* 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); + for(unsigned int i = 0; i < road_length; ++i) + add_sprite(road + i, &sprites[0]); +} + +void do_early_init(void) +{ +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + /* GIMME DAT RAW POWAH!!! */ + rb->cpu_boost(true); +#endif + + /* disable backlight timeout */ + backlight_ignore_timeout(); + + init_alloc(); +} + +#if LCD_DEPTH < 4 +struct _grey_info _grey_info; +#endif + +void do_late_init(void) +{ +#if (LCD_DEPTH < 4) + /* greylib init */ + size_t buf_sz = util_alloc_remaining(); + if(!grey_init(util_alloc(buf_sz), buf_sz, + GREY_BUFFERED|GREY_RAWMAPPED|GREY_ON_COP, + LCD_WIDTH, LCD_HEIGHT, NULL)) + { + error("grey init failed"); + } + grey_show(true); +#endif +} + +enum plugin_status do_flythrough(void) +{ + struct camera_t camera; + camera.depth = camera_calc_depth(CAMERA_FOV); + + LOGF("camera depth: %d", camera.depth); + + 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"); + + if(road_length == (unsigned int)-1) + { + warning("Failed to load map, using random map"); + + road_length = MAX_ROAD_LENGTH; + + generate_random_road(road, road_length, HILLS, CURVES); + } + + long last_timestamp = *rb->current_tick; + + do_late_init(); + + while(1) + { + static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; + int button = pluginlib_getaction(0, plugin_contexts, ARRAYLEN(plugin_contexts)); + switch(button) + { + case PLA_UP: + case PLA_UP_REPEAT: + camera_height+=MANUAL_SPEED; + break; + case PLA_DOWN: + case PLA_DOWN_REPEAT: + camera_height-=MANUAL_SPEED; + break; + case PLA_LEFT: + case PLA_LEFT_REPEAT: + camera.pos.x-=MANUAL_SPEED; + break; + case PLA_RIGHT: + case PLA_RIGHT_REPEAT: + camera.pos.x+=MANUAL_SPEED; + break; + case PLA_CANCEL: +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif + return PLUGIN_OK; + default: + exit_on_usb(button); + break; + } + 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); + + SET_FOREGROUND(LCD_WHITE); + SET_BACKGROUND(LCD_BLACK); + int dt = *rb->current_tick - last_timestamp; + char buf[16]; + //rb->snprintf(buf, sizeof(buf), "FPS: %ld", HZ/(!dt?1:dt)); + rb->snprintf(buf, sizeof(buf), "DT: %d", dt); + PUTSXY(0, 0, buf); + + LCD_UPDATE(); + + //rb->sleep((HZ/100)-dt); + rb->yield(); + + last_timestamp = *rb->current_tick; + } +} + +/* plugin_start(): plugin entry point */ +/* contains main loop */ +enum plugin_status plugin_start(const void *param) +{ + (void) 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/plugins/xracer/map.c b/apps/plugins/xracer/map.c new file mode 100644 index 0000000..6900dab --- /dev/null +++ b/apps/plugins/xracer/map.c @@ -0,0 +1,130 @@ +#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; +} + +unsigned load_external_map(struct road_segment *road, unsigned int max_road_length, const char *filename) +{ + int fd = rb->open(filename, O_RDONLY, 0666); + if(fd < 0) + { + warning("Map file could not be opened"); + return -1; + } + + /* check the header */ + static const unsigned char cmp_header[8] = {'X', 'M', 'a', 'P', + ((MAP_VERSION & 0xFF00) >> 8), + ((MAP_VERSION & 0x00FF) >> 0), + 0xFF, 0xFF }; + unsigned char header[8]; + int ret = rb->read(fd, header, sizeof(header)); + if(ret != sizeof(header) || rb->memcmp(header, cmp_header, sizeof(header)) != 0) + { + warning("Malformed map header (version mismatch?)"); + return -1; + } + + /* read data */ + unsigned char data_buf[16]; + unsigned int back = 0; + bool fail = false; + + gen_reset(); + + do { + + ret = rb->read(fd, data_buf, sizeof(data_buf)); + if(ret != sizeof(data_buf)) + { + break; + } + + uint16_t calc_crc16 = crc16_ccitt(data_buf, 12, 0, 0xFFFF); + uint8_t calc_xor_value = ((calc_crc16 & 0xFF00) >> 8 ) ^ (calc_crc16 & 0xFF); + + uint16_t crc16 = (data_buf[0x0D] << 8) | (data_buf[0x0E]); + uint8_t xor_value = data_buf[0x0F]; + if((calc_crc16 != crc16)) + { + warning("Bad checksum"); + fail = true; + } + if(calc_xor_value != xor_value) + { + warning("Bad XOR value"); + fail = true; + } + + struct road_section section = + { + data_buf[0], + READ_BE_UINT32(&data_buf[1]), + READ_BE_UINT32(&data_buf[5]), + READ_BE_UINT32(&data_buf[9]) + }; + + bool status = add_section(road, max_road_length, &back, §ion); + + if(!status) + { + warning("Unknown map section type"); + fail = true; + } + + } while(ret == sizeof(data_buf)); + + /* last number of bytes read was not zero, this indicates failure */ + if(ret) + { + warning("Data too long"); + fail = true; + } + + rb->close(fd); + + if(fail) + return -1; + else + return back; +} diff --git a/apps/plugins/xracer/map.h b/apps/plugins/xracer/map.h new file mode 100644 index 0000000..1681b12 --- /dev/null +++ b/apps/plugins/xracer/map.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * __________ __ ___. + * 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); + +/* loads a map in interchange format from a file */ +unsigned load_external_map(struct road_segment*, unsigned int max_road_length, const char*); + +#endif diff --git a/apps/plugins/xracer/maps.c b/apps/plugins/xracer/maps.c new file mode 100644 index 0000000..770f3a6 --- /dev/null +++ b/apps/plugins/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/plugins/xracer/maps.h b/apps/plugins/xracer/maps.h new file mode 100644 index 0000000..cab72d5 --- /dev/null +++ b/apps/plugins/xracer/maps.h @@ -0,0 +1,3 @@ +#include "map.h" + +struct road_section loop_map[10]; diff --git a/apps/plugins/xracer/road.h b/apps/plugins/xracer/road.h new file mode 100644 index 0000000..2c1fe44 --- /dev/null +++ b/apps/plugins/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/plugins/xracer/sprite.c b/apps/plugins/xracer/sprite.c new file mode 100644 index 0000000..1ad6ee9 --- /dev/null +++ b/apps/plugins/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/plugins/xracer/sprite.h b/apps/plugins/xracer/sprite.h new file mode 100644 index 0000000..ae7f00e --- /dev/null +++ b/apps/plugins/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/plugins/xracer/util.c b/apps/plugins/xracer/util.c new file mode 100644 index 0000000..a518649 --- /dev/null +++ b/apps/plugins/xracer/util.c @@ -0,0 +1,170 @@ +/*************************************************************************** + * __________ __ ___. + * 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; + +void init_alloc(void) +{ + if(!plugin_buffer) + { + plugin_buffer = rb->plugin_get_buffer(&bytes_left); + } +} + +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]; + va_list va; + va_start(va, msg); + rb->vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + rb->splashf(HZ * 2, "ERROR: %s!", buf); + LOGF("ERROR: %s!", buf); + exit(-1); +} + +/* 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, ...) { + char buf[256]; + va_list va; + va_start(va, msg); + rb->vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + rb->splashf(HZ * 2, "WARNING: %s!", buf); + LOGF("WARNING: %s!", buf); +} diff --git a/apps/plugins/xracer/util.h b/apps/plugins/xracer/util.h new file mode 100644 index 0000000..2112c88 --- /dev/null +++ b/apps/plugins/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/plugins/xracer/xracer.h b/apps/plugins/xracer/xracer.h new file mode 100644 index 0000000..967f948 --- /dev/null +++ b/apps/plugins/xracer/xracer.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * __________ __ ___. + * 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 _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 512 +#define CAMERA_FOV 120 /* in degrees */ +#define CAMERA_HEIGHT 100 + +/* 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/apps/plugins/xracer/xracer.make b/apps/plugins/xracer/xracer.make new file mode 100644 index 0000000..f669e01 --- /dev/null +++ b/apps/plugins/xracer/xracer.make @@ -0,0 +1,27 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +XRACERSRCDIR := $(APPSDIR)/plugins/xracer +XRACERBUILDDIR := $(BUILDDIR)/apps/plugins/xracer + +ROCKS += $(XRACERBUILDDIR)/xracer.rock + +XRACER_SRC := $(call preprocess, $(XRACERSRCDIR)/SOURCES) +XRACER_OBJ := $(call c2obj, $(XRACER_SRC)) + +# add source files to OTHER_SRC to get automatic dependencies +OTHER_SRC += $(XRACER_SRC) + +XRACERFLAGS = $(filter-out -O%,$(PLUGINFLAGS)) -O2 + +$(XRACERBUILDDIR)/xracer.rock: $(XRACER_OBJ) + +$(XRACERBUILDDIR)/%.o: $(XRACERSRCDIR)/%.c $(wildcard (XRACERSRCDIR)/*.h) $(XRACERSRCDIR)/xracer.make + $(SILENT)mkdir -p $(dir $@) + $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(XRACERFLAGS) -c $< -o $@ |