Last active
June 7, 2023 09:39
-
-
Save Beherith/3fd98a485765a67c72312fac059e63ef to your computer and use it in GitHub Desktop.
Defenserange_atunit_gl4.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
include("keysym.h.lua") | |
function widget:GetInfo() | |
return { | |
name = "Defense Range GL4", | |
desc = "Displays range of defenses (enemy and ally)", | |
author = "Beherith", -- yeah this is now a rewrite from scratch | |
date = "2021.04.26", | |
license = "Lua: GPLv2, GLSL: (c) Beherith (mysterme@gmail.com)", | |
layer = -100, | |
enabled = false | |
} | |
end | |
-- GL4 dev Notes: | |
-- AA should be purple :D | |
-- heightboost is going to be a bitch - > use $heightmap and hope that heightboost is kinda linear | |
-- Vertex Buffer should have: a circle with 256 subdivs | |
-- basically a set of vec2's | |
-- each elem of this vec2 should also have a normal vector, for ez heightboost | |
-- whole thing needs an 'override' type thing, | |
-- needs masking of the instance buffer | |
-- configurability: | |
-- have multiple VBOs' for each unit type? | |
-- TODO2 | |
--X separate cylsph and cannon types!!!! | |
--X smaller vertex VBO for regular, larger for cannons | |
--X separate air and ground types and show based on selection (UNIFORM OR NOT?) | |
-- better animations!!! -- NOT NEEDED | |
--x correct colorization | |
--X correct popElementInstance keys | |
-- FADE/VIS CONTROL: | |
-- 0. Color gets darkened outside los | |
-- 1. out of map gets faded to 0 | |
-- 2. zoomed out anti fades in, all others fade out | |
-- 3. mouse will always return it to full vis, with teamcolorized stipples at 1/4th distribution | |
--X allow for distance fade config for each class | |
--X minalpha, maxalpha, fadestart, fadend | |
--X also pass in mouse cursor ground pos as uniform, and fade ground def based on that :) | |
--X uniforms: mousemapx, mousemapz, selectiontype (air, ground, mixed, none), globalalpha | |
--X sphcyl resample with heightmod boosting | |
--X add height offsets to common turrets! | |
-- raytracin' cannons? | |
--X do something with LOS (darken to half?) | |
--X cordoom multiweapon :) | |
--X merge mobile antis into this | |
-- TODO3: 2022.10.10 | |
-- allow specs to enable? Doesnt make much sense with new stencil based drawing... | |
-- X LRPCs | |
-- X Fog | |
-- X dont check allied defenses for losness | |
-- X use luashader uvhm implementation | |
-- X fix mobile antis | |
-- isallied is totally wrong | |
-- dont check for losness in non fullview spec mode! | |
-- smartly reinit when selected allyteam changes and there are > 2 allyteams | |
------------------ CONFIGURABLES -------------- | |
local enabledAsSpec = true | |
local buttonConfig = { | |
ally = { ground = true, air = true, nuke = true }, | |
enemy = { ground = true, air = true, nuke = true } | |
} | |
local colorConfig = { --An array of R, G, B, Alpha | |
drawStencil = true, -- wether to draw the outer, merged rings (quite expensive!) | |
drawInnerRings = true, -- wether to draw inner, per defense rings (very cheap) | |
externalalpha = 0.70, -- alpha of outer rings | |
internalalpha = 0.0, -- alpha of inner rings | |
distanceScaleStart = 2000, -- Linewidth is 100% up to this camera height | |
distanceScaleEnd = 4000, -- Linewidth becomes 50% above this camera height | |
ground = { | |
color = {1.0, 0.2, 0.0, 1.0}, | |
fadeparams = { 2000, 5000, 1.0, 0.0}, -- FadeStart, FadeEnd, StartAlpha, EndAlpha | |
externallinethickness = 4.0, | |
internallinethickness = 2.0, | |
}, | |
air = { | |
color = {0.90, 0.45, 1.2, 1.0}, | |
fadeparams = { 2000, 5000, 0.4, 0.0}, -- FadeStart, FadeEnd, StartAlpha, EndAlpha | |
externallinethickness = 4.0, | |
internallinethickness = 2.0, | |
}, | |
nuke = { | |
color = {0.7, 0.8, 1.0, 1.0}, | |
fadeparams = {5000, 4000, 0.6, 0.0}, -- FadeStart, FadeEnd, StartAlpha, EndAlpha | |
externallinethickness = 4.0, | |
internallinethickness = 2.0, | |
}, | |
cannon = { | |
color = {1.0, 0.6, 0.0, 1.0}, | |
fadeparams = {3000, 6000, 0.8, 0.0}, -- FadeStart, FadeEnd, StartAlpha, EndAlpha | |
externallinethickness = 4.0, | |
internallinethickness = 2.0, | |
}, | |
} | |
--- Camera Height based line shrinkage: | |
---------------------------------- | |
local buttonconfigmap ={'ground','air','nuke','ground'} | |
local DEBUG = false --generates debug message | |
local weaponTypeMap = {'ground','air','nuke','cannon'} | |
local unitDefRings = {} --each entry should be a unitdefIDkey to very specific table: | |
-- a list of tables, ideally ranged from 0 where | |
local mobileAntiUnitDefs = { | |
[UnitDefNames.armscab.id ] = true, | |
[UnitDefNames.armcarry.id] = true, | |
[UnitDefNames.cormabm.id ] = true, | |
[UnitDefNames.corcarry.id] = true, | |
} | |
local defensePosHash = {} -- key: {poshash=unitID} | |
-- poshash is 4096 * posx/8 + posz/8 | |
local featureDefIDtoUnitDefID = {} -- this table maps featureDefIDs to unitDefIDs for faster lookups on feature creation | |
local vtoldamagetag = Game.armorTypes['vtol'] | |
local defaultdamagetag = Game.armorTypes['default'] | |
local function initializeUnitDefRing(unitDefID) | |
local weapons = UnitDefs[unitDefID].weapons | |
unitDefRings[unitDefID]['rings'] = {} | |
for weaponNum = 1, #weapons do | |
local weaponDef = weapons[weaponNum] | |
local weaponDefID = weapons[weaponNum].weaponDef | |
local weaponDef = WeaponDefs[weaponDefID] | |
local range = weaponDef.range | |
local dps = 0 | |
local weaponType = unitDefRings[unitDefID]['weapons'][weaponNum] | |
--Spring.Echo(weaponType) | |
if weaponType ~= nil and weaponType > 0 then | |
local damage = 0 | |
if weaponType == 2 then --AA | |
damage = weaponDef.damages[vtoldamagetag] | |
elseif weaponType == 3 then -- antinuke | |
damage = 0 | |
range = weaponDef.coverageRange | |
--Spring.Echo("init antinuke", range) | |
else | |
damage = weaponDef.damages[defaultdamagetag] | |
end | |
dps = damage * (weaponDef.salvoSize or 1) / (weaponDef.reload or 1) | |
local color = colorConfig[weaponTypeMap[weaponType]].color | |
local fadeparams = colorConfig[weaponTypeMap[weaponType]].fadeparams | |
local isCylinder = 1 | |
if weaponType == 1 or weaponType == 4 then -- all non-cannon ground weapons are spheres, aa and antinuke are cyls | |
isCylinder = 0 | |
end | |
local ringParams = {range, color[1],color[2], color[3], color[4], | |
fadeparams[1], fadeparams[2], fadeparams[3], fadeparams[4], | |
weaponDef.projectilespeed or 1, | |
isCylinder, | |
weaponDef.heightBoostFactor or 0, | |
weaponDef.heightMod or 0 } | |
unitDefRings[unitDefID]['rings'][weaponNum] = ringParams | |
end | |
end | |
end | |
local function initUnitList() | |
unitDefRings = { | |
-- ARMADA | |
[UnitDefNames['armclaw'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armllt'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armbeamer'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armhlt'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armguard'].id] = { weapons = { 4} }, | |
[UnitDefNames['armrl'].id] = { weapons = { 2 } }, --light aa | |
[UnitDefNames['armferret'].id] = { weapons = { 2 } }, | |
[UnitDefNames['armcir'].id] = { weapons = { 2 } }, --chainsaw | |
[UnitDefNames['armdl'].id] = { weapons = { 1 } }, --depthcharge | |
[UnitDefNames['armjuno'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armtl'].id] = { weapons = { 1 } }, --torp launcher | |
[UnitDefNames['armfhlt'].id] = { weapons = { 1 } }, --floating hlt | |
[UnitDefNames['armfrt'].id] = { weapons = { 2 } }, --floating rocket laucher | |
[UnitDefNames['armfflak'].id] = { weapons = { 2 } }, --floating flak AA | |
[UnitDefNames['armatl'].id] = { weapons = { 1 } }, --adv torpedo launcher | |
[UnitDefNames['armamb'].id] = { weapons = { 4 } }, --ambusher | |
[UnitDefNames['armpb'].id] = { weapons = { 4 } }, --pitbull | |
[UnitDefNames['armanni'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armflak'].id] = { weapons = { 2 } }, | |
[UnitDefNames['armmercury'].id] = { weapons = { 2 } }, | |
[UnitDefNames['armemp'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armamd'].id] = { weapons = { 3 } }, --antinuke | |
[UnitDefNames['armbrtha'].id] = { weapons = { 4 } }, | |
[UnitDefNames['armvulc'].id] = { weapons = { 4 } }, | |
-- CORTEX | |
[UnitDefNames['cormaw'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corexp'].id] = { weapons = { 1} }, | |
[UnitDefNames['cormexp'].id] = { weapons = { 1,1 } }, | |
[UnitDefNames['corllt'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corhllt'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corhlt'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corpun'].id] = { weapons = { 4} }, | |
[UnitDefNames['corrl'].id] = { weapons = { 2 } }, | |
[UnitDefNames['cormadsam'].id] = { weapons = { 2 } }, | |
[UnitDefNames['corerad'].id] = { weapons = { 2 } }, | |
[UnitDefNames['cordl'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corjuno'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corfhlt'].id] = { weapons = { 1 } }, --floating hlt | |
[UnitDefNames['cortl'].id] = { weapons = { 1 } }, --torp launcher | |
[UnitDefNames['coratl'].id] = { weapons = { 1 } }, --T2 torp launcher | |
[UnitDefNames['corfrt'].id] = { weapons = { 2 } }, --floating rocket laucher | |
[UnitDefNames['corenaa'].id] = { weapons = { 2 } }, --floating flak AA | |
[UnitDefNames['cortoast'].id] = { weapons = { 4 } }, | |
[UnitDefNames['corvipe'].id] = { weapons = { 1 } }, | |
[UnitDefNames['cordoom'].id] = { weapons = { 1, 1, 1} }, | |
[UnitDefNames['corflak'].id] = { weapons = { 2 } }, | |
[UnitDefNames['corscreamer'].id] = { weapons = { 2 } }, | |
[UnitDefNames['cortron'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corfmd'].id] = { weapons = { 3 } }, | |
[UnitDefNames['corint'].id] = { weapons = { 4 } }, | |
[UnitDefNames['corbuzz'].id] = { weapons = { 4 } }, | |
[UnitDefNames['armscab'].id] = { weapons = { 3 } }, | |
[UnitDefNames['armcarry'].id] = { weapons = { 3 } }, | |
[UnitDefNames['cormabm'].id] = { weapons = { 3 } }, | |
[UnitDefNames['corcarry'].id] = { weapons = { 3 } }, | |
-- SCAVENGERS | |
[UnitDefNames['scavengerdroppodbeacon_scav'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armannit3'].id] = { weapons = { 1 } }, | |
[UnitDefNames['armminivulc'].id] = { weapons = { 1 } }, | |
[UnitDefNames['cordoomt3'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corhllllt'].id] = { weapons = { 1 } }, | |
[UnitDefNames['corminibuzz'].id] = { weapons = { 1 } } | |
} | |
for unitDefID, _ in pairs(unitDefRings) do | |
initializeUnitDefRing(unitDefID) | |
end | |
-- Initialize Colors too | |
local scavlist = {} | |
for k,_ in pairs(unitDefRings) do | |
scavlist[k] = true | |
end | |
-- add scavs | |
for k,_ in pairs(scavlist) do | |
--Spring.Echo(k, UnitDefs[k].name) | |
if UnitDefNames[UnitDefs[k].name .. '_scav'] then | |
unitDefRings[UnitDefNames[UnitDefs[k].name .. '_scav'].id] = unitDefRings[k] | |
end | |
end | |
local scavlist = {} | |
for k,_ in pairs(mobileAntiUnitDefs) do | |
scavlist[k] = true | |
end | |
for k,v in pairs(scavlist) do | |
mobileAntiUnitDefs[UnitDefNames[UnitDefs[k].name .. '_scav'].id] = mobileAntiUnitDefs[k] | |
end | |
-- Initialize featureDefIDtoUnitDefID | |
local wreckheaps = {"_dead","_heap"} | |
for unitDefID,_ in pairs(unitDefRings) do | |
local unitDefName = UnitDefs[unitDefID].name | |
for i, suffix in pairs(wreckheaps) do | |
if FeatureDefNames[unitDefName..suffix] then | |
featureDefIDtoUnitDefID[FeatureDefNames[unitDefName..suffix].id] = unitDefID | |
--Spring.Echo(FeatureDefNames[unitDefName..suffix].id, unitDefID) | |
end | |
end | |
end | |
end | |
--Button display configuration | |
--position only relevant if no saved config data found | |
local spGetSpectatingState = Spring.GetSpectatingState | |
local spec, fullview = spGetSpectatingState() | |
local myAllyTeam = Spring.GetMyAllyTeamID() | |
local numallyteams = 2 | |
local defenses = {} -- table of unitID keys to info tables: | |
--unitID = {posx = 0, posy = 0, posz = 0, teamID = 0, | |
-- vaokeys = {key1 = targetvao1, ... } | |
--} | |
local enemydefenses = {} -- a minor optimization to prevent iterating over our own on removal search | |
local mobileAntiUnits = {} | |
-------------------------------------------------------------------------------- | |
local glDepthTest = gl.DepthTest | |
local glLineWidth = gl.LineWidth | |
local glTexture = gl.Texture | |
local glClear = gl.Clear | |
local glColorMask = gl.ColorMask | |
local glStencilTest = gl.StencilTest | |
local glStencilMask = gl.StencilMask | |
local glStencilFunc = gl.StencilFunc | |
local glStencilOp = gl.StencilOp | |
local GL_KEEP = 0x1E00 --GL.KEEP | |
local GL_REPLACE = GL.REPLACE --GL.KEEP | |
local spGetPositionLosState = Spring.GetPositionLosState | |
local spGetUnitDefID = Spring.GetUnitDefID | |
local spGetUnitPosition = Spring.GetUnitPosition | |
local chobbyInterface | |
function widget:TextCommand(command) | |
local mycommand=false --buttonConfig["enemy"][tag] | |
if string.find(command, "defrange", nil, true) then | |
mycommand = true | |
local ally = 'ally' | |
local rangetype = 'ground' | |
local enabled = false | |
if string.find(command, "enemy", nil, true) then | |
ally = 'enemy' | |
end | |
if string.find(command, "air", nil, true) then | |
rangetype = 'air' | |
elseif string.find(command, "nuke", nil, true) then | |
rangetype = 'nuke' | |
end | |
if string.find(command, "+", nil, true) then | |
enabled = true | |
end | |
buttonConfig[ally][rangetype]=enabled | |
Spring.Echo("Range visibility of "..ally.." "..rangetype.." defenses set to",enabled) | |
return true | |
end | |
return false | |
end | |
------ GL4 THINGS ----- | |
-- nukes and cannons: | |
local largeCircleVBO = nil | |
local largeCircleSegments = 512 | |
-- others: | |
local smallCircleVBO = nil | |
local smallCircleSegments = 128 | |
local weaponTypeToString = {"ground","air","nuke","cannon"} | |
local allyenemypairs = {"ally","enemy"} | |
local defenseRangeClasses = {'enemyair','enemyground','enemynuke','allyair','allyground','allynuke', 'enemycannon', 'allycannon'} | |
local defenseRangeVAOs = {} | |
local circleInstanceVBOLayout = { | |
{id = 1, name = 'posscale', size = 4}, -- a vec4 for pos + scale | |
{id = 2, name = 'color1', size = 4}, -- vec4 the color of this new | |
{id = 3, name = 'visibility', size = 4}, --- vec4 heightdrawstart, heightdrawend, fadefactorin, fadefactorout | |
{id = 4, name = 'projectileParams', size = 4}, --- heightboost gradient | |
{id = 5, name = 'instData', size = 4, type = GL.UNSIGNED_INT}, | |
} | |
local luaShaderDir = "LuaUI/Widgets/Include/" | |
local LuaShader = VFS.Include(luaShaderDir.."LuaShader.lua") | |
VFS.Include(luaShaderDir.."instancevbotable.lua") | |
local defenseRangeShader = nil | |
local function goodbye(reason) | |
Spring.Echo("DefenseRange GL4 widget exiting with reason: "..reason) | |
widgetHandler:RemoveWidget() | |
end | |
local function makeCircleVBO(circleSegments) | |
circleSegments = circleSegments -1 -- for po2 buffers | |
local circleVBO = gl.GetVBO(GL.ARRAY_BUFFER,true) | |
if circleVBO == nil then goodbye("Failed to create circleVBO") end | |
local VBOLayout = { | |
{id = 0, name = "position", size = 4}, | |
} | |
local VBOData = {} | |
for i = 0, circleSegments do -- this is +1 | |
VBOData[#VBOData+1] = math.sin(math.pi*2* i / circleSegments) -- X | |
VBOData[#VBOData+1] = math.cos(math.pi*2* i / circleSegments) -- Y | |
VBOData[#VBOData+1] = i / circleSegments -- circumference [0-1] | |
VBOData[#VBOData+1] = 0 | |
end | |
circleVBO:Define( | |
circleSegments + 1, | |
VBOLayout | |
) | |
circleVBO:Upload(VBOData) | |
return circleVBO | |
end | |
local vsSrc = [[ | |
#version 420 | |
#extension GL_ARB_uniform_buffer_object : require | |
#extension GL_ARB_shader_storage_buffer_object : require | |
#extension GL_ARB_shading_language_420pack: require | |
#line 10000 | |
//__DEFINES__ | |
layout (location = 0) in vec4 circlepointposition; | |
layout (location = 1) in vec4 posscale; | |
layout (location = 2) in vec4 color1; | |
layout (location = 3) in vec4 visibility; // FadeStart, FadeEnd, StartAlpha, EndAlpha | |
layout (location = 4) in vec4 projectileParams; // projectileSpeed, iscylinder!!!! , heightBoostFactor , heightMod | |
layout (location = 5) in uvec4 instData; | |
uniform float lineAlphaUniform = 1.0; | |
uniform float cannonmode = 0.0; | |
uniform sampler2D heightmapTex; | |
uniform sampler2D losTex; // hmm maybe? | |
out DataVS { | |
flat vec4 blendedcolor; | |
vec4 circleprogress; | |
}; | |
//__ENGINEUNIFORMBUFFERDEFS__ | |
layout(std140, binding=0) readonly buffer MatrixBuffer { | |
mat4 UnitPieces[]; | |
}; | |
#line 11000 | |
float heightAtWorldPos(vec2 w){ | |
vec2 uvhm = heighmapUVatWorldPos(w); | |
return textureLod(heightmapTex, uvhm, 0.0).x; | |
} | |
float GetRangeFactor(float projectileSpeed) { // returns >0 if weapon can shoot here, <0 if it cannot, 0 if just right | |
// on first run, with yDiff = 0, what do we get? | |
float speed2d = projectileSpeed * 0.707106; | |
float gravity = 120.0 * (0.001111111); | |
return ((speed2d * speed2d) * 2.0 ) / (gravity); | |
} | |
float GetRange2DCannon(float yDiff,float projectileSpeed,float rangeFactor,float heightBoostFactor) { // returns >0 if weapon can shoot here, <0 if it cannot, 0 if just right | |
// on first run, with yDiff = 0, what do we get? | |
//float factor = 0.707106; | |
float smoothHeight = 100.0; | |
float speed2d = projectileSpeed*0.707106; | |
float speed2dSq = speed2d * speed2d; | |
float gravity = -1.0* (120.0 /900); | |
if (heightBoostFactor < 0){ | |
heightBoostFactor = (2.0 - rangeFactor) / sqrt(rangeFactor); | |
} | |
if (yDiff < -100.0){ | |
yDiff = yDiff * heightBoostFactor; | |
}else { | |
if (yDiff < 0.0) { | |
yDiff = yDiff * (1.0 + (heightBoostFactor - 1.0 ) * (-1.0 * yDiff) * 0.01); | |
} | |
} | |
float root1 = speed2dSq + 2 * gravity *yDiff; | |
if (root1 < 0.0 ){ | |
return 0.0; | |
}else{ | |
return rangeFactor * ( speed2dSq + speed2d * sqrt( root1 ) ) / (-1.0 * gravity); | |
} | |
} | |
//float heightMod default: 0.2 (0.8 for #Cannon, 1.0 for #BeamLaser and #LightningCannon) | |
//Changes the spherical weapon range into an ellipsoid. Values above 1.0 mean the weapon cannot target as high as it can far, values below 1.0 mean it can target higher than it can far. For example 0.5 would allow the weapon to target twice as high as far. | |
//float heightBoostFactor default: -1.0 | |
//Controls the boost given to range by high terrain. Values > 1.0 result in increased range, 0.0 means the cannon has fixed range regardless of height difference to target. Any value < 0.0 (i.e. the default value) result in an automatically calculated value based on range and theoretical maximum range. | |
#define RANGE posscale.w | |
#define PROJECTILESPEED projectileParams.x | |
#define ISCYLINDER projectileParams.y | |
#define HEIGHTBOOSTFACTOR projectileParams.z | |
#define HEIGHTMOD projectileParams.w | |
#define YGROUND posscale.y | |
#define OUTOFBOUNDSALPHA alphaControl.y | |
#define FADEALPHA alphaControl.z | |
#define MOUSEALPHA alphaControl.w | |
void main() { | |
// Get the center pos of the unit | |
uint baseIndex = instData.x; // this tells us which unit matrix to find | |
mat4 modelMatrix = UnitPieces[baseIndex]; // This gives us the models world pos and rot matrix | |
vec3 modelWorldPos = modelMatrix[3].xyz; | |
circleprogress.xy = circlepointposition.xy; | |
circleprogress.w = circlepointposition.z; | |
// translate to world pos: | |
vec4 circleWorldPos = vec4(1.0); | |
circleWorldPos.xz = circlepointposition.xy * RANGE + modelWorldPos.xz; | |
vec4 alphaControl = vec4(1.0); | |
// get heightmap | |
circleWorldPos.y = heightAtWorldPos(circleWorldPos.xz); | |
if (cannonmode > 0.5){ | |
// BAR only has 3 distinct ballistic projectiles, heightBoostFactor is only a handful from -1 to 2.8 and 6 and 8 | |
// gravity we can assume to be linear | |
float heightDiff = (circleWorldPos.y - YGROUND) * 0.5; | |
float rangeFactor = RANGE / GetRangeFactor(PROJECTILESPEED); //correct | |
if (rangeFactor > 1.0 ) rangeFactor = 1.0; | |
if (rangeFactor <= 0.0 ) rangeFactor = 1.0; | |
float radius = RANGE;// - heightDiff; | |
float adjRadius = GetRange2DCannon(heightDiff * HEIGHTMOD, PROJECTILESPEED, rangeFactor, HEIGHTBOOSTFACTOR); | |
float adjustment = radius * 0.5; | |
float yDiff = 0; | |
float adds = 0; | |
//for (int i = 0; i < mod(timeInfo.x/8,16); i ++){ //i am a debugging god | |
for (int i = 0; i < 16; i ++){ | |
if (adjRadius > radius){ | |
radius = radius + adjustment; | |
adds = adds + 1; | |
}else{ | |
radius = radius - adjustment; | |
adds = adds - 1; | |
} | |
adjustment = adjustment * 0.5; | |
circleWorldPos.xz = circlepointposition.xy * radius + modelWorldPos.xz; | |
float newY = heightAtWorldPos(circleWorldPos.xz ); | |
yDiff = abs(circleWorldPos.y - newY); | |
circleWorldPos.y = max(0, newY); | |
heightDiff = circleWorldPos.y - modelWorldPos.y; | |
adjRadius = GetRange2DCannon(heightDiff * HEIGHTMOD, PROJECTILESPEED, rangeFactor, HEIGHTBOOSTFACTOR); | |
} | |
}else{ | |
if (ISCYLINDER < 0.5){ // isCylinder | |
//simple implementation, 4 samples per point | |
//for (int i = 0; i<mod(timeInfo.x/4,30); i++){ | |
for (int i = 0; i<8; i++){ | |
// draw vector from centerpoint to new height point and normalize it to range length | |
vec3 tonew = circleWorldPos.xyz - modelWorldPos.xyz; | |
tonew.y *= HEIGHTMOD; | |
tonew = normalize(tonew) * RANGE; | |
circleWorldPos.xz = modelWorldPos.xz + tonew.xz; | |
circleWorldPos.y = heightAtWorldPos(circleWorldPos.xz); | |
} | |
} | |
} | |
circleWorldPos.y += 6; // lift it from the ground | |
// -- MAP OUT OF BOUNDS | |
vec2 mymin = min(circleWorldPos.xz,mapSize.xy - circleWorldPos.xz); | |
float inboundsness = min(mymin.x, mymin.y); | |
OUTOFBOUNDSALPHA = 1.0 - clamp(inboundsness*(-0.02),0.0,1.0); | |
//--- DISTANCE FADE --- | |
vec4 camPos = cameraViewInv[3]; | |
float distToCam = length(modelWorldPos.xyz - camPos.xyz); //dist from cam | |
// FadeStart, FadeEnd, StartAlpha, EndAlpha | |
float fadeDist = visibility.y - visibility.x; | |
FADEALPHA = clamp((visibility.y - distToCam)/(fadeDist),0,1);//,visibility.z,visibility.w); | |
//--- Optimize by anything faded out getting transformed back to origin with 0 range? | |
//seems pretty ok! | |
if (FADEALPHA < 0.001) { | |
circleWorldPos.xyz = modelWorldPos.xyz; | |
} | |
if (cannonmode > 0.5){ | |
// cannons should fade distance based on their range | |
float cvmin = max(visibility.x, 2* RANGE); | |
float cvmax = max(visibility.y, 4* RANGE); | |
//FADEALPHA = clamp((cvmin - distToCam)/(cvmax - cvmin + 1.0),visibility.z,visibility.w); | |
} | |
blendedcolor = color1; | |
// -- DARKEN OUT OF LOS | |
vec4 losTexSample = texture(losTex, vec2(circleWorldPos.x / mapSize.z, circleWorldPos.z / mapSize.w)); // lostex is PO2 | |
float inlos = dot(losTexSample.rgb,vec3(0.33)); | |
inlos = clamp(inlos*5 -1.4 , 0.5,1.0); // fuck if i know why, but change this if LOSCOLORS are changed! | |
blendedcolor.rgb *= inlos; | |
// --- YES FOG | |
float fogDist = length((cameraView * vec4(circleWorldPos.xyz,1.0)).xyz); | |
float fogFactor = clamp((fogParams.y - fogDist) * fogParams.w, 0, 1); | |
blendedcolor.rgb = mix(fogColor.rgb, vec3(blendedcolor), fogFactor); | |
// -- IN-SHADER MOUSE-POS BASED HIGHLIGHTING | |
float disttomousefromunit = 1.0 - smoothstep(48, 64, length(modelWorldPos.xz - mouseWorldPos.xz)); | |
// this will be positive if in mouse, negative else | |
float highightme = clamp( (disttomousefromunit ) + 0.0, 0.0, 1.0); | |
MOUSEALPHA = highightme; | |
// ------------ dump the stuff for FS -------------------- | |
//worldPos = circleWorldPos; | |
//worldPos.a = RANGE; | |
alphaControl.x = circlepointposition.z; // save circle progress here | |
gl_Position = cameraViewProj * vec4(circleWorldPos.xyz, 1.0); | |
//lets blend the alpha here, and save work in FS: | |
float outalpha = OUTOFBOUNDSALPHA * (MOUSEALPHA + FADEALPHA * lineAlphaUniform); | |
blendedcolor.a *= outalpha ; | |
//blendedcolor.rgb = vec3(fract(distToCam/100)); | |
} | |
]] | |
local fsSrc = [[ | |
#version 330 | |
#extension GL_ARB_uniform_buffer_object : require | |
#extension GL_ARB_shading_language_420pack: require | |
//_DEFINES__ | |
#line 20000 | |
uniform float drawMode = 0.0; // 0.0 is default, 1.0 is stipple circle, 2.0 is shade disc | |
uniform sampler2D discTex; | |
//_ENGINEUNIFORMBUFFERDEFS__ | |
in DataVS { | |
flat vec4 blendedcolor; | |
vec4 circleprogress; | |
}; | |
out vec4 fragColor; | |
void main() { | |
fragColor = blendedcolor; // now pared down to only this, all work is done in vertex shader now | |
if (drawMode > 0.5){ | |
if (drawMode > 1.5){ // shade disc | |
fragColor = vec4 (abs(circleprogress.xy), 0, 1.0); | |
fragColor.rgb = texture(discTex, abs(circleprogress.xy)).rgb; | |
fragColor.rgb = vec3(length(circleprogress.xy)); | |
}else { | |
fragColor = vec4 (vec3(step(0.5, fract(circleprogress.w * 100))), 1.0); | |
} | |
} | |
} | |
]] | |
local function makeShaders() | |
local engineUniformBufferDefs = LuaShader.GetEngineUniformBufferDefs() | |
vsSrc = vsSrc:gsub("//__ENGINEUNIFORMBUFFERDEFS__", engineUniformBufferDefs) | |
fsSrc = fsSrc:gsub("//__ENGINEUNIFORMBUFFERDEFS__", engineUniformBufferDefs) | |
defenseRangeShader = LuaShader( | |
{ | |
vertex = vsSrc:gsub("//__DEFINES__", "#define MYGRAVITY "..tostring(Game.gravity+0.1)), | |
fragment = fsSrc, | |
--geometry = gsSrc, no geom shader for now | |
uniformInt = { | |
heightmapTex = 0, | |
losTex = 1, | |
discTex = 2, | |
}, | |
uniformFloat = { | |
lineAlphaUniform = 1, | |
cannonmode = 0, | |
}, | |
}, | |
"defenseRangeShader GL4" | |
) | |
shaderCompiled = defenseRangeShader:Initialize() | |
if not shaderCompiled then | |
goodbye("Failed to compile defenseRangeShader GL4 ") | |
return false | |
end | |
return true | |
end | |
local function initGL4() | |
smallCircleVBO = makeCircleVBO(smallCircleSegments) | |
largeCircleVBO = makeCircleVBO(largeCircleSegments) | |
for i,defRangeClass in ipairs(defenseRangeClasses) do | |
defenseRangeVAOs[defRangeClass] = makeInstanceVBOTable(circleInstanceVBOLayout,16,defRangeClass, 5) -- 5 is unitIDattribID (instData) | |
if defRangeClass:find("cannon", nil, true) or defRangeClass:find("nuke", nil, true) then | |
defenseRangeVAOs[defRangeClass].vertexVBO = largeCircleVBO | |
defenseRangeVAOs[defRangeClass].numVertices = largeCircleSegments | |
else | |
defenseRangeVAOs[defRangeClass].vertexVBO = smallCircleVBO | |
defenseRangeVAOs[defRangeClass].numVertices = smallCircleSegments | |
end | |
local newVAO = makeVAOandAttach(defenseRangeVAOs[defRangeClass].vertexVBO,defenseRangeVAOs[defRangeClass].instanceVBO) | |
defenseRangeVAOs[defRangeClass].VAO = newVAO | |
end | |
return makeShaders() | |
end | |
function widget:Initialize() | |
initUnitList() | |
if initGL4() == false then | |
return | |
end | |
WG['defrange'] = {} | |
for _,ae in ipairs({'ally','enemy'}) do | |
local Ae = string.upper(string.sub(ae, 1, 1)) .. string.sub(ae, 2) | |
for _,wt in ipairs({'ground','air','nuke'}) do | |
local Wt = string.upper(string.sub(wt, 1, 1)) .. string.sub(wt, 2) | |
WG['defrange']['get'..Ae..Wt] = function() return buttonConfig[ae][wt] end | |
WG['defrange']['set'..Ae..Wt] = function(value) | |
buttonConfig[ae][wt] = value | |
Spring.Echo(string.format("Defense Range GL4 Setting %s%s to %s",Ae,Wt, value and 'on' or 'off')) | |
if WG['unittrackerapi'] and WG['unittrackerapi'].visibleUnits then | |
widget:VisibleUnitsChanged(WG['unittrackerapi'].visibleUnits, nil) | |
end | |
end | |
end | |
end | |
myAllyTeam = Spring.GetMyAllyTeamID() | |
local allyteamlist = Spring.GetAllyTeamList( ) | |
--Spring.Echo("# of allyteams = ", #allyteamlist) | |
numallyteams = #allyteamlist | |
if WG['unittrackerapi'] and WG['unittrackerapi'].visibleUnits then | |
widget:VisibleUnitsChanged(WG['unittrackerapi'].visibleUnits, nil) | |
end | |
end | |
local floor = math.floor | |
local function hashPos(x,z) | |
return floor(x/8)*4096 + floor(z/8) | |
end | |
local cacheTable = {} | |
for i=1,20 do cacheTable[i] = 0 end | |
local function UnitDetected(unitID, unitDefID, unitTeam, noUpload) | |
if unitDefRings[unitDefID] == nil then return end -- no rings for this | |
if defenses[unitID] ~= nil then return end -- already has rings | |
-- otherwise we must add it! | |
--local weapons = unitDefs[unitDefID].weapons | |
local alliedUnit = (Spring.GetUnitAllyTeam(unitID) == myAllyTeam) | |
local x, y, z, mpx, mpy, mpz, apx, apy, apz = spGetUnitPosition(unitID, true, true) | |
--for weaponNum = 1, #weapons do | |
local addedrings = 0 | |
for i, weaponType in pairs(unitDefRings[unitDefID]['weapons']) do | |
local allystring = alliedUnit and "ally" or "enemy" | |
if buttonConfig[allystring][buttonconfigmap[weaponType]] then | |
--local weaponType = unitDefRings[unitDefID]['weapons'][weaponNum] | |
cacheTable[1] = mpx | |
cacheTable[2] = mpy | |
cacheTable[3] = mpz | |
local vaokey = allystring .. weaponTypeToString[weaponType] | |
local ringParams = unitDefRings[unitDefID]['rings'][i] | |
for i = 1,13 do | |
cacheTable[i+3] = ringParams[i] | |
end | |
if true then | |
local s = ' ' | |
for i = 1,16 do | |
s = s .. "; " ..tostring(cacheTable[i]) | |
end | |
--Spring.Echo("Adding rings for", unitID, x,z) | |
--Spring.Echo("added",vaokey,s) | |
end | |
local instanceID = 1000000 * weaponType + unitID | |
pushElementInstance(defenseRangeVAOs[vaokey], cacheTable, instanceID, true, noUpload, unitID) | |
addedrings = addedrings + 1 | |
if defenses[unitID] == nil then | |
--lazy creation | |
defenses[unitID] = { posx = mpx, posy = mpy, posz = mpz, vaokeys = {}, allied = alliedUnit, unitDefID = unitDefID} | |
end | |
defenses[unitID].vaokeys[instanceID] = vaokey | |
end | |
end | |
if addedrings == 0 then | |
return | |
end | |
if mobileAntiUnitDefs[unitDefID] then | |
mobileAntiUnits[unitID] = true | |
end | |
if alliedUnit then -- if allied rings are on, then add them! | |
else | |
enemydefenses[unitID] = true | |
defensePosHash[hashPos(x,z)] = unitID | |
end | |
end | |
function widget:VisibleUnitAdded(unitID, unitDefID, unitTeam) | |
UnitDetected(unitID, unitDefID, unitTeam) | |
end | |
function widget:VisibleUnitsChanged(extVisibleUnits, extNumVisibleUnits) | |
-- the set of visible units changed. Now is a good time to reevalueate our life choices | |
-- This happens when we move from team to team, or when we move from spec to other | |
-- my | |
spec, fullview = Spring.GetSpectatingState() | |
if (not enabledAsSpec) and spec then | |
Spring.Echo("Defense Range GL4 disabled in spectating state") | |
widget:RemoveWidget() | |
return | |
end | |
defenses = {} | |
enemydefenses = {} | |
defensePosHash = {} | |
mobileAntiUnits = {} | |
for vaokey, instanceTable in pairs(defenseRangeVAOs) do | |
clearInstanceTable(instanceTable) -- clear all instances | |
end | |
for unitID, unitDefID in pairs(extVisibleUnits) do | |
UnitDetected(unitID, unitDefID, Spring.GetUnitTeam(unitID), true) -- add them with noUpload = true | |
end | |
for vaokey, instanceTable in pairs(defenseRangeVAOs) do | |
uploadAllElements(instanceTable) -- clear all instances | |
end | |
end | |
local function checkEnemyUnitConfirmedDead(unitID, defense) | |
local x, y, z = defense["posx"], defense["posy"], defense["posz"] | |
local _, losState, _ = spGetPositionLosState(x, y, z) | |
--Spring.Echo("checkEnemyUnitConfirmedDead",unitID, losState, spGetUnitDefID(unitID), Spring.GetUnitIsDead(unitID)) | |
if losState then -- visible | |
if Spring.GetUnitIsDead(unitID) ~= false then -- If its cloaked and jammed, we cant see it i think | |
return true | |
end | |
end | |
return false | |
end | |
local function removeUnit(unitID,defense) | |
mobileAntiUnits[unitID] = nil | |
enemydefenses[unitID] = nil | |
defensePosHash[hashPos(defense.posx,defense.posz)] = nil | |
for instanceKey,vaoKey in pairs(defense.vaokeys) do | |
--Spring.Echo(vaoKey,instanceKey) | |
popElementInstance(defenseRangeVAOs[vaoKey],instanceKey) | |
end | |
defenses[unitID] = nil | |
end | |
function widget:VisibleUnitRemoved(unitID) -- remove the corresponding ground plate if it exists | |
if defenses[unitID] == nil then return end -- nothing to do | |
local defense = defenses[unitID] | |
--local teamID = Spring.GetUnitTeam(unitID) | |
local removeme = false | |
if mobileAntiUnits[unitID] then | |
removeme = true | |
else | |
if defense.allied then | |
removeme = true | |
else | |
removeme = checkEnemyUnitConfirmedDead(unitID, defense) | |
-- if we cant get unitDefID, then its probably an enemy unit | |
-- we also dont know the reason for removal, but we can check wether its pos is in los: | |
end | |
end | |
if removeme then | |
removeUnit(unitID, defense) | |
end | |
end | |
function widget:FeatureCreated(featureID, allyTeam) | |
-- check if the feature we created could be related to a defense that we currently have active? | |
-- ugh this will require a unitdefid based hash and some other nasty tricks | |
-- check if the feature was created outside of LOS | |
local featureDefID = Spring.GetFeatureDefID(featureID) | |
if featureDefID and featureDefIDtoUnitDefID[featureDefID] then | |
local fx, fy, fz = Spring.GetFeaturePosition(featureID) | |
local poshash = floor(fx/8)*4096 + floor(fz/8) | |
local unitID = defensePosHash[poshash] | |
if unitID then | |
if defenses[unitID] and defenses[unitID].allied == false and | |
featureDefIDtoUnitDefID[featureDefID] == defenses[unitID].unitDefID then | |
--Spring.Echo("feature created at a likely dead defense pos!") | |
removeUnit(unitID,defenses[unitID]) | |
end | |
end | |
end | |
end | |
function widget:PlayerChanged(playerID) | |
--[[ | |
Spring.Echo("playerchanged", playerID) | |
local GetLocalPlayerID = Spring.GetLocalPlayerID( ) | |
--Spring.Echo("GetLocalPlayerID", GetLocalPlayerID) | |
local GetMyTeamID = Spring.GetMyTeamID ( ) | |
--Spring.Echo("GetMyTeamID", GetMyTeamID) | |
]]-- | |
local nowspGetSpectatingState = Spring.GetSpectatingState() | |
local nowspec, nowfullview = spGetSpectatingState() | |
local nowmyAllyTeam = Spring.GetMyAllyTeamID() | |
-- When we start, check if there are >2 allyteams | |
local reinit = false | |
-- check spec transition | |
if spec ~= nowspec then | |
--keep allyteam, but reinit | |
reinit = true | |
-- When widget starts, allied check is fine, its correct w.r.t to myteamid | |
end | |
spec = nowspec | |
if numallyteams > 3 then -- one for gaia | |
if nowmyAllyTeam ~= myAllyTeam then | |
reinit = true | |
end | |
else | |
-- if there are only 2 ally teams, no need to reinit | |
end | |
if reinit then | |
myAllyTeam = nowmyAllyTeam -- only update if we reinit | |
--Spring.Echo("DefenseRange GL4 allyteam change detected, reinitializing") | |
if WG['unittrackerapi'] and WG['unittrackerapi'].visibleUnits then | |
widget:VisibleUnitsChanged(WG['unittrackerapi'].visibleUnits, nil) | |
end | |
else | |
--Spring.Echo("No change needed", numallyteams, myAllyTeam) | |
end | |
end | |
local gameFrame = 0 | |
local lastUpdatedGameFrame = 0 | |
local antiupdaterate = 1 | |
local removalRate = 6 | |
local lastRemoval = 0 | |
local removestep = 0 | |
function widget:GameFrame(gf) | |
gameFrame = gf | |
end | |
function widget:Update(dt) | |
--spec, fullview = spGetSpectatingState() | |
--if spec then | |
-- return | |
--end | |
if gameFrame >= lastUpdatedGameFrame + antiupdaterate then | |
lastUpdatedGameFrame = gameFrame | |
--update the goddamned stupid mobile anti vbo ffs | |
for unitID, mobileantiinfo in pairs(mobileAntiUnits) do | |
local px, py, pz = spGetUnitPosition(unitID) | |
if px then | |
local defense = defenses[unitID] | |
defense.posx = px | |
defense.posy = py | |
defense.posz = pz | |
for instanceKey,vaoKey in pairs(defense.vaokeys) do | |
local cacheTable = getElementInstanceData(defenseRangeVAOs[vaoKey], instanceKey, cacheTable) -- this is horrible perf wise | |
--Spring.Echo("Anti at",unitID, px, pz,mobileantiinfo[1],mobileantiinfo[2],vbodata[1],vbodata[2]) | |
cacheTable[1] = px | |
cacheTable[2] = py | |
cacheTable[3] = pz | |
pushElementInstance(defenseRangeVAOs[vaoKey],cacheTable,instanceKey, true, unitID) -- last true is updateExisting | |
end | |
end | |
end | |
end | |
if gameFrame >= lastRemoval + removalRate then | |
lastRemoval = gameFrame | |
removestep = (removestep + 1) % removalRate | |
--remove dead units | |
local scanned = 0 | |
for unitID, _ in pairs(enemydefenses) do | |
if unitID % removalRate == removestep then | |
local defense = defenses[unitID] | |
scanned = scanned + 1 | |
if defense.allied == false then | |
local x, y, z = defense["posx"], defense["posy"], defense["posz"] | |
local _, losState, _ = spGetPositionLosState(x, y, z) | |
--Spring.Echo("removal",unitID, losState) | |
if losState then | |
if not spGetUnitDefID(unitID) then | |
removeUnit(unitID, defense) | |
end | |
end | |
end | |
end | |
end | |
--Spring.Echo("removestep", removestep , scanned) | |
end | |
end | |
function widget:RecvLuaMsg(msg, playerID) | |
if msg:sub(1,18) == 'LobbyOverlayActive' then | |
chobbyInterface = (msg:sub(1,19) == 'LobbyOverlayActive1') | |
end | |
end | |
local drawcounts = {} | |
local cameraHeightFactor = 0 | |
local function GetCameraHeightFactor() -- returns a smoothstepped value between 0 and 1 for height based rescaling of line width. | |
local camX, camY, camZ = Spring.GetCameraPosition() | |
local camheight = camY - math.max(Spring.GetGroundHeight(camX, camZ), 0) | |
-- Smoothstep to half line width as camera goes over 2k height to 4k height | |
--genType t; /* Or genDType t; */ | |
--t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); | |
--return t * t * (3.0 - 2.0 * t); | |
camheight = math.max(0.0, math.min(1.0, (camheight - colorConfig.distanceScaleStart) / (colorConfig.distanceScaleEnd - colorConfig.distanceScaleStart))) | |
--return camheight * camheight * (3 - 2 *camheight) | |
return 1 | |
end | |
local groundnukeair = {"ground","air","nuke"} | |
local function DRAWRINGS(primitiveType, linethickness) | |
local stencilMask | |
defenseRangeShader:SetUniform("cannonmode",0) | |
for i,allyState in ipairs(allyenemypairs) do | |
for j, wt in ipairs(groundnukeair) do | |
local defRangeClass = allyState..wt | |
local iT = defenseRangeVAOs[defRangeClass] | |
stencilMask = 2 ^ ( 4 * (i-1) + (j-1)) -- from 1 to 128 | |
drawcounts[stencilMask] = iT.usedElements | |
if iT.usedElements > 0 and buttonConfig[allyState][wt] then | |
if linethickness then | |
glLineWidth(colorConfig[wt][linethickness] * cameraHeightFactor) | |
end | |
glStencilMask(stencilMask) -- only allow these bits to get written | |
glStencilFunc(GL.NOTEQUAL, stencilMask, stencilMask) -- what to do with the stencil | |
iT.VAO:DrawArrays(primitiveType,iT.numVertices,0,iT.usedElements,0) -- +1!!! | |
end | |
end | |
end | |
defenseRangeShader:SetUniform("cannonmode",1) | |
for i,allyState in ipairs(allyenemypairs) do | |
local defRangeClass = allyState.."cannon" | |
local iT = defenseRangeVAOs[defRangeClass] | |
stencilMask = 2 ^ ( 4 * (i-1) + 3) | |
drawcounts[stencilMask] = iT.usedElements | |
if iT.usedElements > 0 and buttonConfig[allyState]["ground"] then | |
if linethickness then | |
glLineWidth(colorConfig['cannon'][linethickness] * cameraHeightFactor) | |
end | |
glStencilMask(stencilMask) | |
glStencilFunc(GL.NOTEQUAL, stencilMask, stencilMask) | |
iT.VAO:DrawArrays(primitiveType,iT.numVertices,0,iT.usedElements,0) -- +1!!! | |
end | |
end | |
end | |
function widget:DrawWorldPreUnit() | |
--if fullview and not enabledAsSpec then | |
-- return | |
--end | |
if chobbyInterface then return end | |
if not Spring.IsGUIHidden() and (not WG['topbar'] or not WG['topbar'].showingQuit()) then | |
cameraHeightFactor = GetCameraHeightFactor() * 0.5 + 0.5 | |
glTexture(0, "$heightmap") | |
glTexture(1, "$info") | |
glTexture(2, "luaui/images/aliasing_test_grid_128.tga") | |
-- Stencil Setup | |
-- -- https://learnopengl.com/Advanced-OpenGL/Stencil-testing | |
if colorConfig.drawStencil then | |
glClear(GL.STENCIL_BUFFER_BIT) -- clear prev stencil | |
glDepthTest(false) -- always draw | |
--glColorMask(false, false, false, false) -- disable color drawing | |
glStencilTest(true) -- enable stencil test | |
glStencilMask(255) -- all 8 bits | |
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) -- Set The Stencil Buffer To 1 Where Draw Any Polygon | |
defenseRangeShader:Activate() | |
defenseRangeShader:SetUniform("drawMode", 2.0) | |
DRAWRINGS(GL.TRIANGLE_FAN) -- FILL THE CIRCLES | |
--glLineWidth(math.max(0.1,4 + math.sin(gameFrame * 0.04) * 10)) | |
glColorMask(true, true, true, true) -- re-enable color drawing | |
glStencilMask(0) | |
defenseRangeShader:SetUniform("lineAlphaUniform",colorConfig.externalalpha) | |
glDepthTest(GL.LEQUAL) -- test for depth on these outside cases | |
defenseRangeShader:SetUniform("drawMode", 0.0) | |
DRAWRINGS(GL.LINE_LOOP, 'externallinethickness') -- DRAW THE OUTER RINGS | |
glStencilTest(false) | |
end | |
if colorConfig.drawInnerRings then | |
defenseRangeShader:SetUniform("lineAlphaUniform",colorConfig.internalalpha) | |
defenseRangeShader:SetUniform("drawMode", 1.0) | |
DRAWRINGS(GL.LINE_LOOP, 'internallinethickness') -- DRAW THE INNER RINGS | |
end | |
defenseRangeShader:Deactivate() | |
glTexture(0, false) | |
glTexture(1, false) | |
glDepthTest(false) | |
if false and Spring.GetDrawFrame() % 60 == 0 then | |
local s = 'drawcounts: ' | |
for k,v in pairs(drawcounts) do s = s .. " " .. tostring(k) .. ":" .. tostring(v) end | |
Spring.Echo(s) | |
end | |
end | |
end | |
--- SHIT THAT NEEDS TO BE IN CONFIG: | |
-- ALLY/ENEMY | |
-- AIR/NUKE/GROUND | |
-- OPACITY | |
-- ENABLE IN SPEC MODE | |
-- LINEWIDTH | |
-- internalrings | |
-- nostencil mode | |
--SAVE / LOAD CONFIG FILE | |
function widget:GetConfigData() | |
local data = {} | |
data["enabled"] = buttonConfig | |
return data | |
end | |
function widget:SetConfigData(data) | |
if data ~= nil then | |
if data["enabled"] ~= nil then | |
buttonConfig = data["enabled"] | |
--printDebug("enabled config found...") | |
end | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment