-- $Id: UnitSmoke.lua 3171 2008-11-06 09:06:29Z det $ ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- local UnitSmoke = {} UnitSmoke.__index = UnitSmoke local UnitSmokeShader local widthLoc, timeLoc, headingLoc local trailDirsUniform = {} ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function UnitSmoke.GetInfo() return { name = "UnitSmoke", backup = "", --// backup class, if this class doesn't work (old cards,ati's,etc.) desc = "", layer = 1, --// extreme simply z-ordering :x --// gfx requirement fbo = false, shader = true, rtt = false, ctt = false, } end UnitSmoke.Default = { layer = 1, life = math.huge, pos = {0,0,0}, size = 20, width = 5, quads = 10, --//max 16 repeatEffect = false, dieGameFrame = math.huge } ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- local glUniform = gl.Uniform local glUseShader = gl.UseShader ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function UnitSmoke:BeginDraw() glUseShader(UnitSmokeShader) glUniform(timeLoc, thisGameFrame * 0.01 ) gl.Texture(1,"bitmaps/GPL/Lups/mynoise.png") gl.Texture(0,":c:bitmaps/GPL/Lups/smoketrail.png") --gl.Texture(0,":c:bitmaps/GPL/Lups/flametrail.png") --gl.Texture(0,":c:bitmaps/GPL/Lups/firetrail.png") --gl.Texture(false) --gl.Blending(GL.SRC_ALPHA,GL.ONE) local modelview = {gl.GetMatrixData("camera")} gl.MatrixMode(GL.TEXTURE) gl.PushMatrix() gl.LoadMatrix(modelview) --//FIXME: gl.MultMatrix("camera") gl.MatrixMode(GL.MODELVIEW) gl.PushMatrix() gl.LoadIdentity() --gl.PolygonMode(GL.FRONT_AND_BACK, GL.LINE) end function UnitSmoke:EndDraw() glUseShader(0) --gl.Blending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA) gl.Texture(0,false) gl.Texture(1,false) gl.MatrixMode(GL.TEXTURE) gl.PopMatrix() gl.MatrixMode(GL.MODELVIEW) gl.PopMatrix() gl.PolygonMode(GL.FRONT_AND_BACK, GL.FILL) end function UnitSmoke:Draw() local pos = self.pos glUniform(widthLoc, self.width ) glUniform(headingLoc, Spring.GetUnitHeading(self.unit)/32000 ); local quads = self.quads-1 --// "-1" cause glsl is 0-indexed and lua 1-indexed for i=1,quads+1 do local dir = self.trailDirs[i] glUniform( trailDirsUniform[i] , dir[1], dir[2] + self.size*(i-1)/quads , dir[3] ) end gl.PushMatrix() gl.Translate(pos[1],pos[2],pos[3]) gl.BeginEnd(GL.QUADS,function() for i=0,quads-1 do --local tex_t = 1 - self.trailTexCoords[i] / self.totalLength --local tex_t_next = 1 - self.trailTexCoords[i+1] / self.totalLength local tex_t = 1 - i/quads local tex_t_next = 1 - (i+1)/quads gl.TexCoord(-1,tex_t_next,0,i+1) gl.Vertex(0,0,0) gl.TexCoord(1,tex_t_next,1,i+1) gl.Vertex(0,0,0) gl.TexCoord(1,tex_t,1,i) gl.Vertex(0,0,0) gl.TexCoord(-1,tex_t,0,i) gl.Vertex(0,0,0) end end) gl.PopMatrix() end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function UnitSmoke.Initialize() UnitSmokeShader = gl.CreateShader({ vertex = [[ uniform float width; uniform float time; uniform float heading; uniform vec3 traildirs[16]; void main() { vec3 updir,right; gl_Position = (gl_ModelViewMatrix * gl_Vertex); updir = traildirs[int(gl_MultiTexCoord0.w)]; gl_Position.xyz += updir; //gl_TexCoord[0].pq = updir.xy*vec2(0.1) + vec2(heading, -time*3.0); gl_Position = gl_TextureMatrix[0] * gl_Position; updir = ( gl_TextureMatrix[0] * vec4(updir,0.0) ).xyz - gl_Position.xyz; right = normalize( cross(updir,gl_Position.xyz) ); //gl_Position.x += gl_MultiTexCoord0.x * size * 0.35; gl_Position.xyz += right * gl_MultiTexCoord0.x * width; gl_Position = gl_ProjectionMatrix * gl_Position; //gl_FrontColor = vec4(1.0,1.0,1.0,1.0); gl_TexCoord[0].st = gl_MultiTexCoord0.pt; //gl_TexCoord[0].st = gl_Position.xy; gl_TexCoord[0].pq = gl_TexCoord[0].st + vec2(heading, time*3.0); } ]], fragment = [[ uniform sampler2D SmokeTex; uniform sampler2D noiseMap; void main() { vec4 noise = texture2D(noiseMap, gl_TexCoord[0].pq*0.8); //vec4(0.0); gl_FragColor = texture2D(SmokeTex, gl_TexCoord[0].st + vec2( (noise.r-0.5) ,0.0) ); //gl_FragColor.a *= (gl_FragColor.r+gl_FragColor.g+gl_FragColor.b)*0.333; gl_FragColor.a *= 0.9; } ]], uniformInt={ SmokeTex = 0, noiseMap = 1, }, }) if (UnitSmokeShader == nil) then print(PRIO_MAJOR,"LUPS->UnitSmoke: critical shader error: "..gl.GetShaderLog()) return false end widthLoc = gl.GetUniformLocation(UnitSmokeShader, 'width') timeLoc = gl.GetUniformLocation(UnitSmokeShader, 'time') headingLoc = gl.GetUniformLocation(UnitSmokeShader, 'heading') for i=1,16 do trailDirsUniform[i] = gl.GetUniformLocation(UnitSmokeShader,"traildirs["..(i-1).."]") end end function UnitSmoke.Finalize() if (gl.DeleteShader) then gl.DeleteShader(UnitSmokeShader) end end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function UnitSmoke:Update() local vel = {Spring.GetUnitVelocity(self.unit)} vel = Vmul( -1 , vel ) local x,y,z = Spring.GetWind() local wind = Vmul( 0.125 , {z,y,-x} ) self.trailDirs[2] = Vadd( Vadd(vel,wind), {0,2,0}) for i=self.quads,3,-1 do self.trailDirs[i] = Vadd( self.trailDirs[i-1], Vadd(vel,wind) ) end --[[ local tlength = 0 for i=1,16 do tlength = tlength + Vlength( self.trailDirs[i] ) self.trailTexCoords[i] = tlength end self.totalLength = tlength --]] end -- used if repeatEffect=true; function UnitSmoke:ReInitialize() self.dieGameFrame = self.dieGameFrame + self.life end function UnitSmoke:CreateParticle() --[[ self.trailTexCoords = { [0] = 0 } self.totalLength = 0 --]] if (self.quads>16) then self.quads=16 elseif (self.quads<5) then self.quads=5 end self.trailDirs = {} for i=1,self.quads do self.trailDirs[i] = {0,0.05,0} end self.startGameFrame = thisGameFrame self.dieGameFrame = self.startGameFrame + self.life end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- local MergeTable = MergeTable local setmetatable = setmetatable function UnitSmoke.Create(Options) local newObject = MergeTable(Options, UnitSmoke.Default) setmetatable(newObject,UnitSmoke) -- make handle lookup newObject:CreateParticle() return newObject end function UnitSmoke:Destroy() end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- return UnitSmoke