Aw, too bad. So I guess you'll have to use use the fixed memory way (right-hand fill method) to do this. But it is quite slow with complex shapes. So, good luck
I don't know anything about Axe... Does it allow recursive functions ? If yes, it's really easy... Anyway, Wikipédia is really interesting about that. http://en.wikipedia.org/wiki/Flood_fill
function multiplyMatrix(matrix,vector) local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3] local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3] local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3] return x,y,z end
function rotate(vertices,angle,x,y,z) local sum=x+y+z x,y,z=x/sum,y/sum,z/sum local c,s=math.cos(angle),math.sin(angle) local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}} for i,e in pairs(vertices) do vertices[i]={multiplyMatrix(matrix,e)} end end
function translate(vertices,x,y,z) for i,e in pairs(vertices) do vertices[i]={e[1]+x,e[2]+y,e[3]+z} end end
function scale(vertices,x,y,z) for i,e in pairs(vertices) do vertices[i]={e[1]*x,e[2]*y,e[3]*z} end end
function width() return platform.window:width() end function height() return platform.window:height() end
function reverseTable(tbl) local tbl2={} for i,e in ipairs(tbl) do tbl2[#tbl-i+1]=e end return tbl2 end
function replaceFaces(tbl1,tbl2,faces) local faces2,count={},1 for i,e in pairs(tbl1) do for j,e2 in pairs(tbl2) do if e2 then if e==e2 then faces2[count]=faces[j] count=count+1 tbl2[j]=nil end end end end return reverseTable(faces2) end
function sortFaces(vertices,faces) local faces2,distTbl,facesTbl={},{},{} local middle={} local dist,xsum,ysum,zsum=0,0,0,0 for i,e in pairs(faces) do xsum,ysum,zsum=0,0,0,0 for j,e2 in pairs(e) do xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3] end middle={xsum/#e,ysum/#e+5,zsum/#e} dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3] distTbl[i]=dist facesTbl[i]=dist end table.sort(distTbl) return replaceFaces(distTbl,facesTbl,faces) end
function chooseColor(gc,vertices,face,color) if #face<3 then gc:setColorRGB(color[1],color[2],color[3]) else local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3] local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3] local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)} local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2]) local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50 R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B gc:setColorRGB(R,G,B) end end
function renderFaces(gc,vertices,faces,pos,mode,color) local polygon,size={},0 local faces2=sortFaces(vertices,faces) for i,e in pairs(faces2) do polygon,size={},0 drawPoly=true for j,f in pairs(faces2[i]) do if not pos[f] then drawPoly=false else polygon[j*2-1]=pos[f][1] polygon[j*2]=pos[f][2] size=size+2 end end if drawPoly then polygon[size+1]=pos[faces2[i][1]][1] polygon[size+2]=pos[faces2[i][1]][2] if mode==4 then gc:setColorRGB(color[1],color[2],color[3]) gc:fillPolygon(polygon) elseif mode==5 then chooseColor(gc,vertices,e,color) gc:fillPolygon(polygon) end if mode==2 or mode==3 or mode==4 then gc:setColorRGB(0,0,0) gc:setPen("thin","smooth") gc:drawPolyLine(polygon) end end end end
function renderVertices(gc,pos) gc:setColorRGB(0,0,0) for i,e in pairs(pos) do if e then gc:fillRect(e[1]-1,e[2]-1,3,3) end end end
function render(gc,vertices,faces,mode,color) local yDist,pos=0,{} for i,e in pairs(vertices) do if e[2]>-5 then yDist=5/(e[2]+5) pos[i]={e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25} else pos[i]=false end end if mode==1 or mode==2 then renderVertices(gc,pos) end if #faces>0 and (mode==2 or mode==3 or mode==4 or mode==5) then renderFaces(gc,vertices,faces,pos,mode,color) end end
It does not... It only calculates the angle with the camera. But to choose which polygon I draw first, I use table.sort(). Is that bad ? And I don't say that it's fast, but it is fast enough to be playable... (Actually It's just a bit faster than Make3D, so I think I could optimize)
function multiplyMatrix(matrix,vector) local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3] local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3] local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3] return x,y,z end
function rotate(vertices,angle,x,y,z) local sum=x+y+z x,y,z=x/sum,y/sum,z/sum local c,s=math.cos(angle),math.sin(angle) local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}} for i,e in pairs(vertices) do vertices[i]={multiplyMatrix(matrix,e)} end end
function translate(vertices,x,y,z) for i,e in pairs(vertices) do vertices[i]={e[1]+x,e[2]+y,e[3]+z} end end
function scale(vertices,x,y,z) for i,e in pairs(vertices) do vertices[i]={e[1]*x,e[2]*y,e[3]*z} end end
function width() return platform.window:width() end function height() return platform.window:height() end
function reverseTable(tbl) local tbl2={} for i,e in ipairs(tbl) do tbl2[#tbl-i+1]=e end return tbl2 end
function replaceFaces(tbl1,tbl2,faces) local faces2={} for i,e in pairs(tbl1) do for j,e2 in pairs(tbl2) do if e2 then if e==e2 then table.insert(faces2,faces[j]) tbl2[j]=nil end end end end return reverseTable(faces2) end
function sortFaces(vertices,faces) local faces2,distTbl,facesTbl={},{},{} local middle={} local dist,xsum,ysum,zsum=0,0,0,0 for i,e in pairs(faces) do xsum,ysum,zsum=0,0,0,0 for j,e2 in pairs(e) do xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3] end middle={xsum/#e,ysum/#e+5,zsum/#e} dist=middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3] distTbl[i]=dist facesTbl[i]=dist end table.sort(distTbl) return replaceFaces(distTbl,facesTbl,faces) end
function chooseColor(gc,vertices,face,color) if #face<3 then gc:setColorRGB(color[1],color[2],color[3]) else local a,b,c=vertices[face[1]][1]-vertices[face[2]][1],vertices[face[1]][2]-vertices[face[2]][2],vertices[face[1]][3]-vertices[face[2]][3] local d,e,f=vertices[face[1]][1]-vertices[face[3]][1],vertices[face[1]][2]-vertices[face[3]][2],vertices[face[1]][3]-vertices[face[3]][3] local normale={math.abs(b*f-c*e),math.abs(c*d-a*f),math.abs(a*e-b*d)} local angle=math.atan(math.sqrt(normale[1]*normale[1]+normale[3]*normale[3])/normale[2]) local R,G,B=color[1]+angle*-60+50,color[2]+angle*-60+50,color[3]+angle*-60+50 R,G,B=R>255 and 255 or R,G>255 and 255 or G,B>255 and 255 or B R,G,B=R<0 and 0 or R,G<0 and 0 or G,B<0 and 0 or B gc:setColorRGB(R,G,B) end end
function renderFaces(gc,vertices,faces,pos,mode,color) local polygon={} local faces2=sortFaces(vertices,faces) for i,e in pairs(faces2) do polygon={} drawPoly=true for j,f in pairs(faces2[i]) do if not pos[f] then drawPoly=false else table.insert(polygon,pos[f][1]) table.insert(polygon,pos[f][2]) end end if drawPoly then table.insert(polygon,pos[faces2[i][1]][1]) table.insert(polygon,pos[faces2[i][1]][2]) if mode==4 then gc:setColorRGB(color[1],color[2],color[3]) gc:fillPolygon(polygon) elseif mode==5 then chooseColor(gc,vertices,e,color) gc:fillPolygon(polygon) end if mode==2 or mode==3 or mode==4 then gc:setColorRGB(0,0,0) gc:setPen("thin","smooth") gc:drawPolyLine(polygon) end end end end
function renderVertices(gc,pos) gc:setColorRGB(0,0,0) for i,e in pairs(pos) do if e then gc:fillRect(e[1]-1,e[2]-1,3,3) end end end
function render(gc,vertices,faces,mode,color) local yDist,pos=0,{} for i,e in pairs(vertices) do if e[2]>-5 then yDist=5/(e[2]+5) table.insert(pos,{e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25}) else table.insert(pos,false) end end if mode==1 or mode==2 then renderVertices(gc,pos) end if mode==2 or mode==3 or mode==4 or mode==5 then renderFaces(gc,vertices,faces,pos,mode,color) end end
function multiplyMatrix(matrix,vector) local x=matrix[1][1]*vector[1]+matrix[1][2]*vector[2]+matrix[1][3]*vector[3] local y=matrix[2][1]*vector[1]+matrix[2][2]*vector[2]+matrix[2][3]*vector[3] local z=matrix[3][1]*vector[1]+matrix[3][2]*vector[2]+matrix[3][3]*vector[3] return x,y,z end
function rotate(vertices,angle,x,y,z) local sum=x+y+z x,y,z=x/sum,y/sum,z/sum local c,s=math.cos(angle),math.sin(angle) local matrix={{x*x+(1-x*x)*c,x*y*(1-c)-z*s,x*z*(1-c)+y*s},{x*y*(1-c)+z*s,y*y+(1-y*y)*c,y*z*(1-c)-x*s},{x*z*(1-c)-y*s,y*z*(1-c)+x*s,z*z+(1-z*z)*c}} for i,e in pairs(vertices) do vertices[i]={multiplyMatrix(matrix,e)} end end
function translate(vertices,x,y,z) for i,e in pairs(vertices) do vertices[i]={e[1]+x,e[2]+y,e[3]+z} end end
function scale(vertices,x,y,z) for i,e in pairs(vertices) do vertices[i]={e[1]*x,e[2]*y,e[3]*z} end end
function width() return platform.window:width() end function height() return platform.window:height() end
function reverseTable(tbl) local tbl2={} for i,e in ipairs(tbl) do tbl2[#tbl-i+1]=e end return tbl2 end
function replaceFaces(tbl1,tbl2,faces) local faces2={} for i,e in pairs(tbl1) do for j,e2 in pairs(tbl2) do if e2 then if e==e2 then table.insert(faces2,faces[j]) tbl2[j]=nil end end end end return reverseTable(faces2) end
function sortFaces(vertices,faces) local faces2,distTbl,facesTbl={},{},{} local middle={} local dist,xsum,ysum,zsum=0,0,0,0 for i,e in pairs(faces) do xsum,ysum,zsum=0,0,0,0 for j,e2 in pairs(e) do xsum,ysum,zsum=xsum+vertices[e2][1],ysum+vertices[e2][2],zsum+vertices[e2][3] end middle={xsum/#e,ysum/#e+5,zsum/#e} dist=math.sqrt(middle[1]*middle[1]+middle[2]*middle[2]+middle[3]*middle[3]) table.insert(distTbl,dist) table.insert(facesTbl,dist) end table.sort(distTbl) return replaceFaces(distTbl,facesTbl,faces) end
function renderFaces(gc,vertices,faces,pos,mode,color) local polygon={} local faces2=sortFaces(vertices,faces) for i,e in pairs(faces2) do polygon={} drawPoly=true for j,f in pairs(faces2[i]) do if not pos[f] then drawPoly=false else table.insert(polygon,pos[f][1]) table.insert(polygon,pos[f][2]) end end if drawPoly then table.insert(polygon,pos[faces2[i][1]][1]) table.insert(polygon,pos[faces2[i][1]][2]) if mode==4 or mode==5 then gc:setColorRGB(color[1],color[2],color[3]) gc:fillPolygon(polygon) end if mode==2 or mode==3 or mode==4 then gc:setColorRGB(0,0,0) gc:drawPolyLine(polygon) end end end end
function renderVertices(gc,pos) gc:setColorRGB(0,0,0) for i,e in pairs(pos) do if e then gc:fillRect(e[1]-1,e[2]-1,3,3) end end end
function render(gc,vertices,faces,mode,color) local yDist,pos=0,{} for i,e in pairs(vertices) do if e[2]>-5 then yDist=5/(e[2]+5) table.insert(pos,{e[1]*yDist*25+width()/2,height()/2-e[3]*yDist*25}) else table.insert(pos,false) end end if mode==1 or mode==2 then renderVertices(gc,pos) end if mode==2 or mode==3 or mode==4 or mode==5 then renderFaces(gc,vertices,faces,pos,mode,color) end end
HOMER-16 : Here is how the (latest) function render works : render(gc,vertices,faces,mode,color) -gc is the graphic context (given in on.paint(gc)) -color is a table which contains RGB values ex : {200,200,200} -mode : 1 to render vertices only 2 to render vertices and edges 3 to render edges only 4 to render edges and faces 5 to render faces only -vertices is a table which contains vertices pos ex : {{0,0,0},{1,1,1},{1,2,1},{0,1,2}} -faces is a table which contains table of vertices. ex : {{1,2,3,4},{1,2,3}}
For now, to render 3D object with tiny3D library, you have to send them to the render() function in the Lua code. I've made a 3D-viewer in which you can modify vertices and faces with TI-Nspire-Basic. (You can also modify them with the spreadsheet application) I'll release it soon...