diff --git a/luarules/gadgets/unit_seismic_ping.lua b/luarules/gadgets/unit_seismic_ping.lua index 0d9c42fb173..e602f970177 100644 --- a/luarules/gadgets/unit_seismic_ping.lua +++ b/luarules/gadgets/unit_seismic_ping.lua @@ -23,7 +23,11 @@ end local spGetSpectatingState = Spring.GetSpectatingState local spGetMyAllyTeamID = Spring.GetMyAllyTeamID local spGetGroundHeight = Spring.GetGroundHeight -local spGetViewGeometry = Spring.GetViewGeometry +local spGetCameraPosition = Spring.GetCameraPosition +local spGetUnitAllyTeam = Spring.GetUnitAllyTeam +local spGetUnitIsCloaked = Spring.GetUnitIsCloaked +local spIsGUIHidden = Spring.IsGUIHidden +local spIsSphereInView = Spring.IsSphereInView local glColor = gl.Color local glPushMatrix = gl.PushMatrix @@ -34,159 +38,98 @@ local glScale = gl.Scale local glBlending = gl.Blending local glDepthTest = gl.DepthTest local glBillboard = gl.Billboard -local glCallList = gl.CallList -local glCreateList = gl.CreateList -local glDeleteList = gl.DeleteList -local glBeginEnd = gl.BeginEnd -local glVertex = gl.Vertex +local glTexture = gl.Texture +local glTexRect = gl.TexRect local GL_SRC_ALPHA = GL.SRC_ALPHA local GL_ONE = GL.ONE local GL_ONE_MINUS_SRC_ALPHA = GL.ONE_MINUS_SRC_ALPHA -local GL_QUADS = GL.QUADS -local sin = math.sin -local cos = math.cos -local pi = math.pi -local pi2 = pi * 2 local max = math.max local min = math.min +local sqrt = math.sqrt +local floor = math.floor -------------------------------------------------------------------------------- -- Config -------------------------------------------------------------------------------- local pingLifetime = 0.95 -local baseRadius = 16 -local maxRadius = 22 -local baseThickness = 2.4 +local baseRadius = 15 +local maxRadius = 19 +local onlyCloakedUnits = true +local drawFlatOnMap = true +local hideWhenTerrainOccluded = true +local terrainOcclusionSamples = 6 +local terrainOcclusionMargin = 8 +local pingHeightOffset = drawFlatOnMap and 1.5 or 5 -------------------------------------------------------------------------------- -- State -------------------------------------------------------------------------------- local pings = {} +local pingCount = 0 +local pingPool = {} +local pingPoolCount = 0 local gameTime = 0 local thicknessScale = 1.2 -------------------------------------------------------------------------------- --- Display lists for arc geometry (pre-generated at unit radius with proportional thickness) +-- Textures -------------------------------------------------------------------------------- -local displayLists = { - outerArcs = {}, -- 4 arcs at 60 degrees each - middleArcs = {}, -- 3 arcs at 80 degrees each - innerArcs = {}, -- 2 arcs at 120 degrees each - centerCircle = nil, -- Full circle - -- Outlines (slightly larger versions for dark border) - outerOutlines = {}, - middleOutlines = {}, - innerOutlines = {}, +local atlasTexture = "LuaRules/Images/seismic_ping/seismic_atlas.png" +local atlasSprites = { + outerRing = { 0 / 7, 0, 1 / 7, 1 }, + outerOutline = { 1 / 7, 0, 2 / 7, 1 }, + middleRing = { 2 / 7, 0, 3 / 7, 1 }, + middleOutline = { 3 / 7, 0, 4 / 7, 1 }, + innerRing = { 4 / 7, 0, 5 / 7, 1 }, + innerOutline = { 5 / 7, 0, 6 / 7, 1 }, + centerDot = { 6 / 7, 0, 7 / 7, 1 }, } --- Proportional thicknesses (relative to unit radius 1.0) -local outerThicknessRatio = baseThickness * 1.05 / baseRadius -local middleThicknessRatio = baseThickness * 0.8 / baseRadius -local innerThicknessRatio = baseThickness * 1 / baseRadius -local centerThicknessRatio = baseThickness * 1.8 / baseRadius -local outlineExtra = 0.02 -- How much larger the outline is on each side +-- Texture radius in source image does not fill full quad, so apply scale compensation. +local outerQuadScale = 1.17 +local middleQuadScale = 1.18 +local innerQuadScale = 1.24 +local centerQuadScale = 2.2 -------------------------------------------------------------------------------- --- Helper: Draw a thick arc as geometry (for display list creation) +-- Draw a textured billboard quad -------------------------------------------------------------------------------- -local function DrawThickArcVertices(innerRadius, outerRadius, startAngle, endAngle, segments) - local angleStep = (endAngle - startAngle) / segments - for i = 0, segments - 1 do - local angle1 = startAngle + i * angleStep - local angle2 = startAngle + (i + 1) * angleStep - local cos1, sin1 = cos(angle1), sin(angle1) - local cos2, sin2 = cos(angle2), sin(angle2) - glVertex(cos1 * innerRadius, sin1 * innerRadius, 0) - glVertex(cos1 * outerRadius, sin1 * outerRadius, 0) - glVertex(cos2 * outerRadius, sin2 * outerRadius, 0) - glVertex(cos2 * innerRadius, sin2 * innerRadius, 0) +local function DrawTexturedQuad(sprite, scale, rotation) + local s1, t1, s2, t2 = sprite[1], sprite[2], sprite[3], sprite[4] + glPushMatrix() + if rotation then + glRotate(rotation, 0, 0, 1) end + glScale(scale, scale, 1) + glTexRect(-1, -1, 1, 1, s1, t1, s2, t2) + glPopMatrix() end --------------------------------------------------------------------------------- --- Create display lists for all arc types --------------------------------------------------------------------------------- -local function CreateDisplayLists() - -- Outer arcs: 4 arcs, 60 degrees each, at unit radius with proportional thickness - local outerInner = 1.08 - outerThicknessRatio / 2 - local outerOuter = 1.08 + outerThicknessRatio / 2 - for i = 0, 3 do - local startAngle = (i * 90) * pi / 180 - local arcLength = 60 * pi / 180 - -- Outline (slightly larger) - displayLists.outerOutlines[i] = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, outerInner - outlineExtra, outerOuter + outlineExtra, startAngle - 0.02, startAngle + arcLength + 0.02, 12) - end) - -- Main arc - displayLists.outerArcs[i] = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, outerInner, outerOuter, startAngle, startAngle + arcLength, 12) - end) - end - - -- Middle arcs: 3 arcs, 80 degrees each, at 0.85 of unit radius - local middleRadiusRatio = 0.85 - local middleInner = middleRadiusRatio - middleThicknessRatio / 2 - local middleOuter = middleRadiusRatio + middleThicknessRatio / 2 - for i = 0, 2 do - local startAngle = (i * 120) * pi / 180 - local arcLength = 80 * pi / 180 - -- Outline (slightly larger) - displayLists.middleOutlines[i] = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, middleInner - outlineExtra, middleOuter + outlineExtra, startAngle - 0.02, startAngle + arcLength + 0.02, 12) - end) - -- Main arc - displayLists.middleArcs[i] = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, middleInner, middleOuter, startAngle, startAngle + arcLength, 12) - end) - end - - -- Inner arcs: 2 arcs, 120 degrees each, at 0.66 of unit radius - local innerRadiusRatio = 0.66 - local innerInner = innerRadiusRatio - innerThicknessRatio / 2 - local innerOuter = innerRadiusRatio + innerThicknessRatio / 2 - for i = 0, 1 do - local startAngle = (i * 180) * pi / 180 - local arcLength = 120 * pi / 180 - -- Outline (slightly larger) - displayLists.innerOutlines[i] = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, innerInner - outlineExtra, innerOuter + outlineExtra, startAngle - 0.02, startAngle + arcLength + 0.02, 16) - end) - -- Main arc - displayLists.innerArcs[i] = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, innerInner, innerOuter, startAngle, startAngle + arcLength, 16) - end) +-- Cheap terrain line test: if terrain crosses camera->ping center line, hide full ping. +local function IsTerrainOccluded(camX, camY, camZ, pingX, pingY, pingZ) + local dx = pingX - camX + local dy = pingY - camY + local dz = pingZ - camZ + local distance = sqrt(dx * dx + dy * dy + dz * dz) + local samples = terrainOcclusionSamples + min(8, floor(distance / 700)) + local step = 1 / (samples + 1) + + for i = 1, samples do + local t = i * step + local sx = camX + dx * t + local sy = camY + dy * t + local sz = camZ + dz * t + if spGetGroundHeight(sx, sz) > sy + terrainOcclusionMargin then + return true + end end - -- Center circle: full circle at unit radius with proportional thickness - local centerInner = 1 - centerThicknessRatio / 1.3 - local centerOuter = 1.25 + centerThicknessRatio / 1.3 - displayLists.centerCircle = glCreateList(function() - glBeginEnd(GL_QUADS, DrawThickArcVertices, centerInner, centerOuter, 0, pi2, 20) - end) -end - --------------------------------------------------------------------------------- --- Delete display lists --------------------------------------------------------------------------------- -local function DeleteDisplayLists() - for i = 0, 3 do - if displayLists.outerArcs[i] then glDeleteList(displayLists.outerArcs[i]) end - if displayLists.outerOutlines[i] then glDeleteList(displayLists.outerOutlines[i]) end - end - for i = 0, 2 do - if displayLists.middleArcs[i] then glDeleteList(displayLists.middleArcs[i]) end - if displayLists.middleOutlines[i] then glDeleteList(displayLists.middleOutlines[i]) end - end - for i = 0, 1 do - if displayLists.innerArcs[i] then glDeleteList(displayLists.innerArcs[i]) end - if displayLists.innerOutlines[i] then glDeleteList(displayLists.innerOutlines[i]) end - end - if displayLists.centerCircle then glDeleteList(displayLists.centerCircle) end + return false end -------------------------------------------------------------------------------- --- Draw a single seismic ping with rotating arcs using display lists +-- Draw a single seismic ping with rotating textured rings -------------------------------------------------------------------------------- local function DrawPing(ping, currentTime, cameraDistance) local age = currentTime - ping.startTime @@ -199,8 +142,13 @@ local function DrawPing(ping, currentTime, cameraDistance) local wx, wy, wz = ping.x, ping.y, ping.z glPushMatrix() - glTranslate(wx, wy + 5, wz) - glBillboard() + glTranslate(wx, wy + pingHeightOffset, wz) + if drawFlatOnMap then + glRotate(90, 1, 0, 0) + else + glBillboard() + end + glTexture(atlasTexture) -- Calculate all progress/alpha values local rotation1 = currentTime * 70 @@ -223,33 +171,21 @@ local function DrawPing(ping, currentTime, cameraDistance) glBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) -- Outer outlines - glColor(0.09, 0, 0, outerAlpha * 0.25) - for i = 0, 3 do - glPushMatrix() - glRotate(rotation1, 0, 0, 1) - glScale(outerRadius, outerRadius, 1) - glCallList(displayLists.outerOutlines[i]) - glPopMatrix() + if outerAlpha > 0.001 then + glColor(0.09, 0, 0, outerAlpha * 0.25) + DrawTexturedQuad(atlasSprites.outerOutline, outerRadius * outerQuadScale, rotation1) end -- Middle outlines - glColor(0.09, 0, 0, middleAlpha * 0.25) - for i = 0, 2 do - glPushMatrix() - glRotate(rotation2, 0, 0, 1) - glScale(middleRadius, middleRadius, 1) - glCallList(displayLists.middleOutlines[i]) - glPopMatrix() + if middleAlpha > 0.001 then + glColor(0.09, 0, 0, middleAlpha * 0.25) + DrawTexturedQuad(atlasSprites.middleOutline, middleRadius * middleQuadScale, rotation2) end -- Inner outlines - glColor(0.07, 0, 0, innerAlpha * 0.25) - for i = 0, 1 do - glPushMatrix() - glRotate(rotation3, 0, 0, 1) - glScale(innerRadius, innerRadius, 1) - glCallList(displayLists.innerOutlines[i]) - glPopMatrix() + if innerAlpha > 0.001 then + glColor(0.07, 0, 0, innerAlpha * 0.25) + DrawTexturedQuad(atlasSprites.innerOutline, innerRadius * innerQuadScale, rotation3) end end @@ -257,33 +193,21 @@ local function DrawPing(ping, currentTime, cameraDistance) glBlending(GL_SRC_ALPHA, GL_ONE) -- Outer ring - 4 arcs rotating clockwise - glColor(1, 0.1, 0.09, outerAlpha) - for i = 0, 3 do - glPushMatrix() - glRotate(rotation1, 0, 0, 1) - glScale(outerRadius, outerRadius, 1) - glCallList(displayLists.outerArcs[i]) - glPopMatrix() + if outerAlpha > 0.001 then + glColor(1, 0.1, 0.09, outerAlpha) + DrawTexturedQuad(atlasSprites.outerRing, outerRadius * outerQuadScale, rotation1) end -- Middle ring - 3 arcs rotating counter-clockwise - glColor(1, 0.22, 0.2, middleAlpha) - for i = 0, 2 do - glPushMatrix() - glRotate(rotation2, 0, 0, 1) - glScale(middleRadius, middleRadius, 1) - glCallList(displayLists.middleArcs[i]) - glPopMatrix() + if middleAlpha > 0.001 then + glColor(1, 0.22, 0.2, middleAlpha) + DrawTexturedQuad(atlasSprites.middleRing, middleRadius * middleQuadScale, rotation2) end -- Inner ring - 2 arcs rotating clockwise - glColor(1, 0.37, 0.33, innerAlpha) - for i = 0, 1 do - glPushMatrix() - glRotate(rotation3, 0, 0, 1) - glScale(innerRadius, innerRadius, 1) - glCallList(displayLists.innerArcs[i]) - glPopMatrix() + if innerAlpha > 0.001 then + glColor(1, 0.37, 0.33, innerAlpha) + DrawTexturedQuad(atlasSprites.innerRing, innerRadius * innerQuadScale, rotation3) end -- Center dot (shrinks from large to small with fade in/out) @@ -298,12 +222,10 @@ local function DrawPing(ping, currentTime, cameraDistance) end local centerAlpha = max(0, centerAlphaMultiplier * 0.6) glColor(1, 0.25, 0.23, centerAlpha) - glPushMatrix() - glScale(centerScale, centerScale, 1) - glCallList(displayLists.centerCircle) - glPopMatrix() + DrawTexturedQuad(atlasSprites.centerDot, centerScale * centerQuadScale) end + glTexture(false) glBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glPopMatrix() @@ -314,30 +236,46 @@ end -- callins -------------------------------------------------------------------------------- function gadget:Initialize() - CreateDisplayLists() +end + +function gadget:ViewResize(vsx, vsy) end function gadget:Shutdown() - DeleteDisplayLists() end function gadget:UnitSeismicPing(x, y, z, strength, allyTeam, unitID, unitDefID) local spec, fullview = spGetSpectatingState() local myAllyTeam = spGetMyAllyTeamID() - local unitAllyTeam = Spring.GetUnitAllyTeam(unitID) + local unitAllyTeam = spGetUnitAllyTeam(unitID) if (spec or allyTeam == myAllyTeam) and unitAllyTeam ~= allyTeam then if spec and not fullview then if allyTeam ~= myAllyTeam then return end end + if onlyCloakedUnits and not spGetUnitIsCloaked(unitID) then + return + end + + local ping + if pingPoolCount > 0 then + ping = pingPool[pingPoolCount] + pingPool[pingPoolCount] = nil + pingPoolCount = pingPoolCount - 1 + else + ping = {} + end + + ping.x = x + ping.y = spGetGroundHeight(x, z) or y + ping.z = z + ping.startTime = gameTime - table.insert(pings, { - x = x, - y = spGetGroundHeight(x, z) or y, - z = z, - strength = strength, - startTime = gameTime, - }) + pingCount = pingCount + 1 + pings[pingCount] = ping + + -- Inform LuaUI with full payload; widgets that only use first args stay compatible. + Script.LuaUI.UnitSeismicPing(x, y, z, strength, allyTeam, unitID, unitDefID) end end @@ -345,44 +283,57 @@ function gadget:Update(dt) gameTime = gameTime + dt end -function gadget:DrawWorld() - if #pings == 0 or Spring.IsGUIHidden() then +function gadget:DrawWorldPreUnit() + if pingCount == 0 or spIsGUIHidden() then return end glDepthTest(false) - -- Get visible world bounds for culling - local cx, cy, cz = Spring.GetCameraPosition() - local cs = Spring.GetCameraState() - local vsx, vsy = spGetViewGeometry() - - -- Calculate visible world area based on camera state - local viewDistance = cy / math.tan(math.rad(cs.fov or 45)) - local viewWidth = viewDistance * (vsx / vsy) - local margin = maxRadius * thicknessScale * 3 -- Add margin for ping radius - - local minX = cx - viewWidth - margin - local maxX = cx + viewWidth + margin - local minZ = cz - viewDistance - margin - local maxZ = cz + viewDistance + margin + local cx, cy, cz = spGetCameraPosition() + local cullRadius = maxRadius * thicknessScale * 2.5 local currentTime = gameTime local i = 1 - while i <= #pings do + while i <= pingCount do local ping = pings[i] - -- Check if ping is within visible bounds - if ping.x < minX or ping.x > maxX or ping.z < minZ or ping.z > maxZ then - -- Ping is outside view, skip drawing but don't remove yet - if currentTime - ping.startTime > pingLifetime then - table.remove(pings, i) + if spIsSphereInView(ping.x, ping.y + pingHeightOffset, ping.z, cullRadius) then + local isOccluded = false + if hideWhenTerrainOccluded then + isOccluded = IsTerrainOccluded(cx, cy, cz, ping.x, ping.y + pingHeightOffset, ping.z) + end + + if isOccluded then + if currentTime - ping.startTime > pingLifetime then + local dead = ping + pings[i] = pings[pingCount] + pings[pingCount] = nil + pingCount = pingCount - 1 + pingPoolCount = pingPoolCount + 1 + pingPool[pingPoolCount] = dead + else + i = i + 1 + end + -- Ping is visible and not terrain-occluded, try to draw it + elseif not DrawPing(ping, currentTime, cy) then + local dead = ping + pings[i] = pings[pingCount] + pings[pingCount] = nil + pingCount = pingCount - 1 + pingPoolCount = pingPoolCount + 1 + pingPool[pingPoolCount] = dead else i = i + 1 end else - -- Ping is visible, try to draw it - if not DrawPing(ping, currentTime, cy) then - table.remove(pings, i) + -- Ping is outside frustum, skip drawing but only remove when expired + if currentTime - ping.startTime > pingLifetime then + local dead = ping + pings[i] = pings[pingCount] + pings[pingCount] = nil + pingCount = pingCount - 1 + pingPoolCount = pingPoolCount + 1 + pingPool[pingPoolCount] = dead else i = i + 1 end diff --git a/luarules/images/seismic_ping/center_dot.png b/luarules/images/seismic_ping/center_dot.png new file mode 100644 index 00000000000..20828fb706c Binary files /dev/null and b/luarules/images/seismic_ping/center_dot.png differ diff --git a/luarules/images/seismic_ping/inner_outline.png b/luarules/images/seismic_ping/inner_outline.png new file mode 100644 index 00000000000..504e74a8622 Binary files /dev/null and b/luarules/images/seismic_ping/inner_outline.png differ diff --git a/luarules/images/seismic_ping/inner_ring.png b/luarules/images/seismic_ping/inner_ring.png new file mode 100644 index 00000000000..7effc422c7b Binary files /dev/null and b/luarules/images/seismic_ping/inner_ring.png differ diff --git a/luarules/images/seismic_ping/middle_outline.png b/luarules/images/seismic_ping/middle_outline.png new file mode 100644 index 00000000000..7980213cf70 Binary files /dev/null and b/luarules/images/seismic_ping/middle_outline.png differ diff --git a/luarules/images/seismic_ping/middle_ring.png b/luarules/images/seismic_ping/middle_ring.png new file mode 100644 index 00000000000..2971455bfdc Binary files /dev/null and b/luarules/images/seismic_ping/middle_ring.png differ diff --git a/luarules/images/seismic_ping/outer_outline.png b/luarules/images/seismic_ping/outer_outline.png new file mode 100644 index 00000000000..e561d5458db Binary files /dev/null and b/luarules/images/seismic_ping/outer_outline.png differ diff --git a/luarules/images/seismic_ping/outer_ring.png b/luarules/images/seismic_ping/outer_ring.png new file mode 100644 index 00000000000..2ac77f4c816 Binary files /dev/null and b/luarules/images/seismic_ping/outer_ring.png differ diff --git a/luarules/images/seismic_ping/seismic_atlas.png b/luarules/images/seismic_ping/seismic_atlas.png new file mode 100644 index 00000000000..c82fd3f6385 Binary files /dev/null and b/luarules/images/seismic_ping/seismic_atlas.png differ diff --git a/luaui/Widgets/gui_pip.lua b/luaui/Widgets/gui_pip.lua index 05e8a0c5a0a..8f18d922dc4 100644 --- a/luaui/Widgets/gui_pip.lua +++ b/luaui/Widgets/gui_pip.lua @@ -1853,15 +1853,31 @@ local commandFX = { MAX = 300, -- max simultaneous FX entries } -local seismicPingDlists = { - outerArcs = {}, - middleArcs = {}, - innerArcs = {}, - centerCircle = nil, - outerOutlines = {}, - middleOutlines = {}, - innerOutlines = {}, +seismicPingAtlasTexture = "LuaRules/Images/seismic_ping/seismic_atlas.png" +seismicPingAtlasSprites = { + outerRing = { 0 / 7, 0, 1 / 7, 1 }, + outerOutline = { 1 / 7, 0, 2 / 7, 1 }, + middleRing = { 2 / 7, 0, 3 / 7, 1 }, + middleOutline = { 3 / 7, 0, 4 / 7, 1 }, + innerRing = { 4 / 7, 0, 5 / 7, 1 }, + innerOutline = { 5 / 7, 0, 6 / 7, 1 }, + centerDot = { 6 / 7, 0, 7 / 7, 1 }, } +seismicOuterQuadScale = 1.17 +seismicMiddleQuadScale = 1.18 +seismicInnerQuadScale = 1.24 +seismicCenterQuadScale = 2.2 + +function DrawSeismicTexturedQuad(sprite, scale, rotation) + local s1, t1, s2, t2 = sprite[1], sprite[2], sprite[3], sprite[4] + glFunc.PushMatrix() + if rotation then + glFunc.Rotate(rotation, 0, 0, 1) + end + glFunc.Scale(scale, scale, 1) + glFunc.TexRect(-1, -1, 1, 1, s1, t1, s2, t2) + glFunc.PopMatrix() +end local gameHasStarted local gaiaTeamID = Spring.GetGaiaTeamID() cache.gaiaAllyTeamID = select(6, Spring.GetTeamInfo(gaiaTeamID)) @@ -6375,40 +6391,29 @@ local function DrawSeismicPings() local innerAlpha = math.max(0, (1 - innerProgress)) local innerRadius = radius - (radius * progress * 0.45) - gl.Scale(2.3,2.3,0) -- scale up so it is visible in pip + glFunc.Scale(2.3, 2.3, 1) -- scale up so it is visible in pip + glFunc.Texture(seismicPingAtlasTexture) -- PASS 1: Draw all dark outlines with normal blending if cameraState.zoom > 0.5 then gl.Blending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA) -- Outer outlines - glFunc.Color(0.09, 0, 0, outerAlpha * 0.25) - for j = 0, 3 do - glFunc.PushMatrix() - glFunc.Rotate(rotation1, 0, 0, 1) - glFunc.Scale(outerRadius, outerRadius, 1) - glFunc.CallList(seismicPingDlists.outerOutlines[j]) - glFunc.PopMatrix() + if outerAlpha > 0.001 then + glFunc.Color(0.09, 0, 0, outerAlpha * 0.25) + DrawSeismicTexturedQuad(seismicPingAtlasSprites.outerOutline, outerRadius * seismicOuterQuadScale, rotation1) end -- Middle outlines - glFunc.Color(0.09, 0, 0, middleAlpha * 0.25) - for j = 0, 2 do - glFunc.PushMatrix() - glFunc.Rotate(rotation2, 0, 0, 1) - glFunc.Scale(middleRadius, middleRadius, 1) - glFunc.CallList(seismicPingDlists.middleOutlines[j]) - glFunc.PopMatrix() + if middleAlpha > 0.001 then + glFunc.Color(0.09, 0, 0, middleAlpha * 0.25) + DrawSeismicTexturedQuad(seismicPingAtlasSprites.middleOutline, middleRadius * seismicMiddleQuadScale, rotation2) end -- Inner outlines - glFunc.Color(0.07, 0, 0, innerAlpha * 0.25) - for j = 0, 1 do - glFunc.PushMatrix() - glFunc.Rotate(rotation3, 0, 0, 1) - glFunc.Scale(innerRadius, innerRadius, 1) - glFunc.CallList(seismicPingDlists.innerOutlines[j]) - glFunc.PopMatrix() + if innerAlpha > 0.001 then + glFunc.Color(0.07, 0, 0, innerAlpha * 0.25) + DrawSeismicTexturedQuad(seismicPingAtlasSprites.innerOutline, innerRadius * seismicInnerQuadScale, rotation3) end end @@ -6416,33 +6421,21 @@ local function DrawSeismicPings() gl.Blending(GL.SRC_ALPHA, GL.ONE) -- Outer ring - 4 arcs rotating clockwise - glFunc.Color(1, 0.1, 0.09, outerAlpha) - for j = 0, 3 do - glFunc.PushMatrix() - glFunc.Rotate(rotation1, 0, 0, 1) - glFunc.Scale(outerRadius, outerRadius, 1) - glFunc.CallList(seismicPingDlists.outerArcs[j]) - glFunc.PopMatrix() + if outerAlpha > 0.001 then + glFunc.Color(1, 0.1, 0.09, outerAlpha) + DrawSeismicTexturedQuad(seismicPingAtlasSprites.outerRing, outerRadius * seismicOuterQuadScale, rotation1) end -- Middle ring - 3 arcs rotating counter-clockwise - glFunc.Color(1, 0.22, 0.2, middleAlpha) - for j = 0, 2 do - glFunc.PushMatrix() - glFunc.Rotate(rotation2, 0, 0, 1) - glFunc.Scale(middleRadius, middleRadius, 1) - glFunc.CallList(seismicPingDlists.middleArcs[j]) - glFunc.PopMatrix() + if middleAlpha > 0.001 then + glFunc.Color(1, 0.22, 0.2, middleAlpha) + DrawSeismicTexturedQuad(seismicPingAtlasSprites.middleRing, middleRadius * seismicMiddleQuadScale, rotation2) end -- Inner ring - 2 arcs rotating clockwise - glFunc.Color(1, 0.37, 0.33, innerAlpha) - for j = 0, 1 do - glFunc.PushMatrix() - glFunc.Rotate(rotation3, 0, 0, 1) - glFunc.Scale(innerRadius, innerRadius, 1) - glFunc.CallList(seismicPingDlists.innerArcs[j]) - glFunc.PopMatrix() + if innerAlpha > 0.001 then + glFunc.Color(1, 0.37, 0.33, innerAlpha) + DrawSeismicTexturedQuad(seismicPingAtlasSprites.innerRing, innerRadius * seismicInnerQuadScale, rotation3) end -- Center dot (shrinks from large to small with fade in/out) @@ -6457,12 +6450,10 @@ local function DrawSeismicPings() end local centerAlpha = math.max(0, centerAlphaMultiplier * 0.6) glFunc.Color(1, 0.25, 0.23, centerAlpha) - glFunc.PushMatrix() - glFunc.Scale(centerScale, centerScale, 1) - glFunc.CallList(seismicPingDlists.centerCircle) - glFunc.PopMatrix() + DrawSeismicTexturedQuad(seismicPingAtlasSprites.centerDot, centerScale * seismicCenterQuadScale) end + glFunc.Texture(false) gl.Blending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA) glFunc.PopMatrix() i = i + 1 @@ -7555,110 +7546,6 @@ end -- Callins ---------------------------------------------------------------------------------------------------- --- Helper: Draw a thick arc as geometry (for display list creation) -local function DrawThickArcVertices(innerRadius, outerRadius, startAngle, endAngle, segments) - local angleStep = (endAngle - startAngle) / segments - local cos, sin = math.cos, math.sin - for i = 0, segments - 1 do - local angle1 = startAngle + i * angleStep - local angle2 = startAngle + (i + 1) * angleStep - local cos1, sin1 = cos(angle1), sin(angle1) - local cos2, sin2 = cos(angle2), sin(angle2) - glFunc.Vertex(cos1 * innerRadius, sin1 * innerRadius, 0) - glFunc.Vertex(cos1 * outerRadius, sin1 * outerRadius, 0) - glFunc.Vertex(cos2 * outerRadius, sin2 * outerRadius, 0) - glFunc.Vertex(cos2 * innerRadius, sin2 * innerRadius, 0) - end -end - --- Create display lists for seismic ping rotating arcs -local function CreateSeismicPingDlists() - local pi = math.pi - local pi2 = pi * 2 - local baseRadius = 16 - local baseThickness = 2.4 - - -- Proportional thicknesses (relative to unit radius 1.0) - local outerThicknessRatio = baseThickness * 1.05 / baseRadius - local middleThicknessRatio = baseThickness * 0.8 / baseRadius - local innerThicknessRatio = baseThickness * 1 / baseRadius - local centerThicknessRatio = baseThickness * 1.8 / baseRadius - local outlineExtra = 0.02 - - -- Outer arcs: 4 arcs, 60 degrees each - local outerInner = 1.08 - outerThicknessRatio / 2 - local outerOuter = 1.08 + outerThicknessRatio / 2 - for i = 0, 3 do - local startAngle = (i * 90) * pi / 180 - local arcLength = 60 * pi / 180 - -- Outline - seismicPingDlists.outerOutlines[i] = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, outerInner - outlineExtra, outerOuter + outlineExtra, startAngle - 0.02, startAngle + arcLength + 0.02, 12) - end) - -- Main arc - seismicPingDlists.outerArcs[i] = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, outerInner, outerOuter, startAngle, startAngle + arcLength, 12) - end) - end - - -- Middle arcs: 3 arcs, 80 degrees each, at 0.85 of unit radius - local middleRadiusRatio = 0.85 - local middleInner = middleRadiusRatio - middleThicknessRatio / 2 - local middleOuter = middleRadiusRatio + middleThicknessRatio / 2 - for i = 0, 2 do - local startAngle = (i * 120) * pi / 180 - local arcLength = 80 * pi / 180 - -- Outline - seismicPingDlists.middleOutlines[i] = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, middleInner - outlineExtra, middleOuter + outlineExtra, startAngle - 0.02, startAngle + arcLength + 0.02, 12) - end) - -- Main arc - seismicPingDlists.middleArcs[i] = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, middleInner, middleOuter, startAngle, startAngle + arcLength, 12) - end) - end - - -- Inner arcs: 2 arcs, 120 degrees each, at 0.66 of unit radius - local innerRadiusRatio = 0.66 - local innerInner = innerRadiusRatio - innerThicknessRatio / 2 - local innerOuter = innerRadiusRatio + innerThicknessRatio / 2 - for i = 0, 1 do - local startAngle = (i * 180) * pi / 180 - local arcLength = 120 * pi / 180 - -- Outline - seismicPingDlists.innerOutlines[i] = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, innerInner - outlineExtra, innerOuter + outlineExtra, startAngle - 0.02, startAngle + arcLength + 0.02, 16) - end) - -- Main arc - seismicPingDlists.innerArcs[i] = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, innerInner, innerOuter, startAngle, startAngle + arcLength, 16) - end) - end - - -- Center circle: full circle - local centerInner = 1 - centerThicknessRatio / 1.3 - local centerOuter = 1.25 + centerThicknessRatio / 1.3 - seismicPingDlists.centerCircle = gl.CreateList(function() - glFunc.BeginEnd(glConst.QUADS, DrawThickArcVertices, centerInner, centerOuter, 0, pi2, 20) - end) -end - --- Delete seismic ping display lists -local function DeleteSeismicPingDlists() - for i = 0, 3 do - if seismicPingDlists.outerArcs[i] then gl.DeleteList(seismicPingDlists.outerArcs[i]) end - if seismicPingDlists.outerOutlines[i] then gl.DeleteList(seismicPingDlists.outerOutlines[i]) end - end - for i = 0, 2 do - if seismicPingDlists.middleArcs[i] then gl.DeleteList(seismicPingDlists.middleArcs[i]) end - if seismicPingDlists.middleOutlines[i] then gl.DeleteList(seismicPingDlists.middleOutlines[i]) end - end - for i = 0, 1 do - if seismicPingDlists.innerArcs[i] then gl.DeleteList(seismicPingDlists.innerArcs[i]) end - if seismicPingDlists.innerOutlines[i] then gl.DeleteList(seismicPingDlists.innerOutlines[i]) end - end - if seismicPingDlists.centerCircle then gl.DeleteList(seismicPingDlists.centerCircle) end -end -- Register (or re-register) WG['minimap'] API for full compatibility with widgets -- expecting the original minimap API. Called from Initialize and again from DrawScreen @@ -8070,9 +7957,6 @@ end function widget:Initialize() RebuildAllUnitsCache() - -- Create seismic ping display lists - CreateSeismicPingDlists() - drawData.unitOutlineList = gl.CreateList(function() glFunc.BeginEnd(GL.LINE_LOOP, function() glFunc.Vertex( 1, 0, 1) @@ -9247,8 +9131,6 @@ function widget:Shutdown() gl.DeleteList(drawData.unitOutlineList) gl.DeleteList(drawData.radarDotList) - DeleteSeismicPingDlists() - if shaders.los then gl.DeleteShader(shaders.los) shaders.los = nil @@ -18996,9 +18878,13 @@ function widget:UnitSeismicPing(x, y, z, strength, allyTeam, unitID, unitDefID) local myAllyTeam = Spring.GetMyAllyTeamID() local spec, fullview = Spring.GetSpectatingState() - local unitAllyTeam = unitID and Spring.GetUnitAllyTeam(unitID) or allyTeam + local unitAllyTeam = unitID and Spring.GetUnitAllyTeam(unitID) + + if (spec or allyTeam == myAllyTeam) and ((not unitAllyTeam) or unitAllyTeam ~= allyTeam) then + if spec and not fullview then + if allyTeam ~= myAllyTeam then return end + end - if (spec or allyTeam == myAllyTeam) and unitAllyTeam ~= allyTeam then -- Calculate ping radius based on strength (strength is typically 1-10) -- Use larger base radius for visibility local maxRadius = 100 + math.min(strength, 20) * 15