1
0

RAYCAST.C 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. * Raycaster, based on lodev engine tutorial
  3. * Plan:
  4. * - Improve collision detection:
  5. * - During movement function,
  6. * - Check if new pos has distance from possible wall hor and ver
  7. * - Make rendering variables global with prefix
  8. * - Convert rendering function to assembly
  9. * - Add sprites (as this is done after walls)
  10. */
  11. #define word char
  12. #include "LIB/MATH.C"
  13. #include "LIB/STDLIB.C"
  14. #include "LIB/SYS.C"
  15. #include "LIB/GFX.C"
  16. #include "LIB/FP.C"
  17. // Note: these are also hardcoded in the render assembly, so update there as well!
  18. #define FB_ADDR 0xD00000
  19. #define screenWidth 320
  20. #define screenHeight 240
  21. #define texWidth 64
  22. #define texHeight 64
  23. #define mapWidth 24
  24. #define mapHeight 24
  25. // Input
  26. #define BTN_LEFT 256
  27. #define BTN_RIGHT 257
  28. #define BTN_UP 258
  29. #define BTN_DOWN 259
  30. // Colors
  31. #define COLOR_RED 224
  32. #define COLOR_DARK_RED 96
  33. #define COLOR_GREEN 28
  34. #define COLOR_DARK_GREEN 12
  35. #define COLOR_BLUE 3
  36. #define COLOR_DARK_BLUE 2
  37. #define COLOR_WHITE 0xFF
  38. #define COLOR_GREY 0xB6
  39. #define COLOR_YELLOW 0xFC
  40. #define COLOR_DARK_YELLOW 0x90
  41. // Data
  42. /*
  43. - LUTdirX
  44. - LUTdirY
  45. - LUTplaneX
  46. - LUTplaney
  47. - texture
  48. */
  49. #include "DATA/RAYDAT.C"
  50. // Framebuffer. fb[Y][X] (bottom right is [239][319])
  51. char (*fb)[screenWidth] = (char (*)[screenWidth])FB_ADDR;
  52. word worldMap[mapWidth][mapHeight] = {
  53. {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7},
  54. {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 7},
  55. {4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7},
  56. {4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7},
  57. {4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 7},
  58. {4, 0, 4, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 0, 7, 7, 7, 7, 7},
  59. {4, 0, 5, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 1, 0, 2, 7, 0, 0, 0, 7, 7, 7, 1},
  60. {4, 0, 6, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 7, 0, 0, 0, 0, 0, 0, 8},
  61. {4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 1},
  62. {4, 0, 8, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 0, 0, 8},
  63. {4, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 7, 7, 7, 1},
  64. {4, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 1},
  65. {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
  66. {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
  67. {6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
  68. {4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 6, 0, 6, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3},
  69. {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2},
  70. {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 5, 0, 0, 2, 0, 0, 0, 2},
  71. {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2},
  72. {4, 0, 6, 0, 6, 0, 0, 0, 0, 4, 6, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 2},
  73. {4, 0, 0, 5, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2},
  74. {4, 0, 6, 0, 6, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 5, 0, 0, 2, 0, 0, 0, 2},
  75. {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2},
  76. {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3}};
  77. // Global variables, so render function can access it
  78. word drawStart = 0;
  79. word drawEnd = 0;
  80. word texNum = 0;
  81. word side = 0; // was a NorthSouth or a EastWest wall hit?
  82. // Globalr vars
  83. // x and y start position
  84. fixed_point_t RAY_posX;
  85. fixed_point_t RAY_posY;
  86. // initial direction vector
  87. fixed_point_t RAY_dirX;
  88. fixed_point_t RAY_dirY;
  89. // the 2d raycaster version of camera plane
  90. fixed_point_t RAY_planeX;
  91. fixed_point_t RAY_planeY;
  92. // Local vars to store
  93. // Render entire screen
  94. // Registers (global):
  95. // r1 x current vertical line (x of screen)
  96. void RAYFX_renderScreen()
  97. {
  98. // reg 4 5 6 7 (args) and 2 3 (retval) are safe
  99. asm(
  100. // backdup registers
  101. "push r1\n"
  102. "push r8\n"
  103. "push r9\n"
  104. "push r10\n"
  105. "push r11\n"
  106. "push r12\n"
  107. "push r13\n"
  108. "push r14\n"
  109. "push r15\n"
  110. );
  111. asm(
  112. // r1: current vertical line (x of screen)
  113. "load32 0 r1\n"
  114. // for each vertical line (x)
  115. "RAYFX_screenXloop:\n"
  116. // cameraX
  117. "addr2reg LUTcameraX r15\n" // r15 = LUTcameraX
  118. "add r15 r1 r15\n" // r15 = LUTcameraX[x] addr
  119. "read 0 r15 r15\n" // r15 = LUTcameraX[x] value
  120. // r2 rayDirx [FP] x dir of ray
  121. // r3 rayDiry [FP] y dir of ray
  122. // r2: rayDirX
  123. "addr2reg RAY_dirX r14\n" // r14 = RAY_dirX addr
  124. "read 0 r14 r14\n" // r14 = RAY_dirX value
  125. "addr2reg RAY_planeX r13\n" // r13 = RAY_planeX addr
  126. "read 0 r13 r13\n" // r13 = RAY_planeX value
  127. "multfp r13 r15 r2\n" // r2 = FP_Mult(RAY_planeX, cameraX)
  128. "add r2 r14 r2\n" // r2 += RAY_dirX
  129. // r3: rayDirY
  130. "addr2reg RAY_dirY r14\n" // r14 = RAY_dirY addr
  131. "read 0 r14 r14\n" // r14 = RAY_dirY value
  132. "addr2reg RAY_planeY r13\n" // r13 = RAY_planeY addr
  133. "read 0 r13 r13\n" // r13 = RAY_planeY value
  134. "multfp r13 r15 r3\n" // r3 = FP_Mult(RAY_planeY, cameraX)
  135. "add r3 r14 r3\n" // r3 += RAY_dirY
  136. // r4: deltaDistX
  137. "load32 1 r15\n" // r15 = 1
  138. "shiftl r15 16 r15\n" // r15 = FP(1)
  139. "load32 0xC02742 r14\n" // r14 = addr fpdiv_writea
  140. "write 0 r14 r15\n" // write a (fp1) to divider
  141. "write 1 r14 r2\n" // write b (rayDirX) to divider and perform division
  142. "read 1 r14 r4\n" // read result to r4
  143. "shiftrs r4 31 r13\n" // r13 = y = x >>(signed) 31 (start of abs)
  144. "xor r4 r13 r4\n" // r4 = (x ^ y)
  145. "sub r4 r13 r4\n" // r4 -= y (result of abs)
  146. // r5: deltaDistY (uses r14 and r15 from above)
  147. "write 0 r14 r15\n" // write a (fp1) to divider
  148. "write 1 r14 r3\n" // write b (rayDirY) to divider and perform division
  149. "read 1 r14 r5\n" // read result to r5
  150. "shiftrs r5 31 r13\n" // r13 = y = x >>(signed) 31 (start of abs)
  151. "xor r5 r13 r5\n" // r5 = (x ^ y)
  152. "sub r5 r13 r5\n" // r5 -= y (result of abs)
  153. // if (rayDirX < 0), else
  154. // r6: stepX
  155. // r7: stepY
  156. // r8: sideDistX
  157. // r9: sideDistY
  158. // r10: mapX
  159. // r11: mapY
  160. "blts r2 r0 2\n" // if (rayDirX < 0) skip next line
  161. "jump RAYFX_rayDirXge0\n" // goto RAYFX_rayDirXge0
  162. "load32 -1 r6\n" // r6 = stepX = -1
  163. "addr2reg RAY_posX r15\n" // r15 = RAY_posX addr
  164. "read 0 r15 r15\n" // r15 = RAY_posX value
  165. "shiftrs r15 16 r10\n" // mapX = int(RAY_posX)
  166. "load32 0xFFFF r14\n" // r14 = decimal part mask
  167. "and r15 r14 r15\n" // r15 = RAY_posX decimal part
  168. "multfp r15 r4 r8\n" // sideDistX = RAY_posX decimal part * deltaDistX
  169. "jump RAYFX_rayDirXltEnd\n" // skip the else part
  170. "RAYFX_rayDirXge0:\n"
  171. "load32 1 r6\n" // stepX = 1
  172. "addr2reg RAY_posX r15\n" // r15 = RAY_posX addr
  173. "read 0 r15 r15\n" // r15 = RAY_posX value
  174. "shiftrs r15 16 r10\n" // r10 (mapX) = r15 >> 16 (to int)
  175. "add r10 1 r14\n" // r14 = int(RAY_posX) + 1
  176. "shiftl r14 16 r14\n" // r14 <<=16 (to FP)
  177. "sub r14 r15 r15\n" // r15 = r14 - RAY_posX
  178. "multfp r15 r4 r8\n" // sideDistX = RAY_posX-ish * deltaDistX
  179. "RAYFX_rayDirXltEnd:\n"
  180. // if (rayDirY < 0), else
  181. "blts r3 r0 2\n" // if (rayDirY < 0) skip next line
  182. "jump RAYFX_rayDirYge0\n" // goto RAYFX_rayDirYge0
  183. "load32 -1 r7\n" // r7 = stepY = -1
  184. "addr2reg RAY_posY r15\n" // r15 = RAY_posY addr
  185. "read 0 r15 r15\n" // r15 = RAY_posY value
  186. "shiftrs r15 16 r11\n" // mapY = int(RAY_posY)
  187. "load32 0xFFFF r14\n" // r14 = decimal part mask
  188. "and r15 r14 r15\n" // r15 = RAY_posY decimal part
  189. "multfp r15 r5 r9\n" // sideDistY = RAY_posY decimal part * deltaDistY
  190. "jump RAYFX_rayDirYltEnd\n" // skip the else part
  191. "RAYFX_rayDirYge0:\n"
  192. "load32 1 r7\n" // stepY = 1
  193. "addr2reg RAY_posY r15\n" // r15 = RAY_posY addr
  194. "read 0 r15 r15\n" // r15 = RAY_posY value
  195. "shiftrs r15 16 r11\n" // r11 (mapY) = r15 >> 16 (to int)
  196. "add r11 1 r14\n" // r14 = int(RAY_posY) + 1
  197. "shiftl r14 16 r14\n" // r14 <<=16 (to FP)
  198. "sub r14 r15 r15\n" // r15 = r14 - RAY_posX
  199. "multfp r15 r5 r9\n" // sideDistY = RAY_posX-ish * deltaDistY
  200. "RAYFX_rayDirYltEnd:\n"
  201. // DDA (uses tmp r15)
  202. "load32 0 r15\n" // hit = 0
  203. "RAYFX_DDAwhileNoHit:\n" // while (hit == 0)
  204. "beq r15 r0 2\n" // while check
  205. "jump RAYFX_DDAwhileNoHitDone\n"
  206. // if (sideDistX < sideDistY), else
  207. "blts r8 r9 2\n" // if (sideDistX < sideDistY) skip next line
  208. "jump RAYFX_sideDistXltY\n" // goto RAYFX_sideDistXltY
  209. "add r8 r4 r8\n" // sideDistX += deltaDistX;
  210. "add r10 r6 r10\n" // mapX += stepX;
  211. "addr2reg side r14\n" // side;
  212. "write 0 r14 r0\n" // side = 0;
  213. "jump RAYFX_sideDistXltYend\n" // skip the else part
  214. "RAYFX_sideDistXltY:\n"
  215. "add r9 r5 r9\n" // sideDistY += deltaDistY;
  216. "add r11 r7 r11\n" // mapY += stepY;
  217. "addr2reg side r14\n" // side;
  218. "load32 1 r13\n" // 1
  219. "write 0 r14 r13\n" // side = 1;
  220. "RAYFX_sideDistXltYend:\n"
  221. "addr2reg worldMap r14\n" // r14 = worldMap addr;
  222. "multu r10 24 r13\n" // r13 = mapX offset using mapHeight
  223. "add r13 r11 r13\n" // r13 += mapY offset
  224. "add r13 r14 r14\n" // r14 = worldMap[mapX][mapY] addr
  225. "read 0 r14 r14\n" // r14 = worldMap[mapX][mapY] value
  226. "bles r14 r0 2\n" // skip next instruction if worldMap[mapX][mapY] <= 0
  227. "load 1 r15\n" // hit = 1
  228. "jump RAYFX_DDAwhileNoHit\n" // return to while loop start
  229. "RAYFX_DDAwhileNoHitDone:\n"
  230. // From this point, r10 r11 mapx mapy (and r15) are free
  231. // texNum = worldMap[mapX][mapY] - 1;
  232. // assumes worldMap[mapX][mapY] value is still in r14
  233. "addr2reg texNum r13\n" // r13 = texNum addr;
  234. "sub r14 1 r14\n" // r14 = worldMap[mapX][mapY] - 1
  235. "write 0 r13 r14\n" // write texNum;
  236. // r10: perpWallDist (FP)
  237. "addr2reg side r15\n" // side addr
  238. "read 0 r15 r15\n" // side value
  239. // if (side == 0), else
  240. "bne r15 r0 3\n" // if (side != 0) skip next two lines
  241. "sub r8 r4 r10\n" // perpWallDist = (sideDistX - deltaDistX); (match)
  242. "jumpo 2\n" // skip else part
  243. "sub r9 r5 r10\n" // perpWallDist = (sideDistY - deltaDistY); (else)
  244. // From this point sideDistX&Y and deltaDistX&Y are free
  245. // this frees up regs 4 5 8 and 9
  246. // leaving to use: 4, 5, 8, 9, 11, 12, 13, 14, 15
  247. // r4: lineHeight
  248. "load32 240 r15\n" // r15 = screenHeight
  249. "shiftl r15 16 r15\n" // r15 = FP(screenHeight)
  250. "load32 0xC02742 r14\n" // r14 = addr fpdiv_writea
  251. "write 0 r14 r15\n" // write a (FP(screenHeight) to divider
  252. "write 1 r14 r10\n" // write b (perpWallDist) to divider and perform division
  253. "read 1 r14 r4\n" // read result to r4
  254. "shiftrs r4 16 r4\n" // r4 = lineHeight = int(r4)
  255. "shiftrs r4 1 r15\n" // r15 = lineHeight >> 1
  256. "load32 -1 r14\n" // r14 = -1
  257. "mults r15 r14 r15\n" // r15 = -r15
  258. "load32 120 r14\n" // r14 = screenHeight >> 1
  259. "add r14 r15 r15\n" // r15 = drawStart value (r14+r15)
  260. "bges r15 r0 2\n" // skip next line if drawStart >= 0
  261. "load 0 r15\n" // set drawStart to 0 if < 0
  262. "addr2reg drawStart r14\n" // r14 = drawStart addr
  263. "write 0 r14 r15\n" // write drawStart value
  264. // skip render if start > 238
  265. "load32 238 r14\n"
  266. "blts r15 r14 2 \n"
  267. "jump RAYFX_skipRenderLine\n"
  268. "shiftrs r4 1 r15\n" // r15 = lineHeight >> 1
  269. "load32 120 r14\n" // r14 = screenHeight >> 1
  270. "add r14 r15 r15\n" // r15 = drawEnd value (r14+r15)
  271. "load32 240 r14\n" // r14 = screenHeight
  272. "blts r15 r14 2\n" // skip next line if drawEnd < screenHeight
  273. "load 239 r15\n" // set drawEnd to screenHeight - 1
  274. "addr2reg drawEnd r14\n" // r14 = drawEnd addr
  275. "write 0 r14 r15\n" // write drawEnd value
  276. // texture calculations
  277. // r8: side
  278. // r5: wallX
  279. "addr2reg side r8\n" // r8 = side addr
  280. "read 0 r8 r8\n" // r8 = side value
  281. "bne r8 r0 7\n" // if side != 0, goto else part (addr2reg is two instructions!)
  282. "addr2reg RAY_posY r15\n" // r15 = RAY_posY addr
  283. "read 0 r15 r15\n" // r15 = RAY_posY value
  284. "multfp r10 r3 r14\n" // r14 = perpWallDist * rayDirY
  285. "add r14 r15 r5\n" // r5 = wallX = r14 + RAY_posY
  286. "jumpo 5\n" // skip else
  287. // else
  288. "addr2reg RAY_posX r15\n" // r15 = RAY_posX addr
  289. "read 0 r15 r15\n" // r15 = RAY_posX value
  290. "multfp r10 r2 r14\n" // r14 = perpWallDist, rayDirX
  291. "add r14 r15 r5\n" // r5 = wallX = r14 + RAY_posX
  292. "load32 0xFFFF r15\n" // r15 = floormask
  293. "and r5 r15 r5\n" // wallX-=floor(wallX)
  294. // r6: texX
  295. "load32 64 r15\n" // r15 = texWidth
  296. "shiftl r15 16 r14\n" // r14 = FP(texWidth)
  297. "multfp r14 r5 r6\n" // r6 = FP_Mult(wallX, FP_intToFP(texWidth))
  298. "shiftrs r6 16 r6\n" // r6 = int(r6)
  299. "bne r8 r0 4\n" // skip if side != 0
  300. "bles r2 r0 3\n" // skip if rayDirX <= 0
  301. "sub r15 r6 r6\n" // texX = texWidth - texX
  302. "sub r6 1 r6\n" // texX -= 1
  303. "beq r8 r0 4\n" // skip if side == 0
  304. "bges r3 r0 3\n" // skip if rayDirY >= 0
  305. "sub r15 r6 r6\n" // texX = texWidth - texX
  306. "sub r6 1 r6\n" // texX -= 1
  307. // r2 and r3 are free now (no rayDirX&Y needed)
  308. // r5: step
  309. "load32 64 r15\n" // r15 = texHeight
  310. "shiftl r15 16 r15\n" // r15 = FP(texHeight)
  311. "shiftl r4 16 r14\n" // r14 = FP(lineHeight)
  312. "load32 0xC02742 r13\n" // r13 = addr fpdiv_writea
  313. "write 0 r13 r15\n" // write a (FP(screenHeight) to divider
  314. "write 1 r13 r14\n" // write b (FP(lineHeight)) to divider and perform division
  315. "read 1 r13 r5\n" // read result to r5
  316. // r4: texPos
  317. "addr2reg drawStart r15\n" // r15 = drawStart addr
  318. "read 0 r15 r15\n" // r15 = drawStart value
  319. "sub r15 120 r15\n" // r15 -= (screenHeight >> 1)
  320. "shiftrs r4 1 r14\n" // r14 = lineHeight >> 1
  321. "add r15 r14 r15\n" // r15 += lineHeight >> 1
  322. "shiftl r15 16 r15\n" // r15 = FP(r15)
  323. "multfp r15 r5 r4\n" // r4 = r15 * step
  324. "or r1 r0 r7\n" // move x to r7
  325. // Render vertical line in pixel plane with textures
  326. // Registers:
  327. // r1 first pixel addr VRAM addr of first pixel in line (top pixel)
  328. // r2 (a2r) drawStart Starting pixel of wall
  329. // r3 (a2r) drawEnd Ending pixel of wall
  330. // r4 texPos Starting texture coordinate
  331. // r5 step How much to increase the texture coordinate per screen pixel
  332. // r6 texX X coordinate on the texture
  333. // r7 x X position of line to render
  334. // r8 current FB pos Current framebuffer position in VRAM (top to bottom)
  335. // r9 end loop FB pos Last framebuffer position in VRAM of current loop
  336. // r10 texY Y coordinate on the texture
  337. // r11 gp Used as temp reg in calculations
  338. // r12 texture[texNum] Texture array of texture to draw
  339. // r13 color Pixel color
  340. // r14 ceil or floor col Ceiling or floor color
  341. // r15 side North South or East West wall side
  342. "push r1\n"
  343. "push r2\n"
  344. "push r3\n"
  345. "push r4\n"
  346. "push r5\n"
  347. "push r6\n"
  348. "push r7\n"
  349. "push r8\n"
  350. "push r9\n"
  351. "push r10\n"
  352. "push r11\n"
  353. "push r12\n"
  354. "push r13\n"
  355. "push r14\n"
  356. "push r15\n"
  357. "addr2reg drawStart r2 ; r2 = drawStart addr\n"
  358. "read 0 r2 r2 ; r2 = drawStart value\n"
  359. "addr2reg drawEnd r3 ; r3 = drawEnd addr\n"
  360. "read 0 r3 r3 ; r3 = drawEnd value\n"
  361. "load32 0xD00000 r1 ; r1 = framebuffer addr\n"
  362. "add r1 r7 r1 ; r1 = first pixel in line (fb+x)\n"
  363. "or r0 r1 r8 ; r8 = current pixel\n"
  364. "multu r2 320 r9 ; r9 = drawStart VRAM offset\n"
  365. "add r9 r1 r9 ; r9 = last FB pos of before wall\n"
  366. "addr2reg texNum r12 ; r12 = texNum addr\n"
  367. "read 0 r12 r12 ; r12 = texNum value\n"
  368. "multu r12 4096 r12 ; r12 = texture offset (64*64 per texture)\n"
  369. "addr2reg texture r11 ; r11 = texture array\n"
  370. "add r12 r11 r12 ; r12 = texture[texNum]\n"
  371. "load32 0x0082F0 r14 ; r14 = ceiling color\n"
  372. "addr2reg side r15 ; r15 = side addr\n"
  373. "read 0 r15 r15 ; r15 = side value\n"
  374. // draw until start
  375. "RAYFX_drawVlineLoopCeiling:\n"
  376. " write 0 r8 r14 ; write ceiling pixel\n"
  377. " add r8 320 r8 ; go to next line pixel\n"
  378. " bge r8 r9 2 ; keep looping until reached wall\n"
  379. " jump RAYFX_drawVlineLoopCeiling\n"
  380. "multu r3 320 r9 ; r9 = drawEnd VRAM offset\n"
  381. "add r9 r1 r9 ; r9 = last FB pos of wall\n"
  382. "load32 8355711 r2 ; r2 = mask for darken color\n"
  383. // draw until floor
  384. "RAYFX_drawVlineLoopWall:\n"
  385. " shiftrs r4 16 r11 ; r11 = texY = FPtoInt(texPos)\n"
  386. " and r11 63 r11 ; r11 = r11 & (texHeight-1)\n"
  387. " add r4 r5 r4 ; texPos += step\n"
  388. " multu r11 64 r11 ; r11 = texHeight * texY \n"
  389. " add r11 r6 r11 ; r11 += texX\n"
  390. " add r11 r12 r13 ; r13 = addr of color in texture array\n"
  391. " read 0 r13 r13 ; r13 = pixel color\n"
  392. " beq r15 r0 3 ; skip next two lines if not side of wall is hit\n"
  393. " shiftrs r13 1 r13\n" // r13 >> 1
  394. " and r13 r2 r13 ; r13 & darken color mask\n"
  395. " write 0 r8 r13 ; write texture pixel\n"
  396. " add r8 320 r8 ; go to next line pixel\n"
  397. " bge r8 r9 2 ; keep looping until reached floor\n"
  398. " jump RAYFX_drawVlineLoopWall\n"
  399. "load32 239 r9 ; r9 = last y position\n"
  400. "multu r9 320 r9 ; r9 = screen end VRAM offset\n"
  401. "add r9 r1 r9 ; r9 = last FB pos of line\n"
  402. "load32 0x9E9E9E r14 ; r14 = floor color\n"
  403. "; draw until end of screen\n"
  404. "RAYFX_drawVlineLoopFloor:\n"
  405. " write 0 r8 r14 ; write floor pixel\n"
  406. " add r8 320 r8 ; go to next line pixel\n"
  407. " bgt r8 r9 2 ; keep looping until reached end of screen\n"
  408. " jump RAYFX_drawVlineLoopFloor\n"
  409. "pop r15\n"
  410. "pop r14\n"
  411. "pop r13\n"
  412. "pop r12\n"
  413. "pop r11\n"
  414. "pop r10\n"
  415. "pop r9\n"
  416. "pop r8\n"
  417. "pop r7\n"
  418. "pop r6\n"
  419. "pop r5\n"
  420. "pop r4\n"
  421. "pop r3\n"
  422. "pop r2\n"
  423. "pop r1\n"
  424. "RAYFX_skipRenderLine:\n"
  425. "add r1 1 r1\n" // r1 = x++
  426. "load32 320 r15\n" // r15 = stop x loop (screenWidth)
  427. "bge r1 r15 2\n" // keep looping until reached final vline (x) of screen
  428. "jump RAYFX_screenXloop\n"
  429. );
  430. asm(
  431. // restore registers
  432. "pop r15\n"
  433. "pop r14\n"
  434. "pop r13\n"
  435. "pop r12\n"
  436. "pop r11\n"
  437. "pop r10\n"
  438. "pop r9\n"
  439. "pop r8\n"
  440. "pop r1\n"
  441. );
  442. }
  443. int main() {
  444. // clear screen from text
  445. GFX_clearWindowtileTable();
  446. GFX_clearWindowpaletteTable();
  447. GFX_clearBGtileTable();
  448. GFX_clearBGpaletteTable();
  449. // x and y start position
  450. RAY_posX = FP_intToFP(15);
  451. RAY_posY = FP_StringToFP("11.5");
  452. // initial direction vector
  453. RAY_dirX = LUTdirX[0];
  454. RAY_dirY = LUTdirY[0];
  455. // the 2d raycaster version of camera plane
  456. RAY_planeX = LUTplaneX[0];
  457. RAY_planeY = LUTplaneY[0];
  458. // rotation angle (loops at 360)
  459. word rotationAngle = 0;
  460. word rotationSpeed = 5; // degrees per frame
  461. fixed_point_t moveSpeed = FP_StringToFP("0.15");
  462. fixed_point_t movePadding = 0;//FP_StringToFP("0.3");
  463. word quitGame = 0;
  464. while (!quitGame) {
  465. // render screen
  466. RAYFX_renderScreen();
  467. // check which button is held
  468. if (BDOS_USBkeyHeld(BTN_LEFT)) {
  469. // both camera direction and camera plane must be rotated
  470. rotationAngle -= rotationSpeed;
  471. if (rotationAngle < 0) {
  472. rotationAngle += 360;
  473. }
  474. RAY_dirX = LUTdirX[rotationAngle];
  475. RAY_dirY = LUTdirY[rotationAngle];
  476. RAY_planeX = LUTplaneX[rotationAngle];
  477. RAY_planeY = LUTplaneY[rotationAngle];
  478. } else if (BDOS_USBkeyHeld(BTN_RIGHT)) {
  479. // both camera direction and camera plane must be rotated
  480. rotationAngle += rotationSpeed;
  481. if (rotationAngle >= 360) {
  482. rotationAngle -= 360;
  483. }
  484. RAY_dirX = LUTdirX[rotationAngle];
  485. RAY_dirY = LUTdirY[rotationAngle];
  486. RAY_planeX = LUTplaneX[rotationAngle];
  487. RAY_planeY = LUTplaneY[rotationAngle];
  488. }
  489. if (BDOS_USBkeyHeld(BTN_UP)) {
  490. word worldMapX = FP_FPtoInt(RAY_posX + FP_Mult(RAY_dirX, moveSpeed + movePadding));
  491. word worldMapY = FP_FPtoInt(RAY_posY);
  492. if (worldMap[worldMapX][worldMapY] == 0) {
  493. RAY_posX += FP_Mult(RAY_dirX, moveSpeed);
  494. }
  495. worldMapX = FP_FPtoInt(RAY_posX);
  496. worldMapY = FP_FPtoInt(RAY_posY + FP_Mult(RAY_dirY, moveSpeed + movePadding));
  497. if (worldMap[worldMapX][worldMapY] == 0) {
  498. RAY_posY += FP_Mult(RAY_dirY, moveSpeed);
  499. }
  500. } else if (BDOS_USBkeyHeld(BTN_DOWN)) {
  501. word worldMapX = FP_FPtoInt(RAY_posX - FP_Mult(RAY_dirX, moveSpeed + movePadding));
  502. word worldMapY = FP_FPtoInt(RAY_posY);
  503. if (worldMap[worldMapX][worldMapY] == 0) {
  504. RAY_posX -= FP_Mult(RAY_dirX, moveSpeed);
  505. }
  506. worldMapX = FP_FPtoInt(RAY_posX);
  507. worldMapY = FP_FPtoInt(RAY_posY - FP_Mult(RAY_dirY, moveSpeed + movePadding));
  508. if (worldMap[worldMapX][worldMapY] == 0) {
  509. RAY_posY -= FP_Mult(RAY_dirY, moveSpeed);
  510. }
  511. }
  512. if (HID_FifoAvailable()) {
  513. word c = HID_FifoRead();
  514. if (c == 27) // escape
  515. {
  516. GFX_clearPXframebuffer();
  517. quitGame = 1;
  518. }
  519. }
  520. }
  521. return 'q';
  522. }
  523. void interrupt() {
  524. // handle all interrupts
  525. word i = getIntID();
  526. switch (i) {
  527. case INTID_TIMER1:
  528. timer1Value = 1; // notify ending of timer1
  529. break;
  530. case INTID_TIMER2:
  531. break;
  532. case INTID_UART0:
  533. break;
  534. case INTID_GPU:
  535. break;
  536. case INTID_TIMER3:
  537. break;
  538. case INTID_PS2:
  539. break;
  540. case INTID_UART1:
  541. break;
  542. case INTID_UART2:
  543. break;
  544. }
  545. }