Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Stooberton committed May 17, 2024
1 parent 40aa481 commit 66cc895
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 119 deletions.
112 changes: 66 additions & 46 deletions lua/acf/core/utilities/traces_sh.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ do -- ACF.trace
-- Does NOT modify the original filter
local util = util
local sqrt = math.sqrt
local v0 = Vector()

local function doRecursiveTrace(traceData)
local Output = traceData.output
Expand Down Expand Up @@ -81,83 +82,102 @@ do -- ACF.trace
return Output
end

local function findOtherSideOfSphere(point, dir, ent)
local function findOtherSideOfSphere(ent, rayOrigin, rayDir)

Check warning on line 85 in lua/acf/core/utilities/traces_sh.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Unused variable"

Unused variable: findOtherSideOfSphere

Check warning on line 85 in lua/acf/core/utilities/traces_sh.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Unused variable"

Unused variable: rayDir
local radius = ent:Radius()
local center = ent:GetPos()

local displacement = point - origin
local displacement = rayOrigin - center

local ie = ray:Dot(displacement)^2 - displacement:LengthSqr()

Check warning on line 91 in lua/acf/core/utilities/traces_sh.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Whitespace style"

Style: Please put some whitespace after ')'
local exit = ray:Dot(point - center) + sqrt(ie)
local exit = ray:Dot(displacement) + sqrt(ie)
local length = (point - exit):Length() * 25.4

return exit, length
return exit, length, point + dir * radius * 2, radius * 2
end

local function findOtherSideOfPoly(Ent, Origin, Dir)
local Mesh = Ent:GetPhysicsObject():GetMeshConvexes()
local Min = math.huge
local function rayIntersectTri(rayOrigin, rayNormal, p1, edge1, edge2)

for K in pairs(Mesh) do -- Loop over mesh
local Hull = Mesh[K]
if rayNormal:Dot(edge1:Cross(edge2)) > 0 then return false end -- Plane facing the wrong way

for I = 1, #Hull, 3 do -- Loop over each tri (groups of 3)
-- Points on tri
local P1 = Ent:LocalToWorld(Hull[I].pos)
local P2 = Ent:LocalToWorld(Hull[I + 1].pos)
local P3 = Ent:LocalToWorld(Hull[I + 2].pos)
local h = rayNormal:Cross(edge2)
local a = edge1:Dot(h)

-- Two edges to test with
local Edge1 = P2 - P1
local Edge2 = P3 - P1
if a > -0.0001 and a < 0.0001 then return false end -- Ray is perpendicular to plane

-- Ray passes through the triangle?
local f = 1 / a
local s = rayOrigin - p1 -- Displacement from to origin from p1
local u = f * s:Dot(h)

if u < 0 or u > 1 then return false end

local q = s:Cross(edge1)
local v = f * rayNormal:Dot(q)

if v < 0 or u + v > 1 then return false end

-- Plane facing the wrong way?
if Dir:Dot(Edge1:Cross(Edge2)) > 0 then continue end
-- Ray intersects triangle
-- Length of ray to intersection
local t = f * edge2:Dot(q)

-- Ray is perpendicular to plane?
local H = Dir:Cross(Edge2)
local A = Edge1:Dot(H)
if t < 0.0001 then return false end -- Ray is too close

if A > -0.0001 and A < 0.0001 then continue end
return t
end

-- Ray passes through the triangle?
local F = 1 / A
local S = Origin - P1 -- Displacement from to origin from P1
local U = F * S:Dot(H)
local function findOtherSideOfPoly(ent, rayOrigin, rayNormal, surfaceNormal)
local nominalPos = v0

Check warning on line 129 in lua/acf/core/utilities/traces_sh.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Unused variable"

Unused variable: nominalPos
local nominalLen = math.huge
local incidentalPos = v0

Check warning on line 131 in lua/acf/core/utilities/traces_sh.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Unused variable"

Unused variable: incidentalPos
local incidentalLen = math.huge

if U < 0 or U > 1 then continue end
for _, hull in pairs(ent:GetPhysicsObject():GetMeshConvexes()) do -- Loop over mesh

local Q = S:Cross(Edge1)
local V = F * Dir:Dot(Q)
for i = 1, #hull, 3 do -- Loop over each tri (groups of 3)
-- Points on tri
local p1 = ent:LocalToWorld(hull[i].pos)
local p2 = ent:LocalToWorld(hull[i + 1].pos)
local p3 = ent:LocalToWorld(hull[i + 2].pos)

if V < 0 or U + V > 1 then continue end
-- Two edges to test with
local edge1 = p2 - p1
local edge2 = p3 - p1

-- Ray intersects triangle
-- Length of ray to intersection
local T = F * Edge2:Dot(Q)
nomTest = rayIntersectTri(rayOrigin, surfaceNormal, p1, edge1, edge2)
incTest = rayIntersectTri(rayOrigin, rayNormal, p1, edge1, edge2)

