Ray casting engine implemented on the mBuino platform using the ST7735 LCD controller.

Dependencies:   LCD_ST7735 mbed

Ray casting engine written to test performance of the LCD_ST7735 library I wrote as a learning exercise on the mbed platform.

Committer:
taylorza
Date:
Sat Oct 25 04:23:24 2014 +0000
Revision:
3:e32f5c25a352
Parent:
1:fdbc2be25831
Updated the engine to use the latest LCD_ST7735 library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
taylorza 0:303768292f44 1 #include "mbed.h"
taylorza 0:303768292f44 2 #include "common.h"
taylorza 0:303768292f44 3 #include "LCD_ST7735.h"
taylorza 0:303768292f44 4 #include "Raycaster.h"
taylorza 0:303768292f44 5
taylorza 0:303768292f44 6 Raycaster::Raycaster(int left, int top, int width, int height,
taylorza 0:303768292f44 7 int viewerDistance, int viewerHeight,
taylorza 0:303768292f44 8 const uint8_t *pMap, int mapWidth, int mapHeight,
taylorza 0:303768292f44 9 const uint16_t *pPalette) :
taylorza 0:303768292f44 10 _display(P0_15, // backlight
taylorza 0:303768292f44 11 P0_10, // reset
taylorza 0:303768292f44 12 P0_18, // ds
taylorza 0:303768292f44 13 P0_21, // mosi
taylorza 0:303768292f44 14 P0_22, // miso
taylorza 0:303768292f44 15 P1_15, // clk
taylorza 0:303768292f44 16 P0_19),// cs
taylorza 0:303768292f44 17 _pMap(pMap),
taylorza 0:303768292f44 18 _mapWidth(mapWidth),
taylorza 0:303768292f44 19 _mapHeight(mapHeight),
taylorza 0:303768292f44 20 _pPalette(pPalette),
taylorza 0:303768292f44 21 _left(left),
taylorza 0:303768292f44 22 _width(width),
taylorza 0:303768292f44 23 _top(top),
taylorza 0:303768292f44 24 _height(height)
taylorza 0:303768292f44 25 {
taylorza 0:303768292f44 26 _display.setOrientation(LCD_ST7735::Rotate90, false);
taylorza 0:303768292f44 27 _display.clearScreen();
taylorza 0:303768292f44 28
taylorza 0:303768292f44 29 _right = left + width;
taylorza 0:303768292f44 30 _halfWidth = width >> 1;
taylorza 0:303768292f44 31 _horizCenter = left + _halfWidth;
taylorza 0:303768292f44 32
taylorza 0:303768292f44 33 _bottom = top + height;
taylorza 0:303768292f44 34 _halfHeight = height >> 1;
taylorza 0:303768292f44 35 _vertCenter = top + _halfHeight;
taylorza 0:303768292f44 36
taylorza 0:303768292f44 37 _viewerDistance = viewerDistance;
taylorza 0:303768292f44 38 _viewerHeight = viewerHeight;
taylorza 0:303768292f44 39
taylorza 0:303768292f44 40 _viewVolume = 60 * PI / 180;
taylorza 0:303768292f44 41 _halfViewVolume = _viewVolume / 2;
taylorza 0:303768292f44 42
taylorza 0:303768292f44 43 _ainc = _viewVolume / _width;
taylorza 0:303768292f44 44
taylorza 0:303768292f44 45 _viewDistanceTimesHeight = _viewerDistance * _viewerHeight;
taylorza 0:303768292f44 46 _heightRatio = (_viewerDistance << CELL_SIZE_SHIFT);
taylorza 0:303768292f44 47 _pSlivers = new Sliver[_width >> 1];
taylorza 0:303768292f44 48 }
taylorza 0:303768292f44 49
taylorza 1:fdbc2be25831 50 Raycaster::~Raycaster()
taylorza 1:fdbc2be25831 51 {
taylorza 1:fdbc2be25831 52 if (_pSlivers != NULL)
taylorza 1:fdbc2be25831 53 {
taylorza 1:fdbc2be25831 54 delete[] _pSlivers;
taylorza 1:fdbc2be25831 55 _pSlivers = NULL;
taylorza 1:fdbc2be25831 56 }
taylorza 1:fdbc2be25831 57 }
taylorza 1:fdbc2be25831 58
taylorza 0:303768292f44 59 void Raycaster::setCellPosition(int x, int y)
taylorza 0:303768292f44 60 {
taylorza 0:303768292f44 61 _playerX = x << CELL_SIZE_SHIFT;
taylorza 0:303768292f44 62 _playerY = y << CELL_SIZE_SHIFT;
taylorza 0:303768292f44 63 _playerViewAngle = 0;
taylorza 0:303768292f44 64 }
taylorza 0:303768292f44 65
taylorza 0:303768292f44 66 void Raycaster::rotate(float radians)
taylorza 0:303768292f44 67 {
taylorza 0:303768292f44 68 _playerViewAngle += radians;
taylorza 0:303768292f44 69 if (_playerViewAngle > PI2) _playerViewAngle -= PI2;
taylorza 0:303768292f44 70 if (_playerViewAngle < 0) _playerViewAngle += PI2;
taylorza 0:303768292f44 71 }
taylorza 0:303768292f44 72
taylorza 0:303768292f44 73 void Raycaster::move(int distance)
taylorza 0:303768292f44 74 {
taylorza 0:303768292f44 75 int mx;
taylorza 0:303768292f44 76 int my;
taylorza 0:303768292f44 77
taylorza 0:303768292f44 78 // Calculate the change in x and y coordinates
taylorza 0:303768292f44 79 float dx = sin(_playerViewAngle) * distance;
taylorza 0:303768292f44 80 float dy = cos(_playerViewAngle) * -distance;
taylorza 0:303768292f44 81
taylorza 0:303768292f44 82 // Check for collisions with walls
taylorza 0:303768292f44 83 float nx = _playerX + (dx * 4);
taylorza 0:303768292f44 84 float ny = _playerY + (dy * 4);
taylorza 0:303768292f44 85
taylorza 0:303768292f44 86 // Check for wall in the x direction and move if open
taylorza 0:303768292f44 87 mx = ((int)nx) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 88 my = ((int)_playerY) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 89 if (_pMap[mx + (my * _mapWidth)] == 0)
taylorza 0:303768292f44 90 {
taylorza 0:303768292f44 91 _playerX += dx;
taylorza 0:303768292f44 92 }
taylorza 0:303768292f44 93
taylorza 0:303768292f44 94 // Check for wall in the y direction and move if open
taylorza 0:303768292f44 95 mx = ((int)_playerX) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 96 my = ((int)ny) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 97 if (_pMap[mx + (my * _mapWidth)] == 0)
taylorza 0:303768292f44 98 {
taylorza 0:303768292f44 99 _playerY += dy;
taylorza 0:303768292f44 100 }
taylorza 0:303768292f44 101 }
taylorza 0:303768292f44 102
taylorza 0:303768292f44 103 void Raycaster::renderFrame()
taylorza 0:303768292f44 104 {
taylorza 0:303768292f44 105 int xd, yd;
taylorza 0:303768292f44 106 int grid_x, grid_y;
taylorza 0:303768292f44 107 float xcross_x, xcross_y;
taylorza 0:303768292f44 108 float ycross_x, ycross_y;
taylorza 0:303768292f44 109 int xmaze, ymaze;
taylorza 0:303768292f44 110 float distance;
taylorza 0:303768292f44 111 int tmcolumn;
taylorza 0:303768292f44 112 uint8_t cellValue;
taylorza 0:303768292f44 113
taylorza 0:303768292f44 114 int xview = FLOAT2INT(_playerX);
taylorza 0:303768292f44 115 int yview = FLOAT2INT(_playerY);
taylorza 0:303768292f44 116
taylorza 0:303768292f44 117 float columnAngle = _halfViewVolume;
taylorza 0:303768292f44 118 float ainc2 = _ainc * 2;
taylorza 0:303768292f44 119 Sliver *pSliver = _pSlivers;
taylorza 0:303768292f44 120 for (int column = 0; column < _width; column += 2, columnAngle -= ainc2, pSliver++)
taylorza 0:303768292f44 121 {
taylorza 0:303768292f44 122 float radians = _playerViewAngle - columnAngle;
taylorza 0:303768292f44 123
taylorza 0:303768292f44 124 int xdiff = FLOAT2INT(CELL_SIZE * sin(radians));
taylorza 0:303768292f44 125 int ydiff = FLOAT2INT(-CELL_SIZE * cos(radians));
taylorza 0:303768292f44 126
taylorza 0:303768292f44 127 if (xdiff == 0) xdiff = 1;
taylorza 0:303768292f44 128
taylorza 0:303768292f44 129 float slope = (float)ydiff / xdiff;
taylorza 0:303768292f44 130 if (slope == 0.0f) slope = 0.001f;
taylorza 0:303768292f44 131
taylorza 0:303768292f44 132 int x = xview;
taylorza 0:303768292f44 133 int y = yview;
taylorza 0:303768292f44 134
taylorza 0:303768292f44 135 for(;;)
taylorza 0:303768292f44 136 {
taylorza 0:303768292f44 137 if (xdiff > 0)
taylorza 0:303768292f44 138 {
taylorza 0:303768292f44 139 grid_x = ((int)x & CELL_BIT_MASK) + CELL_SIZE;
taylorza 0:303768292f44 140 }
taylorza 0:303768292f44 141 else
taylorza 0:303768292f44 142 {
taylorza 0:303768292f44 143 grid_x = ((int)x & CELL_BIT_MASK) - 1;
taylorza 0:303768292f44 144 }
taylorza 0:303768292f44 145
taylorza 0:303768292f44 146 if (ydiff > 0)
taylorza 0:303768292f44 147 {
taylorza 0:303768292f44 148 grid_y = ((int)y & CELL_BIT_MASK) + CELL_SIZE;
taylorza 0:303768292f44 149 }
taylorza 0:303768292f44 150 else
taylorza 0:303768292f44 151 {
taylorza 0:303768292f44 152 grid_y = ((int)y & CELL_BIT_MASK) - 1;
taylorza 0:303768292f44 153 }
taylorza 0:303768292f44 154
taylorza 0:303768292f44 155 xcross_x = grid_x;
taylorza 0:303768292f44 156 xcross_y = y + slope * (grid_x - x);
taylorza 0:303768292f44 157
taylorza 0:303768292f44 158 ycross_x = x + (grid_y - y) / slope;
taylorza 0:303768292f44 159 ycross_y = grid_y;
taylorza 0:303768292f44 160
taylorza 0:303768292f44 161 xd = xcross_x - x;
taylorza 0:303768292f44 162 yd = xcross_y - y;
taylorza 0:303768292f44 163 int xdist = (xd * xd) + (yd * yd);
taylorza 0:303768292f44 164
taylorza 0:303768292f44 165 xd = ycross_x - x;
taylorza 0:303768292f44 166 yd = ycross_y - y;
taylorza 0:303768292f44 167 int ydist = (xd * xd) + (yd * yd);
taylorza 0:303768292f44 168
taylorza 0:303768292f44 169 if (xdist < ydist)
taylorza 0:303768292f44 170 {
taylorza 0:303768292f44 171 xmaze = (int)xcross_x >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 172 ymaze = (int)xcross_y >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 173
taylorza 0:303768292f44 174 x = xcross_x;
taylorza 0:303768292f44 175 y = xcross_y;
taylorza 0:303768292f44 176
taylorza 0:303768292f44 177 tmcolumn = (int)y & CELL_SIZE_MASK;
taylorza 0:303768292f44 178 }
taylorza 0:303768292f44 179 else
taylorza 0:303768292f44 180 {
taylorza 0:303768292f44 181 xmaze = (int)ycross_x >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 182 ymaze = (int)ycross_y >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 183
taylorza 0:303768292f44 184 x = ycross_x;
taylorza 0:303768292f44 185 y = ycross_y;
taylorza 0:303768292f44 186
taylorza 0:303768292f44 187 tmcolumn = (int)x & CELL_SIZE_MASK;
taylorza 0:303768292f44 188 }
taylorza 0:303768292f44 189
taylorza 0:303768292f44 190 cellValue = _pMap[xmaze + (ymaze * _mapWidth)];
taylorza 0:303768292f44 191 if (cellValue != 0) break;
taylorza 0:303768292f44 192 }
taylorza 0:303768292f44 193
taylorza 0:303768292f44 194 xd = x - xview;
taylorza 0:303768292f44 195 yd = y - yview;
taylorza 0:303768292f44 196 distance = sqrt(((xd * xd) + (yd * yd)) * cos(columnAngle));
taylorza 0:303768292f44 197 if (distance == 0) distance = 1;
taylorza 0:303768292f44 198
taylorza 0:303768292f44 199 int height = _heightRatio / distance;
taylorza 0:303768292f44 200 if (height == 0) height = 1;
taylorza 0:303768292f44 201
taylorza 0:303768292f44 202 int bot = _viewDistanceTimesHeight / distance + _vertCenter;
taylorza 0:303768292f44 203 int top = bot - height;
taylorza 0:303768292f44 204
taylorza 0:303768292f44 205 int t = tmcolumn;
taylorza 0:303768292f44 206 int dheight = height;
taylorza 0:303768292f44 207 int iheight = CELL_SIZE;
taylorza 0:303768292f44 208 float yratio = (float)CELL_SIZE / height;
taylorza 0:303768292f44 209
taylorza 0:303768292f44 210 if (top < _top)
taylorza 0:303768292f44 211 {
taylorza 0:303768292f44 212 int clipBy = _top - top;
taylorza 0:303768292f44 213 int clipRatio = (int)(clipBy * yratio);
taylorza 0:303768292f44 214 dheight-= clipBy;
taylorza 0:303768292f44 215 t += clipRatio << CELL_SIZE_SHIFT;
taylorza 0:303768292f44 216 iheight -= clipRatio;
taylorza 0:303768292f44 217 top = _top;
taylorza 0:303768292f44 218 }
taylorza 0:303768292f44 219
taylorza 0:303768292f44 220 if (bot >= _bottom)
taylorza 0:303768292f44 221 {
taylorza 0:303768292f44 222 int clipBy = bot - _bottom;
taylorza 0:303768292f44 223 dheight -= clipBy;
taylorza 0:303768292f44 224 iheight -= (int)(clipBy * yratio);
taylorza 0:303768292f44 225 bot = _bottom;
taylorza 0:303768292f44 226 }
taylorza 0:303768292f44 227
taylorza 0:303768292f44 228 uint16_t color = 0xf800;
taylorza 0:303768292f44 229
taylorza 0:303768292f44 230 color = _pPalette[cellValue];
taylorza 0:303768292f44 231
taylorza 0:303768292f44 232 pSliver->top = top;
taylorza 0:303768292f44 233 pSliver->bottom = bot;
taylorza 0:303768292f44 234 pSliver->color = color;
taylorza 0:303768292f44 235 }
taylorza 0:303768292f44 236
taylorza 0:303768292f44 237 int x = _left;
taylorza 0:303768292f44 238 pSliver = _pSlivers;
taylorza 0:303768292f44 239 for(int column = 0; column < _width; column += 2, x += 2, pSliver++)
taylorza 0:303768292f44 240 {
taylorza 0:303768292f44 241 _display.fillRect(x, _top, x + 1, pSliver->top, *_pPalette);
taylorza 0:303768292f44 242 _display.fillRect(x, pSliver->top, x + 1, pSliver->bottom, pSliver->color);
taylorza 0:303768292f44 243 _display.fillRect(x, pSliver->bottom, x + 1, _bottom, *_pPalette);
taylorza 0:303768292f44 244 }
taylorza 0:303768292f44 245 }