-- $Id: NanoLasers.lua 3357 2008-12-05 11:08:54Z jk $ ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- local NanoLasers = {} NanoLasers.__index = NanoLasers local dlist local laserShader local knownNanoLasers = {} local lastTexture = "" ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function NanoLasers.GetInfo() return { name = "NanoLasers", backup = "NanoLasersNoShader", --// backup class, if this class doesn't work (old cards,ati's,etc.) desc = "", layer = -16, --// extreme simply z-ordering :x --// gfx requirement fbo = false, shader = true, rtt = false, ctt = false, } end NanoLasers.Default = { layer = 0, worldspace = true, repeatEffect = false, --// shared options with all nanofx pos = {0,0,0}, --// start pos targetpos = {0,0,0}, targetradius = 0, --// terraform/unit radius color = {0, 0, 0, 0}, count = 1, inversed = false, --// reclaim? terraform = false, --// for terraform (2d target) unit = -1, nanopiece = -1, --// some unit informations targetID = -1, unitID = -1, unitpiece = -1, unitDefID = -1, teamID = -1, allyID = -1, --// custom (user) options life = 30, flare = false, streamSpeed = 10, streamThickness = -1, --//streamThickness = 4+self.count*0.34, corethickness = 1, corealpha = 1, texture = "bitmaps/largelaserfalloff.tga", } ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- --//speed ups local GL_ONE = GL.ONE local GL_SRC_ALPHA = GL.SRC_ALPHA local GL_ONE_MINUS_SRC_ALPHA = GL.ONE_MINUS_SRC_ALPHA local GL_QUADS = GL.QUADS local GL_TEXTURE = GL.TEXTURE local GL_MODELVIEW = GL.MODELVIEW local glColor = gl.Color local glTexture = gl.Texture local glBlending = gl.Blending local glMultiTexCoord = gl.MultiTexCoord local glVertex = gl.Vertex local glTranslate = gl.Translate local glMatrixMode = gl.MatrixMode local glPushMatrix = gl.PushMatrix local glPopMatrix = gl.PopMatrix local glBeginEnd = gl.BeginEnd local glUseShader = gl.UseShader local glAlphaTest = gl.AlphaTest local glCallList = gl.CallList local max = math.max local GetCameraVectors = Spring.GetCameraVectors local IsSphereInView = Spring.IsSphereInView ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function NanoLasers:BeginDraw() glUseShader(laserShader) glBlending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) glAlphaTest(false) end function NanoLasers:EndDraw() glUseShader(0) glColor(1,1,1,1) glTexture(false) glBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glAlphaTest(true) -- i hate that nv bug! glMultiTexCoord(0,0,0,0) glMultiTexCoord(1,0,0,0) glMultiTexCoord(2,0,0,0) glMultiTexCoord(3,0,0,0) lastTexture="" end function NanoLasers:Draw() if (lastTexture~=self.texture) then glTexture(self.texture) lastTexture=self.texture end local color = self.color local startPos = self.pos local endPos = self.targetpos glColor(color[1],color[2],color[3],0.0003) glMultiTexCoord(0,endPos[1] - self.normdir[3] * self.scane_mult ,endPos[2],endPos[3] + self.normdir[1] * self.scane_mult,1) glMultiTexCoord(1,startPos[1],startPos[2],startPos[3],1) if (self.inversed) then glMultiTexCoord(2, (thisGameFrame+Spring.GetFrameTimeOffset())*self.streamSpeed, self.streamThickness, self.corealpha, self.corethickness) else glMultiTexCoord(2, -(thisGameFrame+Spring.GetFrameTimeOffset())*self.streamSpeed, self.streamThickness, self.corealpha, self.corethickness) end glCallList(dlist) end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function NanoLasers:Update(n) UpdateNanoParticles(self) self.fpos = (self.fpos or 0) + self.count * 5 * n if (self.inversed) then self.scane_mult = 4 * math.cos(6*(self.fpos%4001)/4000*math.pi) else self.scane_mult = 8 * math.cos(2*(self.fpos%4001)/4000*math.pi) end if (self._dead) then RemoveParticles(self.id) end end -- used if repeatEffect=true; function NanoLasers:ReInitialize() self.dieGameFrame = self.dieGameFrame + self.life end function NanoLasers:Visible() if (self.allyID ~= LocalAllyTeamID)and(self.visibility == 0) then return false end local midPos = self._midpos return IsSphereInView(midPos[1],midPos[2],midPos[3], self._radius) end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function NanoLasers:Initialize() laserShader = gl.CreateShader({ vertex = [[ //gl.vertex.xy := length,width //gl.vertex.zw := texcoord #define startpos gl_MultiTexCoord0 #define endpos gl_MultiTexCoord1 #define streamTranslate gl_MultiTexCoord2.x #define streamThickness gl_MultiTexCoord2.y #define coreAlpha gl_MultiTexCoord2.z #define coreThickness gl_MultiTexCoord2.w #define isCore gl_MultiTexCoord3.x varying vec3 texCoord; void main() { texCoord = vec3(gl_Vertex.z - streamTranslate, gl_Vertex.w, gl_Vertex.z); vec3 dir3; if (gl_Vertex.x>0.5) { gl_Position = (gl_ModelViewMatrix * endpos); dir3 = gl_Position.xyz - (gl_ModelViewMatrix * (startpos)).xyz; } else { gl_Position = (gl_ModelViewMatrix * startpos); dir3 = (gl_ModelViewMatrix * (endpos)).xyz - gl_Position.xyz; } vec3 v = normalize( dir3 ); vec3 w = normalize( -gl_Position.xyz ); vec3 u = normalize( cross(w,v) ); if (isCore>0.0) { gl_Position.xyz += (gl_Vertex.y * coreThickness) * u; gl_FrontColor.rgb = vec3(coreAlpha); gl_FrontColor.a = 0.003; }else{ gl_Position.xyz += (gl_Vertex.y * streamThickness) * u; gl_FrontColor = gl_Color; } gl_Position = gl_ProjectionMatrix * gl_Position; } ]], fragment = [[ uniform sampler2D tex0; varying vec3 texCoord; void main() { gl_FragColor = texture2D(tex0, texCoord.st) * gl_Color; if (texCoord.p>0.95) gl_FragColor *= vec4(1.0 - texCoord.p) * 20.0; if (texCoord.p<0.05) gl_FragColor *= vec4(texCoord.p) * 20.0; } ]], uniformInt = { tex0=0, } }) if (laserShader == nil) then print(PRIO_MAJOR,"LUPS->nanoLaserShader: shader error: "..gl.GetShaderLog()) return false end dlist = gl.CreateList(glBeginEnd,GL_QUADS,function() glMultiTexCoord(3,0) glVertex(1,-1, 1,0) glVertex(0,-1, 0,0) glVertex(0, 1, 0,1) glVertex(1, 1, 1,1) glMultiTexCoord(3,1) glVertex(1,-1, 1,0) glVertex(0,-1, 0,0) glVertex(0, 1, 0,1) glVertex(1, 1, 1,1) end) end function NanoLasers:Finalize() if (gl.DeleteShader) then gl.DeleteShader(laserShader) end gl.DeleteList(dlist) end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function NanoLasers:CreateParticle() self.life = self.life + 1 --// so we can reuse existing fx's self.firstGameFrame = thisGameFrame self.dieGameFrame = self.firstGameFrame + self.life if (self.flare) then --[[if you add those flares, then the laser is slower as the engine, so it needs some tweaking]]-- if (self.flare1id and particles[self.flare1id] and particles[self.flare2id]) then local flare1 = particles[self.flare1id] flare1.size = self.count*0.1 flare1:ReInitialize() local flare2 = particles[self.flare2id] flare2.size = self.count*0.75 flare2:ReInitialize() return else local r,g,b = max(self.color[1],0.13),max(self.color[2],0.13),max(self.color[3],0.13) local flare = { unit = self.unitID, piecenum = self.unitpiece, layer = self.layer, life = 31, size = self.count*0.1, sizeSpread = 1, sizeGrowth = 0.1, colormap = { {r*2,g*2,b*2,0.01},{r*2,g*2,b*2,0.01},{r*2,g*2,b*2,0.01} }, texture = 'bitmaps/GPL/groundflash.tga', count = 2, repeatEffect = false, } self.flare1id = AddParticles("StaticParticles",flare) flare.size = self.count*0.75 flare.texture = 'bitmaps/flare.tga' flare.colormap = { {r*2,g*2,b*2,0.009},{r*2,g*2,b*2,0.009},{r*2,g*2,b*2,0.009} } flare.count = 2 self.flare2id = AddParticles("StaticParticles",flare) end end self.visibility = 0 self:Update(0) --//update los if (self.streamThickness<0) then self.streamThickness = 4+self.count*0.34 end end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- function NanoLasers.Create(Options) local unit,nanopiece=Options.unitID,Options.nanopiece if (unit and nanopiece)and(knownNanoLasers[unit])and(knownNanoLasers[unit][nanopiece]) then local reuseFx = knownNanoLasers[unit][nanopiece] CopyTable(reuseFx,Options) reuseFx:CreateParticle() return false,reuseFx.id else local newObject = MergeTable(Options, NanoLasers.Default) setmetatable(newObject,NanoLasers) -- make handle lookup newObject:CreateParticle() if (unit and nanopiece) then if (not knownNanoLasers[unit]) then knownNanoLasers[unit] = {} end knownNanoLasers[unit][nanopiece] = newObject end return newObject end end function NanoLasers:Destroy() local unit,nanopiece=self.unitID,self.nanopiece knownNanoLasers[unit][nanopiece] = nil if (not next(knownNanoLasers[unit])) then knownNanoLasers[unit] = nil end if (self.flare) then RemoveParticles(self.flare1id) RemoveParticles(self.flare2id) end end ----------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- return NanoLasers