if T > 0.0001 and T < Min then Min = T end
if nomTest and nomTest < nominalLen then nominalLen = nomTest end
if incTest and incTest < incTest then incidentalLen = incTest end
end
end

return Origin + Dir * Min
return rayOrigin + rayNormal * incidentalLen, incidentalLen, rayOrigin + surfaceNormal * nominalLen, nominalLen
end

function ACF.getTraceDepth(trace)
local output = {nominal = 0, incidental = 0, normalPos = false, incidentalPos = false}

function ACF.getThickness(entity, rayPos, rayNormal, surfaceNormal)
-- Traces from the surface of an object to the furthest tri on the opposite side
-- Stops at any other object that is intersecting inside

local ent = trace.Entity
local origin = trace.StartPos
local enter = trace.HitPos
local rayDir = (enter - trace.StartPos):GetNormalized()
if not IsValid(entity) or entity:IsWorld() then
output.nominal = 0
output.incidental = 0
output.normalPos = pos
output.incidentalPos = pos
else
surfaceNormal = -surfaceNormal

local ip, il, np, nl = findOtherSideOfPoly(entity, rayPos, rayNormal, surfaceNormal)

Check warning on line 171 in lua/acf/core/utilities/traces_sh.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Unused variable"

Unused variable: il

local tempFilter = {}; for k, v in pairs(trace.Filter) do filter[k] = v end -- Shallow copy of the original filter (presumably a projectile trace) prevents two overlapping cubes from infinitely intersecting
local exit = ACF.trace({start = rayPos, endpos = ip, filter = {entity}}).HitPos -- Not strictly an exit... may have run into an intersecting entity inside

local opposite = ent._IsSpherical and findOtherSideOfSphere(enter, rayDir, ent:GetPos()) or findOtherSideOfPoly(ent, origin, rayDir)
local exit = ACF.trace({start = enter, endpos = opposite, filter = tempFilter}).HitPos -- Not strictly an exit... may have run into an intersecting entity
local length = (exit - enter):Length() * 25.4 -- Inches to mm
output.nominal = nl * 25.4
output.incidental = (exit - rayPos):Length() * 25.4
output.normalPos = np
output.incidentalPos = ip
end

return exit, length
return output
end
end
122 changes: 49 additions & 73 deletions lua/weapons/gmod_tool/stools/acfarmorprop.lua
Original file line number Diff line number Diff line change
Expand Up @@ -163,84 +163,49 @@ if CLIENT then
})

