This commit is contained in:
Elmārs Āboliņš 2020-08-14 01:59:12 +03:00
parent c764f3ca9a
commit f023959137
3 changed files with 124 additions and 57 deletions

View File

@ -12,19 +12,12 @@ local type,pcall = type,pcall
setmetatable(element, { setmetatable(element, {
__call = function(cls, ...) __call = function(cls, ...)
local self local self
local func, loader, param = ... local func, param, w, h = ...
self = setmetatable({}, element) self = setmetatable({}, element)
self.parentFunc = func self.parentFunc = func
if loader then self:new(param,nil, w, h)
local function f(newFunc)
self:reLoader(newFunc)
end
loader(f)
end
self:new(param)
self:createProxies(param) self:createProxies(param)
return self return self
@ -33,7 +26,7 @@ setmetatable(element, {
--Control functions --Control functions
--The new function that should be used for element creation --The new function that should be used for element creation
function element:new(param, immediate) function element:new(param, immediate, w, h)
self.parameters = {} self.parameters = {}
self.baseParams = param self.baseParams = param
@ -43,27 +36,34 @@ function element:new(param, immediate)
isSetup = false, isSetup = false,
pendingUpdate = true, pendingUpdate = true,
needsRendering = true, needsRendering = true,
remove = false,
--Unused for now? --Unused for now?
calculatedDimensions = true, calculatedDimensions = true,
--Is this the first render --Is this the first render
firstDraw = true, firstDraw = true,
--Stabilize the internal canvas, draw it twice on first load
stabilize = true,
--Has it been inserted in to the buffer --Has it been inserted in to the buffer
inserted = false, inserted = false,
--Whether this element is created and drawn instantly (and doesn't need a canvas) --Whether this element is created and drawn instantly (and doesn't need a canvas)
immediate = immediate or false, immediate = immediate or false,
--Render this element in the external buffer with absolute coordinates --Whether this element has a canvas assigned
absolutePosition = false, hasCanvas = false,
--Current test render passes to be benchmarked
testRenderPasses = love.math.random(3, 6),
--
failedCanvas = false
}
self.renderBench = {
} }
self.baseView = { self.baseView = {
x = 0, x = 0,
y = 0, y = 0,
w = 10, w = w or 10,
h = 10, h = h or 10,
minW = 10, minW = w or 10,
minH = 10, minH = h or 10,
} }
self.view = self.baseView self.view = self.baseView
@ -100,6 +100,34 @@ function element:createProxies()
self.context = context.new(self) self.context = context.new(self)
end end
--Random coefficients, if these reach 1.5 then canvas is made
local childrenNum = 5
local selfRenderTime = 0.0005
local screenSize = 1/8
local coefficient = 1.5
function element:calculateCanvasCoeficient(selfTime)
local sW, sH = love.graphics.getDimensions()
local areaBelow = (sW * sH) * screenSize
local area = self.view.h * self.view.w
local areaCoef = 1 - (area/areaBelow)
local childCoef = self.context:getChildrenCount()/childrenNum
local sizeCoef = selfTime/selfRenderTime
return (areaCoef+childCoef+sizeCoef)>coefficient
end
local newCanvas, newQuad = love.graphics.newCanvas, love.graphics.newQuad
function element:createCanvas()
self.settings.canvasW = self.view.w*1.25
self.settings.canvasH = self.view.h*1.25
self.canvas = newCanvas(self.view.w*1.25, self.view.h*1.25)
self.quad = newQuad(0, 0, self.view.w, self.view.h, self.view.w*1.25, self.view.h*1.25)
end
function element:setParam(p) function element:setParam(p)
self.baseParams = p self.baseParams = p
self.context:bubbleUpdate() self.context:bubbleUpdate()
@ -113,8 +141,8 @@ function element:setCalculatedSize(w, h)
end end
function element:updateInputCtx() function element:updateInputCtx()
self.context.inputContext:update() --self.context.inputContext:update()
if self.settings.canvasW then --[[if self.settings.canvasW then
--If canvas too small make a bigger one --If canvas too small make a bigger one
if self.settings.canvasW < self.view.w or self.settings.canvasH < self.view.h then if self.settings.canvasW < self.view.w or self.settings.canvasH < self.view.h then
self.settings.canvasW = self.view.w*1.25 self.settings.canvasW = self.view.w*1.25
@ -130,7 +158,7 @@ function element:updateInputCtx()
end end
self.quad = love.graphics.newQuad(0, 0, self.view.w, self.view.h, self.settings.canvasW, self.settings.canvasH) self.quad = love.graphics.newQuad(0, 0, self.view.w, self.view.h, self.settings.canvasW, self.settings.canvasH)
end end]]
end end
local dummy = function() end local dummy = function() end
@ -143,23 +171,16 @@ function element.immediate(param, func, x, y, w, h)
local self = setmetatable({}, element) local self = setmetatable({}, element)
self = element:new(param, true) self = element:new(param, true)
else else
error("Can't render immediate outside of element") error("Can't render immediate outside of persistent")
end end
end end
local newCanvas, newQuad = love.graphics.newCanvas, love.graphics.newQuad
--Called once dimensions are validated --Called once dimensions are validated
function element:setup() function element:setup()
self.context:set() self.context:set()
self.renderer = self.parentFunc(self.parameters, self.view.w, self.view.h) self.renderer = self.parentFunc(self.parameters, self.view.w, self.view.h)
self.context:unset() self.context:unset()
self.settings.canvasW = self.view.w*1.25
self.settings.canvasH = self.view.h*1.25
self.canvas = newCanvas(self.view.w*1.25, self.view.h*1.25)
self.quad = newQuad(0, 0, self.view.w, self.view.h, self.view.w*1.25, self.view.h*1.25)
self.settings.isSetup = true self.settings.isSetup = true
end end
@ -171,33 +192,40 @@ function element:errorRender(msg)
printf("Error: "..msg, 0, 0, self.view.w) printf("Error: "..msg, 0, 0, self.view.w)
end end
local calcT
function element:internalRender() function element:internalRender()
if type(self.renderer) == 'function' then love.graphics.push()
love.graphics.push() if self.settings.hasCanvas then
love.graphics.origin() love.graphics.origin()
local status, err = pcall(self.renderer) else
love.graphics.pop() love.graphics.translate(self.view.x, self.view.y)
local gx, gy = love.graphics.transformPoint(self.view.x, self.view.y)
end
if self.settings.testRenderPasses > 0 then
calcT = love.timer.getTime()
end
local status, err = pcall(self.renderer)
if self.settings.testRenderPasses > 0 then
self.settings.testRenderPasses = self.settings.testRenderPasses-1
local selfTime = love.timer.getTime()-calcT
table.insert(self.renderBench, self.context:endSelfRender(selfTime))
end
if not status then love.graphics.pop()
if helium.conf.HARD_ERROR then
error(status)
end
self:errorRender(status)
end
elseif type(self.renderer) == 'string' then if not status then
if helium.conf.HARD_ERROR then if helium.conf.HARD_ERROR then
error(self.renderer) error(status)
end end
self:errorRender(self.renderer) self:errorRender(status)
end end
end end
local draw = love.graphics.draw
local getCanvas, setCanvas, clear = love.graphics.getCanvas, love.graphics.setCanvas, love.graphics.clear local getCanvas, setCanvas, clear = love.graphics.getCanvas, love.graphics.setCanvas, love.graphics.clear
function element:renderWrapper() function element:renderWrapper()
self.context:set() self.context:set()
local cnvs = getCanvas()
setCanvas({self.canvas, stencil = true})
clear() clear()
@ -206,32 +234,51 @@ function element:renderWrapper()
self.settings.pendingUpdate = false self.settings.pendingUpdate = false
end end
setCanvas(cnvs)
self.context:unset() self.context:unset()
end end
local draw = love.graphics.draw
function element:externalRender() function element:externalRender()
if self.settings.stabilize and not self.settings.needsRendering then local cnvs = getCanvas()
self.settings.stabilize = false
self.settings.needsRendering = true
end
if not self.settings.isSetup then if not self.settings.isSetup then
self:setup() self:setup()
self.settings.isSetup = true self.settings.isSetup = true
end end
setCanvas(self.canvas)
if self.settings.needsRendering then if self.settings.needsRendering then
self:renderWrapper() self:renderWrapper()
self.settings.needsRendering = false self.settings.needsRendering = not self.settings.hasCanvas
end end
setColor(1,1,1) setCanvas(cnvs)
draw(self.canvas, self.quad, self.view.x, self.view.y) if self.settings.hasCanvas then
setColor(1,1,1)
draw(self.canvas, self.quad, self.view.x, self.view.y)
love.graphics.rectangle('line', self.view.x, self.view.y, self.view.w, self.view.h)
end
print(self.view.x, self.view.y)
end end
function element:externalUpdate() function element:externalUpdate()
if not self.settings.failedCanvas and self.settings.testRenderPasses == 0 and not self.settings.hasCanvas then
local avg, sum = 0, 0
for i, e in ipairs(self.renderBench) do
sum = sum + e
end
avg = sum/#self.renderBench
if self:calculateCanvasCoeficient(avg) then
self:createCanvas()
self.settings.hasCanvas = true
else
self.settings.failedCanvas = true
end
end
if self.settings.pendingUpdate then if self.settings.pendingUpdate then
if self.updater then if self.updater then
self:updater() self:updater()

View File

@ -15,7 +15,8 @@ function context.new(elem)
view = elem.view, view = elem.view,
element = elem, element = elem,
childrenContexts = {}, childrenContexts = {},
inputContext = helium.input.newContext(elem) inputContext = helium.input.newContext(elem),
childRenderTime = 0
}, context) }, context)
return ctx return ctx
@ -66,6 +67,21 @@ function context:unsuspend()
self.inputContext:unsuspend() self.inputContext:unsuspend()
end end
function context:startSelfRender()
self.childRenderTime = 0
end
function context:passTimeTo(time)
self.childRenderTime = self.childRenderTime + time
end
function context:endSelfRender(time)
if self.parentCtx then
self.parentCtx:passTimeTo(time)
end
return time-self.childRenderTime
end
function context:destroy() function context:destroy()
self.elem:undraw() self.elem:undraw()
for i = 1, #self.childrenContexts do for i = 1, #self.childrenContexts do
@ -79,10 +95,15 @@ function context:suspend()
self.inputContext:unset() self.inputContext:unset()
end end
function context:getChildrenCount()
return #self.childrenContexts
end
--Function meant for external context capture --Function meant for external context capture
function context.getContext() function context.getContext()
return activeContext return activeContext
end end
return context return context

View File

@ -19,15 +19,14 @@ setmetatable(helium, {__call = function(s, chunk)
return helium.element.immediate(param, inputs, chunk, x, y, w, h) return helium.element.immediate(param, inputs, chunk, x, y, w, h)
end end
}, },
{__call = function(s, param) {__call = function(s, param, w, h)
return helium.element(chunk, param) return helium.element(chunk, param, w, h)
end,}) end,})
end}) end})
function helium.render() function helium.render()
--We don't want any side effects affecting internal rendering --We don't want any side effects affecting internal rendering
love.graphics.reset() love.graphics.reset()
for i, e in ipairs(helium.elementBuffer) do for i, e in ipairs(helium.elementBuffer) do
e:externalRender() e:externalRender()
end end