Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created October 20, 2015 03:10
Show Gist options
  • Save dermotbalson/56aef88dcca08f9d7445 to your computer and use it in GitHub Desktop.
Save dermotbalson/56aef88dcca08f9d7445 to your computer and use it in GitHub Desktop.
Tank 4
--# Test
--[
function setup()
img=readImage("Dropbox:3D-grass2x"):copy(0,50,25,50)
b1=CreateBlock(10,5,5,color(255,255,0),nil,img)
b2=CreateBlock(10,5,5,color(255),nil,img) --b2:setColors(color(100,0,0))
b1.pos=vec3(0,0,100) b1.a=0
b2.pos=vec3(0,0,0) b2.a=40
s=vec3(10,5,5)
dp=1
ap=0.25
camPos,camLook=b1.pos,b2.pos
end
function draw()
background(102, 173, 202, 255)
perspective()
camera(camPos.x,camPos.y,camPos.z,camLook.x,camLook.y,camLook.z)
pushMatrix()
translate(b2.pos:unpack())
rotate(b2.a,0,1,0)
b2:draw()
X,Y,w,h=GetScreenRect(b1,b2,s)
popMatrix()
b2.pos.z=b2.pos.z+dp if b2.pos.z<-300 or b2.pos.z>80 then dp=-dp end
b2.a=b2.a+ap
ortho()
viewMatrix(matrix())
fill(255,255,0,50)
rect(X,Y,w,h)
end
function GetScreenRect(t1,t2,s) --t1 is camera, t2 is target, s is vec3 size of object
--assume target only rotates on y, take larger of x and z size to set rect size
local u=math.max(s.x,s.z)
--get direction and distance
local v=(t2.pos-t1.pos)
local d=v:len()-u/2 --position of t2 is assumed to be its centre, so adjust by 1\2 depth
v=v/d
--get drawing rectangle
local w = u*WIDTH*projectionMatrix()[1]/d/2
local h = s.y*HEIGHT*projectionMatrix()[6]/d/2
--draw our tank
local m = modelMatrix()*viewMatrix()*projectionMatrix()
--m = m:translate(0,0,-d)
local X,Y=(m[13]/m[16]+1)*WIDTH/2, (m[14]/m[16]+1)*HEIGHT/2
return X-w/2,Y-h/2,w,h
end
--]]
--# Test3
function setup()
img=readImage("Platformer Art:Block Brick")
b1=CreateBlock(10,5,5,color(255,255,0),nil,img)
b2=CreateBlock(10,5,5,color(255),nil,img)
b1.pos=vec3(0,0,100) b1.a=0
b2.pos=vec3(0,0,0) b2.a=40
s=vec3(10,5,5)
target=image(WIDTH,HEIGHT)
camPos,camLook=b1.pos,b2.pos
dp,ap=1,0.5
parameter.number("FPS",1,60,60)
end
function draw()
FPS=FPS*0.9+0.1/DeltaTime
background(150)
perspective()
camera(camPos.x,camPos.y,camPos.z,camLook.x,camLook.y,camLook.z)
pushMatrix()
translate(b2.pos:unpack())
rotate(b2.a,0,1,0)
b2:draw()
local X,Y,w,h=GetScreenRect(b1,b2,s)
local img=DrawTarget(X,Y,w,h,b2,b1.pos:dist(b2.pos))
popMatrix()
b2.pos.z=b2.pos.z+dp if b2.pos.z<-300 or b2.pos.z>80 then dp=-dp end
b2.a=b2.a+ap
--ortho()
--viewMatrix(matrix())
--sprite(img,w/2,h/2)
end
function GetScreenRect(t1,t2,s) --t1 is camera, t2 is target, s is vec3 size of object
--assume target only rotates on y, take larger of x and z size to set rect size
local u=math.max(s.x,s.z)
--get direction and distance
local v=(t2.pos-t1.pos)
local d=v:len()-u/2 --position of t2 is assumed to be its centre, so adjust by 1\2 depth
v=v/d
--get drawing rectangle
local w = u*WIDTH*projectionMatrix()[1]/d/2
local h = s.y*HEIGHT*projectionMatrix()[6]/d/2
--draw our tank
local m = modelMatrix()*viewMatrix()*projectionMatrix()
--m = m:translate(0,0,-d)
local X,Y=(m[13]/m[16]+1)*WIDTH/2, (m[14]/m[16]+1)*HEIGHT/2
return X-w/2,Y-h/2,w,h
end
function DrawTarget(X,Y,w,h,t,d)
setContext(target)
background(50)
perspective(45,WIDTH/HEIGHT,0.1,d)
clip(X,Y,w,h)
t:draw()
clip()
setContext()
local XX,YY,ww,hh=math.floor(X),math.floor(Y),math.ceil(w),math.ceil(h)
return target:copy(XX,YY,ww,hh)
end
--# Test5
function setup()
targetColor=color(255,0,0) --target colour
--draw a target image with a red square in the middle on a green background
--we want to count the red pixels
img=image(200,200)
noSmooth()
setContext(img)
background(0,255,0)
fill(targetColor)
rect(50,50,50,50)
setContext()
smooth()
--count yellow pixels ------------------
--create the smallest mesh possible, seems to be a triangle with 2x2 pixels
mm=mesh()
mm.vertices={vec2(1,1),vec2(2,1),vec2(1,2)}
mm.shader=shader(pixelCountShader.vertexShader,pixelCountShader.fragmentShader)
mm.shader.c=targetColor --target colour
mm.shader.w=200 --width of texture
mm.shader.h=200 --height of texture
mm.shader.threshold=3000 --number of pixels required to pass threshold
img2=image(2,2)
mm.texture=img --pass through test image
mm:draw()
-----------------------------------
r,g,b=img2:get(2,2) --this seems to be the best pixel to get
setContext()
print("time=",os.time()-t)
print("Result=",r/255,2500/mm.shader.threshold)
end
function draw()
background(200)
sprite(img,WIDTH/2,HEIGHT/2,300) --draw test image
end
pixelCountShader = {
vertexShader=[[
uniform mat4 modelViewProjection;
attribute vec4 position;
varying lowp vec4 vPosition;
void main()
{
gl_Position = modelViewProjection * position;
vPosition=position;
}
]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
uniform vec4 c;
uniform float w;
uniform float h;
uniform float threshold;
varying highp vec4 vPosition;
void main()
{
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
if (vPosition.x>1.0 && vPosition.y>1.0) {
float t=0.0;
for (float x=0.0; x<w; x++)
for (float y=0.0; y<h; y++) {
vec4 p=texture2D(texture,vec2(x/w,y/h));
if (p.r==c.r) t+=1.0;
}
gl_FragColor.a = t/threshold;
}
}
]]}
--# Test6
function setup()
targetColor=color(0,0,255) --target colour
--draw a target image with a red square in the middle on a green background
--we want to count the red pixels
img=image(200,200)
--noSmooth()
setContext(img)
background(0,255,0)
fill(targetColor)
s=200/3
rect(50-s/2,50-s/2,s,s)
setContext()
img2=image(4,4)
setContext(img2)
sprite(img,2,2,4)
setContext()
t=0
for i=1,img2.width do
for j=1,img2.height do
r,g,b=img2:get(i,j)
print(r,g,b)
t=t+b
end
end
print("Result=",t/255/img2.width/img2.height)
end
function draw()
background(200)
sprite(img,WIDTH/2,HEIGHT/2,300) --draw test image
sprite(img2,WIDTH/2,HEIGHT/2,50)
end
--# Test7
function setup()
tank=BuildTank(color(150, 189, 128, 255))
camPos=vec3(0,0,50)
ax,ay=0,0
backgroundColor=color(220)
end
function draw()
background(backgroundColor)
perspective()
camera(camPos.x,camPos.y,camPos.z,0,0,0)
rotate(ay,0,1,0) rotate(ax,1,0,0)
for _,m in pairs(tank) do
m.shader.mModel=modelMatrix()
m.shader.camPos=camPos
m:draw()
end
end
function touched(t)
if t.state~=ENDED then
ay,ax=ay+t.deltaX,ax+t.deltaY
end
end
function BuildTank(col)
local x1,x2,y1,y2,y3,z1,z2
--body of tank
local body=mesh()
local v,t,c={},{},{}
x1,x2,y,z1,z2=-8.25,8.25,6.5,4.5,-4.5 --deck
v[#v+1]=vec3(x1,y,z1) v[#v+1]=vec3(x2,y,z1) v[#v+1]=vec3(x2,y,z2)
v[#v+1]=vec3(x2,y,z2) v[#v+1]=vec3(x1,y,z2) v[#v+1]=vec3(x1,y,z1)
x,y1,y2,z1,z2=8.25,2,6.5,4.5,-4.5 --back
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x,y1,z2) v[#v+1]=vec3(x,y2,z2)
v[#v+1]=vec3(x,y2,z2) v[#v+1]=vec3(x,y2,z1) v[#v+1]=vec3(x,y1,z1)
x,y1,y2,z1,z2=-8.25,4.5,6.5,4.5,-4.5 --front
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x,y1,z2) v[#v+1]=vec3(x,y2,z2)
v[#v+1]=vec3(x,y2,z2) v[#v+1]=vec3(x,y2,z1) v[#v+1]=vec3(x,y1,z1)
x1,x2,y1,y2,z1,z2=-11,-8.25,3,4.5,4.5,-4.5 --front #2 angle
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,y3,z1,z2=-8.25,8.25,2,2,6.5,4.5,-4.5 --sides
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x2,y3,z1)
v[#v+1]=vec3(x2,y3,z1) v[#v+1]=vec3(x1,y3,z1) v[#v+1]=vec3(x1,y1,z1)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x1,y3,z2)
v[#v+1]=vec3(x1,y3,z2) v[#v+1]=vec3(x2,y3,z2) v[#v+1]=vec3(x2,y2,z2)
x1,x2,y1,z1,z2=-11,8.25,2,-2.5,2.5 --underneath
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y1,z2)
v[#v+1]=vec3(x2,y1,z2) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x1,y1,z1)
x,y1,y2,z1,z2=-11,2,3,-2.5,2.5 --front bottom
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x,y1,z2) v[#v+1]=vec3(x,y2,z2)
v[#v+1]=vec3(x,y2,z2) v[#v+1]=vec3(x,y2,z1) v[#v+1]=vec3(x,y1,z1)
body.vertices=v
body:setColors(color(90))
body.texture=MakeBodyTexture()
--tracks
local track,v=mesh(),{}
x1,x2,y1,y2,z1,z2=8.25,8.25,1,2,4.5,2.5 --back right vert
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
z1,z2=-2.5,-4.5 --back left vert
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,z1,z2=7.25,8.25,0,1,4.5,2.5 --back right slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
z1,z2=-2.5,-4.5 --back left slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,z1,z2=-11,-11,2,3,2.5,4.5 --front right vert
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
z1,z2=-4.5,-2.5 --front left vert
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,z1,z2=-9,-11,0,2,2.5,4.5 --front right slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
z1,z2=-4.5,-2.5 --front left slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,z1,z2=-9,7.25,0,0,2.5,4.5 --bottom right track
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y1,z2)
v[#v+1]=vec3(x2,y1,z2) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x1,y1,z1)
z1,z2=-2.5,-4.5 --bottom left track
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y1,z2)
v[#v+1]=vec3(x2,y1,z2) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x1,y1,z1)
track.vertices=v
track:setColors(color(40))
track.texture=MakeTrackTexture()
local a={body=body,track=track}
for _,m in pairs(a) do
local norm={}
local v=m:buffer("position")
for i=1,m.size,3 do
local v1,v2=v[i]-v[i+2],v[i+1]-v[i+2]
local n=(v1:cross(v2)):normalize()
norm[i],norm[i+1],norm[i+2]=n,n,n
end
m.normals=norm
m=SetLighting(m)
end
print("vertices=",body.size+track.size)
return a
end
function SetLighting(m)
m.shader=shader(TankShader.v,TankShader.f)
m.shader.directDirection=vec4(-1,1,1,0):normalize()
m.shader.ambientColor=color(255)*0.3
m.shader.directColor=color(255)*0.7
m.shader.fog=1000
m.shader.mistColor=backgroundColor
return m
end
function MakeBodyTexture()
local img=image(50,50)
setContext(img)
background(122, 184, 121, 255)
setContext()
return img
end
function MakeTrackTexture()
local img=image(50,50)
setContext(img)
background(110, 104, 102, 255)
setContext()
return img
end
--# TerrainShader
--Terrain plus shader
local atan,rand,min,max=math.atan,math.random,math.min,math.max
local rad=math.pi/180
local Terrain={}
function MakeTerrain()
local w,d,pic,f=1000,1000,"Dropbox:3D-grass2x",.02
LoadImages()
local floor=mesh()
local img=readImage(pic)
floor.texture=img
local wn,dn=w/img.width/f,d/img.height/f
floor.vertices={vec3(0,0,0),vec3(w,0,0),vec3(w,0,-d),vec3(w,0,-d),vec3(0,0,-d),vec3(0,0,0)}
floor.texCoords={vec2(0,0),vec2(wn,0),vec2(wn,dn),vec2(wn,dn),vec2(0,dn),vec2(0,0)}
floor.shader=shader(TileShader.v,TileShader.f)
floor.shader.fog=5000
floor.shader.mistColor=backgroundColor
floor.shader.mModel=modelMatrix()
local trees,treePos=mesh(),{}
for i=1,400 do
local a=1 --rand(1,#treeImages)
local s=0.15*(0.5+rand())
local ww,hh=treeImages[a].width*s,treeImages[a].height*s
local pos=vec3(rand(1,w),hh/2,rand(-d,-1))
local n=trees.size
trees:addRect(0,0,ww,hh)
local v=trees:buffer("position")
if i==1 then for i=1,6 do print(v[i]) end end
for i=n+1,n+6 do v[i]=v[i]+pos end
treePos[i]=pos
end
trees.texture=treeImages[1]
trees=SetLighting(trees,TreeShader)
trees.shader.mModel=modelMatrix()
Terrain={floor=floor,trees=trees}
end
function LoadImages()
treeImages={readImage("Dropbox:3D-tree"),readImage("Dropbox:3D-tree3"),readImage("Dropbox:3D-tree7"),
readImage("Dropbox:3D-tree8")}
end
function DrawTerrain()
Terrain.floor.shader.camPos=camPos
Terrain.floor:draw()
noSmooth()
Terrain.trees:draw()
smooth()
end
TreeShader={
v=[[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec4 directColor;
uniform vec4 directDirection;
uniform vec4 ambientColor;
uniform float fog;
uniform vec4 mistColor;
uniform vec3 camPos;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
gl_Position = modelViewProjection * position;
vTexCoord = texCoord;
vec4 norm = normalize(mModel * vec4( normal, 0.0 ));
float diffuse = max( 0.0, dot( norm, directDirection ));
vec4 p=mModel*position;
float f = clamp(distance(p.xyz,camPos)/fog,0.0,1.0);
vColor = mix(( diffuse * directColor + ambientColor ),mistColor,f);
vColor.a=1.0;
}
]],
f=[[
precision highp float;
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
vec4 col=texture2D(texture,vTexCoord);
if (col.a<.01) discard;
else gl_FragColor=col*vColor;
}
]]}
--# Terrain
--Terrain
function MakeTerrain(pos,width,depth,height,cellSize,smoothness)
local ws,ds=width/cellSize,depth/cellSize
local grid0={}
local rw,rd=math.random(),math.random()
for w=0,ws do
grid0[w]={}
for d=0,ds do
local h=height/2*(1+noise(rw+w*smoothness,rd+d*smoothness))-1
grid0[w][d]=vec3(w*cellSize,h,-d*cellSize)+pos
end
end
local grid={}
for w=0,ws do
grid[w]={}
for d=0,ds do
grid[w][d]=grid0[w][d]
end
end
for w=1,ws-1 do
for d=1,ds-1 do
grid[w][d]=(grid0[w][d-1]+grid0[w-1][d]+grid0[w][d+1]+grid0[w+1][d])/8+grid0[w][d]/2
end
end
--normals are averaged
gn={}
for w=0,ws do
gn[w]={}
for d=0,ds do
if w==0 or w==ws or d==0 or d==ds then gn[w][d]=vec3(0,1,0)
else
gn[w][d]=(GetNormal(grid[w][d],grid[w-1][d],grid[w][d-1])+
GetNormal(grid[w][d],grid[w+1][d],grid[w][d-1])+
GetNormal(grid[w][d],grid[w+1][d],grid[w][d+1])+
GetNormal(grid[w][d],grid[w-1][d],grid[w][d+1]))/4
end
end
end
local v,c,n={},{},{}
col=color(62, 208, 72, 255)
for w=1,ws do
for d=1,ds do
local v1,v2,v3,v4=grid[w-1][d-1],grid[w][d-1],grid[w][d],grid[w-1][d]
local n1,n2,n3,n4=gn[w-1][d-1],gn[w][d-1],gn[w][d],gn[w-1][d]
local c1,c2,c3,c4=col,col,col,col
v[#v+1]=v1 n[#n+1]=n1 c[#c+1]=c1
v[#v+1]=v2 n[#n+1]=n2 c[#c+1]=c2
v[#v+1]=v3 n[#n+1]=n3 c[#c+1]=c3
v[#v+1]=v3 n[#n+1]=n3 c[#c+1]=c3
v[#v+1]=v4 n[#n+1]=n4 c[#c+1]=c4
v[#v+1]=v1 n[#n+1]=n1 c[#c+1]=c1
end
end
local m=mesh()
m.vertices=v
m.normals=n
m.colors=c
m.shader=shader(LightingShader.v,LightingShader.f)
m.shader.directDirection=vec4(0,3,0,0):normalize()
m.shader.ambientColor=color(255)*0.3
m.shader.directColor=color(255)*0.7
m.shader.fog=500000
m.shader.mistColor=backgroundColor
return m
end
function GetNormal(v1,v2,v3)
local a,b=v1-v3,v2-v3
return (a:cross(b)):normalize()
end
displayMode(NORMAL)
function setup()
backgroundColor=color(154, 197, 208, 255)
camPos=vec3(0,100,50)
camLook=vec3(500,50,-500)
camDist,camAngle,deltaAngle=100,0,0.01
terrain=MakeTerrain(vec3(0,0,0),1000,1000,100,10,0.06)
ax,ay=0,0
tank=BuildTank(color(150, 189, 128, 255))
end
function draw()
background(backgroundColor)
perspective()
camAngle=camAngle+deltaAngle
camPos.x,camPos.z=camLook.x+camDist*math.cos(camAngle),camLook.z-camDist*math.sin(camAngle)
camera(camPos.x,camPos.y,camPos.z,camLook.x,camLook.y,camLook.z)
terrain.shader.mModel=modelMatrix()
terrain.shader.camPos=camPos
terrain:draw()
translate(500,50,-500)
for _,t in pairs(tank) do
t.shader.mModel=modelMatrix()
t.shader.camPos=camPos
t:draw()
end
end
--# Utility
--Utility
function CreateBlock(w,h,d,col,pos,tex,ms) --width,height,depth,colour,position,texture
pos=pos or vec3(0,0,0)
local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
end
local n={vec3(0,0,1),vec3(1,0,0),vec3(0,0,-1),vec3(-1,0,0),vec3(0,1,0),vec3(0,-1,0)}
local norm={}
for i=1,6 do for j=1,6 do norm[#norm+1]=n[i] end end
if not ms then ms=mesh() end
if ms.size==0 then
ms.vertices=vert
ms.normals=norm
if tex then ms.texture,ms.texCoords=tex,texCoords end
else
for i=1,#vert do
table.insert(ms.vertices,vert[i])
table.insert(ms.normals,norm[i])
if tex then table.insert(ms.texCoords,texCoords[i]) end
end
end
ms:setColors(col or color(255))
return ms
end
function AddBlock(w,h,d,col,pos,rot,texture,vertices,texCoords,normals,colors) --width,height,depth,colour,position,texture
local x,X,y,Y,z,Z=-w/2,w/2,-h/2,h/2,-d/2,d/2
local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
if rot then
m=modelMatrix()
m=m:translate(pos:unpack())
m=m:rotate(rot.x,1,0,0) m=m:rotate(r.y,0,1,0) m=m:rotate(r.z,0,0,1)
for i=1,#vert do vertices[#vertices+1]=m*vert[i] end
else
for i=1,#vert do vertices[#vertices+1]=pos+vert[i] end
end
local tex
if texture then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
tex={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
for i=1,#tex do texCoords[#texCoords+1]=tex[i] end
end
local n={vec3(0,0,1),vec3(1,0,0),vec3(0,0,-1),vec3(-1,0,0),vec3(0,1,0),vec3(0,-1,0)}
for i=1,6 do
for j=1,6 do
normals[#normals+1]=n[i]
colors[#colors+1]=col
end
end
return vertices,texCoords,normals,colors
end
--# Shaders
--Shaders
TankShader={
v=[[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec4 directColor;
uniform vec4 directDirection;
uniform vec4 ambientColor;
uniform float offset;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;
void main()
{
gl_Position = modelViewProjection * position;
vTexCoord = vec2(texCoord.x+offset,texCoord.y);
vec4 norm = normalize(mModel * vec4( normal, 0.0 ));
float diffuse = max( 0.0, dot( norm, directDirection ));
vPosition = mModel*position;
vColor = diffuse * directColor + ambientColor;
}
]],
f=[[
precision highp float;
uniform lowp sampler2D texture;
uniform float offset2;
uniform vec4 mistColor;
uniform float fog;
uniform vec3 camPos;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;
void main()
{
vec4 col = texture2D(texture, vec2(mod(vTexCoord.x+offset2,1.0),mod(vTexCoord.y,1.0)))*vColor;
float f = clamp(distance(vPosition.xyz,camPos)/fog,0.0,1.0);
col = mix( col, mistColor, f);
col.a=1.0;
gl_FragColor=col;
}
]]}
TreeShader={
v=[[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec2 texCoord;
varying highp vec2 vTexCoord;
void main()
{
gl_Position = modelViewProjection * position;
vTexCoord = texCoord;
}
]],
f=[[
precision highp float;
uniform lowp sampler2D texture;
uniform vec4 mistColor;
uniform float visibility;
varying highp vec2 vTexCoord;
void main()
{
vec4 col = texture2D(texture,vTexCoord);
if (col.a<0.05) discard;
else {
col=mix(mistColor,col,visibility);
gl_FragColor=col;
}
}
]]}
LightingShader={
v=[[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
uniform vec4 directColor;
uniform vec4 directDirection;
uniform vec4 ambientColor;
uniform float fog;
uniform vec4 mistColor;
uniform vec3 camPos;
attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
varying lowp vec4 vColor;
void main()
{
gl_Position = modelViewProjection * position;
vec4 norm = normalize(mModel * vec4( normal, 0.0 ));
float diffuse = max( 0.0, dot( norm, directDirection ));
vec4 p=mModel*position;
float f = clamp(distance(p.xyz,camPos)/fog,0.0,1.0);
vColor = mix(color * ( diffuse * directColor + ambientColor ),mistColor,f);
vColor.a=1.0;
}
]],
f=[[
precision highp float;
varying lowp vec4 vColor;
void main()
{
gl_FragColor=vColor;
}
]]}
--Tile
TileShader = {
v = [[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
attribute vec4 position;
attribute vec2 texCoord;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;
void main()
{
vTexCoord = texCoord;
vPosition=mModel*position;
gl_Position = modelViewProjection * position;
}
]],
f = [[
precision highp float;
uniform lowp sampler2D texture;
uniform float fog;
uniform vec4 mistColor;
uniform vec3 camPos;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;
void main()
{
lowp vec4 col = texture2D(texture, vec2(mod(vTexCoord.x,1.0),mod(vTexCoord.y,1.0)));
float f = clamp(distance(vPosition.xyz,camPos)/fog,0.0,1.0);
gl_FragColor = mix(col,mistColor,f);
}
]]}
--# Terrain2
--Terrain2
local atan,rand,min,max,cos=math.atan,math.random,math.min,math.max,math.cos
local rad=math.pi/180
local Terrain={}
function MakeTerrain()
local w,d,pic,f=1000,1000,"Dropbox:3D-grass2x",.02
LoadImages()
local floor=mesh()
local img=readImage(pic)
floor.texture=img
local wn,dn=w/img.width/f,d/img.height/f
floor.vertices={vec3(0,0,0),vec3(w,0,0),vec3(w,0,-d),vec3(w,0,-d),vec3(0,0,-d),vec3(0,0,0)}
floor.texCoords={vec2(0,0),vec2(wn,0),vec2(wn,dn),vec2(wn,dn),vec2(0,dn),vec2(0,0)}
floor=SetLighting(floor,TileShader)
local trees={}
for i=1,400 do
table.insert(trees,AddBillboard(0,0,w,-d,treeImages,0.15))
end
Terrain={floor=floor,trees=trees}
end
function LoadImages()
treeImages={readImage("Dropbox:3D-tree"),readImage("Dropbox:3D-tree3"),readImage("Dropbox:3D-tree7"),
readImage("Dropbox:3D-tree8")}
end
function AddBillboard(x1,z1,x2,z2,imgList,f)
local i=rand(1,#imgList)
local h=0.5+rand()
local w=imgList[i].width*h*f --width
local pos=vec3(rand(x1,x2),imgList[i].height*f/4*h,rand(min(z1,z2),max(z1,z2)))
local m=mesh()
m:addRect(0,0,w,imgList[i].height*h*f)
m.texture=imgList[i]
m.shader=shader(TreeShader.v,TreeShader.f)
m.shader.mistColor=backgroundColor
return {m=m,pos=pos,r=w/2}
end
--[[
function DrawBillboards(billboards)
local PM1=projectionMatrix()[1]
local lookPos=camPos+(camLook-camPos):normalize()*5000
for _,b in pairs(billboards) do
if lineDistB(b.pos,camPos,lookPos)-b.r>camPos:dist(b.pos)/PM1 then b.pov=0 else b.pov=1 end
b.visibility=max(0,1-b.pos:dist(camPos)/fogRange)
end
--calc distance to camera and sort from furthest to nearest, every two seconds
if ElapsedTime>(lastSort or -9) +2 then
--for _,b in pairs(billboards) do b.visibility=max(0,1-b.pos:dist(camPos)/fogRange) end
table.sort(billboards,function(a,b) return a.visibility<b.visibility end)
lastSort=ElapsedTime
end
for i=1,#billboards do
local b=billboards[i]
if b.visibility*b.pov>0 then
pushMatrix()
--move to the centre of our image
local p=b.pos
translate(p:unpack())
--calculate difference in x and z
local dx,dz=p.x-camPos.x,-p.z+camPos.z
--calculate angle we need to turn
local ang=atan(dx/-dz)/rad
--turn and draw
rotate(ang,0,1,0) --print(i,-ang)
b.m.shader.visibility=b.visibility
b.m:draw()
popMatrix()
end
end
end
--]]
function DrawTerrain()
Terrain.floor.shader.camPos=camPos
Terrain.floor:draw()
DrawBillboards(Terrain.trees,camPos)
end
function LookAt(source,target)
local z=(source-target):normalize()
local x=(vec3(0,1,0):cross(z)):normalize()
local y=(z:cross(x)):normalize()
return matrix(x.x,x.y,x.z,0, y.x,y.y,y.z,0, z.x,z.y,z.z,0, source.x,source.y,source.z,1)
end
function GetScreenRect(t1,t2,s) --t1 is camera, t2 is target, s is vec3 size of object
--get direction and distance
local v=(t2.pos-t1.pos)
local d=v:len()-u/2 --position of t2 is assumed to be its centre, so adjust by 1\2 depth
v=v/d
--get drawing rectangle
local w = u*WIDTH*projectionMatrix()[1]/d/2
local h = s.y*HEIGHT*projectionMatrix()[6]/d/2
--draw our tank
local m = modelMatrix()*viewMatrix()*projectionMatrix()
--m = m:translate(0,0,-d)
local X,Y=(m[13]/m[16]+1)*WIDTH/2, (m[14]/m[16]+1)*HEIGHT/2
return X-w/2,Y-h/2,w,h
end
function DrawBillboards(billboards)
local PM1=projectionMatrix()[1]
--local lookPos=camPos+(camLook-camPos):normalize()*5000
for _,b in pairs(billboards) do
b.pov=IsVisible(b.pos,camPos,camLook,b.r)
b.visibility=max(0,1-b.pos:dist(camPos)/fogRange)
end
--calc distance to camera and sort from furthest to nearest, every two seconds
if ElapsedTime>(lastSort or -9) +2 then
--for _,b in pairs(billboards) do b.visibility=max(0,1-b.pos:dist(camPos)/fogRange) end
table.sort(billboards,function(a,b) return a.visibility<b.visibility end)
lastSort=ElapsedTime
end
for i=1,#billboards do
local b=billboards[i]
if b.pov and b.visibility>0 then
pushMatrix()
--move to the centre of our image
local p=b.pos
translate(p:unpack())
--calculate difference in x and z
local dx,dz=p.x-camPos.x,-p.z+camPos.z
--calculate angle we need to turn
local ang=atan(dx/-dz)/rad
--turn and draw
rotate(ang,0,1,0) --print(i,-ang)
b.m.shader.visibility=b.visibility
b.m:draw()
popMatrix()
end
end
end
function IsVisible(pos,camPos,camLook,radius)
local xDist=(pos-camPos):dist(math.max(math.min((pos-camPos):dot(camLook-camPos)/
(camLook-camPos):lenSqr(),1),0)*(camLook-camPos))
return xDist-radius<camPos:dist(pos)/projectionMatrix()[1]
end
--# Model2
--Model2
Tank=class()
Tank.turretMaxAngle=40
Tank.barrelMaxAngles=vec2(-3,20)
Tank.width=19
Tank.colors={color(158, 171, 48, 255),color(74, 81, 45, 255)}
function Tank:init()
if not Tank.model then
Tank.LoadTextures()
Tank.CreateModel()
end
self.trackOffset=0
self.turretAngle=0
self.gunAngle=0
self.health=100
self.speed=0.25
self.angle=-90
self.rad=math.rad(self.angle)
self.pos=vec3(0,0,0)
self.offset2=math.random()
end
function Tank:draw(camPos,camLook)
self.trackOffset=self.trackOffset-self.speed/200
self.pos=self.pos+vec3(math.cos(self.rad),0,math.sin(self.rad))*self.speed
if not IsVisible(self.pos,camPos,camLook,Tank.width/2) then return end
local m=Tank.model
m.track.shader.offset=self.trackOffset
pushMatrix()
translate(self.pos:unpack())
rotate(self.angle,0,1,0)
Tank.Wobble()
m.wheels.shader.mModel=modelMatrix()
m.wheels.shader.camPos=camPos
m.wheels:draw()
m.track.shader.mModel=modelMatrix()
m.track.shader.camPos=camPos
m.track:draw()
m.body.shader.mModel=modelMatrix()
m.body.shader.camPos=camPos
m.body.shader.offset2=self.offset2
m.body:draw()
rotate(self.turretAngle,0,1,0)
m.turret.shader.mModel=modelMatrix()
m.turret.shader.camPos=camPos
m.turret.shader.offset2=self.offset2
m.turret:draw()
translate(-3.8,5.75,0)
rotate(self.gunAngle,0,0,1)
m.barrel.shader.mModel=modelMatrix()
m.barrel.shader.camPos=camPos
m.barrel.shader.offset2=self.offset2
m.barrel:draw()
popMatrix()
end
function Tank:rotate(a)
self.angle=self.angle+a
self.rad=math.rad(self.angle)
end
function Tank.Wobble()
local f=.1
local a,b=ElapsedTime*f,ElapsedTime*math.pi*f
rotate(10*noise(a,b),1,0,0)
rotate(3*noise(b,a),0,0,1)
end
function Tank.LoadTextures()
Tank.texBody=readImage("Dropbox:Tank_Body")
if not Tank.texBody then
local w,h,f=400,400,5
local img1=image(w,h)
for i=1,w do
for j=1,h do
local m=(noise(i/w*f,j/h*f)+1)/2
img1:set(i,j,Tank.colors[1]:mix(Tank.colors[2],m))
end
end
saveImage("Dropbox:Tank_Body",img1)
Tank.texBody=img1
end
--Track-------
Tank.texTrack=readImage("Dropbox:Tank_Track")
if not Tank.texTrack then
local img=image(50,5)
setContext(img)
pushStyle()
noSmooth()
background(123, 122, 122, 255)
stroke(25)
strokeWidth(0.5)
for i=1,img.width do
line(i,0,i,5)
end
popStyle()
setContext()
saveImage("Dropbox:Tank_Track",img)
Tank.texTrack=img
end
--Wheel-------
Tank.texWheel=readImage("Dropbox:Tank_Wheel")
if not Tank.texWheel then
img=image(100,10)
local col=Tank.colors[1]*2/3+Tank.colors[2]/3 col.a=255
print(col)
setContext(img)
background(0)
pushStyle()
noSmooth()
fill(col)
stroke(Tank.colors[2])
strokeWidth(2)
for i=1,4 do
ellipse(i*26-11,10,20)
end
fill(Tank.colors[2])
for i=1,4 do
ellipse(i*26-11,10,4)
end
fill(col)
for i=1,3 do
ellipse(2+i*26,9,20)
end
fill(Tank.colors[2])
for i=1,4 do
ellipse(2+i*26,9,4)
end
popStyle()
setContext()
saveImage("Dropbox:Tank_Wheel",img)
Tank.texWheel=img
end
end
function Tank.CreateModel()
local x1,x2,x3,y1,y2,y3,z1,z2,z3,z4,f1,f2
--body of tank
local body=mesh()
local v,t,c={},{},{}
x1,x2,y,z1,z2=-8.25,8.25,4.5,3.5,-3.5 --deck
v[#v+1]=vec3(x1,y,z1) v[#v+1]=vec3(x2,y,z1) v[#v+1]=vec3(x2,y,z2)
v[#v+1]=vec3(x2,y,z2) v[#v+1]=vec3(x1,y,z2) v[#v+1]=vec3(x1,y,z1)
x,y1,y2,z1,z2=8.25,2,4.5,3.5,-3.5 --back
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x,y1,z2) v[#v+1]=vec3(x,y2,z2)
v[#v+1]=vec3(x,y2,z2) v[#v+1]=vec3(x,y2,z1) v[#v+1]=vec3(x,y1,z1)
x1,x2,y1,y2,z1,z2,z3,z4=-11,-8.25,3,4.5,-4.5,4.5,-3.5,3.5 --front #2 angle
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z4)
v[#v+1]=vec3(x2,y2,z4) v[#v+1]=vec3(x2,y2,z3) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,y3,z1,z2=-8.25,8.25,2,2,3.5,4.5,-4.5 --sides
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x2,y3,z1)
v[#v+1]=vec3(x2,y3,z1) v[#v+1]=vec3(x1,y3,z1) v[#v+1]=vec3(x1,y1,z1)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x1,y3,z2)
v[#v+1]=vec3(x1,y3,z2) v[#v+1]=vec3(x2,y3,z2) v[#v+1]=vec3(x2,y2,z2)
x1,x2,y1,y2,z1,z2=-8.25,8.25,3.5,4.5,4.5,3.5
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x1,y2,z2) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,z1,z2=8.25,-8.25,3.5,4.5,-4.5,-3.5
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x1,y2,z2) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,z1,z2=-10,7.25,1,-2.5,2.5 --underneath
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x2,y1,z2)
v[#v+1]=vec3(x2,y1,z2) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x1,y1,z1)
x,y1,y2,z1,z2=-11,2,3,-4.5,4.5 --front bottom
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x,y1,z2) v[#v+1]=vec3(x,y2,z2)
v[#v+1]=vec3(x,y2,z2) v[#v+1]=vec3(x,y2,z1) v[#v+1]=vec3(x,y1,z1)
x1,x2,y1,y2,z1,z2=-10,-11,1,2,-2.5,2.5 --front under slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,y1,y2,z1,z2=7.25,8.25,1,2,2.5,-2.5 --back under slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
x1,x2,x3,y1,y2,y3,z1,z2=-11,-8.25,-8.25,3,2,3.5,4.5,3.5 --fill the cracks
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x3,y3,z1)
z1=-4.5
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x3,y3,z1) v[#v+1]=vec3(x2,y2,z1)
x1,x2,x3,y1,y2,y3,z1=-11,-11,-8.25,3,2,2,4.5
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x3,y3,z1)
z1=-4.5
v[#v+1]=vec3(x,y1,z1) v[#v+1]=vec3(x3,y3,z1) v[#v+1]=vec3(x2,y2,z1)
x1,x2,y1,y2,y3,z1,z2=-11,-8.25,3,3.5,4.5,4.5,3.5
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x2,y3,z2)
v[#v+1]=vec3(x1,y1,-z1) v[#v+1]=vec3(x2,y3,-z2) v[#v+1]=vec3(x2,y2,-z1)
x1,y1,y2,z1,z2=8.25,5.5,6.5,3.5,-3.5
x1,y1,y2,z1,z2=8.25,2,3.5,4.5,3.5
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x1,y2,z2)
v[#v+1]=vec3(x1,y2,z2) v[#v+1]=vec3(x1,y2,z1) v[#v+1]=vec3(x1,y1,z1)
v[#v+1]=vec3(x1,y1,-z1) v[#v+1]=vec3(x1,y2,-z2) v[#v+1]=vec3(x1,y1,-z2)
v[#v+1]=vec3(x1,y2,-z2) v[#v+1]=vec3(x1,y1,-z1) v[#v+1]=vec3(x1,y2,-z1)
x1,y1,y2,z1,z2=8.25,3.5,4.5,4.5,3.5
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x1,y2,z2)
z1,z2=-3.5,-4.5
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x1,y2,z1)
body.vertices=v
body:setColors(color(90))
body.texture=Tank.texBody
body.name="body"
--tracks
local track,v,t=mesh(),{},{}
local f=.05
x1,x2,y1,y2,z1,z2,f1,f2=8.25,8.25,1,2,4.5,2.5,0,f*2 --back right vert
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f2,1)
t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f1,0)
z1,z2=-2.5,-4.5 --back left vert
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f2,1)
t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f1,0)
x1,x2,y1,y2,z1,z2,f1,f2=7.25,8.25,0,1,4.5,2.5,f*2,f*4 --back right slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f2,1)
t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f1,0)
z1,z2=-2.5,-4.5 --back left slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f2,1)
t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f1,0)
x1,x2,y1,y2,z1,z2,f1,f2=-9,-11,0,2,2.5,4.5,0,f*2 --front right slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f1,1)
t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f2,0)
z1,z2=-4.5,-2.5 --front left slant
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y2,z2)
v[#v+1]=vec3(x2,y2,z2) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f1,1)
t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f2,0)
x1,x2,y1,y2,z1,z2,f1,f2=-9,7.25,0,0,4.5,2.5,4*f,20.25*f --bottom right track
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y1,z2)
v[#v+1]=vec3(x2,y1,z2) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f2,1)
t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f1,0)
z1,z2=-2.5,-4.5 --bottom left track
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y1,z2) v[#v+1]=vec3(x2,y1,z2)
v[#v+1]=vec3(x2,y1,z2) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x1,y1,z1)
t[#t+1]=vec2(f1,0) t[#t+1]=vec2(f1,1) t[#t+1]=vec2(f2,1)
t[#t+1]=vec2(f2,1) t[#t+1]=vec2(f2,0) t[#t+1]=vec2(f1,0)
track.vertices=v
track.texCoords=t
track:setColors(color(40))
track.texture=Tank.texTrack
track.name="track"
wheels,v,t=mesh(),{},{}
x1,x2,y1,y2,z1=-11,-9,2,0,4
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x2,y1,z1)
x1,x2,y1,y2,z1=-9,7.25,2,0,4
v[#v+1]=vec3(x1,y2,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x2,y1,z1)
v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y2,z1)
x1,x2,y1,y2,y3,z1=7.25,8.25,0,1,2,4
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y3,z1)
v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x2,y3,z1) v[#v+1]=vec3(x1,y3,z1)
x1,x2,y1,y2,z1=-11,-9,2,0,-4
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x2,y2,z1)
x1,x2,y1,y2,z1=-9,7.25,2,0,-4
v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y2,z1) v[#v+1]=vec3(x1,y1,z1)
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x2,y1,z1) v[#v+1]=vec3(x2,y2,z1)
x1,x2,y1,y2,y3,z1=7.25,8.25,0,1,2,-4
v[#v+1]=vec3(x1,y1,z1) v[#v+1]=vec3(x1,y3,z1) v[#v+1]=vec3(x2,y2,z1)
v[#v+1]=vec3(x2,y2,z1) v[#v+1]=vec3(x1,y3,z1) v[#v+1]=vec3(x2,y3,z1)
for i=1,#v/2 do t[#t+1]=vec2((v[i].x+11)/19,v[i].y/2) end
for i=#v/2+1,#v do t[#t+1]=vec2(-(8.25-v[i].x)/19,v[i].y/2) end
wheels.vertices=v
wheels.texCoords=t
wheels:setColors(color(255,0,0))
wheels.texture=Tank.texWheel
wheels.name="wheels"
local turret,v=mesh(),{}
local h,y,slope=2.5,4.5,0.5
local p={vec3(-4,0,1.5),vec3(0,0,3.5),vec3(2,0,3),vec3(4,0,1),vec3(4,0,-1),
vec3(2,0,-3),vec3(0,0,-3.5),vec3(-4,0,-1.5)}
for i=1,#p do p[i].y=y+(p[i].x/8+0.5)*slope end
for i=1,#p do
local a,b=p[i],p[i+1] or p[1]
v[#v+1]=vec3(a.x,y,a.z)
v[#v+1]=vec3(b.x,y,b.z)
v[#v+1]=vec3(b.x,b.y+h,b.z)
v[#v+1]=vec3(b.x,b.y+h,b.z)
v[#v+1]=vec3(a.x,a.y+h,a.z)
v[#v+1]=vec3(a.x,y,a.z)
end
local norm={}
for i=1,#v do norm[i]=v[i]:normalize() end
--roof
for i=1,#p do
local a,b=p[i],p[i+1] or p[1]
v[#v+1]=vec3(a.x,a.y+h,a.z)
v[#v+1]=vec3(b.x,b.y+h,b.z)
v[#v+1]=vec3(0,y+h+slope/2,0)
for j=1,3 do norm[#norm+1]=vec3(0,1,0) end
end
turret.vertices=v
turret.normals=norm
turret:setColors(color(90))
turret.texture=Tank.texBody
turret.name="turret"
barrel,p,v,norm=mesh(),{},{},{}
local x1,x2,r1,r2,y=-4,-7,0.75,0.4,7.75
for i=1,8 do p[i]=vec3(0,math.cos(i*math.pi/4),math.sin(i*math.pi/4)) end
for i=1,8 do
local p1,p2=p[i],p[i+1] or p[1]
v[#v+1]=vec3(x1,y+p1.y*r1,p1.z*r1)
v[#v+1]=vec3(x2,y+p1.y*r2,p1.z*r2)
v[#v+1]=vec3(x2,y+p2.y*r2,p2.z*r2)
v[#v+1]=vec3(x2,y+p2.y*r2,p2.z*r2)
v[#v+1]=vec3(x1,y+p2.y*r1,p2.z*r1)
v[#v+1]=vec3(x1,y+p1.y*r1,p1.z*r1)
end
local x1,x2,r1,r2,y=-7,-17,0.4,0.3,7.75
for i=1,8 do p[i]=vec3(0,math.cos(i*math.pi/4),math.sin(i*math.pi/4)) end
for i=1,8 do
local p1,p2=p[i],p[i+1] or p[1]
v[#v+1]=vec3(x1,y+p1.y*r1,p1.z*r1)
v[#v+1]=vec3(x2,y+p1.y*r2,p1.z*r2)
v[#v+1]=vec3(x2,y+p2.y*r2,p2.z*r2)
v[#v+1]=vec3(x2,y+p2.y*r2,p2.z*r2)
v[#v+1]=vec3(x1,y+p2.y*r1,p2.z*r1)
v[#v+1]=vec3(x1,y+p1.y*r1,p1.z*r1)
end
for i=1,#v do norm[i]=(v[i]-vec3(v[i].x,y,0)):normalize() end
for i=1,#v do v[i].x,v[i].y=v[i].x+4,v[i].y-7.75 end
barrel.vertices=v
barrel.normals=norm
barrel:setColors(color(90))
barrel.texture=Tank.texBody
barrel.name="barrel"
print("vertices=",body.size+track.size+turret.size+barrel.size+wheels.size)
local tank={body=body,track=track,turret=turret,barrel=barrel,wheels=wheels}
for _,m in pairs(tank) do
local norm={}
local nn=m:buffer("normal")
if nn[1]==nil then
local v=m:buffer("position")
for i=1,m.size,3 do
local v1,v2=v[i]-v[i+2],v[i+1]-v[i+2]
local n=(v1:cross(v2)):normalize()
norm[i],norm[i+1],norm[i+2]=n,n,n
end
m.normals=norm
end
if m.texture==Tank.texBody then
local t={}
local v=m:buffer("position")
for i=1,m.size do
t[i]=vec2(v[i].x/8+v[i].y/5,v[i].z/6+v[i].y/9)/2
end
m.texCoords=t
end
m=SetLighting(m)
m.shader.offset2=0
end
Tank.model=tank
end
--# Main
-- Tiger
displayMode(FULLSCREEN)
function setup()
backgroundColor=color(129, 162, 201, 255)
T=Tank()
T.speed=0
camPos=vec3(0,10,30)
ax,ay=0,0
da=0.1
end
function draw()
background(backgroundColor)
perspective()
camera(camPos.x,camPos.y,camPos.z,0,0,0)
rotate(ay,0,1,0) rotate(ax,1,0,0)
--T.turretAngle=T.turretAngle+0.5
--T.gunAngle=T.gunAngle-da
--if -T.gunAngle<T.turretMaxAngles[1] or -T.gunAngle>T.turretMaxAngles[2] then da=-da end
T:draw(camPos)
end
function touched(t)
if t.state~=ENDED then
ay,ax=ay+t.deltaX,ax+t.deltaY
end
end
function SetLighting(m,s)
local s=s or TankShader
m.shader=shader(s.v,s.f)
m.shader.directDirection=vec4(-1,1,1,0):normalize()
m.shader.ambientColor=color(255)*0.3
m.shader.directColor=color(255)*0.7
m.shader.fog=5000
m.shader.mistColor=backgroundColor
m.shader.offset=0
return m
end
--# Main2
-- Tiger2
displayMode(FULLSCREEN)
function setup()
backgroundColor=color(255)
fogRange=5000
FOV=45
-- angleFOV=math.cos(math.rad(FOV/2*WIDTH/HEIGHT))
T={}
for j=1,20 do
T[j]=Tank()
T[j].pos=vec3(500+math.random(-40,40),0.5,-900+j*40)
T[j].turretAngle=0
T[j]:rotate(180)
T[j].turretAngle=math.random(-35,35)
T[j].gunAngle=math.random(0,5)
T[j].turretAngleChange=0.25
T[j].gunAngleChange=0.1
end
camPos=vec3(500,10,-200)
camLook=vec3(0,0,0)
camAngle=math.pi/2
speed=0
maxSpeed=1
FPS=60
MakeTerrain()
joy=JoyStick({damp=nil})
end
function draw()
background(backgroundColor)
FPS=FPS*0.9+0.1/DeltaTime
perspective(FOV)
local d=joy:update()
camAngle=camAngle-d.x/60
speed=d.y/2
local v=vec3(math.cos(camAngle),0,-math.sin(camAngle))
camPos=camPos+v*speed
camLook=camPos+v*5000
camera(camPos.x,camPos.y,camPos.z,camLook.x,camLook.y,camLook.z)
for _,t in pairs(T) do
a=t.turretAngle+t.turretAngleChange
if math.abs(a)>Tank.turretMaxAngle then t.turretAngleChange=-t.turretAngleChange end
t.turretAngle=t.turretAngle+t.turretAngleChange
local a=t.gunAngle+t.gunAngleChange
if -a<Tank.barrelMaxAngles[1] or -a>Tank.barrelMaxAngles[2] then
t.gunAngleChange=-t.gunAngleChange
end
t.gunAngle=t.gunAngle+t.gunAngleChange
t:draw(camPos,camLook)
end
DrawTerrain(camPos)
joy:draw()
ortho()
viewMatrix(matrix())
fill(0)
fontSize(18)
text("FPS: "..math.floor(FPS),50,50)
end
function SetLighting(m,s)
s=s or TankShader
m.shader=shader(s.v,s.f)
m.shader.directDirection=vec4(-2,2,1,0):normalize()
m.shader.ambientColor=color(255)*0.5
m.shader.directColor=color(255)*0.5
m.shader.fog=fogRange
m.shader.mistColor=backgroundColor
m.shader.offset=0
m.shader.mModel=modelMatrix()
return m
end
function touched(t)
--if t.state~=ENDED then
-- camAngle=camAngle+t.deltaX/300
--end
joyTouched=joy:touched(t)
end
--# Controls
--joystick
JoyStick = class()
local tick=1/60
--Note all the options you can set below. Pass them through in a named table
function JoyStick:init(t)
t = t or {}
self.radius = t.radius or 100 --size of joystick on screen
self.stick = t.stick or 30 --size of inner circle
self.centre = t.centre or self.radius * vec2(1,1) + vec2(5,5)
self.damp=nil
self.position = vec2(0,0) --initial position of inner circle
self.target = vec2(0,0) --current position of inner circle (used when we interpolate movement)
self.value = vec2(0,0)
self.delta = vec2(0,0)
self.mspeed = 30
self.moving = 0
end
function JoyStick:draw()
ortho()
viewMatrix(matrix())
pushStyle()
fill(160, 182, 191, 1)
stroke(118, 154, 195, 100) stroke(0,0,0,25)
strokeWidth(3)
ellipse(self.centre.x,self.centre.y,2*self.radius)
fill(78, 131, 153, 1)
ellipse(self.centre.x+self.position.x, self.centre.y+self.position.y, self.stick*2)
popStyle()
end
function JoyStick:touched(t)
if t.state == BEGAN then
local v = vec2(t.x,t.y)
if v:dist(self.centre)<self.radius-self.stick then
self.touch = t.id
--else return false
end
end
if t.id == self.touch then
if t.state~=ENDED then
local v = vec2(t.x,t.y)
if v:dist(self.centre)>self.radius-self.stick then
v = (v - self.centre):normalize()*(self.radius - self.stick) + self.centre
end --set x,y values for joy based on touch
self.target=v - self.centre
else --reset joystick to centre when touch ends
self.target=vec2(0,0)
self.touch = false
end
else return false
end
return true
end
function JoyStick:update()
local p = self.target - self.position
if p:len() < tick * self.mspeed then
self.position = self.target
if not self.touch then
if self.moving ~= 0 then
self.moving = self.moving - 1
end
else
self.moving = 2
end
else
self.position = self.position + p:normalize() * tick * self.mspeed
self.moving = 2
end
local v=self.position/(self.radius - self.stick)
return self:Dampen(v)
end
function JoyStick:Dampen(v)
if not self.damp then return v end
if v.x>0 then v.x=math.max(0,(v.x-self.damp.x)/(1-self.damp.x))
else v.x=math.min(0,(v.x+self.damp.x)/(1-self.damp.x)) end
if v.y>0 then v.y=math.max(0,(v.y-self.damp.y)/(1-self.damp.y))
else v.y=math.min(0,(v.y+self.damp.y)/(1-self.damp.y)) end
return v
end
function JoyStick:isMoving()
return self.moving
end
function JoyStick:isTouched()
return self.touch
end
--# Test8
--[[
function setup()
perspective()
camPos=vec3(100,0,-50) print("camPos",camPos)
look=vec3(0,0,-1) print("look",look)
pos=vec3(-200,0,-1000) print("pos",pos)
r=25 print("r",r)
d=camPos:dist(pos) print("d",d)
local lookX=camPos.x+look.x*d print("lookX",lookX)
local limit=d/2/projectionMatrix()[1] print("PM1",projectionMatrix()[1]) print("limit",limit)
local treeDir=(pos-camPos):normalize() print("treeDir",treeDir)
local treeWidth=treeDir.z*r print("treeWidth",treeWidth)
local x0=pos.x print("x0",x0)
local x1,x2=x0-treeWidth,x0+treeWidth print("x1",x1) print("x2",x2)
print("<x0",math.abs(lookX-x0))
print("<x1",math.abs(lookX-x1))
print("<x2",math.abs(lookX-x2))
end
function draw()
background(0)
--sprite(img1,300,300)
end
--]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment