GUI fixes; Mesh loader WIP

This commit is contained in:
Nikita Kruglickiy 2021-01-19 14:08:53 +06:00
parent d4dd889bb5
commit ceaada7e2d
16 changed files with 433 additions and 58 deletions

View File

@ -1,9 +1,7 @@
--@include label.txt --@include label.txt
--@include radius_mixin.txt --@include radius_mixin.txt
--@include /koptilnya/libs/utils.txt
require("label.txt") require("label.txt")
require("/koptilnya/libs/utils.txt")
EButton = class("EButton", ELabel) EButton = class("EButton", ELabel)
EButton:include(require("radius_mixin.txt")) EButton:include(require("radius_mixin.txt"))
@ -28,9 +26,6 @@ function EButton:initialize()
}) })
end end
function EButton:onClick()
end
function EButton:onMousePressed(x, y, key, keyName) function EButton:onMousePressed(x, y, key, keyName)
if keyName == "MOUSE1" then if keyName == "MOUSE1" then
self:onClick() self:onClick()
@ -52,3 +47,8 @@ function EButton:paint(x, y, w, h)
render.setColor(self:getColorFromScheme("text")) render.setColor(self:getColorFromScheme("text"))
render.drawSimpleText(x + w / 2 - textW / 2, y + h / 2 - textH / 2, self:getText()) render.drawSimpleText(x + w / 2 - textW / 2, y + h / 2 - textH / 2, self:getText())
end end
-- STUB
function EButton:onClick()
end

View File

@ -1,8 +1,6 @@
--@include element.txt --@include element.txt
--@include /koptilnya/libs/utils.txt
require("element.txt") require("element.txt")
require("/koptilnya/libs/utils.txt")
ECheckbox = class("ECheckbox", Element) ECheckbox = class("ECheckbox", Element)
@ -47,12 +45,14 @@ end
function ECheckbox:paint(x, y, w, h) function ECheckbox:paint(x, y, w, h)
render.setColor(self:isChecked() and self:getColorFromScheme("mark") or Color(0, 0, 0, 0)) render.setColor(self:isChecked() and self:getColorFromScheme("mark") or Color(0, 0, 0, 0))
render.drawRectFast(x, y, h, h) render.drawRectFast(x + 4, y + 4, w - 8, h - 8)
render.setColor(self:getColorFromScheme("border")) render.setColor(self:getColorFromScheme("border"))
render.drawRectOutline(x, y, h, h, 1) render.drawRectOutline(x, y, w, h, 1)
render.drawRectOutline(x + 1, y + 1, h - 2, h - 2, 1) render.drawRectOutline(x + 1, y + 1, w - 2, h - 2, 1)
end end
-- STUB
function ECheckbox:onChange(state) function ECheckbox:onChange(state)
end end

View File

@ -24,7 +24,7 @@ end
function Element:setWidth(width) function Element:setWidth(width)
self._width = width self._width = width
self:performLayout(self:getSize()) self:invalidateLayout()
end end
function Element:getWidth() function Element:getWidth()
@ -34,7 +34,7 @@ end
function Element:setHeight(height) function Element:setHeight(height)
self._height = height self._height = height
self:performLayout(self:getSize()) self:invalidateLayout()
end end
function Element:getHeight() function Element:getHeight()
@ -56,7 +56,7 @@ function Element:setPos(x, y)
end end
function Element:getPos() function Element:getPos()
return self._x, self._y return self:getX(), self:getY()
end end
function Element:getAbsolutePos(x, y) function Element:getAbsolutePos(x, y)
@ -182,7 +182,7 @@ function Element:cursorIntersect(x, y)
--local self:getAbsoluteBounds() --local self:getAbsoluteBounds()
local aX, aY = self:getAbsolutePos() local aX, aY = self:getAbsolutePos()
if x >= aX and x <= aX + self:getWidth() and y >= aY and y <= aY + self:getHeight() then if x >= aX and x < aX + self:getWidth() and y >= aY and y < aY + self:getHeight() then
return true return true
end end
@ -256,10 +256,8 @@ function Element:_postEventToAllReverse(eventKey, ...)
end end
function Element:_onThink() function Element:_onThink()
if self:isEnabled() then if self:isEnabled() and self:isVisible() then
if type(self.think) == "function" then
self:think() self:think()
end
if self._firstChild then if self._firstChild then
self._firstChild:_postEventToAllReverse("THINK") self._firstChild:_postEventToAllReverse("THINK")
@ -357,6 +355,13 @@ end
function Element:performLayout() function Element:performLayout()
end end
function Element:invalidateLayout()
self:performLayout(self:getSize())
end
function Element:think()
end
function Element:paint() function Element:paint()
end end

View File

@ -40,6 +40,15 @@ function ELabeledCheckbox:isChecked()
return self.checkbox:isChecked() return self.checkbox:isChecked()
end end
function ELabeledCheckbox:setEnabled(state)
self.checkbox:setEnabled(state)
self.label:setEnabled(state)
end
function ELabeledCheckbox:isEnabled()
return self.checkbox:isEnabled() and self.label:isEnabled()
end
function ELabeledCheckbox:toggle() function ELabeledCheckbox:toggle()
self.checkbox:toggle() self.checkbox:toggle()
end end
@ -55,7 +64,7 @@ function ELabeledCheckbox:setFont(font)
end end
function ELabeledCheckbox:sizeToContents() function ELabeledCheckbox:sizeToContents()
self:performLayout(self:getSize()) self:invalidateLayout()
self:setWidth(self.label:getX() + self.label:getWidth()) self:setWidth(self.label:getX() + self.label:getWidth())
self:setHeight(math.max(self.checkbox:getHeight(), self.label:getHeight())) self:setHeight(math.max(self.checkbox:getHeight(), self.label:getHeight()))
end end
@ -65,5 +74,7 @@ function ELabeledCheckbox:performLayout(w, h)
self.label:setX(self.checkbox:getWidth() + self:getIndent()) self.label:setX(self.checkbox:getWidth() + self:getIndent())
end end
-- STUB
function ELabeledCheckbox:onChange(state) function ELabeledCheckbox:onChange(state)
end end

View File

@ -16,6 +16,7 @@ function EPanel:initialize()
Element.initialize(self) Element.initialize(self)
self._minimized = false self._minimized = false
self._lastHeight = 0
self.title = ELabel:new() self.title = ELabel:new()
self.title:setPos(12, 8) self.title:setPos(12, 8)
@ -30,17 +31,18 @@ function EPanel:initialize()
} }
self.minimizeButton = EButton:new() self.minimizeButton = EButton:new()
self.minimizeButton:setFont(GUI.fonts["icons"])
self.minimizeButton:setText("_") self.minimizeButton:setText("_")
self.minimizeButton:setSize(32, 32) self.minimizeButton:setSize(32, 32)
self.minimizeButton:setRadius(0) self.minimizeButton:setRadius(0)
self.minimizeButton:setColorScheme(colorScheme) self.minimizeButton:setColorScheme(colorScheme)
self.minimizeButton:setEnabled(false) self.minimizeButton.onClick = function()
self:minimizeMaximize()
end
self:addChild(self.minimizeButton) self:addChild(self.minimizeButton)
self.closeButton = EButton:new() self.closeButton = EButton:new()
self.closeButton:setFont(GUI.fonts["icons"]) self.closeButton:setFont(GUI.fonts["icons"])
self.closeButton:setText("X") self.closeButton:setText(string.utf8char(10005))
self.closeButton:setSize(32, 32) self.closeButton:setSize(32, 32)
self.closeButton:setRadius(0) self.closeButton:setRadius(0)
self.closeButton:setColorScheme(colorScheme) self.closeButton:setColorScheme(colorScheme)
@ -85,8 +87,48 @@ function EPanel:close()
end end
function EPanel:open() function EPanel:open()
self:setVisible(false) self:setVisible(true)
self:setEnabled(false) self:setEnabled(true)
end
function EPanel:minimize()
self._lastHeight = self:getHeight()
self.minimizeButton:setText(string.utf8char(10063))
self:setMinimized(true)
self:setHeight(34)
local child = self._firstChild
while child do
if child ~= self.title and child ~= self.minimizeButton and child ~= self.closeButton then
child:setVisible(false)
end
child = child._nextSibling
end
end
function EPanel:maximize()
self.minimizeButton:setText("_")
self:setMinimized(false)
self:setHeight(self._lastHeight)
local child = self._firstChild
while child do
if child ~= self.title and child ~= self.minimizeButton and child ~= self.closeButton then
child:setVisible(true)
end
child = child._nextSibling
end
end
function EPanel:minimizeMaximize()
if self:isMinimized() then
self:maximize()
else
self:minimize()
end
end end
function EPanel:onMousePressed(x, y, key, keyName) function EPanel:onMousePressed(x, y, key, keyName)
@ -125,8 +167,8 @@ function EPanel:onMouseLeave()
end end
function EPanel:performLayout(w, h) function EPanel:performLayout(w, h)
self.closeButton:setPos(w - 33, 1)
self.minimizeButton:setPos(w - 65, 1) self.minimizeButton:setPos(w - 65, 1)
self.closeButton:setPos(w - 33, 1)
end end
function EPanel:paint(x, y, w, h) function EPanel:paint(x, y, w, h)

View File

@ -0,0 +1,20 @@
--@include checkbox.txt
--@include /koptilnya/libs/utils.txt
--@include /koptilnya/libs/render.txt
require("checkbox.txt")
require("/koptilnya/libs/utils.txt")
require("/koptilnya/libs/render.txt")
ERadio = class("ERadio", ECheckbox)
function ERadio:paint(x, y, w, h)
render.setColor(self:isChecked() and self:getColorFromScheme("mark") or Color(0, 0, 0, 0))
render.setMaterial()
render.drawFilledCircle(x + w / 2, y + h / 2, w / 2 - 4, 6)
render.setColor(self:getColorFromScheme("border"))
render.setMaterial()
render.drawCircle(x + w / 2, y + h / 2, w / 2)
render.drawCircle(x + w / 2, y + h / 2, w / 2 - 1)
end

View File

@ -8,7 +8,7 @@ GUI = class("GUI")
GUI.static.fonts = { GUI.static.fonts = {
main = render.createFont("Roboto", 16, 700, true), main = render.createFont("Roboto", 16, 700, true),
icons = render.createFont("Roboto Mono", 16, 700, true) icons = render.createFont("Roboto Mono", 24, 400, true)
} }
function GUI:initialize(renderDevice) function GUI:initialize(renderDevice)

View File

@ -29,7 +29,7 @@ function render.drawWedge(x, y, w, h, angle, mouthSize, fidelity)
end end
end end
function render.drawArc(x, y, ang, p, rad, color, seg) function render.drawArc(x, y, ang, p, rad, seg)
seg = seg || 80 seg = seg || 80
ang = (-ang) + 180 ang = (-ang) + 180
local vertices = {} local vertices = {}
@ -42,3 +42,18 @@ function render.drawArc(x, y, ang, p, rad, color, seg)
render.drawPoly(vertices) render.drawPoly(vertices)
end end
function render.drawFilledCircle(x, y, radius, seg)
local cir = {}
table.insert(cir, { x = x, y = y, u = 0.5, v = 0.5 })
for i = 0, seg do
local a = math.rad(( i / seg ) * -360)
table.insert(cir, { x = x + math.sin( a ) * radius, y = y + math.cos( a ) * radius, u = math.sin( a ) / 2 + 0.5, v = math.cos( a ) / 2 + 0.5 })
end
local a = math.rad(0)
table.insert(cir, { x = x + math.sin( a ) * radius, y = y + math.cos( a ) * radius, u = math.sin( a ) / 2 + 0.5, v = math.cos( a ) / 2 + 0.5 })
render.drawPoly(cir)
end

View File

@ -1,5 +0,0 @@
BaseEntity = class("BaseEntity")
function BaseEntity:initialize()
end

View File

@ -6,12 +6,17 @@ MeshBuilder = class("MeshBuilder")
function MeshBuilder:initialize() function MeshBuilder:initialize()
self._objects = {} self._objects = {}
self._bundle = {} self._setups = {}
if CLIENT then if CLIENT then
self._setups = {}
self._meshData = {} self._meshData = {}
--[[
self._shouldBuild = false
self._shouldRevision = true
]]
net.receive("sendHolograms", function(len) net.receive("holograms", function(len)
local hasNext = net.readBit() local hasNext = net.readBit()
while hasNext == 1 do while hasNext == 1 do
@ -33,9 +38,47 @@ function MeshBuilder:initialize()
hasNext = net.readBit() hasNext = net.readBit()
end end
end) end)
else
net.receive("sendObjects", function(len, ply) --[[
net.receive("revision", function()
local hasNext = net.readBit()
while hasNext == 1 do
local key = net.readString()
net.readEntity(function(ent)
local holo = ent:toHologram()
self._objects[key] = holo
end)
hasNext = net.readBit()
end
self._shouldRevision = false
if self._shouldBuild then
self:build()
self._shouldBuild = false
end
end)
]]
else
--[[
net.receive("revision", function(len, ply)
net.start("revision")
for k, v in pairs(self._objects) do
net.writeBit(1)
net.writeString(k)
net.writeEntity(v)
end
net.writeBit(0)
net.send()
end)
]]
net.receive("setups", function(len, ply)
local hasNext = net.readBit() local hasNext = net.readBit()
while hasNext == 1 do while hasNext == 1 do
@ -62,15 +105,15 @@ function MeshBuilder:initialize()
self._objects[key] = holo self._objects[key] = holo
end end
if not self._bundle[key] then if not self._setups[key] then
self._bundle[key] = self._objects[key] self._setups[key] = self._objects[key]
end end
hasNext = net.readBit() hasNext = net.readBit()
end end
net.start("sendHolograms") net.start("holograms")
for k, v in pairs(self._bundle) do for k, v in pairs(self._setups) do
net.writeBit(1) net.writeBit(1)
net.writeString(k) net.writeString(k)
net.writeEntity(v) net.writeEntity(v)
@ -78,7 +121,7 @@ function MeshBuilder:initialize()
net.writeBit(0) net.writeBit(0)
net.send(ply) net.send(ply)
table.empty(self._bundle) table.empty(self._setups)
end) end)
end end
end end
@ -89,8 +132,8 @@ if CLIENT then
end end
function MeshBuilder:setup(key, pos, ang, scale, color, mat, parent, relativeTo) function MeshBuilder:setup(key, pos, ang, scale, color, mat, parent, relativeTo)
if not self._objects[key] and not self._bundle[key] and self._meshData[key] then if not self._objects[key] and not self._setups[key] and self._meshData[key] then
self._bundle[key] = { self._setups[key] = {
pos = pos, pos = pos,
ang = ang, ang = ang,
scale = scale, scale = scale,
@ -109,9 +152,20 @@ if CLIENT then
end end
function MeshBuilder:build() function MeshBuilder:build()
local function send(objects) --[[
net.start("sendObjects") if self._shouldRevision then
for k, v in pairs(objects) do net.start("revision")
net.send()
self._shouldBuild = true
return
end
]]
local function sendSetups(setups)
net.start("setups")
for k, v in pairs(setups) do
net.writeBit(1) net.writeBit(1)
net.writeString(k) net.writeString(k)
net.writeVector(v.pos) net.writeVector(v.pos)
@ -126,28 +180,28 @@ if CLIENT then
net.send() net.send()
end end
local bundleKeys = table.getKeys(self._bundle) local bundleKeys = table.getKeys(self._setups)
if #bundleKeys > BUNDLE_SIZE then if #bundleKeys > BUNDLE_SIZE then
local i = 1 local i = 1
timer.create("send", SEND_DELAY, math.ceil(#bundleKeys / BUNDLE_SIZE), function() timer.create("sendSetups", SEND_DELAY, math.ceil(#bundleKeys / BUNDLE_SIZE), function()
local from = (i - 1) * BUNDLE_SIZE + 1 local from = (i - 1) * BUNDLE_SIZE + 1
local objects = {} local setups = {}
for _, v in pairs({ unpack(bundleKeys, from, from + BUNDLE_SIZE - 1) }) do for _, v in pairs({ unpack(bundleKeys, from, from + BUNDLE_SIZE - 1) }) do
objects[v] = self._bundle[v] setups[v] = self._setups[v]
end end
send(objects) sendSetups(setups)
if i < math.ceil(#bundleKeys / BUNDLE_SIZE) then if i < math.ceil(#bundleKeys / BUNDLE_SIZE) then
i = i + 1 i = i + 1
else else
table.empty(self._bundle) table.empty(self._setups)
end end
end) end)
else else
send(self._bundle) send(self._setups)
end end
end end
end end

View File

@ -0,0 +1,109 @@
local MODEL_PLACEHOLDER = "models/holograms/cube.mdl"
MeshBuilder = class("MeshBuilder")
function MeshBuilder:initialize()
self._holograms = {}
if SERVER then
self._meshObjects = {}
self._setupAllArgs = nil
net.receive("meshDataSet", function(_, ply)
self._meshObjects = net.readTable()
if self._setupAllArgs ~= nil then
self:setupAll(unpack(self._setupAllArgs))
self._setupAllArgs = nil
end
net.start("holograms")
for k, v in pairs(self._holograms) do
net.writeBit(1)
net.writeString(k)
net.writeEntity(v)
end
net.writeBit(0)
net.send(ply)
end)
else
self._meshData = {}
self._hologramsReceived = false
net.receive("holograms", function()
local hasNext = net.readBit()
while hasNext == 1 do
local key = net.readString()
net.readEntity(function(ent)
if not isValid(ent) then return end
if self._meshData[key] and not self._holograms[key] then
self._holograms[key] = ent:toHologram()
end
end)
hasNext = net.readBit()
end
self._hologramsReceived = true
self:applyMeshes()
end)
end
end
if SERVER then
function MeshBuilder:setup(key, pos, ang, scale, color, mat, parent, relativeTo)
if isValid(self._holograms[key]) then return end
if isValid(relativeTo) then
pos = relativeTo:localToWorld(pos)
ang = relativeTo:localToWorldAngles(ang)
end
local holo = holograms.create(pos, ang, MODEL_PLACEHOLDER, scale)
holo:setColor(color)
holo:setMaterial(mat)
holo:setParent(parent)
self._meshes[key] = Mesh:new()
self._holograms[key] = holo
return holo
end
function MeshBuilder:setupAll(pos, ang, scale, color, mat, parent, relativeTo)
if #self._meshObjects > 0 then
for _, v in pairs(self._meshObjects) do
self:setup(v, pos, ang, scale, color, mat, parent, relativeTo)
end
else
self._setupAllArgs = {pos, ang, scale, color, mat, parent, relativeTo}
end
end
else
function MeshBuilder:setMeshData(meshData)
self._meshData = meshData
if self._hologramsReceived then
self:applyMeshes()
else
net.start("meshDataSet")
net.writeTable(table.getKeys(meshData))
net.send()
end
end
function MeshBuilder:applyMeshes()
for k, v in pairs(self._holograms) do
if isValid(v) then
v:setMesh(self._meshData[k])
v:setRenderBounds(Vector(-200), Vector(200))
end
end
end
end

View File

@ -0,0 +1,3 @@
--@include /koptilnya/libs/utils.txt
require("/koptilnya/libs/utils.txt")

View File

@ -0,0 +1,18 @@
--@include /koptilnya/libs/utils.txt
require("/koptilnya/libs/utils.txt")
Mesh = class("Mesh")
accessorFunc(Mesh, "_entity", "Entity", chip())
if SERVER then
else
function Mesh:setData(data)
self:getEntity():setMesh(data)
self:getEntity():setRenderBounds(Vector(-200), Vector(200))
end
end
--function Mesh:get

View File

@ -2,6 +2,11 @@ local MAX_QUOTA = 0.75
Parser = class("Parser") Parser = class("Parser")
local initialChipName = chip():getChipName()
local function setStatus(status)
setName(string.format("%s (%s)", initialChipName, status))
end
function Parser:initialize(link) function Parser:initialize(link)
if CLIENT then if CLIENT then
local triangles = mesh.trianglesLeft() local triangles = mesh.trianglesLeft()
@ -9,7 +14,7 @@ function Parser:initialize(link)
self:OnLoaded(objData, mesh.createFromObj(objData, true)) self:OnLoaded(objData, mesh.createFromObj(objData, true))
end) end)
print("Getting file...") setStatus("Getting file...")
http.get(link, function(objData) http.get(link, function(objData)
local loadMesh = coroutine.wrap(function() local loadMesh = coroutine.wrap(function()
self.meshData = mesh.createFromObj(objData, true) self.meshData = mesh.createFromObj(objData, true)
@ -17,10 +22,11 @@ function Parser:initialize(link)
return true return true
end) end)
print("File received, start parsing...") setStatus("File received, start parsing...")
hook.add("think", "loadingMesh", function() hook.add("think", "loadingMesh", function()
while quotaAverage() < quotaMax() * MAX_QUOTA do while quotaAverage() < quotaMax() * MAX_QUOTA do
if loadMesh() then if loadMesh() then
setName(initialChipName)
self:onLoaded(objData, self.meshData, triangles - mesh.trianglesLeft()) self:onLoaded(objData, self.meshData, triangles - mesh.trianglesLeft())
hook.remove("think", "loadingMesh") hook.remove("think", "loadingMesh")

View File

@ -0,0 +1,97 @@
--@include /koptilnya/libs/utils.txt
require("/koptilnya/libs/utils.txt")
accessorFunc(Mesh, "_relativeTo", "RelativeTo", nil)
function Mesh:initialize(pos, ang, scale, color, mat, parent, relativeTo)
--create holo
self:setPos(pos)
self:setAng(ang)
self:setScale(scale)
self:setColor(color)
self:setMaterial(mat)
self:setParent(parent)
self:setRelativeTo(relativeTo)
end
function Mesh:getPos()
return self:getEntity():getPos()
end
function Mesh:setPos(pos)
self:getEntity():setPos(pos)
end
function Mesh:getRelativePos()
if isValid(self:getRelativeTo()) then
return self:getRelativeTo():worldToLocal(self:getPos())
else
return self:getPos()
end
end
function Mesh:setRelativePos(pos)
if isValid(self:getRelativeTo()) then
self:setPos(self:getRelativeTo():localToWorld(pos))
else
self:setPos(pos)
end
end
function Mesh:getAng()
return self:getEntity():getAng()
end
function Mesh:setAng(pos)
self:getEntity():setAng(pos)
end
function Mesh:getRelativeAng()
if isValid(self:getRelativeTo()) then
return self:getRelativeTo():worldToLocalAngles(self:getAng())
else
return self:getAng()
end
end
function Mesh:setRelativeAng(ang)
if isValid(self:getRelativeTo()) then
self:setAng(self:getRelativeTo():localToWorldAngles(ang))
else
self:setAng(ang)
end
end
function Mesh:getScale()
return self:getEntity():getScale()
end
function Mesh:setScale(scale)
self:getEntity():setScale(scale)
end
function Mesh:getColor()
return self:getEntity():getColor()
end
function Mesh:setColor(color)
self:getEntity():setColor(color)
end
function Mesh:getMaterial()
return self:getEntity():getMaterial()
end
function Mesh:setMaterial(material)
self:getEntity():setMaterial(material)
end
function Mesh:getParent()
return self:getEntity():getParent()
end
function Mesh:setParent(parent)
self:getEntity():setParent(parent)
end