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:
Sun Sep 21 22:04:22 2014 +0000
Revision:
0:303768292f44
Child:
1:fdbc2be25831
LCD_ST7735 Raycaster on mBuino mbed platform

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 0:303768292f44 50 void Raycaster::setCellPosition(int x, int y)
taylorza 0:303768292f44 51 {
taylorza 0:303768292f44 52 _playerX = x << CELL_SIZE_SHIFT;
taylorza 0:303768292f44 53 _playerY = y << CELL_SIZE_SHIFT;
taylorza 0:303768292f44 54 _playerViewAngle = 0;
taylorza 0:303768292f44 55 }
taylorza 0:303768292f44 56
taylorza 0:303768292f44 57 void Raycaster::rotate(float radians)
taylorza 0:303768292f44 58 {
taylorza 0:303768292f44 59 _playerViewAngle += radians;
taylorza 0:303768292f44 60 if (_playerViewAngle > PI2) _playerViewAngle -= PI2;
taylorza 0:303768292f44 61 if (_playerViewAngle < 0) _playerViewAngle += PI2;
taylorza 0:303768292f44 62 }
taylorza 0:303768292f44 63
taylorza 0:303768292f44 64 void Raycaster::move(int distance)
taylorza 0:303768292f44 65 {
taylorza 0:303768292f44 66 int mx;
taylorza 0:303768292f44 67 int my;
taylorza 0:303768292f44 68
taylorza 0:303768292f44 69 // Calculate the change in x and y coordinates
taylorza 0:303768292f44 70 float dx = sin(_playerViewAngle) * distance;
taylorza 0:303768292f44 71 float dy = cos(_playerViewAngle) * -distance;
taylorza 0:303768292f44 72
taylorza 0:303768292f44 73 // Check for collisions with walls
taylorza 0:303768292f44 74 float nx = _playerX + (dx * 4);
taylorza 0:303768292f44 75 float ny = _playerY + (dy * 4);
taylorza 0:303768292f44 76
taylorza 0:303768292f44 77 // Check for wall in the x direction and move if open
taylorza 0:303768292f44 78 mx = ((int)nx) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 79 my = ((int)_playerY) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 80 if (_pMap[mx + (my * _mapWidth)] == 0)
taylorza 0:303768292f44 81 {
taylorza 0:303768292f44 82 _playerX += dx;
taylorza 0:303768292f44 83 }
taylorza 0:303768292f44 84
taylorza 0:303768292f44 85 // Check for wall in the y direction and move if open
taylorza 0:303768292f44 86 mx = ((int)_playerX) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 87 my = ((int)ny) >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 88 if (_pMap[mx + (my * _mapWidth)] == 0)
taylorza 0:303768292f44 89 {
taylorza 0:303768292f44 90 _playerY += dy;
taylorza 0:303768292f44 91 }
taylorza 0:303768292f44 92 }
taylorza 0:303768292f44 93
taylorza 0:303768292f44 94 void Raycaster::renderFrame()
taylorza 0:303768292f44 95 {
taylorza 0:303768292f44 96 int xd, yd;
taylorza 0:303768292f44 97 int grid_x, grid_y;
taylorza 0:303768292f44 98 float xcross_x, xcross_y;
taylorza 0:303768292f44 99 float ycross_x, ycross_y;
taylorza 0:303768292f44 100 int xmaze, ymaze;
taylorza 0:303768292f44 101 float distance;
taylorza 0:303768292f44 102 int tmcolumn;
taylorza 0:303768292f44 103 uint8_t cellValue;
taylorza 0:303768292f44 104
taylorza 0:303768292f44 105 int xview = FLOAT2INT(_playerX);
taylorza 0:303768292f44 106 int yview = FLOAT2INT(_playerY);
taylorza 0:303768292f44 107
taylorza 0:303768292f44 108 float columnAngle = _halfViewVolume;
taylorza 0:303768292f44 109 float ainc2 = _ainc * 2;
taylorza 0:303768292f44 110 Sliver *pSliver = _pSlivers;
taylorza 0:303768292f44 111 for (int column = 0; column < _width; column += 2, columnAngle -= ainc2, pSliver++)
taylorza 0:303768292f44 112 {
taylorza 0:303768292f44 113 float radians = _playerViewAngle - columnAngle;
taylorza 0:303768292f44 114
taylorza 0:303768292f44 115 int xdiff = FLOAT2INT(CELL_SIZE * sin(radians));
taylorza 0:303768292f44 116 int ydiff = FLOAT2INT(-CELL_SIZE * cos(radians));
taylorza 0:303768292f44 117
taylorza 0:303768292f44 118 if (xdiff == 0) xdiff = 1;
taylorza 0:303768292f44 119
taylorza 0:303768292f44 120 float slope = (float)ydiff / xdiff;
taylorza 0:303768292f44 121 if (slope == 0.0f) slope = 0.001f;
taylorza 0:303768292f44 122
taylorza 0:303768292f44 123 int x = xview;
taylorza 0:303768292f44 124 int y = yview;
taylorza 0:303768292f44 125
taylorza 0:303768292f44 126 for(;;)
taylorza 0:303768292f44 127 {
taylorza 0:303768292f44 128 if (xdiff > 0)
taylorza 0:303768292f44 129 {
taylorza 0:303768292f44 130 grid_x = ((int)x & CELL_BIT_MASK) + CELL_SIZE;
taylorza 0:303768292f44 131 }
taylorza 0:303768292f44 132 else
taylorza 0:303768292f44 133 {
taylorza 0:303768292f44 134 grid_x = ((int)x & CELL_BIT_MASK) - 1;
taylorza 0:303768292f44 135 }
taylorza 0:303768292f44 136
taylorza 0:303768292f44 137 if (ydiff > 0)
taylorza 0:303768292f44 138 {
taylorza 0:303768292f44 139 grid_y = ((int)y & CELL_BIT_MASK) + CELL_SIZE;
taylorza 0:303768292f44 140 }
taylorza 0:303768292f44 141 else
taylorza 0:303768292f44 142 {
taylorza 0:303768292f44 143 grid_y = ((int)y & CELL_BIT_MASK) - 1;
taylorza 0:303768292f44 144 }
taylorza 0:303768292f44 145
taylorza 0:303768292f44 146 xcross_x = grid_x;
taylorza 0:303768292f44 147 xcross_y = y + slope * (grid_x - x);
taylorza 0:303768292f44 148
taylorza 0:303768292f44 149 ycross_x = x + (grid_y - y) / slope;
taylorza 0:303768292f44 150 ycross_y = grid_y;
taylorza 0:303768292f44 151
taylorza 0:303768292f44 152 xd = xcross_x - x;
taylorza 0:303768292f44 153 yd = xcross_y - y;
taylorza 0:303768292f44 154 int xdist = (xd * xd) + (yd * yd);
taylorza 0:303768292f44 155
taylorza 0:303768292f44 156 xd = ycross_x - x;
taylorza 0:303768292f44 157 yd = ycross_y - y;
taylorza 0:303768292f44 158 int ydist = (xd * xd) + (yd * yd);
taylorza 0:303768292f44 159
taylorza 0:303768292f44 160 if (xdist < ydist)
taylorza 0:303768292f44 161 {
taylorza 0:303768292f44 162 xmaze = (int)xcross_x >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 163 ymaze = (int)xcross_y >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 164
taylorza 0:303768292f44 165 x = xcross_x;
taylorza 0:303768292f44 166 y = xcross_y;
taylorza 0:303768292f44 167
taylorza 0:303768292f44 168 tmcolumn = (int)y & CELL_SIZE_MASK;
taylorza 0:303768292f44 169 }
taylorza 0:303768292f44 170 else
taylorza 0:303768292f44 171 {
taylorza 0:303768292f44 172 xmaze = (int)ycross_x >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 173 ymaze = (int)ycross_y >> CELL_SIZE_SHIFT;
taylorza 0:303768292f44 174
taylorza 0:303768292f44 175 x = ycross_x;
taylorza 0:303768292f44 176 y = ycross_y;
taylorza 0:303768292f44 177
taylorza 0:303768292f44 178 tmcolumn = (int)x & CELL_SIZE_MASK;
taylorza 0:303768292f44 179 }
taylorza 0:303768292f44 180
taylorza 0:303768292f44 181 cellValue = _pMap[xmaze + (ymaze * _mapWidth)];
taylorza 0:303768292f44 182 if (cellValue != 0) break;
taylorza 0:303768292f44 183 }
taylorza 0:303768292f44 184
taylorza 0:303768292f44 185 xd = x - xview;
taylorza 0:303768292f44 186 yd = y - yview;
taylorza 0:303768292f44 187 distance = sqrt(((xd * xd) + (yd * yd)) * cos(columnAngle));
taylorza 0:303768292f44 188 if (distance == 0) distance = 1;
taylorza 0:303768292f44 189
taylorza 0:303768292f44 190 int height = _heightRatio / distance;
taylorza 0:303768292f44 191 if (height == 0) height = 1;
taylorza 0:303768292f44 192
taylorza 0:303768292f44 193 int bot = _viewDistanceTimesHeight / distance + _vertCenter;
taylorza 0:303768292f44 194 int top = bot - height;
taylorza 0:303768292f44 195
taylorza 0:303768292f44 196 int t = tmcolumn;
taylorza 0:303768292f44 197 int dheight = height;
taylorza 0:303768292f44 198 int iheight = CELL_SIZE;
taylorza 0:303768292f44 199 float yratio = (float)CELL_SIZE / height;
taylorza 0:303768292f44 200
taylorza 0:303768292f44 201 if (top < _top)
taylorza 0:303768292f44 202 {
taylorza 0:303768292f44 203 int clipBy = _top - top;
taylorza 0:303768292f44 204 int clipRatio = (int)(clipBy * yratio);
taylorza 0:303768292f44 205 dheight-= clipBy;
taylorza 0:303768292f44 206 t += clipRatio << CELL_SIZE_SHIFT;
taylorza 0:303768292f44 207 iheight -= clipRatio;
taylorza 0:303768292f44 208 top = _top;
taylorza 0:303768292f44 209 }
taylorza 0:303768292f44 210
taylorza 0:303768292f44 211 if (bot >= _bottom)
taylorza 0:303768292f44 212 {
taylorza 0:303768292f44 213 int clipBy = bot - _bottom;
taylorza 0:303768292f44 214 dheight -= clipBy;
taylorza 0:303768292f44 215 iheight -= (int)(clipBy * yratio);
taylorza 0:303768292f44 216 bot = _bottom;
taylorza 0:303768292f44 217 }
taylorza 0:303768292f44 218
taylorza 0:303768292f44 219 uint16_t color = 0xf800;
taylorza 0:303768292f44 220
taylorza 0:303768292f44 221 color = _pPalette[cellValue];
taylorza 0:303768292f44 222
taylorza 0:303768292f44 223 pSliver->top = top;
taylorza 0:303768292f44 224 pSliver->bottom = bot;
taylorza 0:303768292f44 225 pSliver->color = color;
taylorza 0:303768292f44 226 }
taylorza 0:303768292f44 227
taylorza 0:303768292f44 228 int x = _left;
taylorza 0:303768292f44 229 pSliver = _pSlivers;
taylorza 0:303768292f44 230 for(int column = 0; column < _width; column += 2, x += 2, pSliver++)
taylorza 0:303768292f44 231 {
taylorza 0:303768292f44 232 _display.fillRect(x, _top, x + 1, pSliver->top, *_pPalette);
taylorza 0:303768292f44 233 _display.fillRect(x, pSliver->top, x + 1, pSliver->bottom, pSliver->color);
taylorza 0:303768292f44 234 _display.fillRect(x, pSliver->bottom, x + 1, _bottom, *_pPalette);
taylorza 0:303768292f44 235 }
taylorza 0:303768292f44 236 }