diff --git a/game/engines/default/engine/Target.lua b/game/engines/default/engine/Target.lua index 2b3627bb2a52d1bd97b73fac1a3bd97b9445e941..9009969f83c679650ee3164c18d12de94cd60598 100644 --- a/game/engines/default/engine/Target.lua +++ b/game/engines/default/engine/Target.lua @@ -19,6 +19,7 @@ require "engine.class" local Map = require "engine.Map" +local Shader = require "engine.Shader" --- handles targetting module(..., package.seeall, class.make) @@ -32,34 +33,62 @@ function _M:init(map, source_actor) self.cursor = engine.Tiles:loadImage("target_cursor.png"):glTexture() self.arrow = engine.Tiles:loadImage("target_arrow.png"):glTexture() + self.targetshader = engine.Tiles:loadImage("ui/targetshader.png"):glTexture() + self:createTextures() + + self.source_actor = source_actor + + -- Setup the tracking target table + -- Notice its values are set to weak references, this has no effects on the number for x and y + -- but it means if the entity field is set to an entity, when it disappears this link wont prevent + -- the garbage collection + self.target = {x=self.source_actor.x, y=self.source_actor.y, entity=nil} +-- setmetatable(self.target, {__mode='v'}) +end + +function _M:createTextures() --Use power of two (pot) width and height, rounded up - local pot_width = math.pow(2, math.ceil(math.log(map.tile_w-0.1) / math.log(2.0))) - local pot_height = math.pow(2, math.ceil(math.log(map.tile_h-0.1) / math.log(2.0))) + local pot_width = math.pow(2, math.ceil(math.log(self.tile_w-0.1) / math.log(2.0))) + local pot_height = math.pow(2, math.ceil(math.log(self.tile_h-0.1) / math.log(2.0))) self.sr = core.display.newSurface(pot_width, pot_height) - self.sr:erase(255, 0, 0, 90) + self.sr:erase(255, 0, 0, self.fbo and 150 or 90) self.sr = self.sr:glTexture() self.sb = core.display.newSurface(pot_width, pot_height) - self.sb:erase(0, 0, 255, 90) + self.sb:erase(0, 0, 255, self.fbo and 150 or 90) self.sb = self.sb:glTexture() self.sg = core.display.newSurface(pot_width, pot_height) - self.sg:erase(0, 255, 0, 90) + self.sg:erase(0, 255, 0, self.fbo and 150 or 90) self.sg = self.sg:glTexture() self.sy = core.display.newSurface(pot_width, pot_height) - self.sy:erase(255, 255, 0, 90) + self.sy:erase(255, 255, 0, self.fbo and 150 or 90) self.sy = self.sy:glTexture() self.syg = core.display.newSurface(pot_width, pot_height) - self.syg:erase(153, 204, 50, 90) + self.syg:erase(153, 204, 50, self.fbo and 150 or 90) self.syg = self.syg:glTexture() +end - self.source_actor = source_actor +function _M:enableFBORenderer(texture, shader) + if not shader then + self.fbo = nil + return + self:createTextures() + end + self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height) + if not self.fbo then + self:createTextures() + return + end - -- Setup the tracking target table - -- Notice its values are set to weak references, this has no effects on the number for x and y - -- but it means if the entity field is set to an entity, when it disappears this link wont prevent - -- the garbage collection - self.target = {x=self.source_actor.x, y=self.source_actor.y, entity=nil} --- setmetatable(self.target, {__mode='v'}) + self.fbo_shader = Shader.new(shader) + if not self.fbo_shader.shad then + self.fbo = nil + self:createTextures() + return + end + + self.targetshader = engine.Tiles:loadImage(texture):glTexture() + self:createTextures() end function _M:displayArrow(sx, sy, tx, ty, full) @@ -77,7 +106,41 @@ function _M:displayArrow(sx, sy, tx, ty, full) core.display.glMatrix(false) end -function _M:display(dispx, dispy) +function _M:display(dispx, dispy, prevfbo) + local ox, oy = self.display_x, self.display_y + local sx, sy = game.level.map._map:getScroll() + sx = sx + game.level.map.display_x + sy = sy + game.level.map.display_y + self.display_x, self.display_y = dispx or sx or self.display_x, dispy or sy or self.display_y + + if self.active then + if not self.fbo then + self:realDisplay(self.display_x, self.display_y) + else + self.fbo:use(true, 0, 0, 0, 0) + self:realDisplay(0, 0) + self.fbo:use(false, prevfbo) + self.targetshader:bind(1, false) + self.fbo_shader.shad:paramNumber2("tileSize", self.tile_w, self.tile_h) + self.fbo_shader.shad:paramNumber2("scrollOffset", 0, 0) + self.fbo:toScreen(self.display_x, self.display_y, Map.viewport.width, Map.viewport.height, self.fbo_shader.shad, 1, 1, 1, 1, true) + end + + if not self.target_type.immediate_keys or firstx then + self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my + util.hexOffset(self.target.x)) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom) + end + + if self.target_type.immediate_keys then + for dir, spot in pairs(util.adjacentCoords(self.target_type.start_x, self.target_type.start_y)) do + self:displayArrow(self.target_type.start_x, self.target_type.start_y, spot[1], spot[2], firstx == spot[1] and firsty == spot[2]) + end + end + end + + self.display_x, self.display_y = ox, oy +end + +function _M:realDisplay(dispx, dispy) -- Make sure we have a source if not self.target_type.source_actor then self.target_type.source_actor = self.source_actor @@ -92,13 +155,8 @@ function _M:display(dispx, dispy) self.target_type.start_x = self.target_type.start_x or self.target_type.x or self.target_type.source_actor and self.target_type.source_actor.x or self.x self.target_type.start_y = self.target_type.start_y or self.target_type.y or self.target_type.source_actor and self.target_type.source_actor.y or self.y - local ox, oy = self.display_x, self.display_y - local sx, sy = game.level.map._map:getScroll() - sx = sx + game.level.map.display_x - sy = sy + game.level.map.display_y - self.display_x, self.display_y = dispx or sx or self.display_x, dispy or sy or self.display_y --- self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom) +-- self.cursor:toScreen(dispx + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, dispy + (self.target.y - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom) -- Do not display if not requested if not self.active then return end @@ -107,16 +165,16 @@ function _M:display(dispx, dispy) if util.isHex() then display_highlight = function(texture, tx, ty) texture:toScreenHighlightHex( - self.display_x + (tx - game.level.map.mx) * self.tile_w * Map.zoom, - self.display_y + (ty - game.level.map.my + util.hexOffset(tx)) * self.tile_h * Map.zoom, + dispx + (tx - game.level.map.mx) * self.tile_w * Map.zoom, + dispy + (ty - game.level.map.my + util.hexOffset(tx)) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom) end else display_highlight = function(texture, tx, ty) texture:toScreen( - self.display_x + (tx - game.level.map.mx) * self.tile_w * Map.zoom, - self.display_y + (ty - game.level.map.my) * self.tile_h * Map.zoom, + dispx + (tx - game.level.map.mx) * self.tile_w * Map.zoom, + dispy + (ty - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom) end @@ -205,9 +263,6 @@ function _M:display(dispx, dispy) end end - if not self.target_type.immediate_keys or firstx then - self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my + util.hexOffset(self.target.x)) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom) - end if self.target_type.ball and self.target_type.ball > 0 then core.fov.calc_circle( @@ -275,14 +330,6 @@ function _M:display(dispx, dispy) end, nil) end - - if self.target_type.immediate_keys then - for dir, spot in pairs(util.adjacentCoords(self.target_type.start_x, self.target_type.start_y)) do - self:displayArrow(self.target_type.start_x, self.target_type.start_y, spot[1], spot[2], firstx == spot[1] and firsty == spot[2]) - end - end - - self.display_x, self.display_y = ox, oy end -- @return t The target table used by ActorProject, Projectile, GameTargeting, etc. diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index b73cd6ee7711679fff51b497bdb8075be2267f00..d465ae39792df171068b37bd7f6462f27a80e897 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -134,6 +134,7 @@ function _M:runReal() if not self.player then self:newGame() end engine.interface.GameTargeting.init(self) + if self.target then self.target:enableFBORenderer("ui/targetshader.png", "target_fbo") end self.uiset.hotkeys_display.actor = self.player self.uiset.npcs_display.actor = self.player @@ -515,6 +516,8 @@ function _M:createFBOs() if self.fbo and self.fbo2 then core.particles.defineFramebuffer(self.fbo) else core.particles.defineFramebuffer(nil) end + if self.target then self.target:enableFBORenderer("ui/targetshader.png", "target_fbo") end + -- self.mm_fbo = core.display.newFBO(200, 200) -- if self.mm_fbo then self.mm_fbo_shader = Shader.new("mm_fbo") if not self.mm_fbo_shader.shad then self.mm_fbo = nil self.mm_fbo_shader = nil end end end @@ -1359,13 +1362,13 @@ function _M:displayMap(nb_keyframes) _2DNoise:bind(1, false) self.fbo2:toScreen(map.display_x, map.display_y, map.viewport.width, map.viewport.height, self.fbo_shader.shad) - if self.target then self.target:display() end + if self.target then self.target:display(nil, nil, self.full_fbo) end -- Basic display; no FBOs else if self.level.data.background then self.level.data.background(self.level, map.display_x, map.display_y, nb_keyframes) end map:display(nil, nil, nb_keyframes, config.settings.tome.smooth_fov) - if self.target then self.target:display() end + if self.target then self.target:display(nil, nil, self.full_fbo) end if self.level.data.foreground then self.level.data.foreground(self.level, map.display_x, map.display_y, nb_keyframes) end if self.level.data.weather_particle then self.state:displayWeather(self.level, self.level.data.weather_particle, nb_keyframes) end if self.level.data.weather_shader then self.state:displayWeatherShader(self.level, self.level.data.weather_shader, map.display_x, map.display_y, nb_keyframes) end diff --git a/game/modules/tome/data/gfx/shaders/mm_fbo.frag b/game/modules/tome/data/gfx/shaders/mm_fbo.frag deleted file mode 100644 index 79c44c55d51a9e1860fc78cdc7437fba9054ee90..0000000000000000000000000000000000000000 --- a/game/modules/tome/data/gfx/shaders/mm_fbo.frag +++ /dev/null @@ -1,172 +0,0 @@ -//#version 150 -uniform sampler2D Texture0; -//varying vec2 texCoord; - -#define HueLevCount 6 -#define SatLevCount 7 -#define ValLevCount 4 -float[HueLevCount] HueLevels = float[] (0.0,80.0,160.0,240.0,320.0,360.0); -float[SatLevCount] SatLevels = float[] (0.0,0.15,0.3,0.45,0.6,0.8,1.0); -float[ValLevCount] ValLevels = float[] (0.0,0.3,0.6,1.0); - -vec3 RGBtoHSV( float r, float g, float b) { - float minv, maxv, delta; - vec3 res; - - minv = min(min(r, g), b); - maxv = max(max(r, g), b); - res.z = maxv; // v - - delta = maxv - minv; - - if( maxv != 0.0 ) - res.y = delta / maxv; // s - else { - // r = g = b = 0 // s = 0, v is undefined - res.y = 0.0; - res.x = -1.0; - return res; - } - - if( r == maxv ) - res.x = ( g - b ) / delta; // between yellow & magenta - else if( g == maxv ) - res.x = 2.0 + ( b - r ) / delta; // between cyan & yellow - else - res.x = 4.0 + ( r - g ) / delta; // between magenta & cyan - - res.x = res.x * 60.0; // degrees - if( res.x < 0.0 ) - res.x = res.x + 360.0; - - return res; -} - -vec3 HSVtoRGB(float h, float s, float v ) { - int i; - float f, p, q, t; - vec3 res; - - if( s == 0.0 ) { - // achromatic (grey) - res.x = v; - res.y = v; - res.z = v; - return res; - } - - h /= 60.0; // sector 0 to 5 - i = int(floor( h )); - f = h - float(i); // factorial part of h - p = v * ( 1.0 - s ); - q = v * ( 1.0 - s * f ); - t = v * ( 1.0 - s * ( 1.0 - f ) ); - - switch( i ) { - case 0: - res.x = v; - res.y = t; - res.z = p; - break; - case 1: - res.x = q; - res.y = v; - res.z = p; - break; - case 2: - res.x = p; - res.y = v; - res.z = t; - break; - case 3: - res.x = p; - res.y = q; - res.z = v; - break; - case 4: - res.x = t; - res.y = p; - res.z = v; - break; - default: // case 5: - res.x = v; - res.y = p; - res.z = q; - break; - } - - return res; -} - -float nearestLevel(float col, int mode) { - int levCount; - if (mode==0) levCount = HueLevCount; - if (mode==1) levCount = SatLevCount; - if (mode==2) levCount = ValLevCount; - - for (int i =0; i<levCount-1; i++ ) { - if (mode==0) { - if (col >= HueLevels[i] && col <= HueLevels[i+1]) { - return HueLevels[i+1]; - } - } - if (mode==1) { - if (col >= SatLevels[i] && col <= SatLevels[i+1]) { - return SatLevels[i+1]; - } - } - if (mode==2) { - if (col >= ValLevels[i] && col <= ValLevels[i+1]) { - return ValLevels[i+1]; - } - } - } -} - -// averaged pixel intensity from 3 color channels -float avg_intensity(vec4 pix) { - return (pix.r + pix.g + pix.b)/3.; -} - -vec4 get_pixel(vec2 coords, float dx, float dy) { - return texture2D(Texture0,coords + vec2(dx, dy)); -} - -// returns pixel color -float IsEdge(in vec2 coords){ - float dxtex = 1.0 /float(textureSize(Texture0,0)) ; - float dytex = 1.0 /float(textureSize(Texture0,0)); - float pix[9]; - int k = -1; - float delta; - - // read neighboring pixel intensities - for (int i=-1; i<2; i++) { - for(int j=-1; j<2; j++) { - k++; - pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex, - float(j)*dytex)); - } - } - - // average color differences around neighboring pixels - delta = (abs(pix[1]-pix[7])+ - abs(pix[5]-pix[3]) + - abs(pix[0]-pix[8])+ - abs(pix[2]-pix[6]) - )/4.; - - return clamp(5.5*delta,0.0,1.0); -} - -void main(void) -{ - vec4 colorOrg = texture2D( Texture0, gl_TexCoord[0].st ); - vec3 vHSV = RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b); - vHSV.x = nearestLevel(vHSV.x, 0); - vHSV.y = nearestLevel(vHSV.y, 1); - vHSV.z = nearestLevel(vHSV.z, 2); - float edg = IsEdge(gl_TexCoord[0].st); - vec3 vRGB = (edg >= 0.3)? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z); - gl_FragColor = vec4(vRGB.x,vRGB.y,vRGB.z,1.0); -} diff --git a/game/modules/tome/data/gfx/shaders/target_fbo.frag b/game/modules/tome/data/gfx/shaders/target_fbo.frag new file mode 100644 index 0000000000000000000000000000000000000000..5045fd33dfaeaae0c652eabd4d95ee25e8c01b44 --- /dev/null +++ b/game/modules/tome/data/gfx/shaders/target_fbo.frag @@ -0,0 +1,141 @@ +//#version 150 +uniform sampler2D fboTex; +uniform sampler2D targetSkin; +uniform vec2 mapCoord; +uniform vec2 tileSize; +uniform vec2 scrollOffset; + +void main(void) +{ + vec2 offset = vec2(1.0, 1.0) / mapCoord * tileSize * 0.5; + + /*vec4 colorm0 = texture2D( fboTex, gl_TexCoord[0].xy + vec2(-offset.x, 0.0)); + vec4 colorp0 = texture2D( fboTex, gl_TexCoord[0].xy + vec2( offset.x, 0.0)); + + vec4 color0m = texture2D( fboTex, gl_TexCoord[0].xy + vec2(0.0, -offset.y)); + vec4 color0p = texture2D( fboTex, gl_TexCoord[0].xy + vec2(0.0, offset.y));*/ + + vec4 colormm = texture2D( fboTex, gl_TexCoord[0].xy + vec2(-offset.x,-offset.y)); + vec4 colormp = texture2D( fboTex, gl_TexCoord[0].xy + vec2(-offset.x, offset.y)); + vec4 colorpm = texture2D( fboTex, gl_TexCoord[0].xy + vec2( offset.x,-offset.y)); + vec4 colorpp = texture2D( fboTex, gl_TexCoord[0].xy + vec2( offset.x, offset.y)); + + vec4 color00 = texture2D( fboTex, gl_TexCoord[0].xy); + + vec4 resultColor = color00; + + bool loc1 = false; + bool loc2 = false; + bool loc3 = false; + bool loc4 = false; + bool loc5 = false; + bool loc6 = false; + bool loc7 = false; + bool loc8 = false; + bool loc9 = false; + + if(colormm.a > 0.1) + loc1 = true; + if(colormp.a > 0.1) + loc7 = true; + if(colorpm.a > 0.1) + loc3 = true; + if(colorpp.a > 0.1) + loc9 = true; + if(color00.a > 0.1) + loc5 = true; + + if(gl_TexCoord[0].x + offset.x > 1.0) + { + loc9 = 0; + loc3 = 0; + } + + if(gl_TexCoord[0].x - offset.x < 0.0) + { + loc1 = 0; + loc7 = 0; + } + + if(gl_TexCoord[0].y + offset.y > 1.0) + { + loc7 = 0; + loc9 = 0; + } + + if(gl_TexCoord[0].y - offset.y < 0.0) + { + loc1 = 0; + loc3 = 0; + } + + + vec2 fboCoord = gl_TexCoord[0].xy; + fboCoord.y = 1.0 - fboCoord.y; + vec2 texCoord = (fboCoord * mapCoord + scrollOffset) / tileSize + vec2(0.5, 0.5); + texCoord.x = mod(texCoord.x, 1.0); + texCoord.y = mod(texCoord.y, 1.0); + + vec4 borderColor = vec4(0.0, 0.0, 0.0, 0.0); + + if(loc1 && loc7 && loc3 && !loc9) //1 internal + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 3.0)); + + if(loc9 && !loc7 && !loc3 && !loc1) //1 external + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 1.0)); + + if(loc7 && !loc3 && loc9 && !loc1) //2 + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 1.0)); + + if(loc3 && loc1 && loc9 && !loc7) //3 internal + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 3.0)); + + if(loc7 && !loc1 && !loc9 && !loc3) //3 external + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 1.0)); + + if(loc1 && !loc9 && loc7 && !loc3) //8 + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 3.0, 1.0 / 4.0 * 0.0)); + + if(loc9 && loc7 && loc3 && !loc1) + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 2.0)); + + if(loc1 && !loc7 && !loc3 && !loc9) //9 external + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 1.0, 1.0 / 4.0 * 0.0)); + + if(loc1 && !loc9 && loc3 && !loc7) + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 0.0)); + + if(loc7 && loc1 && loc9 && !loc3) //7 internal + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 2.0)); + + if(loc3 && !loc1 && !loc9 && !loc7) //7 external + borderColor += texture2D( targetSkin, texCoord / 4.0 + vec2(1.0 / 4.0 * 0.0, 1.0 / 4.0 * 0.0)); + + if(loc3 && !loc7 && loc9 && !loc1) //4 + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 3.0, 1.0 / 4.0 * 1.0)); + + if(loc3 && loc7 && !loc9 && !loc1) //3-7 diag + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 2.0)); + + if(!loc3 && !loc7 && loc9 && loc1) //1-9 diag + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 3.0, 1.0 / 4.0 * 2.0)); + + if(loc3 && loc7 && loc9 && loc1) //internal quad + borderColor += texture2D( targetSkin, texCoord / vec2(4.0, 4.0) + vec2(1.0 / 4.0 * 2.0, 1.0 / 4.0 * 3.0)); + + if(!loc5 && borderColor.a > 0.0) + { + vec4 avgColor = + (colormm * colormm.a + colormp * colormp.a + colorpm * colorpm.a + colorpp * colorpp.a) + / (colormm.a + colormp.a + colorpm.a + colorpp.a + 1e-5); + resultColor += avgColor; + resultColor.rgb += borderColor.rgb * borderColor.a; + resultColor.a = borderColor.a; + }else + { + borderColor.rgb *= borderColor.a; + resultColor += borderColor; + } + + gl_FragColor = resultColor; +} diff --git a/game/modules/tome/data/gfx/shaders/mm_fbo.lua b/game/modules/tome/data/gfx/shaders/target_fbo.lua similarity index 87% rename from game/modules/tome/data/gfx/shaders/mm_fbo.lua rename to game/modules/tome/data/gfx/shaders/target_fbo.lua index 6aac51e1be541ccfb4b1986dff09a6b8695e09ab..8e0ba1def4205224fd586ce3cc7d59de8014ac05 100644 --- a/game/modules/tome/data/gfx/shaders/mm_fbo.lua +++ b/game/modules/tome/data/gfx/shaders/target_fbo.lua @@ -18,9 +18,13 @@ -- darkgod@te4.org return { - frag = "mm_fbo", + frag = "target_fbo", vert = nil, args = { + fboTex = { texture = 0 }, + targetSkin = { texture = 1 }, + scrollOffset = {0, 0}, }, clone = false, + permanent = true, } diff --git a/game/modules/tome/data/gfx/ui/targetshader.png b/game/modules/tome/data/gfx/ui/targetshader.png new file mode 100644 index 0000000000000000000000000000000000000000..99db06ac533b4c45731ad11bb84d02a8b70b7749 Binary files /dev/null and b/game/modules/tome/data/gfx/ui/targetshader.png differ