diff --git a/builtin/voxelworld/client_lua/module.lua b/builtin/voxelworld/client_lua/module.lua index 9ab7cd6..b1115b1 100644 --- a/builtin/voxelworld/client_lua/module.lua +++ b/builtin/voxelworld/client_lua/module.lua @@ -27,219 +27,6 @@ M.chunk_size_voxels = nil M.section_size_chunks = nil M.section_size_voxels = nil ---[[ - table.binsearch( table, value [, compval [, reversed] ] ) - - Searches the table through BinarySearch for the given value. - If the value is found: - it returns a table holding all the mathing indices (e.g. { startindice,endindice } ) - endindice may be the same as startindice if only one matching indice was found - If compval is given: - then it must be a function that takes one value and returns a second value2, - to be compared with the input value, e.g.: - compvalue = function( value ) return value[1] end - If reversed is set to true: - then the search assumes that the table is sorted in reverse order (largest value at position 1) - note when reversed is given compval must be given as well, it can be nil/_ in this case - Return value: - on success: a table holding matching indices (e.g. { startindice,endindice } ) - on failure: nil -]]-- -do - -- Avoid heap allocs for performance - local default_fcompval = function(value) return value end - local fcompf = function(a,b) return a < b end - local fcompr = function(a,b) return a > b end - function table_binsearch(t,value,fcompval,reversed) - -- Initialise functions - local fcompval = fcompval or default_fcompval - local fcomp = reversed and fcompr or fcompf - -- Initialise numbers - local iStart,iEnd,iMid = 1,#t,0 - -- Binary Search - while iStart <= iEnd do - -- calculate middle - iMid = math.floor((iStart+iEnd)/2) - -- get compare value - local value2 = fcompval(t[iMid]) - -- get all values that match - if value == value2 then - local tfound,num = {iMid,iMid},iMid - 1 - while value == fcompval(t[num]) do - tfound[1],num = num,num - 1 - end - num = iMid + 1 - while value == fcompval(t[num]) do - tfound[2],num = num,num + 1 - end - return tfound - -- keep searching - elseif fcomp(value, value2) then - iEnd = iMid - 1 - else - iStart = iMid + 1 - end - end - end -end - ---[[ - table.bininsert( table, value [, comp] ) - - Inserts a given value through BinaryInsert into the table sorted by [, comp]. - - If 'comp' is given, then it must be a function that receives - two table elements, and returns true when the first is less - than the second, e.g. comp = function(a, b) return a > b end, - will give a sorted table, with the biggest value on position 1. - [, comp] behaves as in table.sort(table, value [, comp]) - returns the index where 'value' was inserted -]]-- -do - -- Avoid heap allocs for performance - local fcomp_default = function(a,b) return a < b end - function table_bininsert(t, value, fcomp) - -- Initialise compare function - local fcomp = fcomp or fcomp_default - -- Initialise numbers - local iStart,iEnd,iMid,iState = 1,#t,1,0 - -- Get insert position - while iStart <= iEnd do - -- calculate middle - iMid = math.floor((iStart+iEnd)/2) - -- compare - if fcomp(value, t[iMid]) then - iEnd,iState = iMid - 1,0 - else - iStart,iState = iMid + 1,1 - end - end - table.insert(t,(iMid+iState),value) - return (iMid+iState) - end -end - -local function SpatialUpdateQueue() - local function fcomp(a, b) - -- Always maintain all f<=1.0 items at the end of the table - if a.f > 1.0 and b.f <= 1.0 then - return true - end - if a.f <= 1.0 and b.f > 1.0 then - return false - end - return a.fw > b.fw - end - local self = { - p = buildat.Vector3(0, 0, 0), - queue_oldest_p = buildat.Vector3(0, 0, 0), - queue = {}, - old_queue = nil, - - -- This has to be called once per frame or so - update = function(self, max_operations) - max_operations = max_operations or 100 - if self.old_queue then - log:debug("SpatialUpdateQueue(): Items in old queue: ".. - #self.old_queue) - -- Move stuff from old queue to new queue - for i = 1, max_operations do - local item = table.remove(self.old_queue) - if not item then - self.old_queue = nil - break - end - self:put_item(item) - end - end - end, - set_p = function(self, p) - p = buildat.Vector3(p) -- Strip out the heavy Urho3D wrapper - self.p = p - if self.old_queue == nil and - (p - self.queue_oldest_p):length() > 20 then - -- Move queue to old_queue and reset queue - self.old_queue = self.queue - self.queue = {} - self.queue_oldest_p = self.p - end - end, - put_item = function(self, item) - local d = (item.p - self.p):length() - item.f = nil - item.fw = nil - if item.near_trigger_d then - local f_near = d / item.near_trigger_d - local fw_near = f_near / item.near_weight - if item.fw == nil or (fw_near < item.fw and - (item.f == nil or f_near < item.f)) then - item.f = f_near - item.fw = fw_near - end - end - if item.far_trigger_d then - local f_far = item.far_trigger_d / d - local fw_far = f_far / item.far_weight - if item.fw == nil or (fw_far < item.fw and - (item.f == nil or f_far < item.f)) then - item.f = f_far - item.fw = fw_far - end - end - assert(item.f) - assert(item.fw) - log:verbose("put_item".. - ": d="..dump(d).. - ", near_weight="..dump(item.near_weight).. - ", near_trigger_d="..dump(item.near_trigger_d).. - ", far_weight="..dump(item.far_weight).. - ", far_trigger_d="..dump(item.far_trigger_d).. - " -> f="..item.f..", fw="..item.fw) - table_bininsert(self.queue, item, fcomp) - end, - -- Put something to be prioritized bidirectionally - put = function(self, p, near_weight, near_trigger_d, - far_weight, far_trigger_d, value) - if near_trigger_d and far_trigger_d then - assert(near_trigger_d < far_trigger_d) - assert(near_weight) - assert(far_weight) - else - assert((near_trigger_d and near_weight) or - (far_trigger_d and far_weight)) - end - p = buildat.Vector3(p) -- Strip out the heavy Urho3D wrapper - self:put_item({p=p, value=value, - near_weight=near_weight, near_trigger_d=near_trigger_d, - far_weight=far_weight, far_trigger_d=far_trigger_d}) - end, - get = function(self) - local item = table.remove(self.queue) - if not item then return nil end - return item.value - end, - -- item.f is the trigger_d value normalized so that f<1.0 means the item - -- has passed its trigger_d. - peek_next_f = function(self) - local item = self.queue[#self.queue] - if not item then return nil end - return item.f - end, - -- item.fw is a comparison value; both near_priority and far_priority - -- items are normalized so that values that have fw=1 have equal - -- priority. - peek_next_fw = function(self) - local item = self.queue[#self.queue] - if not item then return nil end - return item.fw - end, - get_length = function(self) - return #self.queue - end, - } - return self -end - function M.init() log:info("voxelworld.init()") @@ -367,7 +154,7 @@ function M.init() node_update_queue:set_p(camera_p) -- Scale queue update operations according to the handling time of the -- rest of the processing - node_update_queue:update(max_handling_time_us / 200 + 1) + node_update_queue:update(max_handling_time_us / 50 + 1) for i = 1, 10 do -- Usually there is time only for a few local f = node_update_queue:peek_next_f()