RatcheT2497

Wolf3D Shade Test

Jun 30th, 2016
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.15 KB | None | 0 0
  1. local buffer=term
  2. local loadedAPI=false
  3.  
  4. if redirect then
  5.   buffer=redirect.createRedirectBuffer()
  6.   print("redirect API found, using buffer")
  7. else
  8.   local pe=printError
  9.   rawset(_G,"printError",error)  
  10.   local ok, err=pcall(os.loadAPI,"redirect")
  11.   if not ok then
  12.     print("trying "..shell.dir().."/redirect")
  13.     ok,err=pcall(os.loadAPI,shell.dir().."/redirect")
  14.   end
  15.   if ok then    
  16.     print("Loaded redirect API, using buffer")
  17.     buffer=redirect.createRedirectBuffer()
  18.     loadedAPI=true
  19.   else
  20.     print("redirect API not found or could not be loaded, drawing directly; this may cause flickering.")
  21.   end
  22.   rawset(_G,"printError",pe)
  23.  
  24. end
  25.  
  26.  
  27. local mapW, mapH=16,32
  28. local map={
  29.   "1111111111111111",
  30.   "1   12         1",
  31.   "1 111111111111 1",
  32.   "1 1      1   1 1",
  33.   "1 1 1111 1 1 1 1",
  34.   "1 1   1  1 1   1",
  35.   "1 111 111111 111",
  36.   "1   1          1",
  37.   "111 11111111 1 1",
  38.   "1 1          1 1",
  39.   "1 111111111111 1",
  40.   "1   1 1    1   1",
  41.   "1 111 1 1111 111",
  42.   "1     1    1   1",
  43.   "1 11111111 111 1",
  44.   "1              1",
  45.   "1111114  4111111",
  46.   "1              1",
  47.   "1              1",
  48.   "1  3  3  3  3  1",
  49.   "1              1",
  50.   "1              1",
  51.   "1  2  5  5  2  1",
  52.   "1              1",
  53.   "1              1",
  54.   "1  2  5  5  2  1",
  55.   "1              1",
  56.   "1              1",
  57.   "1  3  2  2  3  1",
  58.   "1              1",
  59.   "1              1",
  60.   "1111111111111111",
  61. }  
  62.  
  63. local colorSchemes = {
  64.   {0,8}, --white+gray
  65.   {3,11}, --blue
  66.   {6,14}, --red
  67.   {5,13}, --green
  68.   {4,1}, --yellow/orange
  69. }
  70.  
  71. local function depthColor(col, depth)
  72.     if depth <= 4 and depth > 0 then
  73.         return col, " "
  74.     elseif depth <= 5 and depth > 4 then
  75.         if col == colors.white then return colors.lightGray, string.char(127)
  76.         elseif col == colors.orange then return colors.red, string.char(127)
  77.         elseif col == colors.magenta then return colors.purple, string.char(127)
  78.         elseif col == colors.lightBlue then return colors.blue, string.char(127)
  79.         elseif col == colors.yellow then return colors.orange, string.char(127)
  80.         elseif col == colors.lime then return colors.green, string.char(127)
  81.         elseif col == colors.pink then return colors.red, string.char(127)
  82.         elseif col == colors.gray then return colors.black, string.char(127)
  83.         elseif col == colors.lightGray then return colors.gray, string.char(127)
  84.         elseif col == colors.cyan then return colors.blue, string.char(127)
  85.         elseif col == colors.purple then return colors.gray, string.char(127)
  86.         elseif col == colors.blue then return colors.magenta, string.char(127)
  87.         elseif col == colors.brown then return colors.gray, string.char(127)
  88.         elseif col == colors.green then return colors.cyan, string.char(127)
  89.         elseif col == colors.red then return colors.brown, string.char(127)
  90.         elseif col == colors.black then return col, string.char(127) end
  91.     elseif depth > 5 then
  92.         if col == colors.white then return colors.gray, string.char(153)
  93.         elseif col == colors.orange then return colors.brown, string.char(153)
  94.         elseif col == colors.magenta then return colors.lightGray, string.char(153)
  95.         elseif col == colors.lightBlue then return colors.magenta, string.char(153)
  96.         elseif col == colors.yellow then return colors.red, string.char(153)
  97.         elseif col == colors.lime then return colors.green, string.char(153)
  98.         elseif col == colors.pink then return colors.brown, string.char(153)
  99.         elseif col == colors.gray then return colors.black, string.char(153)
  100.         elseif col == colors.lightGray then return colors.black, string.char(153)
  101.         elseif col == colors.cyan then return colors.gray, string.char(153)
  102.         elseif col == colors.purple then return colors.lightGray, string.char(153)
  103.         elseif col == colors.blue then return colors.purple, string.char(153)
  104.         elseif col == colors.brown then return colors.black, string.char(153)
  105.         elseif col == colors.green then return colors.lightGray, string.char(153)
  106.         elseif col == colors.red then return colors.gray, string.char(153)
  107.         elseif col == colors.black then return col, string.char(153) end
  108.     else return col, "#"
  109.     end
  110. end
  111. local function cast(cx,cy,angle)
  112.   --direction vector
  113.   local vx,vy=math.cos(angle), math.sin(angle)
  114.   local slope=vy/vx
  115.   --next distance, x and y axis points
  116.   local ndx, ndy
  117.   --steps, distance and block
  118.   local dsx, dsy, bsx, bsy
  119.   if vx<0 then
  120.     local x=(cx%1)
  121.     bsx=-1
  122.     ndx=math.sqrt(x*x*(1+slope*slope))
  123.     dsx=math.sqrt((1+slope*slope))
  124.   else
  125.     local x=1-(cx%1)
  126.     bsx=1
  127.     ndx=math.sqrt(x*x*(1+slope*slope))
  128.     dsx=math.sqrt((1+slope*slope))
  129.   end
  130.  
  131.   if vy<0 then
  132.     local y=(cy%1)
  133.     bsy=-1
  134.     ndy=math.sqrt(y*y*(1+1/(slope*slope)))
  135.     dsy=math.sqrt((1+1/(slope*slope)))
  136.   else
  137.     local y=1-(cy%1)
  138.     bsy=1
  139.     ndy=math.sqrt(y*y*(1+1/(slope*slope)))
  140.     dsy=math.sqrt((1+1/(slope*slope)))
  141.   end
  142.  
  143.   local x,y=math.floor(cx),math.floor(cy)
  144.   while x>0 and x<=mapW and y>0 and y<=mapH do
  145.     local hitD
  146.     local isX
  147.     if ndx<ndy then
  148.       --x crossing is next
  149.       x=x+bsx
  150.       isX=true
  151.       hitD=ndx
  152.       ndx=ndx+dsx
  153.     else
  154.       y=y+bsy
  155.       isX=false
  156.       hitD=ndy
  157.       ndy=ndy+dsy
  158.     end
  159.     local wall=map[y]:sub(x,x)
  160.     if wall~=" " then
  161.         -- term.setBackgroundColor(colors.combine(colors.white, colors.magenta, colours.lightBlue))
  162.         -- term.setCursorPos(1, 1)
  163.         -- term.write(hitD)
  164.         return colorSchemes[tonumber(wall)][isX and 1 or 2], hitD
  165.     end
  166.   end  
  167. end
  168.  
  169. local w,h=term.getSize()
  170. local centerX, centerY=math.floor((w+1)/2), math.floor((h+1)/2)
  171.  
  172. local px, py=9,25
  173. local dir=0
  174. local fx,fy
  175. local speed=.1
  176. local turnSpeed=4
  177.  
  178. local function turn(amt)
  179.   dir=dir+amt
  180.   fx,fy=math.cos(math.rad(dir)), math.sin(math.rad(dir))
  181. end
  182.  
  183. turn(0)
  184.  
  185. --build table of angles and base distances per scanline
  186. local screenDist=.55*w
  187. local scan={}
  188.  
  189. for x=1,w do
  190.   local t={}
  191.   scan[x]=t
  192.   t.angle=math.atan2(x-centerX,screenDist)
  193.   t.dist=((x-centerX)^2+screenDist^2)^.5/screenDist
  194. end
  195.  
  196. local function redraw()
  197.   if buffer.isBuffer then
  198.     term.redirect(buffer)
  199.   end
  200.   for x=1,w do
  201.     local wall, dist=cast(px,py,math.rad(dir)+scan[x].angle)
  202.     local col, chr = depthColor(2^wall, dist, y)
  203.      
  204.     if wall then
  205.       --calc wall height based on distance
  206.       local height=scan[x].dist/dist
  207.       height=math.floor(math.min(height*centerY,(h+1)/2))
  208.       term.setBackgroundColor(colors.gray)
  209.       for y=1,(h+1)/2-height-1 do
  210.         term.setCursorPos(x,y)
  211.         term.write(" ")
  212.       end
  213.       for y=centerY+height+1,h do
  214.         term.setCursorPos(x,y)
  215.         term.write(" ")
  216.       end
  217.       term.setBackgroundColor(col)
  218.       term.setTextColor(2^wall)
  219.      
  220.       for y=centerY-height,centerY+height do
  221.         if chr == string.char(153) then
  222.             if y % 2 == 0 then
  223.                 term.setBackgroundColor(col)
  224.                 term.setTextColor(2^wall)
  225.             else
  226.                 term.setBackgroundColor(2^wall)
  227.                 term.setTextColor(col)
  228.             end
  229.         end
  230.         term.setCursorPos(x,y)
  231.         term.write(chr)
  232.       end
  233.     end
  234.   end
  235.   if buffer.isBuffer then
  236.     term.restore()
  237.     buffer.blit()
  238.   end
  239. end
  240.  
  241. local function clampCollision(x,y,radius)
  242.   --am I *in* a block?
  243.   local gx,gy=math.floor(x),math.floor(y)
  244.   if map[gy]:sub(gx,gx)~=" " then
  245.     --I am. Complete fail, do nothing.
  246.     return x,y
  247.   end
  248.  
  249.   --ok, check the neighbors.
  250.   local right=math.floor(x+radius)>gx
  251.   local left=math.floor(x-radius)<gx
  252.   local front=math.floor(y-radius)<gy
  253.   local back=math.floor(y+radius)>gy
  254.  
  255.   local pushed=false
  256.  
  257.   if right and map[gy]:sub(gx+1,gx+1)~=" " then
  258.     --push left
  259.     pushed=true
  260.     x=gx+1-radius
  261.   elseif left  and map[gy]:sub(gx-1,gx-1)~=" " then
  262.     --push right
  263.     pushed=true
  264.     x=gx+radius
  265.   end
  266.  
  267.   if front and map[gy-1]:sub(gx,gx)~=" " then
  268.     --push back
  269.     pushed=true
  270.     y=gy+radius
  271.   elseif back and map[gy+1]:sub(gx,gx)~=" " then
  272.     --push forward
  273.     pushed=true
  274.     y=gy+1-radius
  275.   end
  276.  
  277.   --if I wasn't pushed out on any side, I might be hitting a corner
  278.   if not pushed then
  279.     --square rad
  280.     local r2=radius^2
  281.     local pushx,pushy=0,0
  282.     if left then
  283.       if front and map[gy-1]:sub(gx-1,gx-1)~=" " then
  284.         --check front-left
  285.         local dist2=(gx-x)^2+(gy-y)^2
  286.         if dist2<r2 then
  287.           local pushd=(r2-dist2)/2^.5
  288.           pushx,pushy=pushd,pushd
  289.         end
  290.       elseif back and map[gy+1]:sub(gx-1,gx-1)~=" " then
  291.         local dist2=(gx-x)^2+(gy+1-y)^2
  292.         if dist2<r2 then
  293.           local pushd=(r2-dist2)/2^.5
  294.           pushx,pushy=pushd,-pushd
  295.         end
  296.       end
  297.     elseif right then
  298.       if front and map[gy-1]:sub(gx+1,gx+1)~=" " then
  299.         --check front-left
  300.         local dist2=(gx+1-x)^2+(gy-y)^2
  301.         if dist2<r2 then
  302.           local pushd=(r2-dist2)/2^.5
  303.           pushx,pushy=-pushd,pushd
  304.         end
  305.       elseif back and map[gy+1]:sub(gx+1,gx+1)~=" " then
  306.         local dist2=(gx+1-x)^2+(gy+1-y)^2
  307.         if dist2<r2 then
  308.           local pushd=(r2-dist2)/2^.5
  309.           pushx,pushy=-pushd,-pushd
  310.         end
  311.       end
  312.     end
  313.     x=x+pushx
  314.     y=y+pushy
  315.   end
  316.  
  317.   return x,y
  318. end
  319.  
  320.  
  321.  
  322. print([[
  323. Basic wolfenstein 3d-style rendering engine proof-of-concept
  324. controls:
  325. asdw - move
  326. left/right - turn left/right
  327. q - quit
  328.  
  329. Press any key to begin...]])
  330.  
  331. os.pullEvent("key")
  332.  
  333. local frameTimer=os.startTimer(0.5)
  334. local prevTick=0
  335. local dirty=true
  336. while true do
  337.   px,py=clampCollision(px,py,.25)
  338.   if dirty then
  339.     redraw()
  340.     dirty=false
  341.   end
  342.  
  343.   local e={os.pullEvent()}
  344.   if e[1]=="key" then
  345.     if e[2]==keys.left then
  346.       turn(-turnSpeed)
  347.       dirty=true
  348.     elseif e[2]==keys.right then
  349.       turn(turnSpeed)
  350.       dirty=true
  351.     elseif e[2]==keys.up or e[2]==keys.w then
  352.       px=px+fx*speed
  353.       py=py+fy*speed
  354.       dirty=true
  355.     elseif e[2]==keys.down or e[2]==keys.s then
  356.       px=px-fx*speed
  357.       py=py-fy*speed
  358.       dirty=true
  359.     elseif e[2]==keys.a then
  360.       px=px+fy*speed
  361.       py=py-fx*speed
  362.       dirty=true
  363.     elseif e[2]==keys.d then
  364.       px=px-fy*speed
  365.       py=py+fx*speed
  366.       dirty=true
  367.     elseif e[2]==keys.q then
  368.       break
  369.     end
  370.   end
  371. end
  372.  
  373.  
  374. if loadedAPI then
  375.   os.unloadAPI("redirect")
  376. end
  377.  
  378. term.setBackgroundColor(colors.black)
  379. os.pullEvent()
  380. term.scroll(1)
  381. term.setCursorPos(1,19)
Add Comment
Please, Sign In to add comment