diff --git a/core/atlas.lua b/core/atlas.lua index e5d2342..db2b112 100644 --- a/core/atlas.lua +++ b/core/atlas.lua @@ -1,15 +1,54 @@ local atlas = {} -local atlases = {} +local createdAtlas atlas.__index = atlas -local BLOCK_SIZE = 10 +local BLOCK_SIZE = 5 + +function atlas.load() + if not createdAtlas then + atlas.init() + end +end + +function atlas.getRatio() + return createdAtlas.taken_area/createdAtlas.ideal_area +end + +function atlas.getFreeArea() + return createdAtlas.ideal_area - createdAtlas.taken_area +end function atlas.init() local w, h = love.graphics.getDimensions() - + createdAtlas = atlas.new(w, h/2) + atlas.createdAtlas = createdAtlas end -function atlas.onscreenchange(newW,newH) +function atlas.assign(element) + local elW = element.view.w + local elH = element.view.h + local canvas, quad = createdAtlas:assignElement(element) + if not canvas and createdAtlas.ideal_area > createdAtlas.taken_area*1.25 then + print('refragmenting ;3') + createdAtlas:refragment() + local canvas, quad = createdAtlas:assignElement(element) + else + print('wont refragment') + end + return canvas, quad +end + +function atlas.unassign(element) + createdAtlas:unassignElement(element) +end + +function atlas.unassignAll() + createdAtlas.users = {} + createdAtlas:unMarkTiles(1, 1, createdAtlas.tileW, createdAtlas.tileH) + createdAtlas.taken_area = 0 +end + +function atlas.onscreenchange(newW, newH) end @@ -17,10 +56,11 @@ function atlas.new(w, h) local tiles = {} local ymax = math.floor(h/BLOCK_SIZE) + local xmax = math.floor(w/BLOCK_SIZE) for y = 1, ymax do tiles[y] = {} - tiles[y].empty = ymax - for x = 1, math.floor(w/BLOCK_SIZE) do + tiles[y].empty = xmax + for x = 1, xmax do tiles[y][x] = { taken = false } @@ -30,7 +70,10 @@ function atlas.new(w, h) local self = { w = w, h = h, + tileW = xmax, + tileH = ymax, ideal_area = w*h, + taken_area = 0, canvas = love.graphics.newCanvas(w, h), users = {}, tiles = tiles, @@ -39,17 +82,98 @@ function atlas.new(w, h) return setmetatable(self, atlas) end -function atlas:assignElement(elW, elH, element) - local tileSizeY, tileSizeW = math.ceil(elH/BLOCK_SIZE), math.ceil(elW/BLOCK_SIZE) +function atlas:assignElement(element) + local elH, elW = element.view.h, element.view.w + local tileSizeY, tileSizeX = math.ceil(elH/BLOCK_SIZE), math.ceil(elW/BLOCK_SIZE) + local t, y, x = self:find(tileSizeY, tileSizeX) + + if t then + local quad + --Refragmenting path + if self.users[element] then + --update by reference owo + self.users[element].quad:setViewport((x-1)*BLOCK_SIZE, (y-1)*BLOCK_SIZE, elW, elH) + quad = self.users[element].quad + else + quad = love.graphics.newQuad((x-1)*BLOCK_SIZE, (y-1)*BLOCK_SIZE, elW, elH, self.w, self.h) + end + + self.users[element] = { + element = element, + x = x, + y = y, + w = tileSizeX, + h = tileSizeY, + quad = quad + } + + self:markTiles(x, y, tileSizeX, tileSizeY) + + self.taken_area = self.taken_area + tileSizeY*BLOCK_SIZE + tileSizeX*BLOCK_SIZE + + return self.canvas, self.users[element].quad + else + print('failed to allocate :X') + return false + end +end + +local function sortFunc(el1, el2) + return el1.view.h > el2.view.h +end + +function atlas:refragment() + self:unMarkTiles(1, 1, self.tileW-1, self.tileH-1) + self.taken_area = 0 + + local elementArray = {} + + for i, e in pairs(self.users) do + i.settings.needsRendering = true + table.insert(elementArray, i) + end + + --self.users = {} + love.graphics.setCanvas(self.canvas) + love.graphics.clear(0,0,0,0) + love.graphics.setCanvas() + --Should be sorted large to small + table.sort(elementArray, sortFunc) + + for index, element in ipairs(elementArray) do + self:assignElement(element) + end +end + +function atlas:markTiles(x, y, w, h) + for y = y, y+h do + self.tiles[y].empty = self.tiles[y].empty - w + + for x = x, x+w do + self.tiles[y][x].taken = true + end + end +end + +function atlas:unMarkTiles(x, y, w, h) + for y = y, y+h do + self.tiles[y].empty = self.tiles[y].empty + w + + for x = x, x+w do + self.tiles[y][x].taken = false + end + end end --Work only with rounded values inside here function atlas:find(sizeY, sizeX) - for y = 1, #self.tiles do + local maxX, maxY = #self.tiles[1], #self.tiles + + for y = 1, #self.tiles-sizeY+1 do local skipUntilX=0 if self.tiles[y].empty > sizeY then - for x = 1, #self.tiles[1] do + for x = 1, #self.tiles[1]-sizeX do if not self.tiles[y][x].taken and x>skipUntilX then local result, y, x = self:slice(y, x, sizeY, sizeX) @@ -62,21 +186,25 @@ function atlas:find(sizeY, sizeX) end end end + + return false end function atlas:slice(startY, startX, sizeY, sizeX) for y = startY, startY+sizeY do - for x = startX, sizeX do + for x = startX, startX+sizeX do if self.tiles[y][x].taken then return false, y, x end end end - return true + return true, startY, startX end function atlas:unassignElement(element) - + local user = self.users[element] + self:unMarkTiles(user.x, user.y, user.w, user.h) + self.users[element] = nil end return atlas \ No newline at end of file diff --git a/core/element.lua b/core/element.lua index 6a685e4..9548e72 100644 --- a/core/element.lua +++ b/core/element.lua @@ -4,7 +4,7 @@ local path = string.sub(..., 1, string.len(...) - string.len(".core.element")) local helium = require(path .. ".dummy") local context = require(path.. ".core.stack") ----@class element +---@class Element local element = {} element.__index = element @@ -103,8 +103,8 @@ end --Random coefficients, if these reach 1.5 then canvas is made local childrenNum = 5 local selfRenderTime = false -local screenSize = 1/50 -local coefficient = 1000000 +local screenSize = 1/4 +local coefficient = 1.50 function element.setBench(time) selfRenderTime = time @@ -112,10 +112,10 @@ end function element:calculateCanvasCoeficient(selfTime) local sW, sH = love.graphics.getDimensions() - local areaBelow = (sW * sH) * screenSize + local areaBelow = helium.atlas.getFreeArea() local area = self.view.h * self.view.w - local areaCoef = 1 - (area/areaBelow) + local areaCoef = (1-helium.atlas.getRatio()) - (area/areaBelow) local childCoef = self.context:getChildrenCount()/childrenNum local sizeCoef = selfTime/selfRenderTime @@ -124,11 +124,10 @@ 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.settings.canvasW = self.view.w + self.settings.canvasH = self.view.h - 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.canvas, self.quad = helium.atlas.assign(self) end function element:setParam(p) @@ -145,7 +144,7 @@ end function element:updateInputCtx() self.context.inputContext:update() - if self.settings.canvasW then + --[[if self.settings.canvasW then --If canvas too small make a bigger one if self.settings.canvasW < self.view.w or self.settings.canvasH < self.view.h then self.settings.canvasW = self.view.w*1.25 @@ -161,7 +160,7 @@ function element:updateInputCtx() end self.quad = love.graphics.newQuad(0, 0, self.view.w, self.view.h, self.settings.canvasW, self.settings.canvasH) - end + end]] end local dummy = function() end @@ -202,19 +201,12 @@ function element:internalRender() calcT = love.timer.getTime() end - local status, err = pcall(self.renderer) + self.renderer() if self.settings.testRenderPasses > 0 and selfRenderTime 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 - if helium.conf.HARD_ERROR then - error(status) - end - self:errorRender(status) - end end local draw = love.graphics.draw @@ -242,9 +234,13 @@ function element:externalRender() if self.settings.needsRendering then if self.settings.hasCanvas then setCanvas(self.canvas) - love.graphics.clear(0,0,0,0) + --need scissors + --love.graphics.clear(0,0,0,0) love.graphics.push('all') love.graphics.origin() + local ox, oy = self.quad:getViewport() + + love.graphics.translate(ox, oy) self:renderWrapper() self.settings.needsRendering = false diff --git a/core/input.lua b/core/input.lua index 324e4d3..f94df45 100644 --- a/core/input.lua +++ b/core/input.lua @@ -37,6 +37,13 @@ end local activeWindow local windowStack = {} +function input.unload() + windowStack = {} + activeWindow = nil + windowMachine = {} + input.subscriptions = {} +end + local dummyfunc = function() end ---@class subscription local subscription = {} diff --git a/init.lua b/init.lua index 4d99312..2eff6b7 100644 --- a/init.lua +++ b/init.lua @@ -10,6 +10,7 @@ helium.utils = require(path..".utils") helium.element = require(path..".core.element") helium.input = require(path..".core.input") helium.loader = require(path..".loader") +helium.atlas = require(path..".core.atlas") helium.elementBuffer = {} helium.__index = helium @@ -26,7 +27,18 @@ end}) local first = true local skip = true -function helium.render() + +function helium.load() + helium.atlas.load() +end + +function helium.unload() + helium.atlas.unassignAll() + helium.elementBuffer = {} +end + + +function helium.draw() if first and not skip then --love.graphics.setScissor(500, 500, 1, 1) @@ -86,7 +98,7 @@ end ]] if helium.conf.AUTO_RUN then function love.run() - if love.load then love.load(love.arg.parseGameArguments(arg), arg) end + if love.load then love.load() end--love.arg.parseGameArguments(arg), arg) end -- We don't want the first frame's dt to include time taken by love.load. if love.timer then love.timer.step() end @@ -128,7 +140,7 @@ if helium.conf.AUTO_RUN then if love.draw then love.draw() end st = love.timer.getTime() - helium.render() + helium.draw() heliumTime=heliumTime+love.timer.getTime()-st love.graphics.present()