function TOOL:DrawToolScreen()
--[[
local Trace = self:GetOwner():GetEyeTrace()
local Ent = Trace.Entity
local Weapon = self.Weapon
local Health = math.Round(Weapon:GetNWFloat("HP", 0))
local MaxHealth = math.Round(Weapon:GetNWFloat("MaxHP", 0))

if Ent.GetArmor then -- Is procedural armor
local Material = Ent.ArmorType
local Mass = math.Round(Weapon:GetNWFloat("WeightMass", 0), 1)
local Angle = math.Round(ACF.GetHitAngle(Trace, (Trace.HitPos - Trace.StartPos):GetNormalized()), 1)
local Armor = math.Round(Ent:GetArmor(Trace))
local Size = Ent:GetSize()
local Nominal = math.Round(math.min(Size[1], Size[2], Size[3]) * 25.4, 1)
local MaxArmor = Ent:GetSize():Length() * 25.4

cam.Start2D()
render.Clear(0, 0, 0, 0)
surface.SetDrawColor(Black)
surface.DrawRect(0, 0, 256, 256)
surface.SetDrawColor(BGGray)
surface.DrawRect(0, 34, 256, 2)

drawText("ACF Armor Data", "ACF_ToolTitle", 128, 20, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
drawText("Material: " .. Material, "ACF_ToolSub", 128, 48, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
drawText("Weight: " .. Mass .. "kg", "ACF_ToolSub", 128, 70, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
drawText("Nominal Armor: " .. Nominal .. "mm", "ACF_ToolSub", 128, 92, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)

draw.RoundedBox(6, 10, 110, 236, 32, BGGray)
draw.RoundedBox(6, 10, 110, Angle / 90 * 236, 32, Green)
drawText("Hit Angle: " .. Angle .. "°", "ACF_ToolLabel", 15, 110, Black, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 0, BGGray)

draw.RoundedBox(6, 10, 160, 236, 32, BGGray)
draw.RoundedBox(6, 10, 160, Armor / MaxArmor * 236, 32, Blue)
drawText("Armor: " .. Armor .. "mm", "ACF_ToolLabel", 15, 160, Black, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 0, BGGray)

draw.RoundedBox(6, 10, 210, 236, 32, BGGray)
draw.RoundedBox(6, 10, 210, Health / MaxHealth * 236, 32, Red)
drawText("Health: " .. Health, "ACF_ToolLabel", 15, 210, Black, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 0, Black)
--drawText("")
cam.End2D()
else
local Armour = math.Round(Weapon:GetNWFloat("Armour", 0), 2)
local MaxArmour = math.Round(Weapon:GetNWFloat("MaxArmour", 0), 2)
local HealthTxt = Health .. "/" .. MaxHealth
local ArmourTxt = Armour .. "/" .. MaxArmour

cam.Start2D()
render.Clear(0, 0, 0, 0)

surface.SetDrawColor(Black)
surface.DrawRect(0, 0, 256, 256)
surface.SetFont("Torchfont")

-- header
draw.SimpleTextOutlined("ACF Stats", "Torchfont", 128, 30, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 4, color_black)

-- armor bar
draw.RoundedBox(6, 10, 83, 236, 64, BGGray)
if Armour ~= 0 and MaxArmour ~= 0 then
draw.RoundedBox(6, 15, 88, Armour / MaxArmour * 226, 54, Blue)
end

draw.SimpleTextOutlined("Armor", "Torchfont", 128, 100, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 4, color_black)
draw.SimpleTextOutlined(ArmourTxt, "Torchfont", 128, 130, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 4, color_black)

-- health bar
draw.RoundedBox(6, 10, 183, 236, 64, BGGray)
if Health ~= 0 and MaxHealth ~= 0 then
draw.RoundedBox(6, 15, 188, Health / MaxHealth * 226, 54, Red)
end

draw.SimpleTextOutlined("Health", "Torchfont", 128, 200, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 4, color_black)
draw.SimpleTextOutlined(HealthTxt, "Torchfont", 128, 230, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 4, color_black)
cam.End2D()
end


-- TODO: Get this to work on ALL entities
local depth = ACF.getThickness(Ent, Trace.HitPos, Trace.Normal, Trace.HitNormal)
local nominal = depth.nominal
local effective = depth.incidental
local Mass = math.Round(Weapon:GetNWFloat("WeightMass", 0), 1)
local Angle = math.Round(ACF.GetHitAngle(Trace, (Trace.HitPos - Trace.StartPos):GetNormalized()), 1)
local Armor = math.Round(effective)
cam.Start2D()
render.Clear(0, 0, 0, 0)
surface.SetDrawColor(Black)
surface.DrawRect(0, 0, 256, 256)
surface.SetDrawColor(BGGray)
surface.DrawRect(0, 34, 256, 2)
drawText("ACF Armor Data", "ACF_ToolTitle", 128, 20, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
--drawText("Material: " .. Material, "ACF_ToolSub", 128, 48, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
drawText("Weight: " .. Mass .. "kg", "ACF_ToolSub", 128, 70, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
drawText("Nominal Armor: " .. nominal .. "mm", "ACF_ToolSub", 128, 92, TextGray, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 0, BGGray)
draw.RoundedBox(6, 10, 110, 236, 32, BGGray)
draw.RoundedBox(6, 10, 110, Angle / 90 * 236, 32, Green)
drawText("Hit Angle: " .. Angle .. "°", "ACF_ToolLabel", 15, 110, Black, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 0, BGGray)
draw.RoundedBox(6, 10, 160, 236, 32, BGGray)
draw.RoundedBox(6, 10, 160, 1 * 236, 32, Blue)
drawText("Armor: " .. Armor .. "mm", "ACF_ToolLabel", 15, 160, Black, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 0, BGGray)
draw.RoundedBox(6, 10, 210, 236, 32, BGGray)
draw.RoundedBox(6, 10, 210, 1 * 236, 32, Red)
drawText("Health: " .. Health, "ACF_ToolLabel", 15, 210, Black, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 0, Black)
--drawText("")
cam.End2D()
]]--
end

-- Clamp thickness if the change in ductility puts mass out of range
Expand Down Expand Up @@ -314,13 +279,24 @@ if CLIENT then
else -- Serverside-only stuff
function TOOL:Think()
local Player = self:GetOwner()
local Ent = Player:GetEyeTrace().Entity
local trace = Player:GetEyeTrace()
local Ent = trace.Entity

if Ent == self.AimEntity then return end

local Weapon = self.Weapon

if ACF.Check(Ent) then
PrintTable(trace)
local depth = ACF.getThickness(Ent, trace.HitPos, (trace.HitPos - trace.StartPos):GetNormalized(), trace.HitNormal)

debugoverlay.Line(trace.HitPos, depth.incidentalPos, 0.3, Color(255, 50, 50), true)
debugoverlay.Line(trace.HitPos, depth.normalPos, 0.3, Color(50, 255, 50), true)

debugoverlay.Cross(trace.HitPos, 6, 0.3, Color(255, 255, 255), true)
debugoverlay.Cross(depth.incidentalPos, 3, 0.3, Color(255, 0, 0 ), true)
debugoverlay.Cross(depth.normalPos, 3, 0.3, Color(0, 255, 0), true)

Player:ConCommand("acfarmorprop_area " .. Ent.ACF.Area)
Player:ConCommand("acfarmorprop_thickness " .. self:GetClientNumber("thickness")) -- Force sliders to update themselves

Expand Down

0 comments on commit 66cc895

Please sign in to comment.