if (type (Require) ~= 'function') then loadstring(exports['nc_libraries']:extend('Extend'), 'Require')() end local dxDrawImage = dxDrawImage; local dxDrawImageSection = dxDrawImageSection; local dxSetBlendMode = dxSetBlendMode; local dxSetRenderTarget = dxSetRenderTarget; local dxSetShaderValue = dxSetShaderValue; local dxCreateShader = dxCreateShader; local dxCreateRenderTarget = dxCreateRenderTarget; local destroyElement = destroyElement; local ResourceName = resourceName or getResourceName(getThisResource()); local Blur = {} function Blur:Constructor() self.Threads = {} end function Blur:Create(Name, Width, Height, Strength) if not Name then return outputDebugString('Blur:Create @ Nome não informado', 4, 255, 0, 0) end if self.Threads[Name] then return outputDebugString('Blur:Create @ Nome já existe', 4, 255, 0, 0) end if not self.Threads[Name] then self.Threads[Name] = { FX = false, Target = false, Strength = Strength or 4, Retry = 0, Width = Width or 512, Height = Height or 512 } end local Thread = self.Threads[Name] Thread.FX = dxCreateShader(Blur.ShaderRaw) if not isElement(Thread.FX) then if Thread.Retry < 4 then Thread.Retry = Thread.Retry + 1 setTimer(function(Name, Width, Height, Strength) Blur:Create(Name, Width, Height, Strength) end, 800, 1, Name, Width, Height, Strength) end else Thread.Target = dxCreateRenderTarget(Thread.Width, Thread.Height, true); if isElement(Thread.Target) then Thread.Target:setData('Texture:Data', { Width = Thread.Width, Height = Thread.Height, CreatedAt = getTickCount(), Type = 'RenderTarget'; TextureType = 'argb'; }) dxSetShaderValue(Thread.FX, 'texture0', Thread.Target) outputDebugString('['..ResourceName..']: ('..os.date('%H:%M:%S')..') Blur:Create @ '..Name..' Created with success', 4, 0, 255, 0) return true else outputDebugString('Blur:Create @ Render target não criado', 4, 255, 0, 0) destroyElement(Thread.FX) Thread.FX = nil Thread.Target = nil end end end function Blur:Exists(Name) return self.Threads[Name] and isElement(self.Threads[Name].FX) and isElement(self.Threads[Name].Target) and true or false end function Blur:Refresh(Name, Width, Height, Texture, Strength) local Thread = self.Threads[Name]; assert(Thread, 'Blur:Refresh @ thread não encontrada') assert(Thread.FX and isElement(Thread.FX), 'Blur:Refresh 2 @ shader não encontrada') assert(Thread.Target and isElement(Thread.Target), 'Blur:Refresh 3 @ render target não encontrada') assert(Texture and isElement(Texture), 'Blur:Refresh 4 @ texture não encontrada') if Strength and Strength ~= Thread.Strength then Thread.Strength = Strength end if dxSetRenderTarget(Thread.Target, true) then dxSetBlendMode('modulate_add') dxDrawImage(0, 0, Thread.Width, Thread.Height, Texture, 0, 0, 0, tocolor(255, 255, 255), false) dxSetBlendMode('blend') for i = 0, 6 do local factor = 0.0020 * Thread.Strength + (i / 8 * 0.001 * Thread.Strength) dxSetShaderValue(Thread.FX, 'factor', factor) dxSetBlendMode('modulate_add') dxDrawImage(0, 0, Thread.Width, Thread.Height, Thread.FX, 0, 0, 0, tocolor(255, 255, 255), false) dxSetBlendMode('blend') end dxSetRenderTarget() end end -- Draw Section, use dxSetBlendMode('modulate_add') function Blur:DrawSection(Name, X, Y, Width, Height, U, V, USize, VSize, Color, PostGUI) local Thread = self.Threads[Name] if Thread and Thread.FX and isElement(Thread.FX) then if type(Draw.ImageSection) == 'function' then return Draw:ImageSection(X, Y, Width, Height, U or 0, V or 0, USize or Width, VSize or Height, Thread.FX, 0, 0, 0, Color, PostGUI) else return dxDrawImageSection(X, Y, Width, Height, U or 0, V or 0, USize or Width, VSize or Height, Thread.FX, 0, 0, 0, Color, PostGUI) end end end -- Draw, use dxSetBlendMode('add') function Blur:Draw(Name, X, Y, Width, Height, Color, PostGUI) local Thread = self.Threads[Name] if Thread and Thread.FX and isElement(Thread.FX) then return dxDrawImage(X, Y, Width, Height, Thread.FX, 0, 0, 0, Color, PostGUI) end end function Blur:Destroy(Name) if Name then if self.Threads[Name] then if self.Threads[Name].FX then if (isElement(self.Threads[Name].FX)) then destroyElement(self.Threads[Name].FX); end self.Threads[Name].FX = nil end if self.Threads[Name].Target then if (isElement(self.Threads[Name].Target)) then destroyElement(self.Threads[Name].Target); end self.Threads[Name].Target = nil end self.Threads[Name] = nil end else for i, v in pairs(self.Threads) do if v.FX then if (isElement(v.FX)) then destroyElement(v.FX); end v.FX = nil end if v.Target then if (isElement(v.Target)) then destroyElement(v.Target); end v.Target = nil end end self.Threads = {} end end addEventHandler('onClientResourceStop', resourceRoot, function() Blur:Destroy() end) _G.Blur = Blur; Blur.ShaderRaw = [[ texture texture0; float factor; sampler Sampler0 = sampler_state { Texture = (texture0); AddressU = Clamp; AddressV = Clamp; }; struct PSInput { float2 TexCoord : TEXCOORD0; float4 Color : COLOR0; // <- Entrada do dxDrawImage tocolor() }; float4 PixelShader_Background(PSInput PS) : COLOR0 { float4 sum = tex2D(Sampler0, PS.TexCoord) * 1.0; float totalWeight = 1.0; float2 offsets[8] = { float2(factor, 0), float2(-factor, 0), float2(0, factor), float2(0, -factor), float2(factor, factor), float2(-factor, factor), float2(factor, -factor), float2(-factor, -factor) }; float weights[8] = { 0.8, 0.8, 0.8, 0.8, 0.5, 0.5, 0.5, 0.5 }; for (int i = 0; i < 8; i++) { float2 uv = saturate(PS.TexCoord + offsets[i]); sum += tex2D(Sampler0, uv) * weights[i]; totalWeight += weights[i]; } sum /= totalWeight; // Multiplica pela cor de entrada float safeAlpha = max(PS.Color.a, 0.05); // mínimo de transparência pra não estourar sum.rgb *= PS.Color.rgb; sum.a *= safeAlpha; return sum; } technique smoothBlur { pass P0 { PixelShader = compile ps_2_0 PixelShader_Background(); } } ]] return Blur;