Effect Radar Implementation v1 #46
|
@ -35,7 +35,8 @@ end
|
||||||
local function renderOutlinedText(pos, text, outlineWidth, color)
|
local function renderOutlinedText(pos, text, outlineWidth, color)
|
||||||
local x, y = pos:coords()
|
local x, y = pos:coords()
|
||||||
|
|
||||||
gfx.FillColor(ColorRGBA.BLACK:components());
|
local dimColor = color:mix(ColorRGBA.BLACK, 0.8)
|
||||||
|
gfx.FillColor(dimColor:components());
|
||||||
gfx.Text(text, x - outlineWidth, y + outlineWidth);
|
gfx.Text(text, x - outlineWidth, y + outlineWidth);
|
||||||
gfx.Text(text, x - outlineWidth, y - outlineWidth);
|
gfx.Text(text, x - outlineWidth, y - outlineWidth);
|
||||||
gfx.Text(text, x + outlineWidth, y + outlineWidth);
|
gfx.Text(text, x + outlineWidth, y + outlineWidth);
|
||||||
|
@ -67,18 +68,20 @@ end
|
||||||
RadarAttributes = {
|
RadarAttributes = {
|
||||||
---Create RadarAttributes instance
|
---Create RadarAttributes instance
|
||||||
---@param text? string # default ""
|
---@param text? string # default ""
|
||||||
---@param pos? Point2D # default (0, 0)
|
---@param offset? Point2D # default (0, 0)
|
||||||
---@param color? ColorRGBA # default BLACK
|
---@param color? ColorRGBA # default BLACK
|
||||||
|
---@param align? integer # gfx.TEXT_ALIGN_<...> values, default gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_BASELINE
|
||||||
---@return RadarAttributes
|
---@return RadarAttributes
|
||||||
new = function (text, pos, color)
|
new = function (text, offset, color, align)
|
||||||
---@class RadarAttributes
|
---@class RadarAttributes
|
||||||
---@field text string
|
---@field text string
|
||||||
---@field pos Point2D
|
---@field offset Point2D
|
||||||
---@field color ColorRGBA
|
---@field color ColorRGBA
|
||||||
local o = {
|
local o = {
|
||||||
text = text or "",
|
text = text or "",
|
||||||
pos = pos or Point2D.ZERO,
|
offset = offset or Point2D.ZERO,
|
||||||
color = color or ColorRGBA.BLACK
|
color = color or ColorRGBA.BLACK,
|
||||||
|
align = align or gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_BASELINE
|
||||||
}
|
}
|
||||||
|
|
||||||
setmetatable(o, RadarAttributes)
|
setmetatable(o, RadarAttributes)
|
||||||
|
@ -92,17 +95,17 @@ RadarAttributes.__index = RadarAttributes
|
||||||
Radar = {
|
Radar = {
|
||||||
---@type RadarAttributes[][]
|
---@type RadarAttributes[][]
|
||||||
ATTRIBUTES = {
|
ATTRIBUTES = {
|
||||||
{RadarAttributes.new("notes", Point2D.new(0, -30), ColorRGBA.CYAN),},
|
{RadarAttributes.new("notes", Point2D.new(0, 0), ColorRGBA.CYAN, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_BOTTOM),},
|
||||||
{RadarAttributes.new("peak", Point2D.new(40, -20), ColorRGBA.RED),},
|
{RadarAttributes.new("peak", Point2D.new(0, 0), ColorRGBA.RED, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_BOTTOM), },
|
||||||
{RadarAttributes.new("tsumami", Point2D.new(40, 20), RADAR_PURPLE),},
|
{RadarAttributes.new("tsumami", Point2D.new(0, 0), RADAR_PURPLE, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_TOP),},
|
||||||
{RadarAttributes.new("tricky", Point2D.new(0, 30), ColorRGBA.YELLOW),},
|
{RadarAttributes.new("tricky", Point2D.new(0, 0), ColorRGBA.YELLOW, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_TOP),},
|
||||||
{
|
{
|
||||||
RadarAttributes.new("hand", Point2D.new(-40, 20), RADAR_MAGENTA),
|
RadarAttributes.new("hand", Point2D.new(0, 0), RADAR_MAGENTA, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_TOP),
|
||||||
RadarAttributes.new("trip", Point2D.new(5, 18), RADAR_MAGENTA),
|
RadarAttributes.new("trip", Point2D.new(5, 16), RADAR_MAGENTA, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_TOP),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
RadarAttributes.new("one", Point2D.new(-40, -20), RADAR_GREEN),
|
RadarAttributes.new("one", Point2D.new(6, -16), RADAR_GREEN, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_BOTTOM),
|
||||||
RadarAttributes.new("hand", Point2D.new(-5, 18), RADAR_GREEN),
|
RadarAttributes.new("hand", Point2D.new(0, 0), RADAR_GREEN, gfx.TEXT_ALIGN_CENTER + gfx.TEXT_ALIGN_BOTTOM),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
RADIUS = 100.0,
|
RADIUS = 100.0,
|
||||||
|
@ -123,34 +126,34 @@ Radar = {
|
||||||
onehand = 0,
|
onehand = 0,
|
||||||
},
|
},
|
||||||
_hexagonMesh = gfx.CreateShadedMesh("radar"),
|
_hexagonMesh = gfx.CreateShadedMesh("radar"),
|
||||||
outlineVertices = {},
|
_outlineVertices = {},
|
||||||
attributePositions = {},
|
_attributePositions = {}, ---@type Point2D[][]
|
||||||
|
_angleStep = (2 * math.pi) / #Radar.ATTRIBUTES, -- 360° / no. attributes, in radians
|
||||||
|
_initRotation = math.pi / 2, -- 90°, in radians
|
||||||
pos = pos or Point2D.ZERO,
|
pos = pos or Point2D.ZERO,
|
||||||
scale = radius and radius / Radar.RADIUS or 1.0,
|
scale = radius and radius / Radar.RADIUS or 1.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
local sides = #Radar.ATTRIBUTES
|
local sides = #Radar.ATTRIBUTES
|
||||||
local angleStep = (2 * math.pi) / sides
|
|
||||||
local rotationAngle = angleStep / 2
|
|
||||||
|
|
||||||
local outlineRadius = Radar.RADIUS
|
local outlineRadius = Radar.RADIUS
|
||||||
local attributeRadius = Radar.RADIUS + 20
|
local attributeRadius = Radar.RADIUS + 30
|
||||||
|
|
||||||
for i = 0, sides - 1 do
|
for i = 0, sides - 1 do
|
||||||
local attrIdx = i + 1
|
local attrIdx = i + 1
|
||||||
local angle = i * angleStep - rotationAngle
|
local angle = i * o._angleStep - o._initRotation
|
||||||
local cosAngle = math.cos(angle)
|
local cosAngle = math.cos(angle)
|
||||||
local sinAngle = math.sin(angle)
|
local sinAngle = math.sin(angle)
|
||||||
-- cache outline vertices
|
-- cache outline vertices
|
||||||
table.insert(o.outlineVertices, Point2D.new(outlineRadius * cosAngle, outlineRadius * sinAngle))
|
table.insert(o._outlineVertices, Point2D.new(outlineRadius * cosAngle, outlineRadius * sinAngle))
|
||||||
-- cache attribute positions
|
-- cache attribute positions
|
||||||
table.insert(o.attributePositions, {})
|
table.insert(o._attributePositions, {})
|
||||||
for j = 1, #Radar.ATTRIBUTES[attrIdx] do
|
for j = 1, #Radar.ATTRIBUTES[attrIdx] do
|
||||||
local attr = Radar.ATTRIBUTES[attrIdx][j]
|
local attr = Radar.ATTRIBUTES[attrIdx][j]
|
||||||
local attributePos = Point2D.new(attributeRadius * cosAngle, attributeRadius * sinAngle)
|
local attributePos = Point2D.new(attributeRadius * cosAngle, attributeRadius * sinAngle)
|
||||||
attributePos.x = attributePos.x + attr.pos.x
|
attributePos.x = attributePos.x + attr.offset.x
|
||||||
attributePos.y = attributePos.y + attr.pos.y
|
attributePos.y = attributePos.y + attr.offset.y
|
||||||
table.insert(o.attributePositions, j, attributePos)
|
table.insert(o._attributePositions[attrIdx], j, attributePos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -165,9 +168,9 @@ Radar.__index = Radar
|
||||||
function Radar:drawOutline(w, color)
|
function Radar:drawOutline(w, color)
|
||||||
---@cast self Radar
|
---@cast self Radar
|
||||||
|
|
||||||
for i = 1, #self.outlineVertices do
|
for i = 1, #self._outlineVertices do
|
||||||
local j = i % #self.outlineVertices + 1
|
local j = i % #self._outlineVertices + 1
|
||||||
drawLine(self.outlineVertices[i], self.outlineVertices[j], w, color)
|
drawLine(self._outlineVertices[i], self._outlineVertices[j], w, color)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -181,7 +184,7 @@ function Radar:drawRadialTicks(color, ticks)
|
||||||
gfx.Save()
|
gfx.Save()
|
||||||
gfx.StrokeColor(color:components())
|
gfx.StrokeColor(color:components())
|
||||||
|
|
||||||
for i, vertex in ipairs(self.outlineVertices) do
|
for i, vertex in ipairs(self._outlineVertices) do
|
||||||
gfx.BeginPath()
|
gfx.BeginPath()
|
||||||
gfx.MoveTo(0, 0)
|
gfx.MoveTo(0, 0)
|
||||||
gfx.LineTo(vertex.x, vertex.y)
|
gfx.LineTo(vertex.x, vertex.y)
|
||||||
|
@ -226,9 +229,9 @@ function Radar:drawBackground(fillColor)
|
||||||
gfx.Save()
|
gfx.Save()
|
||||||
|
|
||||||
gfx.BeginPath()
|
gfx.BeginPath()
|
||||||
gfx.MoveTo(self.outlineVertices[1].x, self.outlineVertices[1].y)
|
gfx.MoveTo(self._outlineVertices[1].x, self._outlineVertices[1].y)
|
||||||
for i = 2, #self.outlineVertices do
|
for i = 2, #self._outlineVertices do
|
||||||
gfx.LineTo(self.outlineVertices[i].x, self.outlineVertices[i].y)
|
gfx.LineTo(self._outlineVertices[i].x, self._outlineVertices[i].y)
|
||||||
end
|
end
|
||||||
gfx.ClosePath()
|
gfx.ClosePath()
|
||||||
|
|
||||||
|
@ -243,13 +246,14 @@ function Radar:drawAttributes()
|
||||||
|
|
||||||
gfx.Save()
|
gfx.Save()
|
||||||
|
|
||||||
gfx.FontSize(20)
|
gfx.LoadSkinFont("contb.ttf")
|
||||||
for i = 1, #self.attributePositions do
|
gfx.FontSize(21)
|
||||||
local attrPos = self.attributePositions[i]
|
for i = 1, #self._attributePositions do
|
||||||
|
local attrPos = self._attributePositions[i]
|
||||||
for j = 1, #attrPos do
|
for j = 1, #attrPos do
|
||||||
local pos = attrPos[j]
|
local pos = attrPos[j]
|
||||||
local attr = Radar.ATTRIBUTES[i][j]
|
local attr = Radar.ATTRIBUTES[i][j]
|
||||||
gfx.TextAlign(gfx.TEXT_ALIGN_MIDDLE + gfx.TEXT_ALIGN_CENTER)
|
gfx.TextAlign(attr.align)
|
||||||
renderOutlinedText(pos, string.upper(attr.text), 1, attr.color)
|
renderOutlinedText(pos, string.upper(attr.text), 1, attr.color)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -257,6 +261,11 @@ function Radar:drawAttributes()
|
||||||
gfx.Restore()
|
gfx.Restore()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Draw shaded radar mesh
|
||||||
|
---
|
||||||
|
---Bug: ForceRender resets every transformation, you need to re-setup view transform afterwards.
|
||||||
|
---ForceRender also resets the gfx stack, USC will crash if you try to call gfx.Restore(),
|
||||||
|
---make sure the gfx stack is clean before calling radar:drawRadarMesh()
|
||||||
function Radar:drawRadarMesh()
|
function Radar:drawRadarMesh()
|
||||||
---@cast self Radar
|
---@cast self Radar
|
||||||
|
|
||||||
|
@ -269,10 +278,8 @@ function Radar:drawRadarMesh()
|
||||||
self._graphdata.onehand,
|
self._graphdata.onehand,
|
||||||
}
|
}
|
||||||
|
|
||||||
local color1 = ColorRGBA.new(255, 12, 48, 230) -- magenta-ish
|
local colorMax = ColorRGBA.new(255, 12, 48, 230) -- magenta-ish
|
||||||
local color2 = ColorRGBA.new(112, 119, 255, 230) -- light blue-ish purple
|
local colorCenter = ColorRGBA.new(112, 119, 255, 230) -- light blue-ish purple
|
||||||
|
|
||||||
local currentTime = 0
|
|
||||||
|
|
||||||
-- Calculate the maximum size based on the constraint
|
-- Calculate the maximum size based on the constraint
|
||||||
local maxSize = self.RADIUS * self.scale + 10
|
local maxSize = self.RADIUS * self.scale + 10
|
||||||
|
@ -280,23 +287,20 @@ function Radar:drawRadarMesh()
|
||||||
self._hexagonMesh:SetParam("maxSize", maxLineLength + .0)
|
self._hexagonMesh:SetParam("maxSize", maxLineLength + .0)
|
||||||
|
|
||||||
-- Set the color of the hexagon
|
-- Set the color of the hexagon
|
||||||
self._hexagonMesh:SetParamVec4("colorMax", color1:componentsFloat())
|
self._hexagonMesh:SetParamVec4("colorMax", colorMax:componentsFloat())
|
||||||
self._hexagonMesh:SetParamVec4("colorCenter", color2:componentsFloat())
|
self._hexagonMesh:SetParamVec4("colorCenter", colorCenter:componentsFloat())
|
||||||
|
|
||||||
-- Set the primitive type to triangles
|
-- Set the primitive type to triangles
|
||||||
self._hexagonMesh:SetPrimitiveType(self._hexagonMesh.PRIM_TRIFAN)
|
self._hexagonMesh:SetPrimitiveType(self._hexagonMesh.PRIM_TRIFAN)
|
||||||
|
|
||||||
-- Calculate the vertices of the hexagon
|
-- Calculate the vertices of the hexagon
|
||||||
local sides = #Radar.ATTRIBUTES
|
local sides = #Radar.ATTRIBUTES
|
||||||
local angleStep = (2 * math.pi) / sides
|
|
||||||
local rotationAngle = angleStep / 2
|
|
||||||
--local rotationAngle = -math.pi / 2
|
|
||||||
local vertices = {}
|
|
||||||
|
|
||||||
|
local vertices = {}
|
||||||
table.insert(vertices, {{0, 0}, {0, 0}})
|
table.insert(vertices, {{0, 0}, {0, 0}})
|
||||||
for i = 0, sides do
|
for i = 0, sides do
|
||||||
local j = i % sides + 1
|
local j = i % sides + 1
|
||||||
local angle = i * angleStep - rotationAngle
|
local angle = i * self._angleStep - self._initRotation
|
||||||
|
|
||||||
--local angle = math.rad(60 * (i-1)) + rotationAngle
|
--local angle = math.rad(60 * (i-1)) + rotationAngle
|
||||||
local scale = scaleFact[j]
|
local scale = scaleFact[j]
|
||||||
|
@ -309,16 +313,18 @@ function Radar:drawRadarMesh()
|
||||||
|
|
||||||
-- Set the hexagon's vertices
|
-- Set the hexagon's vertices
|
||||||
self._hexagonMesh:SetData(vertices)
|
self._hexagonMesh:SetData(vertices)
|
||||||
--self._hexagonMesh:SetPosition(-maxSize, maxSize)
|
|
||||||
self._hexagonMesh:Draw()
|
self._hexagonMesh:Draw()
|
||||||
|
|
||||||
--NOTE: Bug: forcerender resets every transformation, need to re-setup view transform afterwards
|
-- YOU! You are the reason for all my pain!
|
||||||
gfx.ForceRender()
|
gfx.ForceRender()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--NOTE: THIS IS BUGGY, ForceRender fucks up so many things, call the individual draw functions at top level
|
||||||
function Radar:drawGraph()
|
function Radar:drawGraph()
|
||||||
---@cast self Radar
|
---@cast self Radar
|
||||||
|
|
||||||
|
game.Log("Radar:drawGraph() SHOULD NOT BE CALLED", game.LOGGER_WARNING)
|
||||||
|
|
||||||
gfx.Save()
|
gfx.Save()
|
||||||
gfx.Reset()
|
gfx.Reset()
|
||||||
gfx.ResetScissor()
|
gfx.ResetScissor()
|
||||||
|
@ -333,10 +339,10 @@ function Radar:drawGraph()
|
||||||
local strokeColor = ColorRGBA.new(255, 255, 255, 100)
|
local strokeColor = ColorRGBA.new(255, 255, 255, 100)
|
||||||
local fillColor = ColorRGBA.new(0, 0, 0, 191)
|
local fillColor = ColorRGBA.new(0, 0, 0, 191)
|
||||||
|
|
||||||
self:drawBackground(strokeColor, fillColor)
|
self:drawBackground(fillColor)
|
||||||
self:drawOutline(3, ColorRGBA.WHITE)
|
self:drawOutline(3, strokeColor)
|
||||||
self:drawRadarMesh()
|
self:drawRadarMesh()
|
||||||
self:drawRadialTicks()
|
self:drawRadialTicks(strokeColor)
|
||||||
self:drawAttributes()
|
self:drawAttributes()
|
||||||
|
|
||||||
local pos = Point2D.new(self.pos:coords())
|
local pos = Point2D.new(self.pos:coords())
|
||||||
|
|
Loading…
Reference in New Issue