Ray casting engine implemented on the mBuino platform using the ST7735 LCD controller.
Embed:
(wiki syntax)
Show/hide line numbers
Raycaster.cpp
00001 #include "mbed.h" 00002 #include "common.h" 00003 #include "LCD_ST7735.h" 00004 #include "Raycaster.h" 00005 00006 Raycaster::Raycaster(int left, int top, int width, int height, 00007 int viewerDistance, int viewerHeight, 00008 const uint8_t *pMap, int mapWidth, int mapHeight, 00009 const uint16_t *pPalette) : 00010 _display(P0_15, // backlight 00011 P0_10, // reset 00012 P0_18, // ds 00013 P0_21, // mosi 00014 P0_22, // miso 00015 P1_15, // clk 00016 P0_19),// cs 00017 _pMap(pMap), 00018 _mapWidth(mapWidth), 00019 _mapHeight(mapHeight), 00020 _pPalette(pPalette), 00021 _left(left), 00022 _width(width), 00023 _top(top), 00024 _height(height) 00025 { 00026 _display.setOrientation(LCD_ST7735::Rotate90, false); 00027 _display.clearScreen(); 00028 00029 _right = left + width; 00030 _halfWidth = width >> 1; 00031 _horizCenter = left + _halfWidth; 00032 00033 _bottom = top + height; 00034 _halfHeight = height >> 1; 00035 _vertCenter = top + _halfHeight; 00036 00037 _viewerDistance = viewerDistance; 00038 _viewerHeight = viewerHeight; 00039 00040 _viewVolume = 60 * PI / 180; 00041 _halfViewVolume = _viewVolume / 2; 00042 00043 _ainc = _viewVolume / _width; 00044 00045 _viewDistanceTimesHeight = _viewerDistance * _viewerHeight; 00046 _heightRatio = (_viewerDistance << CELL_SIZE_SHIFT); 00047 _pSlivers = new Sliver[_width >> 1]; 00048 } 00049 00050 Raycaster::~Raycaster() 00051 { 00052 if (_pSlivers != NULL) 00053 { 00054 delete[] _pSlivers; 00055 _pSlivers = NULL; 00056 } 00057 } 00058 00059 void Raycaster::setCellPosition(int x, int y) 00060 { 00061 _playerX = x << CELL_SIZE_SHIFT; 00062 _playerY = y << CELL_SIZE_SHIFT; 00063 _playerViewAngle = 0; 00064 } 00065 00066 void Raycaster::rotate(float radians) 00067 { 00068 _playerViewAngle += radians; 00069 if (_playerViewAngle > PI2) _playerViewAngle -= PI2; 00070 if (_playerViewAngle < 0) _playerViewAngle += PI2; 00071 } 00072 00073 void Raycaster::move(int distance) 00074 { 00075 int mx; 00076 int my; 00077 00078 // Calculate the change in x and y coordinates 00079 float dx = sin(_playerViewAngle) * distance; 00080 float dy = cos(_playerViewAngle) * -distance; 00081 00082 // Check for collisions with walls 00083 float nx = _playerX + (dx * 4); 00084 float ny = _playerY + (dy * 4); 00085 00086 // Check for wall in the x direction and move if open 00087 mx = ((int)nx) >> CELL_SIZE_SHIFT; 00088 my = ((int)_playerY) >> CELL_SIZE_SHIFT; 00089 if (_pMap[mx + (my * _mapWidth)] == 0) 00090 { 00091 _playerX += dx; 00092 } 00093 00094 // Check for wall in the y direction and move if open 00095 mx = ((int)_playerX) >> CELL_SIZE_SHIFT; 00096 my = ((int)ny) >> CELL_SIZE_SHIFT; 00097 if (_pMap[mx + (my * _mapWidth)] == 0) 00098 { 00099 _playerY += dy; 00100 } 00101 } 00102 00103 void Raycaster::renderFrame() 00104 { 00105 int xd, yd; 00106 int grid_x, grid_y; 00107 float xcross_x, xcross_y; 00108 float ycross_x, ycross_y; 00109 int xmaze, ymaze; 00110 float distance; 00111 int tmcolumn; 00112 uint8_t cellValue; 00113 00114 int xview = FLOAT2INT(_playerX); 00115 int yview = FLOAT2INT(_playerY); 00116 00117 float columnAngle = _halfViewVolume; 00118 float ainc2 = _ainc * 2; 00119 Sliver *pSliver = _pSlivers; 00120 for (int column = 0; column < _width; column += 2, columnAngle -= ainc2, pSliver++) 00121 { 00122 float radians = _playerViewAngle - columnAngle; 00123 00124 int xdiff = FLOAT2INT(CELL_SIZE * sin(radians)); 00125 int ydiff = FLOAT2INT(-CELL_SIZE * cos(radians)); 00126 00127 if (xdiff == 0) xdiff = 1; 00128 00129 float slope = (float)ydiff / xdiff; 00130 if (slope == 0.0f) slope = 0.001f; 00131 00132 int x = xview; 00133 int y = yview; 00134 00135 for(;;) 00136 { 00137 if (xdiff > 0) 00138 { 00139 grid_x = ((int)x & CELL_BIT_MASK) + CELL_SIZE; 00140 } 00141 else 00142 { 00143 grid_x = ((int)x & CELL_BIT_MASK) - 1; 00144 } 00145 00146 if (ydiff > 0) 00147 { 00148 grid_y = ((int)y & CELL_BIT_MASK) + CELL_SIZE; 00149 } 00150 else 00151 { 00152 grid_y = ((int)y & CELL_BIT_MASK) - 1; 00153 } 00154 00155 xcross_x = grid_x; 00156 xcross_y = y + slope * (grid_x - x); 00157 00158 ycross_x = x + (grid_y - y) / slope; 00159 ycross_y = grid_y; 00160 00161 xd = xcross_x - x; 00162 yd = xcross_y - y; 00163 int xdist = (xd * xd) + (yd * yd); 00164 00165 xd = ycross_x - x; 00166 yd = ycross_y - y; 00167 int ydist = (xd * xd) + (yd * yd); 00168 00169 if (xdist < ydist) 00170 { 00171 xmaze = (int)xcross_x >> CELL_SIZE_SHIFT; 00172 ymaze = (int)xcross_y >> CELL_SIZE_SHIFT; 00173 00174 x = xcross_x; 00175 y = xcross_y; 00176 00177 tmcolumn = (int)y & CELL_SIZE_MASK; 00178 } 00179 else 00180 { 00181 xmaze = (int)ycross_x >> CELL_SIZE_SHIFT; 00182 ymaze = (int)ycross_y >> CELL_SIZE_SHIFT; 00183 00184 x = ycross_x; 00185 y = ycross_y; 00186 00187 tmcolumn = (int)x & CELL_SIZE_MASK; 00188 } 00189 00190 cellValue = _pMap[xmaze + (ymaze * _mapWidth)]; 00191 if (cellValue != 0) break; 00192 } 00193 00194 xd = x - xview; 00195 yd = y - yview; 00196 distance = sqrt(((xd * xd) + (yd * yd)) * cos(columnAngle)); 00197 if (distance == 0) distance = 1; 00198 00199 int height = _heightRatio / distance; 00200 if (height == 0) height = 1; 00201 00202 int bot = _viewDistanceTimesHeight / distance + _vertCenter; 00203 int top = bot - height; 00204 00205 int t = tmcolumn; 00206 int dheight = height; 00207 int iheight = CELL_SIZE; 00208 float yratio = (float)CELL_SIZE / height; 00209 00210 if (top < _top) 00211 { 00212 int clipBy = _top - top; 00213 int clipRatio = (int)(clipBy * yratio); 00214 dheight-= clipBy; 00215 t += clipRatio << CELL_SIZE_SHIFT; 00216 iheight -= clipRatio; 00217 top = _top; 00218 } 00219 00220 if (bot >= _bottom) 00221 { 00222 int clipBy = bot - _bottom; 00223 dheight -= clipBy; 00224 iheight -= (int)(clipBy * yratio); 00225 bot = _bottom; 00226 } 00227 00228 uint16_t color = 0xf800; 00229 00230 color = _pPalette[cellValue]; 00231 00232 pSliver->top = top; 00233 pSliver->bottom = bot; 00234 pSliver->color = color; 00235 } 00236 00237 int x = _left; 00238 pSliver = _pSlivers; 00239 for(int column = 0; column < _width; column += 2, x += 2, pSliver++) 00240 { 00241 _display.fillRect(x, _top, x + 1, pSliver->top, *_pPalette); 00242 _display.fillRect(x, pSliver->top, x + 1, pSliver->bottom, pSliver->color); 00243 _display.fillRect(x, pSliver->bottom, x + 1, _bottom, *_pPalette); 00244 } 00245 }
Generated on Sat Jul 16 2022 14:43:34 by 1.7.2