Advertisement
billysback

render

Jun 27th, 2013
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.04 KB | None | 0 0
  1.    
  2.  
  3.     os.loadAPI("matrix")
  4.     os.loadAPI("graphics")
  5.     os.loadAPI("triapi")
  6.     local w,h = term.getSize()
  7.      
  8.     --[[
  9.                     3D Render
  10.                     Display objects (and eventually textures) mapped in 3D coordinate space
  11.                     Makes use of the graphics API for projection and matrix API for transformations
  12.                    
  13.                     By Nitrogen Fingers
  14.                     Feel free to play with this code as much as you want!
  15.     ]]--
  16.      
  17.     camera = {
  18.             position = vector.new(0,0,0);
  19.             rX = 0; rY = 0; rZ = 0;
  20.     }
  21.      
  22.      
  23.     cube2 = {
  24.             vertices = {
  25.                     [1] = vector.new(6,6,0),
  26.                     [2] = vector.new(6,0,0),
  27.                     [3] = vector.new(0,0,0),
  28.                     [4] = vector.new(0,6,0),
  29.                     [5] = vector.new(6,6,6),
  30.                     [6] = vector.new(6,0,6),
  31.                     [7] = vector.new(0,0,6),
  32.                     [8] = vector.new(0,6,6);
  33.             };
  34.             colors = {
  35.                     [1] = colors.red;
  36.                     [2] = colors.blue;
  37.                     [3] = colors.green;
  38.                     [4] = colors.yellow;
  39.                     [5] = colors.orange;
  40.                     [6] = colors.cyan;
  41.                     [7] = colors.purple;
  42.                     [8] = colors.lime;
  43.             };
  44.             lines = {
  45.                     {1,2},{2,3},{3,4},{1,4},{5,6},{6,7},
  46.                     {7,8},{8,5},{1,5},{2,6},{3,7},{4,8};
  47.             };
  48.             faces = {
  49.                     {1,2,3,4, colors.red, colors.orange, ":"},
  50.                     {5,6,7,8, colors.green, colors.lime, "|"},
  51.                     {5,6,2,1, colors.blue, colors.cyan, "-"},
  52.                     {3,4,8,7, colors.yellow, colors.red, "+"},
  53.                     {1,4,8,5, colors.cyan, colors.blue, "@"},
  54.                     {2,3,7,6, colors.lime, colors.green, "#"};
  55.             };
  56.            
  57.            
  58.             scale = 1;
  59.             translate = vector.new(0,0,5);
  60.             rotateX = 0; rotateY = 0; rotateZ = 0;
  61.     }
  62.      
  63.     cube = {
  64.             vertices = {
  65.                     [1] = vector.new(3,3,-3),
  66.                     [2] = vector.new(3,-3,-3),
  67.                     [3] = vector.new(-3,-3,-3),
  68.                     [4] = vector.new(-3,3,-3),
  69.                     [5] = vector.new(3,3,3),
  70.                     [6] = vector.new(3,-3,3),
  71.                     [7] = vector.new(-3,-3,3),
  72.                     [8] = vector.new(-3,3,3);
  73.             };
  74.             colors = {
  75.                     [1] = colors.red;
  76.                     [2] = colors.blue;
  77.                     [3] = colors.green;
  78.                     [4] = colors.yellow;
  79.                     [5] = colors.orange;
  80.                     [6] = colors.cyan;
  81.                     [7] = colors.purple;
  82.                     [8] = colors.lime;
  83.             };
  84.             lines = {
  85.                     {1,2},{2,3},{3,4},{1,4},{5,6},{6,7},
  86.                     {7,8},{8,5},{1,5},{2,6},{3,7},{4,8};
  87.             };
  88.             faces = {
  89.                     {1,2,3,4, colors.red, colors.orange, ":"},
  90.                     {5,6,7,8, colors.green, colors.lime, "|"},
  91.                     {5,6,2,1, colors.blue, colors.cyan, "-"},
  92.                     {3,4,8,7, colors.yellow, colors.red, "+"},
  93.                     {1,4,8,5, colors.cyan, colors.blue, "@"},
  94.                     {2,3,7,6, colors.lime, colors.green, "#"};
  95.             };
  96.            
  97.             scale = 1;
  98.             translate = vector.new(0,0,5);
  99.             rotateX = 0; rotateY = 0; rotateZ = 0;
  100.     }
  101.      
  102.     cube2.link = {{cube, 1, 1, colors.white, colors.black, "-"}}
  103.    
  104.     --The 'illusion of depth' function, really just for debugging and demo work.
  105.     function drawAtPoint(vert, tab)
  106.             if tab ~= nil then
  107.                 tab[vert.nov] = vert
  108.             end
  109.             term.setCursorPos(vert.x, vert.y)
  110.             if vert.dist < 5 then
  111.                     term.setBackgroundColour(vert.color)
  112.                     term.write(" ")
  113.                     term.setBackgroundColour(colours.black)
  114.             elseif vert.dist < 10 then
  115.                     term.setTextColour(vert.color)
  116.                     term.write("0")
  117.             elseif vert.dist < 15 then
  118.                     term.setTextColour(vert.color)
  119.                     term.write("*")
  120.             else
  121.                     term.setTextColour(vert.color)
  122.                     term.write(".")
  123.             end
  124.     end
  125.    
  126.     local function insertAt(tab, index, value)
  127.         local ntab = {}
  128.         if index > 1 then
  129.             for i=1,index-1 do
  130.                 ntab[#ntab + 1] = tab[i]
  131.             end
  132.             ntab[index] = value
  133.             if index <= #tab then
  134.                 for i=index,#tab do
  135.                     ntab[#ntab + 1] = tab[i]
  136.                 end
  137.             end
  138.         else
  139.             ntab[#ntab + 1] = value
  140.             for i=1,#tab do
  141.                 ntab[#ntab + 1] = tab[i]
  142.             end
  143.         end
  144.         return ntab
  145.     end
  146.      
  147.     --Draws our 3D models. Right now it only draws the vertices, not faces or lines.
  148.     function renderModel(model)
  149.             world = {}
  150.             --Note: Matrix operations, especially rotations are expensive. Rather than re-creating
  151.             --matrices over and over as done here, it is much safer to initialize them at the start
  152.             --of a program, and only update when necessary. If something is beyond the view frustrum,
  153.             --don't render it!!!
  154.      
  155.             --Creating the world space
  156.             global = matrix.identity()
  157.             global = global * matrix.createScale(model.scale)
  158.             global = global * matrix.createRotationX(model.rotateX)
  159.             global = global * matrix.createRotationY(model.rotateY)
  160.             global = global * matrix.createRotationZ(model.rotateZ)
  161.             global = global * matrix.createTranslation(model.translate)
  162.      
  163.             distances = {}
  164.            
  165.             for i,vertex in ipairs(model.vertices) do
  166.                     table.insert(world,global:apply(vertex, i))
  167.                     table.insert(distances, math.sqrt(math.pow(camera.position.x - world[i].x, 2) +
  168.                             math.pow(camera.position.y - world[i].y, 2) +
  169.                             math.pow(camera.position.z - world[i].z, 2)))
  170.             end
  171.             --Converting from world space to camera space
  172.             global = matrix.identity()
  173.             global = global * matrix.createTranslation(-camera.position)
  174.             global = global * matrix.createRotationX(-camera.rX)
  175.      
  176.             for i,vertex in ipairs(world) do
  177.                     --Applying camera space
  178.                     world[i] = global:apply(vertex, vertex.nov)
  179.             end
  180.      
  181.             --Project camera space into screen space
  182.             for i=1,#world do
  183.                     local col = world[i].color
  184.                     local nov = world[i].nov
  185.                    
  186.                     world[i] = graphics.project(world[i])
  187.                     --Here until we sort out depth buffering
  188.                     world[i].color = model.colors[i]
  189.                     world[i].dist = distances[i]
  190.                     world[i].nov = nov
  191.             end
  192.            
  193.             buffer = {}
  194.             --Depth-sorting our points for cleaner drawing. Simple selection sort- not wasting time on this.
  195.             --This is NOT sufficient for long-term. Will clean up later.
  196.             while #world > 0 do
  197.                     local maxDepth = 1
  198.                     for i=2,#world do
  199.                             if world[i].dist > world[maxDepth].dist then maxDepth = i end
  200.                     end
  201.                     table.insert(buffer, world[maxDepth])
  202.                     table.remove(world, maxDepth)
  203.             end
  204.        
  205.             --Draw the verts on screen if you can!
  206.             local verts = {}
  207.             for i,vert in ipairs(buffer) do
  208.                     if vert.x > 0 and vert.x < w and vert.y > 0 and vert.y < h then
  209.                             --drawAtPoint(vert, verts)
  210.                             verts[vert.nov] = vert
  211.                     end
  212.             end
  213.             model.verts = verts
  214.            
  215.            local sqrs = {}
  216.            
  217.             for i=1,#model.faces do
  218.                 local canDraw = true
  219.                 --list of vert ids and a color as the last index
  220.                 local sqtab = model.faces[i]
  221.                 --converted table of true vert coords compared to vert ids
  222.                 local ntab = {}
  223.                 local avgDist = 0
  224.                 local avgi = 0
  225.                 for i=1,(#sqtab - 3) do
  226.                     --ID for vert
  227.                     local id = sqtab[i]
  228.                     if verts[id] ~= nil then
  229.                         ntab[i] = {verts[id].x, verts[id].y}
  230.                         avgDist = avgDist + verts[id].dist
  231.                         avgi = avgi + 1
  232.                     else
  233.                         canDraw = false
  234.                         --break
  235.                     end
  236.                 end
  237.                 if canDraw then
  238.                     local square = triapi.fillSquare(ntab[1], ntab[2], ntab[3], ntab[4])
  239.                    
  240.                     local avgDist = avgDist/avgi
  241.                    
  242.                     square.dist = avgDist
  243.                     square.col = sqtab[5]
  244.                     square.tcol = sqtab[6]
  245.                     square.text = sqtab[7]
  246.                    
  247.                     local centre = {(ntab[1][1]+ntab[2][1]+ntab[3][1]+ntab[4][1])/4, (ntab[1][2]+ntab[2][2]+ntab[3][2]+ntab[4][2])/4}
  248.                     square.centre = centre
  249.                    
  250.                     sqrs[#sqrs + 1] = square
  251.                 end
  252.                 --triapi.drawShape(square, sqtab[5], colors.black, " ")
  253.             end
  254.            
  255.             local lines = {}
  256.              if model.link ~= nil then
  257.                 for i=1,#model.link do
  258.                     local link = model.link[i][1]
  259.                     local mFace = model.link[i][2]
  260.                     local lFace = model.link[i][3]
  261.                     local col = model.link[i][4]
  262.                     local tcol = model.link[i][5]
  263.                     local text = model.link[i][6]
  264.                    
  265.                     local face = link.faces[lFace]
  266.                     centre = {0,0}
  267.                     local n = 0
  268.                     for i=1,(#face - 3) do
  269.                         centre[1] = centre[1] + link.verts[face[i]].x
  270.                         centre[2] = centre[2] + link.verts[face[i]].y
  271.                         n = n + 1
  272.                     end
  273.                     centre[1] = centre[1]/n
  274.                     centre[2] = centre[2]/n
  275.                    
  276.                     modelCentre = sqrs[mFace].centre
  277.                    
  278.                     local line = triapi.drawLine(modelCentre[1], modelCentre[2], centre[1], centre[2])
  279.                     --[[triapi.drawShape(line,
  280.                                       col,
  281.                                       tcol,
  282.                                       text)]]
  283.                     lines[#lines + 1] = {line, col, tcol, text}
  284.                 end
  285.            end
  286.            
  287.             local sqrs_dists = {}
  288.            
  289.             while #sqrs > 0 do
  290.                 local maxDepth = 1
  291.                 for i=2,#sqrs do
  292.                         if sqrs[i].dist > sqrs[maxDepth].dist then maxDepth = i end
  293.                 end
  294.                 table.insert(sqrs_dists, sqrs[maxDepth])
  295.                 table.remove(sqrs, maxDepth)
  296.             end
  297.            
  298.             if #sqrs_dists > 3 then
  299.                 for i=(#sqrs_dists - 3),#sqrs_dists do
  300.                     local sqr = sqrs_dists[i]
  301.                     triapi.drawShape(sqr, sqr.col, sqr.tcol, sqr.text)
  302.                 end
  303.             else
  304.                 for i=1,#sqrs_dists do
  305.                     local sqr = sqrs_dists[i]
  306.                     triapi.drawShape(sqr, sqr.col, sqr.tcol, sqr.text)
  307.                 end
  308.             end
  309.            
  310.             if model.link ~= nil then
  311.                 for i=1,#lines do
  312.                     triapi.drawShape(lines[i][1],
  313.                                      lines[i][2],
  314.                                      lines[i][3],
  315.                                      lines[i][4])
  316.                 end
  317.            end
  318.             --That's it! Your first render!
  319.     end
  320.      
  321.     --Again, a little demo function to show off the operations
  322.     function printHUD()
  323.             term.setCursorPos(1,h)
  324.             term.setTextColour(colours.white)
  325.             term.write("Arrows move, WSAD QE rotate, RF scale. Enter quits.")
  326.     end
  327.      
  328.      local curCube = cube
  329.     --Lets you play with the 3D model a bit.
  330.    
  331.     function run()
  332.             quit = false
  333.             repeat
  334.                     term.setBackgroundColor(colors.black)
  335.                     term.clear()
  336.                     renderModel(cube)
  337.                     renderModel(cube2)
  338.                     printHUD()
  339.                     local _,key = os.pullEvent("key")
  340.            
  341.                     --Arrow keys translate
  342.                     if key == keys.up then
  343.                             curCube.translate.z = curCube.translate.z + 1
  344.                     elseif key == keys.down then
  345.                             curCube.translate.z = curCube.translate.z - 1
  346.                     elseif key == keys.left then
  347.                             curCube.translate.x = curCube.translate.x - 1
  348.                     elseif key == keys.right then
  349.                             curCube.translate.x = curCube.translate.x + 1
  350.                     --WSAD QE keys rotate
  351.                     elseif key == keys.w then
  352.                             curCube.rotateX = curCube.rotateX - (math.pi/16)
  353.                     elseif key == keys.s then
  354.                             curCube.rotateX = curCube.rotateX + (math.pi/16)
  355.                     elseif key == keys.q then
  356.                             curCube.rotateZ = curCube.rotateZ - (math.pi/16)
  357.                     elseif key == keys.e then
  358.                             curCube.rotateZ = curCube.rotateZ + (math.pi/16)
  359.                     elseif key == keys.a then
  360.                             curCube.rotateY = curCube.rotateY + (math.pi/16)
  361.                     elseif key == keys.d then
  362.                             curCube.rotateY = curCube.rotateY - (math.pi/16)
  363.                     --RF scales
  364.                     elseif key == keys.r then
  365.                             curCube.scale = curCube.scale * 1.1
  366.                     elseif key == keys.f then
  367.                             curCube.scale = curCube.scale / 1.1
  368.                     --Enter quits
  369.                     elseif key == keys.z then
  370.                         if curCube == cube then curCube = cube2 else curCube = cube end
  371.                     elseif key == keys.enter then
  372.                             quit = true
  373.                     end
  374.             until quit == true
  375.     end
  376.      
  377.     run()
  378.     term.setBackgroundColor(colors.black)
  379.     shell.run("clear")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement