0]'],±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†31 or q.w<-1 then q:normalize()end;local s=sqrt(1-q.w*q.w);s=s.99999 then q.x,q.y,q.z,q.w=0,0,0,1;return q;elseif dot<-.99999 then vtmp1.x,vtmp1.y,vtmp1.z=1,0,0;vtmp1:cross(u);if #vtmp1UI.width/2 and UI.clicked~=nil)then return 1 else return 0 end end } function table.clone(obj)return {table.unpack(obj)}end function cloneModel(m)return setmetatable({rot=maf.quat(),pos=maf.vec3(0,0,0)},{__index=m})end function cloneShip(s)return setmetatable({vel=maf.vec3(0,0,0),equip={}},{__index=s})end function getTex(idx)local x,y,s,f,o=((idx//2)%16)*8,(idx//32)*8,8,idx%2,.1;return x+s*f,y+s*f,x+s,y+o,x+o,y+s end function getChar(idx) if idx==31 then idx=122 elseif idx==33 or idx==44 then idx=39 elseif idx==38 or idx==123 then idx=32 elseif idx==40 then idx=45 elseif idx==58 then idx=65 elseif idx==64 then idx=57 elseif idx==91 then idx=97 elseif idx==96 then idx=90 end return string.char(idx) end function saveModels() local addr=0x8000 poke(addr,#mdls) if #mdls==0 then trace("No models") return 0 end local write=addr+1 for i,m in ipairs(mdls) do local start_addr=write trace(i) poke(write,#m.verts) trace(#m.verts) poke(write+1,#m.tris) trace(#m.tris) write=write+2 for j,v in ipairs(m.verts) do poke(write,v.x+128) poke(write+1,v.y+128) poke(write+2,v.z+128) write=write+3 end for j,t in ipairs(m.tris) do poke(write,t[1]) poke(write+1,t[2]) poke(write+2,t[3]) if #t==9 then poke(write+3,255) poke(write+4,t[4]) poke(write+5,t[5]) poke(write+6,t[6]) poke(write+7,t[7]) poke(write+8,t[8]) poke(write+9,t[9]) write=write+10 else poke(write+3,t[4]) write=write+4 end end m.byte_size=write-start_addr end sync(4,0,true) trace("saved models") end function loadModels() --This function will load all models --that are stored in map ram. --Each model is stored sequentially, --with vertices followed by tris. --0x8000 - number of models --model bytes: --1 = Number of vertices --2,3,4 = Vertex x,y,z --1+nV*3 = Number of triangles --2,3,4,5= triangle v1,v2,v3,colour --potential expansion: --UV vertices --Colour above 15 corresponds to UV triangle --num UVs --u1,v1,u2,v2,u3,v3 --Maximum 240 uniquely textured triangles local addr=0x8000 local num_mdls=peek(addr) if num_mdls==0 then return 0 end addr=addr+1 for i=1,num_mdls do local start_addr=addr local new_model={scale=0.1,pos=maf.vec3(0,0,0),rot=maf.quat(),verts={},tris={}} local num_verts=peek(addr) local num_tris=peek(addr+1) addr=addr+2 for j=1,num_verts do local new_v=maf.vec3(peek(addr)-128,peek(addr+1)-128,peek(addr+2)-128) new_model.verts[j]=new_v addr=addr+3 end for j=1,num_tris do local new_t={peek(addr),peek(addr+1),peek(addr+2),peek(addr+3)} if new_t[4]>15 then --new_t[4] is the color of the tri. --If it is above 15, the triangle has UV coordinates --This assigns the UVs for the --renderer. for i=4,9 do new_t[i]=peek(addr+i) end addr=addr+10-4 end new_model.tris[j]=new_t addr=addr+4 end new_model.byte_size=addr-start_addr mdls[i]=new_model end end function firstToUpper(str)return (str:gsub("^%l",string.upper))end function sepThou(value) local formatted=value while true do formatted,k=string.gsub(formatted,"^(-?%d+)(%d%d%d)",'%1 %2') if (k==0) then break end end return formatted end function distanceXY(p1,p2)local x,y=p1.x-p2.x,p1.y-p2.y;return sqrt(x*x+y*y)end function lerp(a,b,t)return a+(b-a)*t;end -- Game functions function init() setPalettes() loadModels() model_id = 1 if mdls[model_id]~=nil then current_model=mdls[model_id] else create_new_model() end UI_mdls_init() --Convert pos and vertex data to vec3 for k,m in pairs(mdls) do break m.pos=maf.vec3(0,0,0) for j,v in ipairs(m.verts) do m.verts[j]=maf.vec3(v[1],v[2],v[3]) end --rotX90(m.verts) end end function TIC() --bgCol(0x14,0x0c,0x1c,.2) --poke(0x3FC0,0) drawModel() drawUI() update_mouse_state() if m_state.leftp then UI.focus=m_state.x=140) then poke(0x3FC0,0x1c) poke(0x3FC1,0x38) poke(0x3FC2,0xac) else poke(0x3FC0,80-scanline//2) poke(0x3FC1,80-scanline//2) poke(0x3FC2,100-scanline//2) end vbank(1) end function draw_help_scr() cls(4) print("NAVIGATING THE CAMERA",40,4,15) print("Use ARROWS or MIDDLE CLICK to move camera.",1,10,3) print("Press TAB to switch UI/camera focus.",1,16,3) print("PLUS, MINUS, scroll wheel to zoom in and out.",1,22,3) print("LEFT CLICK to select vertices and faces.",1,28,3) print("NAVIGATING THE MENU",40,36,15) print("UP+DOWN to select menu options.",1,42,3) print("LEFT+RIGHT to increase/decrease value.",1,48,3) print("ENTER to press button.",1,54,3) print("HOTKEYS",40,64,15) print("Ctrl+s - Save",1,70,3) print("Ctrl+f - New triangle",1,76,3) end function drawUI() cls(0) rect(0,0,UI.width,136,4) for i,option in pairs(UI.options) do drawUIOption(option,i) end end function drawUIOption(option, i) local y=i*8-7 local x=print(option[1],1,y,3,false,1,true) local al_r=print(option[2],-9,-9,0,false,1,true) local fg=3 local bg=0 if UI.selected==i then fg=15 bg=12 elseif option.inactive then fg=0 bg=1 print(option[1],1,y,1,false,1,true) elseif option.is_text then fg=2 bg=4 end rect(x+2,y-1,UI.width-x-3,7,bg) print(option[2],UI.width-al_r-1,y,fg,false,1,true) end function drawModel() vbank(0) cls(0) local q=maf.quat local m=current_model m.pos.z=camera.zoom m.rot = q():angleAxis(camera.rotation.x,1,0,0)*q():angleAxis(camera.rotation.y,0,1,0) renderModel(m) drawRenderBuffer(UI.width//2,0) vbank(1) end function UI_mdls_init() highlight.verts=false highlight.tris=false UI.options = {{"EDIT","Models"}, {"ID",model_id}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"","New model"}, {"","Delete model"}, {"","Toggle flicker"}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"CTRL: help","",is_text=true} } UI.update=UI_mdls_controls end function UI_mdls_controls() UI.options[2][2]=model_id UI.options[3][2]=#current_model.verts.." verts" UI.options[4][2]=#current_model.tris.." tris" UI.options[5][2]=current_model.byte_size.." bytes" if not UI.focus then return end local amount_to_add = UI.get_amount_to_add() if UI.selected==1 then if amount_to_add==1 then UI_edit_verts_init() end elseif UI.selected==2 then model_id=model_id+amount_to_add model_id=(model_id-1)%#mdls+1 if amount_to_add~=0 then current_model=mdls[model_id] end end local ek = keyp(enter_key) if (ek and UI.selected==6) or UI.clicked==6 then create_new_model() elseif (ek and UI.selected==7) or UI.clicked==7 then table.remove(mdls,model_id) model_id=(model_id-1)%#mdls+1 current_model=mdls[model_id] elseif (ek and UI.selected==8) or UI.clicked==8 then camera.flicker=not camera.flicker end end function UI_edit_verts_init() selected_id=1 highlight.verts=true highlight.tris=false UI.options = {{"EDIT","Verts"}, {"ID",selected_id}, {"X",current_model.verts[selected_id].x}, {"Y",current_model.verts[selected_id].y}, {"Z",current_model.verts[selected_id].z}, {"","New vert"}, {"","Delete vert"}} UI.update=UI_edit_verts_controls end function UI_edit_verts_controls() if m_state.leftp and m_state.x>UI.width then selected_id = select_nearest_vert_id(m_state.x,m_state.y) end UI.options[2][2]=selected_id UI.options[3][2]=current_model.verts[selected_id].x UI.options[4][2]=current_model.verts[selected_id].y UI.options[5][2]=current_model.verts[selected_id].z if not UI.focus then return end local amount_to_add = UI.get_amount_to_add() if UI.selected==1 then if amount_to_add==-1 then UI_mdls_init() elseif amount_to_add==1 then selected_id=1 UI_edit_tris_init() end elseif UI.selected==2 then selected_id=selected_id+amount_to_add selected_id=(selected_id-1)%#current_model.verts+1 elseif UI.selected==3 then current_model.verts[selected_id].x = (current_model.verts[selected_id].x+128)%256-128+amount_to_add elseif UI.selected==4 then current_model.verts[selected_id].y = (current_model.verts[selected_id].y+128)%256-128+amount_to_add elseif UI.selected==5 then current_model.verts[selected_id].z = (current_model.verts[selected_id].z+128)%256-128+amount_to_add end local ek = keyp(enter_key) if (ek and UI.selected==6) or UI.clicked==6 then create_new_vertex() elseif (ek and UI.selected==7) or UI.clicked==7 then table.remove(current_model.verts,selected_id) selected_id=(selected_id-1)%#current_model.verts+1 end end function UI_edit_tris_init() UI.focus=true highlight.tris=true highlight.verts=false UI.options = {{"EDIT","Tris"}, {"ID",selected_id}, {"V1",current_model.tris[selected_id][1]}, {"V2",current_model.tris[selected_id][2]}, {"V3",current_model.tris[selected_id][3]}, {"Colour",current_model.tris[selected_id][4]}, {"","Flip tri"}, {"","New tri"}, {"","Delete tri"}} UI.update=UI_edit_tris_controls end function UI_edit_tris_controls() if m_state.leftp and m_state.x>UI.width then selected_id = select_triangle_id(m_state.x,m_state.y) end local tri=current_model.tris[selected_id] UI.options[2][2]=selected_id UI.options[3][2]=tri[1] UI.options[4][2]=tri[2] UI.options[5][2]=tri[3] if #tri==4 then UI.options[6][2]=tri[4] UI.options[6].inactive=false elseif #tri==9 then UI.options[6].inactive=true end if not UI.focus then return end local amount_to_add = UI.get_amount_to_add() if UI.selected==1 then if amount_to_add==-1 then selected_id=1 UI_edit_verts_init() elseif amount_to_add==1 then UI_edit_UVs_init() end elseif UI.selected==2 then--id selected_id=selected_id+amount_to_add selected_id=(selected_id-1)%#current_model.tris+1 elseif UI.selected==3 then--vertices current_model.tris[selected_id][1] = current_model.tris[selected_id][1]+amount_to_add elseif UI.selected==4 then current_model.tris[selected_id][2] = current_model.tris[selected_id][2]+amount_to_add elseif UI.selected==5 then current_model.tris[selected_id][3] = current_model.tris[selected_id][3]+amount_to_add elseif UI.selected==6 and #tri==4 then--colour current_model.tris[selected_id][4] = current_model.tris[selected_id][4]%16+amount_to_add end local ek = keyp(enter_key) if (ek and UI.selected==7) or UI.clicked==7 then flip_triangle(current_model.tris[selected_id],1,3,2) elseif (ek and UI.selected==8) or UI.clicked==8 then create_tri_init() elseif (ek and UI.selected==9) or UI.clicked==9 then table.remove(current_model.tris,selected_id) selected_id=(selected_id-1)%#current_model.tris+1 end end function UI_edit_UVs_init() UI.focus=true highlight.tris=true highlight.verts=false UI.options = {{"EDIT","UVs"}, {"Tri",selected_id}, {"","C/R UVs"}, {"U1",""}, {"V1",""}, {"U2",""}, {"V2",""}, {"U3",""}, {"V3",""}, {"","Flip UV"}, {"","Rotate"}, {"","Copy UV"}, {"","",is_text=true}, {"","",is_text=true}, {"","",is_text=true}, {"SHIFT:\nshow image","",is_text=true}} UI.update=UI_edit_UVs_controls end function UI_edit_UVs_controls() if m_state.leftp and m_state.x>UI.width then selected_id = select_triangle_id(m_state.x,m_state.y) UI.selected=1 end local tri=current_model.tris[selected_id] UI.options[2][2]=selected_id if #tri==9 then UI.options[3][2]="Remove UVs" for i=4,9 do UI.options[i][2]=tri[i] end for i=4,#UI.options do UI.options[i].inactive=false end elseif #tri==4 then UI.options[3][2]="Create UVs" for i=4,9 do UI.options[i][2]="" end for i=4,#UI.options do UI.options[i].inactive=true end end if key(shift_key) then local x=UI.width+1 vbank(0) spr(0,x,1,-1,1,0,0,16,16) vbank(1) rectb(x-1,0,130,130,3) if #tri==9 then line(x+tri[4],tri[5]+1,x+tri[6],tri[7]+1,3) line(x+tri[6],tri[7]+1,x+tri[8],tri[9]+1,3) line(x+tri[8],tri[9]+1,x+tri[4],tri[5]+1,3) end end if not UI.focus then return end local amount_to_add = UI.get_amount_to_add() if UI.selected==1 then if amount_to_add==-1 then UI_edit_tris_init() end elseif UI.selected==2 then--id selected_id=selected_id+amount_to_add selected_id=(selected_id-1)%#current_model.tris+1 elseif UI.selected>=4 and UI.selected<=9 then--coordinates tri[UI.selected] = (tri[UI.selected]+amount_to_add)%129 end local ek = keyp(enter_key) if (ek and UI.selected==3) or UI.clicked==3 then if #tri==4 then current_model.tris[selected_id]={ tri[1],tri[2],tri[3], 0,0,128,0,0,128 } elseif #tri==9 then current_model.tris[selected_id]={ tri[1],tri[2],tri[3],1 } end elseif (ek and UI.selected==10) or UI.clicked==10 then flip_UVs(current_model.tris[selected_id],1,3,2) elseif (ek and UI.selected==11) or UI.clicked==11 then flip_UVs(current_model.tris[selected_id],3,1,2) elseif (ek and UI.selected==12) or UI.clicked==12 then copy_UV_init() end end function create_new_model() local new_model={scale=0.1,pos=maf.vec3(0,0,0),rot=maf.quat(),byte_size=0,verts={maf.vec3(-10,0,-10),maf.vec3(10,0,-10),maf.vec3(10,0,10),maf.vec3(-10,0,10)},tris={{1,2,3,1},{4,1,3,1}}} mdls[#mdls+1]=new_model model_id=#mdls current_model=mdls[#mdls] end function create_new_vertex() current_model.verts[#current_model.verts+1]=maf.vec3(0,0,0) selected_id=#current_model.verts end function create_tri_init() selected_id=0 highlight.verts=true highlight.tris=false UI.options = {{"Select 3 verts\nAny key to\ncancel",""}} UI.tri_verts = {} UI.update=create_tri_controls end function create_tri_controls() selected_id=UI.tri_verts[t%3] --triangle complete if #UI.tri_verts==3 then current_model.tris[#current_model.tris+1]={UI.tri_verts[1],UI.tri_verts[2],UI.tri_verts[3],1} selected_id=#current_model.tris UI_edit_tris_init() --cancel elseif keyp()or m_state.rightp or (m_state.leftp and m_state.xUI.width then UI.tri_verts[#UI.tri_verts+1] = select_nearest_vert_id(m_state.x,m_state.y) end end function copy_UV_init() highlight.verts=false highlight.tris=true UI.options = {{"Select a tri\nto copy from\nAny key to\ncancel",""}} UI.update=copy_UV_controls end function copy_UV_controls() --cancel if keyp()or m_state.leftp and m_state.xUI.width then local t_id=select_triangle_id(m_state.x,m_state.y) if t_id~=nil and #current_model.tris[t_id]==9 then for i=4,9 do current_model.tris[selected_id][i]=current_model.tris[t_id][i] end UI_edit_UVs_init() end end end function flip_triangle(tri,v1,v2,v3) local verts = {tri[1], tri[2], tri[3]} tri[1]=verts[v1] tri[2]=verts[v2] tri[3]=verts[v3] end function flip_UVs(tri,v1,v2,v3) local verts = {{tri[4],tri[5]},{tri[6],tri[7]},{tri[8],tri[9]}} tri[4]=verts[v1][1] tri[5]=verts[v1][2] tri[6]=verts[v2][1] tri[7]=verts[v2][2] tri[8]=verts[v3][1] tri[9]=verts[v3][2] end function camera_controls() --mouse controls camera.zoom = camera.zoom-0.3*m_state.scroll if m_state.middle then camera.rotation.y=camera.rotation.y+m_state.dx/20 camera.rotation.x=camera.rotation.x-m_state.dy/20 end --keyboard controls if UI.focus then return end --shift if key(shift_key) then else -- no modifiers if btn(0) then camera.rotation.x=camera.rotation.x+0.03 end if btn(1) then camera.rotation.x=camera.rotation.x-0.03 end if btn(2) then camera.rotation.y=camera.rotation.y-0.03 end if btn(3) then camera.rotation.y=camera.rotation.y+0.03 end if keyp(37) then camera.zoom = camera.zoom*1.2 end if keyp(38) then camera.zoom = camera.zoom/1.2 end end end function UI_controls() UI.clicked=nil if keyp(tab_key) then UI.focus=not UI.focus end if m_state.leftp and m_state.x15 then Tri[4],Tri[5],Tri[6],Tri[7],Tri[8],Tri[9]=getTex(Tri[4]) end if has_outline then table.insert(render_buffer, #render_buffer+1, {v[1].x,v[1].y,v[2].x,v[2].y,4, z=0 } ) table.insert(render_buffer, #render_buffer+1, {v[2].x,v[2].y,v[3].x,v[3].y,4, z=0 } ) table.insert(render_buffer, #render_buffer+1, {v[1].x,v[1].y,v[3].x,v[3].y,4, z=0 } ) end if #Tri==9 then --textured local uv_off=model.uv_off or {0,0} local uv_x=floor(model.anim_pos or 0)*8 + uv_off[1] local uv_y=uv_off[2] table.insert(render_buffer, #render_buffer+1, {v[1].x,v[1].y,v[2].x,v[2].y,v[3].x,v[3].y, Tri[4]+uv_x,Tri[5]+uv_y, Tri[6]+uv_x,Tri[7]+uv_y, Tri[8]+uv_x,Tri[9]+uv_y, z=v[1].z+v[2].z+v[3].z } ) else -- 1-color table.insert(render_buffer, #render_buffer+1, {v[1].x,v[1].y,v[2].x,v[2].y,v[3].x,v[3].y,Tri[4], z=v[1].z+v[2].z+v[3].z } ) end end function drawRenderBuffer(x,y) if #render_buffer<1 then return end table.sort(render_buffer,function(a,b)return a.z>b.z end) if x==nil then x=0;y=0 end for i=1,#render_buffer do local Tri=render_buffer[i] if #Tri==3 then --point if Tri.size==nil or Tri.size==0 then pix(Tri[1]+x,Tri[2]+y,Tri[3]) else circ(Tri[1]+x,Tri[2]+y,Tri.size,Tri[3]) end elseif #Tri==5 then --line line(Tri[1]+x,Tri[2]+y,Tri[3]+x,Tri[4]+y,Tri[5]) elseif #Tri==7 then --untex tri(Tri[1]+x,Tri[2]+y,Tri[3]+x,Tri[4]+y,Tri[5]+x,Tri[6]+y,Tri[7]) elseif #Tri==12 then --tex ttri(Tri[1]+x,Tri[2]+y,Tri[3]+x,Tri[4]+y,Tri[5]+x,Tri[6]+y,Tri[7],Tri[8],Tri[9],Tri[10],Tri[11],Tri[12],false,0) end end render_buffer={} end function isClockwise(Tri) if Tri.a or (Tri[2].y-Tri[1].y)* (Tri[3].x-Tri[2].x)- (Tri[3].y-Tri[2].y)* (Tri[2].x-Tri[1].x)>0 then return false else return true end end --Collisions function pointInTriangle(x1,y1,x2,y2,x3,y3,x,y) local denominator=((y2-y3)*(x1-x3)+(x3-x2)*(y1-y3)) local a=((y2-y3)*(x-x3)+(x3-x2)*(y-y3)) / denominator local b=((y3-y1)*(x-x3)+(x1-x3)*(y-y3)) / denominator local c=1-a-b return 0 <= a and a <= 1 and 0 <= b and b <= 1 and 0 <= c and c <= 1 end function triOnScreen(Tri) local avg={x=0,y=0} for i=1,3 do if Tri[i].x0 and Tri[i].y0 then return true end avg.x=avg.x+Tri[i].x/3 avg.y=avg.y+Tri[i].y/3 end if avg.x0 and avg.y0 then return true end local s={{x=0,y=0},{x=sw,y=0},{x=sw,y=sh},{x=0,y=sh},{x=sw2,y=sh2}} for i=1,5 do if pointInTriangle( Tri[1].x,Tri[1].y, Tri[2].x,Tri[2].y, Tri[3].x,Tri[3].y, s[i].x,s[i].y)then return true end end return false end init()