Procházet zdrojové kódy

All rendering of textured raycaster now done in assembly for significant speed improvement.

bart před 1 rokem
rodič
revize
33d828b6b9
3 změnil soubory, kde provedl 448 přidání a 220 odebrání
  1. 40 0
      BCC/userBDOS/DATA/RAYDAT.C
  2. 397 220
      BCC/userBDOS/RAYCAST.C
  3. 11 0
      Graphics/Raycast/generateCameraX.py

+ 40 - 0
BCC/userBDOS/DATA/RAYDAT.C

@@ -3,6 +3,46 @@
  * E.g. lookup tables and textures
  */
 
+// x-coordinate in camera space
+fixed_point_t LUTcameraX[320] = {
+    -65536, -65125, -64714, -64303, -63892, -63482, -63071, -62660, -62249,
+    -61838, -61427, -61016, -60605, -60195, -59784, -59373, -58962, -58551,
+    -58140, -57729, -57318, -56907, -56497, -56086, -55675, -55264, -54853,
+    -54442, -54031, -53620, -53209, -52799, -52388, -51977, -51566, -51155,
+    -50744, -50333, -49922, -49512, -49101, -48690, -48279, -47868, -47457,
+    -47046, -46635, -46224, -45814, -45403, -44992, -44581, -44170, -43759,
+    -43348, -42937, -42526, -42116, -41705, -41294, -40883, -40472, -40061,
+    -39650, -39239, -38829, -38418, -38007, -37596, -37185, -36774, -36363,
+    -35952, -35541, -35131, -34720, -34309, -33898, -33487, -33076, -32665,
+    -32254, -31844, -31433, -31022, -30611, -30200, -29789, -29378, -28967,
+    -28556, -28146, -27735, -27324, -26913, -26502, -26091, -25680, -25269,
+    -24858, -24448, -24037, -23626, -23215, -22804, -22393, -21982, -21571,
+    -21161, -20750, -20339, -19928, -19517, -19106, -18695, -18284, -17873,
+    -17463, -17052, -16641, -16230, -15819, -15408, -14997, -14586, -14175,
+    -13765, -13354, -12943, -12532, -12121, -11710, -11299, -10888, -10478,
+    -10067, -9656,  -9245,  -8834,  -8423,  -8012,  -7601,  -7190,  -6780,
+    -6369,  -5958,  -5547,  -5136,  -4725,  -4314,  -3903,  -3493,  -3082,
+    -2671,  -2260,  -1849,  -1438,  -1027,  -616,   -205,   205,    616,
+    1027,   1438,   1849,   2260,   2671,   3082,   3493,   3903,   4314,
+    4725,   5136,   5547,   5958,   6369,   6780,   7190,   7601,   8012,
+    8423,   8834,   9245,   9656,   10067,  10478,  10888,  11299,  11710,
+    12121,  12532,  12943,  13354,  13765,  14175,  14586,  14997,  15408,
+    15819,  16230,  16641,  17052,  17463,  17873,  18284,  18695,  19106,
+    19517,  19928,  20339,  20750,  21161,  21571,  21982,  22393,  22804,
+    23215,  23626,  24037,  24448,  24858,  25269,  25680,  26091,  26502,
+    26913,  27324,  27735,  28146,  28556,  28967,  29378,  29789,  30200,
+    30611,  31022,  31433,  31844,  32254,  32665,  33076,  33487,  33898,
+    34309,  34720,  35131,  35541,  35952,  36363,  36774,  37185,  37596,
+    38007,  38418,  38829,  39239,  39650,  40061,  40472,  40883,  41294,
+    41705,  42116,  42526,  42937,  43348,  43759,  44170,  44581,  44992,
+    45403,  45814,  46224,  46635,  47046,  47457,  47868,  48279,  48690,
+    49101,  49512,  49922,  50333,  50744,  51155,  51566,  51977,  52388,
+    52799,  53209,  53620,  54031,  54442,  54853,  55264,  55675,  56086,
+    56497,  56907,  57318,  57729,  58140,  58551,  58962,  59373,  59784,
+    60195,  60605,  61016,  61427,  61838,  62249,  62660,  63071,  63482,
+    63892,  64303,  64714,  65125,  65536
+};
+
 word LUTdirX[360] = {
     -65526, -65496, -65446, -65376, -65287, -65177, -65048, -64898, -64729,
     -64540, -64332, -64104, -63856, -63589, -63303, -62997, -62672, -62328,

+ 397 - 220
BCC/userBDOS/RAYCAST.C

@@ -23,8 +23,6 @@
 #define screenHeight  240
 #define texWidth      64
 #define texHeight     64
-
-// Map
 #define mapWidth  24
 #define mapHeight 24
 
@@ -85,34 +83,37 @@ word worldMap[mapWidth][mapHeight] = {
     {4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 0, 6, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2},
     {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3}};
 
+
 // Global variables, so render function can access it
 word drawStart = 0;
 word drawEnd = 0;
 word texNum = 0;
 word side = 0; // was a NorthSouth or a EastWest wall hit?
 
-// Render vertical line in pixel plane with textures
-// INPUT:
-//   r1        first pixel addr   VRAM addr of first pixel in line (top pixel)
-//   r2 (a2r)  drawStart          Starting pixel of wall
-//   r3 (a2r)  drawEnd            Ending pixel of wall
-//   r4        texPos             Starting texture coordinate
-//   r5        step               How much to increase the texture coordinate per screen pixel
-//   r6        texX               X coordinate on the texture
-//   r7        x                  X position of line to render
-//   r8        current FB pos     Current framebuffer position in VRAM (top to bottom)
-//   r9        end loop FB pos    Last framebuffer position in VRAM of current loop
-//   r10       texY               Y coordinate on the texture
-//   r11       gp                 Used as temp reg in calculations
-//   r12       texture[texNum]    Texture array of texture to draw
-//   r13       color              Pixel color
-//   r14       ceil or floor col  Ceiling or floor color
-//   r15       side               North South or East West wall side
-void RAYFX_drawTextureVertLine(fixed_point_t texPos, fixed_point_t step, word texX, word x)
+// Globalr vars
+// x and y start position
+fixed_point_t RAY_posX;
+fixed_point_t RAY_posY;
+
+// initial direction vector
+fixed_point_t RAY_dirX;
+fixed_point_t RAY_dirY;
+
+// the 2d raycaster version of camera plane
+fixed_point_t RAY_planeX;
+fixed_point_t RAY_planeY;
+
+// Local vars to store
+
+
+// Render entire screen
+// Registers (global):
+//   r1   x         current vertical line (x of screen)
+void RAYFX_renderScreen()
 {
   // reg 4 5 6 7 (args) and 2 3 (retval) are safe
   asm(
-  "; backup registers\n"
+  // backdup registers
   "push r1\n"
   "push r8\n"
   "push r9\n"
@@ -124,93 +125,411 @@ void RAYFX_drawTextureVertLine(fixed_point_t texPos, fixed_point_t step, word te
   "push r15\n"
   );
 
-  // setup registers
   asm(
-  "addr2reg drawStart r2  ; r2 = drawStart addr\n"
-  "read 0 r2 r2           ; r2 = drawStart value\n"
+  
+  // r1: current vertical line (x of screen)
+  "load32 0 r1\n"
+
+  // for each vertical line (x)
+  "RAYFX_screenXloop:\n"
+
+    // cameraX
+    "addr2reg LUTcameraX r15\n" // r15 = LUTcameraX
+    "add r15 r1 r15\n"          // r15 = LUTcameraX[x] addr
+    "read 0 r15 r15\n"          // r15 = LUTcameraX[x] value
+
+    //   r2   rayDirx   [FP] x dir of ray
+    //   r3   rayDiry   [FP] y dir of ray
+
+    // r2: rayDirX
+    "addr2reg RAY_dirX r14\n"   // r14 = RAY_dirX addr
+    "read 0 r14 r14\n"          // r14 = RAY_dirX value
+    "addr2reg RAY_planeX r13\n" // r13 = RAY_planeX addr
+    "read 0 r13 r13\n"          // r13 = RAY_planeX value
+    "multfp r13 r15 r2\n"       // r2 = FP_Mult(RAY_planeX, cameraX)
+    "add r2 r14 r2\n"           // r2 += RAY_dirX
+    
+    // r3: rayDirY
+    "addr2reg RAY_dirY r14\n"   // r14 = RAY_dirY addr
+    "read 0 r14 r14\n"          // r14 = RAY_dirY value
+    "addr2reg RAY_planeY r13\n" // r13 = RAY_planeY addr
+    "read 0 r13 r13\n"          // r13 = RAY_planeY value
+    "multfp r13 r15 r3\n"       // r3 = FP_Mult(RAY_planeY, cameraX)
+    "add r3 r14 r3\n"           // r3 += RAY_dirY
+
+    // r4: deltaDistX
+    "load32 1 r15\n"            // r15 = 1
+    "shiftl r15 16 r15\n"       // r15 = FP(1)
+    "load32 0xC02742 r14\n"     // r14 = addr fpdiv_writea
+    "write 0 r14 r15\n"         // write a (fp1) to divider
+    "write 1 r14 r2\n"          // write b (rayDirX) to divider and perform division
+    "read 1 r14 r4\n"           // read result to r4
+    "shiftrs r4 31 r13\n"       // r13 = y = x >>(signed) 31 (start of abs)
+    "xor r4 r13 r4\n"           // r4 = (x ^ y)
+    "sub r4 r13 r4\n"           // r4 -= y (result of abs)
+
+    // r5: deltaDistY (uses r14 and r15 from above)
+    "write 0 r14 r15\n"         // write a (fp1) to divider
+    "write 1 r14 r3\n"          // write b (rayDirY) to divider and perform division
+    "read 1 r14 r5\n"           // read result to r5
+    "shiftrs r5 31 r13\n"       // r13 = y = x >>(signed) 31 (start of abs)
+    "xor r5 r13 r5\n"           // r5 = (x ^ y)
+    "sub r5 r13 r5\n"           // r5 -= y (result of abs)
+
+    // if (rayDirX < 0), else
+    // r6: stepX
+    // r7: stepY
+    // r8: sideDistX
+    // r9: sideDistY
+    // r10: mapX
+    // r11: mapY
+    "blts r2 r0 2\n"            // if (rayDirX < 0) skip next line
+    "jump RAYFX_rayDirXge0\n"   // goto RAYFX_rayDirXge0
+
+      "load32 -1 r6\n"          // r6 = stepX = -1
+      "addr2reg RAY_posX r15\n" // r15 = RAY_posX addr
+      "read 0 r15 r15\n"        // r15 = RAY_posX value
+      "shiftrs r15 16 r10\n"    // mapX = int(RAY_posX)
+      "load32 0xFFFF r14\n"     // r14 = decimal part mask
+      "and r15 r14 r15\n"       // r15 = RAY_posX decimal part
+      "multfp r15 r4 r8\n"      // sideDistX = RAY_posX decimal part * deltaDistX
+      "jump RAYFX_rayDirXltEnd\n" // skip the else part
+
+    "RAYFX_rayDirXge0:\n"
+      "load32 1 r6\n"           // stepX = 1
+      "addr2reg RAY_posX r15\n" // r15 = RAY_posX addr
+      "read 0 r15 r15\n"        // r15 = RAY_posX value
+      "shiftrs r15 16 r10\n"    // r10 (mapX) = r15 >> 16 (to int)
+      "add r10 1 r14\n"         // r14 = int(RAY_posX) + 1
+      "shiftl r14 16 r14\n"     // r14 <<=16 (to FP)
+      "sub r14 r15 r15\n"       // r15 = r14 - RAY_posX
+      "multfp r15 r4 r8\n"      // sideDistX = RAY_posX-ish * deltaDistX
+
+    "RAYFX_rayDirXltEnd:\n"
+
+    // if (rayDirY < 0), else
+    "blts r3 r0 2\n"            // if (rayDirY < 0) skip next line
+    "jump RAYFX_rayDirYge0\n"   // goto RAYFX_rayDirYge0
+
+      "load32 -1 r7\n"          // r7 = stepY = -1
+      "addr2reg RAY_posY r15\n" // r15 = RAY_posY addr
+      "read 0 r15 r15\n"        // r15 = RAY_posY value
+      "shiftrs r15 16 r11\n"    // mapY = int(RAY_posY)
+      "load32 0xFFFF r14\n"     // r14 = decimal part mask
+      "and r15 r14 r15\n"       // r15 = RAY_posY decimal part
+      "multfp r15 r5 r9\n"      // sideDistY = RAY_posY decimal part * deltaDistY
+      "jump RAYFX_rayDirYltEnd\n" // skip the else part
+
+    "RAYFX_rayDirYge0:\n"
+      "load32 1 r7\n"           // stepY = 1
+      "addr2reg RAY_posY r15\n" // r15 = RAY_posY addr
+      "read 0 r15 r15\n"        // r15 = RAY_posY value
+      "shiftrs r15 16 r11\n"    // r11 (mapY) = r15 >> 16 (to int)
+      "add r11 1 r14\n"         // r14 = int(RAY_posY) + 1
+      "shiftl r14 16 r14\n"     // r14 <<=16 (to FP)
+      "sub r14 r15 r15\n"       // r15 = r14 - RAY_posX
+      "multfp r15 r5 r9\n"      // sideDistY = RAY_posX-ish * deltaDistY
+
+    "RAYFX_rayDirYltEnd:\n"
+
+    // DDA (uses tmp r15)
+    "load32 0 r15\n"            // hit = 0
+    "RAYFX_DDAwhileNoHit:\n"    // while (hit == 0)
+      "beq r15 r0 2\n"          // while check
+      "jump RAYFX_DDAwhileNoHitDone\n"
+
+      // if (sideDistX < sideDistY), else
+      "blts r8 r9 2\n"              // if (sideDistX < sideDistY) skip next line
+      "jump RAYFX_sideDistXltY\n"   // goto RAYFX_sideDistXltY
+
+        "add r8 r4 r8\n"            // sideDistX += deltaDistX;
+        "add r10 r6 r10\n"          // mapX += stepX;
+        "addr2reg side r14\n"       // side;
+        "write 0 r14 r0\n"          // side = 0;
+        "jump RAYFX_sideDistXltYend\n" // skip the else part
+
+      "RAYFX_sideDistXltY:\n"
+        "add r9 r5 r9\n"            // sideDistY += deltaDistY;
+        "add r11 r7 r11\n"          // mapY += stepY;
+        "addr2reg side r14\n"       // side;
+        "load32 1 r13\n"            // 1
+        "write 0 r14 r13\n"         // side = 1;
+
+      "RAYFX_sideDistXltYend:\n"
+
+      "addr2reg worldMap r14\n"     // r14 = worldMap addr;
+      "multu r10 24 r13\n"          // r13 = mapX offset using mapHeight
+      "add r13 r11 r13\n"           // r13 += mapY offset
+      "add r13 r14 r14\n"           // r14 = worldMap[mapX][mapY] addr
+      "read 0 r14 r14\n"            // r14 = worldMap[mapX][mapY] value
+      "bles r14 r0 2\n"             // skip next instruction if worldMap[mapX][mapY] <= 0
+        "load 1 r15\n"            // hit = 1
+
+      "jump RAYFX_DDAwhileNoHit\n" // return to while loop start
+
+    "RAYFX_DDAwhileNoHitDone:\n"
+
+    // From this point, r10 r11 mapx mapy (and r15) are free
+
+    // texNum = worldMap[mapX][mapY] - 1;
+    // assumes worldMap[mapX][mapY] value is still in r14
+    "addr2reg texNum r13\n"     // r13 = texNum addr;
+    "sub r14 1 r14\n"           // r14 = worldMap[mapX][mapY] - 1
+    "write 0 r13 r14\n"         // write texNum;
+
+    // r10: perpWallDist (FP)
+    "addr2reg side r15\n"       // side addr
+    "read 0 r15 r15\n"          // side value
+
+    // if (side == 0), else
+    "bne r15 r0 3\n"            // if (side != 0) skip next two lines
+    "sub r8 r4 r10\n"           // perpWallDist = (sideDistX - deltaDistX); (match)
+    "jumpo 2\n"                 // skip else part
+    "sub r9 r5 r10\n"           // perpWallDist = (sideDistY - deltaDistY); (else)
+
+    // From this point sideDistX&Y and deltaDistX&Y are free
+    // this frees up regs 4 5 8 and 9
+    // leaving to use: 4, 5, 8, 9, 11, 12, 13, 14, 15
+
+    // r4: lineHeight
+    "load32 240 r15\n"          // r15 = screenHeight
+    "shiftl r15 16 r15\n"       // r15 = FP(screenHeight)
+    "load32 0xC02742 r14\n"     // r14 = addr fpdiv_writea
+    "write 0 r14 r15\n"         // write a (FP(screenHeight) to divider
+    "write 1 r14 r10\n"         // write b (perpWallDist) to divider and perform division
+    "read 1 r14 r4\n"           // read result to r4
+    "shiftrs r4 16 r4\n"        // r4 = lineHeight = int(r4)
+
+    "shiftrs r4 1 r15\n"        // r15 = lineHeight >> 1
+    "load32 -1 r14\n"           // r14 = -1
+    "mults r15 r14 r15\n"       // r15 = -r15
+    "load32 120 r14\n"          // r14 = screenHeight >> 1
+    "add r14 r15 r15\n"         // r15 = drawStart value (r14+r15)
+    "bges r15 r0 2\n"           // skip next line if drawStart >= 0
+      "load 0 r15\n"            // set drawStart to 0 if < 0
+    "addr2reg drawStart r14\n"  // r14 = drawStart addr
+    "write 0 r14 r15\n"         // write drawStart value
+
+    // skip render if start > 238
+    "load32 238 r14\n"
+    "blts r15 r14 2 \n"
+      "jump RAYFX_skipRenderLine\n"
+
+    "shiftrs r4 1 r15\n"        // r15 = lineHeight >> 1
+    "load32 120 r14\n"          // r14 = screenHeight >> 1
+    "add r14 r15 r15\n"         // r15 = drawEnd value (r14+r15)
+    "load32 240 r14\n"          // r14 = screenHeight
+    "blts r15 r14 2\n"          // skip next line if drawEnd < screenHeight
+      "load 239 r15\n"          // set drawEnd to screenHeight - 1
+    "addr2reg drawEnd r14\n"    // r14 = drawEnd addr
+    "write 0 r14 r15\n"         // write drawEnd value
+
+
+    // texture calculations
+    // r8: side
+    // r5: wallX
+    "addr2reg side r8\n"      // r8 = side addr
+    "read 0 r8 r8\n"          // r8 = side value
+    "bne r8 r0 7\n"           // if side != 0, goto else part (addr2reg is two instructions!)
+      "addr2reg RAY_posY r15\n" // r15 = RAY_posY addr
+      "read 0 r15 r15\n"        // r15 = RAY_posY value
+      "multfp r10 r3 r14\n"     // r14 = perpWallDist * rayDirY
+      "add r14 r15 r5\n"        // r5 = wallX = r14 + RAY_posY
+      "jumpo 5\n"               // skip else
+
+    // else
+      "addr2reg RAY_posX r15\n" // r15 = RAY_posX addr
+      "read 0 r15 r15\n"        // r15 = RAY_posX value
+      "multfp r10 r2 r14\n"     // r14 = perpWallDist, rayDirX
+      "add r14 r15 r5\n"        // r5 = wallX = r14 + RAY_posX
+
+    "load32 0xFFFF r15\n"       // r15 = floormask
+    "and r5 r15 r5\n"           // wallX-=floor(wallX)
+
+    // r6: texX
+    "load32 64 r15\n"           // r15 = texWidth
+    "shiftl r15 16 r14\n"       // r14 = FP(texWidth)
+    "multfp r14 r5 r6\n"        // r6 = FP_Mult(wallX, FP_intToFP(texWidth))
+    "shiftrs r6 16 r6\n"        // r6 = int(r6)
+
+    "bne r8 r0 4\n"             // skip if side != 0
+    "bles r2 r0 3\n"            // skip if rayDirX <= 0
+
+      "sub r15 r6 r6\n"           // texX = texWidth - texX
+      "sub r6 1 r6\n"             // texX -= 1
+
+    "beq r8 r0 4\n"             // skip if side == 0
+    "bges r3 r0 3\n"            // skip if rayDirY >= 0
+
+      "sub r15 r6 r6\n"           // texX = texWidth - texX
+      "sub r6 1 r6\n"             // texX -= 1
+
+    // r2 and r3 are free now (no rayDirX&Y needed)
+    // r5: step
+    "load32 64 r15\n"           // r15 = texHeight
+    "shiftl r15 16 r15\n"       // r15 = FP(texHeight)
+    "shiftl r4 16 r14\n"        // r14 = FP(lineHeight)
+    "load32 0xC02742 r13\n"     // r13 = addr fpdiv_writea
+    "write 0 r13 r15\n"         // write a (FP(screenHeight) to divider
+    "write 1 r13 r14\n"         // write b (FP(lineHeight)) to divider and perform division
+    "read 1 r13 r5\n"           // read result to r5
+
+    // r4: texPos
+    "addr2reg drawStart r15\n"  // r15 = drawStart addr
+    "read 0 r15 r15\n"          // r15 = drawStart value
+    "sub r15 120 r15\n"         // r15 -= (screenHeight >> 1)
+    "shiftrs r4 1 r14\n"        // r14 = lineHeight >> 1
+    "add r15 r14 r15\n"         // r15 += lineHeight >> 1
+    "shiftl r15 16 r15\n"       // r15 = FP(r15)
+    "multfp r15 r5 r4\n"        // r4 = r15 * step
+
+    "or r1 r0 r7\n"             // move x to r7
+
+
+    // Render vertical line in pixel plane with textures
+    // Registers:
+    //   r1        first pixel addr   VRAM addr of first pixel in line (top pixel)
+    //   r2 (a2r)  drawStart          Starting pixel of wall
+    //   r3 (a2r)  drawEnd            Ending pixel of wall
+    //   r4        texPos             Starting texture coordinate
+    //   r5        step               How much to increase the texture coordinate per screen pixel
+    //   r6        texX               X coordinate on the texture
+    //   r7        x                  X position of line to render
+    //   r8        current FB pos     Current framebuffer position in VRAM (top to bottom)
+    //   r9        end loop FB pos    Last framebuffer position in VRAM of current loop
+    //   r10       texY               Y coordinate on the texture
+    //   r11       gp                 Used as temp reg in calculations
+    //   r12       texture[texNum]    Texture array of texture to draw
+    //   r13       color              Pixel color
+    //   r14       ceil or floor col  Ceiling or floor color
+    //   r15       side               North South or East West wall side
+
+    "push r1\n"
+    "push r2\n"
+    "push r3\n"
+    "push r4\n"
+    "push r5\n"
+    "push r6\n"
+    "push r7\n"
+    "push r8\n"
+    "push r9\n"
+    "push r10\n"
+    "push r11\n"
+    "push r12\n"
+    "push r13\n"
+    "push r14\n"
+    "push r15\n"
+
+    "addr2reg drawStart r2  ; r2 = drawStart addr\n"
+    "read 0 r2 r2           ; r2 = drawStart value\n"
+
+    "addr2reg drawEnd r3    ; r3 = drawEnd addr\n"
+    "read 0 r3 r3           ; r3 = drawEnd value\n"
+
+    "load32 0xD00000 r1     ; r1 = framebuffer addr\n"
+    "add r1 r7 r1           ; r1 = first pixel in line (fb+x)\n"
+
+    "or r0 r1 r8            ; r8 = current pixel\n"
+
+    "multu r2 320 r9        ; r9 = drawStart VRAM offset\n"
+    "add r9 r1 r9           ; r9 = last FB pos of before wall\n"
 
-  "addr2reg drawEnd r3    ; r3 = drawEnd addr\n"
-  "read 0 r3 r3           ; r3 = drawEnd value\n"
+    "addr2reg texNum r12    ; r12 = texNum addr\n"
+    "read 0 r12 r12         ; r12 = texNum value\n"
+    "multu r12 4096 r12     ; r12 = texture offset (64*64 per texture)\n"
 
-  "load32 0xD00000 r1     ; r1 = framebuffer addr\n"
-  "add r1 r7 r1           ; r1 = first pixel in line (fb+x)\n"
+    "addr2reg texture r11   ; r11 = texture array\n"
+    "add r12 r11 r12        ; r12 = texture[texNum]\n"
 
-  "or r0 r1 r8            ; r8 = current pixel\n"
+    "load32 0x0082F0 r14    ; r14 = ceiling color\n"
 
-  "multu r2 320 r9        ; r9 = drawStart VRAM offset\n"
-  "add r9 r1 r9           ; r9 = last FB pos of before wall\n"
+    "addr2reg side r15      ; r15 = side addr\n"
+    "read 0 r15 r15         ; r15 = side value\n"
 
-  "addr2reg texNum r12    ; r12 = texNum addr\n"
-  "read 0 r12 r12         ; r12 = texNum value\n"
-  "multu r12 4096 r12     ; r12 = texture offset (64*64 per texture)\n"
+    // draw until start
+    "RAYFX_drawVlineLoopCeiling:\n"
+    "  write 0 r8 r14     ; write ceiling pixel\n"
+    "  add r8 320 r8     ; go to next line pixel\n"
 
-  "addr2reg texture r11   ; r11 = texture array\n"
-  "add r12 r11 r12        ; r12 = texture[texNum]\n"
+    "  bge r8 r9 2       ; keep looping until reached wall\n"
+    "  jump RAYFX_drawVlineLoopCeiling\n"
 
-  "load32 0x0082F0 r14    ; r14 = ceiling color\n"
 
-  "addr2reg side r15      ; r15 = side addr\n"
-  "read 0 r15 r15         ; r15 = side value\n"
 
-  "; draw until start\n"
-  "RAYFX_drawVlineLoopCeiling:\n"
-  "  write 0 r8 r14     ; write ceiling pixel\n"
-  "  add r8 320 r8     ; go to next line pixel\n"
 
-  "  bge r8 r9 2       ; keep looping until reached wall\n"
-  "  jump RAYFX_drawVlineLoopCeiling\n"
+    "multu r3 320 r9        ; r9 = drawEnd VRAM offset\n"
+    "add r9 r1 r9           ; r9 = last FB pos of wall\n"
 
+    "load32 8355711 r2      ; r2 = mask for darken color\n"
 
+    // draw until floor
+    "RAYFX_drawVlineLoopWall:\n"
+    "  shiftrs r4 16 r11  ; r11 = texY = FPtoInt(texPos)\n"
+    "  and r11 63 r11     ; r11 = r11 & (texHeight-1)\n"
+    "  add r4 r5 r4       ; texPos += step\n"
 
+    "  multu r11 64 r11   ; r11 = texHeight * texY \n"
+    "  add r11 r6 r11     ; r11 += texX\n"
 
-  "multu r3 320 r9        ; r9 = drawEnd VRAM offset\n"
-  "add r9 r1 r9           ; r9 = last FB pos of wall\n"
+    "  add r11 r12 r13    ; r13 = addr of color in texture array\n"
+    "  read 0 r13 r13     ; r13 = pixel color\n"
 
-  "load32 8355711 r2      ; r2 = mask for darken color\n"
+    "  beq r15 r0 3       ; skip next two lines if not side of wall is hit\n"
+    "    shiftrs r13 1 r13\n" // r13 >> 1
+    "    and r13 r2 r13     ; r13 & darken color mask\n"
 
-  "; draw until floor\n"
-  "RAYFX_drawVlineLoopWall:\n"
-  "  shiftrs r4 16 r11  ; r11 = texY = FPtoInt(texPos)\n"
-  "  and r11 63 r11     ; r11 = r11 & (texHeight-1)\n"
-  "  add r4 r5 r4       ; texPos += step\n"
 
-  "  multu r11 64 r11   ; r11 = texHeight * texY \n"
-  "  add r11 r6 r11     ; r11 += texX\n"
+    "  write 0 r8 r13     ; write texture pixel\n"
+    "  add r8 320 r8      ; go to next line pixel\n"
 
-  "  add r11 r12 r13    ; r13 = addr of color in texture array\n"
-  "  read 0 r13 r13     ; r13 = pixel color\n"
+    "  bge r8 r9 2        ; keep looping until reached floor\n"
+    "  jump RAYFX_drawVlineLoopWall\n"
 
-  "  beq r15 r0 3       ; skip next two lines if not side of wall is hit\n"
-  "    shiftrs r13 1 r13  ; r13 >> 1\n"
-  "    and r13 r2 r13     ; r13 & darken color mask\n"
 
 
-  "  write 0 r8 r13     ; write texture pixel\n"
-  "  add r8 320 r8      ; go to next line pixel\n"
 
-  "  bge r8 r9 2        ; keep looping until reached floor\n"
-  "  jump RAYFX_drawVlineLoopWall\n"
+    "load32 239 r9          ; r9 = last y position\n"
+    "multu r9 320 r9        ; r9 = screen end VRAM offset\n"
+    "add r9 r1 r9           ; r9 = last FB pos of line\n"
 
+    "load32 0x9E9E9E r14    ; r14 = floor color\n"
 
+    "; draw until end of screen\n"
+    "RAYFX_drawVlineLoopFloor:\n"
+    "  write 0 r8 r14    ; write floor pixel\n"
+    "  add r8 320 r8     ; go to next line pixel\n"
 
+    "  bgt r8 r9 2       ; keep looping until reached end of screen\n"
+    "  jump RAYFX_drawVlineLoopFloor\n"
 
-  "load 239 r9            ; r9 = last y position\n"
-  "multu r9 320 r9        ; r9 = screen end VRAM offset\n"
-  "add r9 r1 r9           ; r9 = last FB pos of line\n"
 
-  "load32 0x9E9E9E r14    ; r14 = floor color\n"
+    "pop r15\n"
+    "pop r14\n"
+    "pop r13\n"
+    "pop r12\n"
+    "pop r11\n"
+    "pop r10\n"
+    "pop r9\n"
+    "pop r8\n"
+    "pop r7\n"
+    "pop r6\n"
+    "pop r5\n"
+    "pop r4\n"
+    "pop r3\n"
+    "pop r2\n"
+    "pop r1\n"
 
-  "; draw until end of screen\n"
-  "RAYFX_drawVlineLoopFloor:\n"
-  "  write 0 r8 r14    ; write floor pixel\n"
-  "  add r8 320 r8     ; go to next line pixel\n"
+    "RAYFX_skipRenderLine:\n"
+    
 
-  "  bgt r8 r9 2       ; keep looping until reached end of screen\n"
-  "  jump RAYFX_drawVlineLoopFloor\n"
+    "add r1 1 r1\n"             // r1 = x++
+    "load32 320 r15\n"          // r15 = stop x loop (screenWidth)
+    "bge r1 r15 2\n"            // keep looping until reached final vline (x) of screen
+    "jump RAYFX_screenXloop\n"
   );
 
   asm(
-  "; restore registers\n"
+  // restore registers
   "pop r15\n"
   "pop r14\n"
   "pop r13\n"
@@ -223,19 +542,6 @@ void RAYFX_drawTextureVertLine(fixed_point_t texPos, fixed_point_t step, word te
   );
 }
 
-// x and y start position
-fixed_point_t RAY_posX;
-fixed_point_t RAY_posY;
-
-// initial direction vector
-fixed_point_t RAY_dirX;
-fixed_point_t RAY_dirY;
-
-// the 2d raycaster version of camera plane
-fixed_point_t RAY_planeX;
-fixed_point_t RAY_planeY;
-
-word RAY_linex; // current vertical line being rendered (x of screen)
 
 int main() {
   // clear screen from text
@@ -261,143 +567,14 @@ int main() {
   word rotationSpeed = 5;  // degrees per frame
 
   fixed_point_t moveSpeed = FP_StringToFP("0.15");
-  fixed_point_t movePadding = FP_StringToFP("0.3");
+  fixed_point_t movePadding = 0;//FP_StringToFP("0.3");
 
   word quitGame = 0;
 
   while (!quitGame) {
     
-    for (RAY_linex = 0; RAY_linex < screenWidth; RAY_linex++) 
-    {
-      // calculate ray position and direction
-      fixed_point_t cameraX =
-          FP_Div(FP_intToFP(RAY_linex << 1), FP_intToFP(screenWidth)) -
-          FP_intToFP(1);  // x-coordinate in camera space
-
-      fixed_point_t rayDirX = RAY_dirX + FP_Mult(RAY_planeX, cameraX);
-      fixed_point_t rayDirY = RAY_dirY + FP_Mult(RAY_planeY, cameraX);
-
-      // which box of the map we are in
-      word mapX = FP_FPtoInt(RAY_posX);
-      word mapY = FP_FPtoInt(RAY_posY);
-
-      // length of ray from current position to next x or y-side
-      fixed_point_t sideDistX;
-      fixed_point_t sideDistY;
-
-      // length of ray from one x or y-side to next x or y-side
-      // these are derived as:
-      // deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
-      // deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
-      // which can be simplified to abs(|rayDir| / rayDirX) and abs(|rayDir| /
-      // rayDirY) where |rayDir| is the length of the vector (rayDirX, rayDirY).
-      // Its length, unlike (RAY_dirX, RAY_dirY) is not 1, however this does not matter,
-      // only the ratio between deltaDistX and deltaDistY matters, due to the
-      // way the DDA stepping further below works. So the values can be computed
-      // as below.
-      //  Division through zero is prevented by setting the result to a very
-      //  high value
-      fixed_point_t deltaDistX =
-          (rayDirX == 0) ? 1 << 30 : MATH_abs(FP_Div(FP_intToFP(1), rayDirX));
-      fixed_point_t deltaDistY =
-          (rayDirY == 0) ? 1 << 30 : MATH_abs(FP_Div(FP_intToFP(1), rayDirY));
-
-      fixed_point_t perpWallDist;
-
-      // what direction to step in x or y-direction (either +1 or -1)
-      word stepX;
-      word stepY;
-
-      word hit = 0;  // was there a wall hit?
-
-      // calculate step and initial sideDist
-      if (rayDirX < 0) {
-        stepX = -1;
-        sideDistX = FP_Mult((RAY_posX - FP_intToFP(mapX)), deltaDistX);
-      } else {
-        stepX = 1;
-        sideDistX = FP_Mult((FP_intToFP(mapX + 1) - RAY_posX), deltaDistX);
-      }
-      if (rayDirY < 0) {
-        stepY = -1;
-        sideDistY = FP_Mult((RAY_posY - FP_intToFP(mapY)), deltaDistY);
-      } else {
-        stepY = 1;
-        sideDistY = FP_Mult((FP_intToFP(mapY + 1) - RAY_posY), deltaDistY);
-      }
-
-      // perform DDA
-      while (hit == 0) {
-        // jump to next map square, either in x-direction, or in y-direction
-        if (sideDistX < sideDistY) {
-          sideDistX += deltaDistX;
-          mapX += stepX;
-          side = 0;
-        } else {
-          sideDistY += deltaDistY;
-          mapY += stepY;
-          side = 1;
-        }
-        // Check if ray has hit a wall
-        if (worldMap[mapX][mapY] > 0) hit = 1;
-      }
-
-      // Calculate distance projected on camera direction. This is the shortest
-      // distance from the point where the wall is hit to the camera plane.
-      // Euclidean to center camera point would give fisheye effect! This can be
-      // computed as (mapX - RAY_posX + (1 - stepX) / 2) / rayDirX for side == 0, or
-      // same formula with Y for size == 1, but can be simplified to the code
-      // below thanks to how sideDist and deltaDist are computed: because they
-      // were left scaled to |rayDir|. sideDist is the entire length of the ray
-      // above after the multiple steps, but we subtract deltaDist once because
-      // one step more into the wall was taken above.
-      if (side == 0)
-        perpWallDist = (sideDistX - deltaDistX);
-      else
-        perpWallDist = (sideDistY - deltaDistY);
-
-      // Calculate height of line to draw on screen
-      word lineHeight =
-          FP_FPtoInt(FP_Div(FP_intToFP(screenHeight), perpWallDist));
-
-      // calculate lowest and highest pixel to fill in current stripe
-      drawStart = -(lineHeight >> 1) + (screenHeight >> 1);
-      if (drawStart < 0) drawStart = 0;
-      drawEnd = (lineHeight >> 1) + (screenHeight >> 1);
-      if (drawEnd >= screenHeight) drawEnd = screenHeight - 1;
-
-      // texturing calculations
-      texNum = worldMap[mapX][mapY] -
-               1;  // 1 subtracted from it so that texture 0 can be used!
-
-      // calculate value of wallX
-      fixed_point_t wallX;  // where exactly the wall was hit
-      if (side == 0)
-        wallX = RAY_posY + FP_Mult(perpWallDist, rayDirY);
-      else
-        wallX = RAY_posX + FP_Mult(perpWallDist, rayDirX);
-      word floormask = 0xFFFF;
-      wallX &= floormask;  // wallX-=floor(wallX)
-
-      // x coordinate on the texture
-      word texX = FP_FPtoInt(FP_Mult(wallX, FP_intToFP(texWidth)));
-      if (side == 0 && rayDirX > 0) texX = texWidth - texX - 1;
-      if (side == 1 && rayDirY < 0) texX = texWidth - texX - 1;
-
-      // How much to increase the texture coordinate per screen pixel
-      fixed_point_t step =
-          FP_Div(FP_intToFP(texHeight), FP_intToFP(lineHeight));
-      // Starting texture coordinate
-      fixed_point_t texPos = FP_Mult(
-          FP_intToFP(drawStart - (screenHeight >> 1) + (lineHeight >> 1)),
-          step);
-
-      // TMP fix for first line not rendering correctly and prevent crash when
-      // start > screen end
-      if (RAY_linex > 0 && drawStart < screenHeight) {
-        RAYFX_drawTextureVertLine(texPos, step, texX, RAY_linex);
-      }
-    }
+    // render screen
+    RAYFX_renderScreen();
 
     // check which button is held
     if (BDOS_USBkeyHeld(BTN_LEFT)) {

+ 11 - 0
Graphics/Raycast/generateCameraX.py

@@ -0,0 +1,11 @@
+# Script to precalculate cameraX values
+
+screenWidth = 320
+
+def doubleToFP16(x):
+    return round(x * pow(2,16))
+
+print("fixed_point_t cameraX[" + str(screenWidth) + "] = {")
+for i in range(screenWidth):
+    print(str(doubleToFP16(2*i / (screenWidth-1) - 1)) + ", ", end='')
+print("\n};\n")