This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
EveryOS's profile picture

My window API is laggy

Started by EveryOS, 24 June 2016 - 06:49 PM
EveryOS #1
Posted 24 June 2016 - 08:49 PM
I have the following code:
Code

local tHex = {
  ['0'] = colors.white,
  ['1'] = colors.orange,
  ['2'] = colors.magenta,
  ['3'] = colors.lightBlue,
  ['4'] = colors.yellow,
  ['5'] = colors.lime,
  ['6'] = colors.pink,
  ['7'] = colors.gray,
  ['8'] = colors.lightGray,
  ['9'] = colors.cyan,
  ['a'] = colors.purple,
  ['b'] = colors.blue,
  ['c'] = colors.brown,
  ['d'] = colors.green,
  ['e'] = colors.red,
  ['f'] = colors.black,
}
function create( parent, mx, my, l, h, color)
  if parent == term then
   parent = term.current()
  end
  mx = mx-1
  local e = {parent.getSize()}
  if l+mx > e[1] then
	l = e[1]-mx+1
  end
  if h+my > e[2] then
	h = e[2]-my+1
  end
  e = nil
  local parent = parent
  local focusedLine = h
  local x, y = 2, 1
  local Cx, Cy = mx, my-1
  local tc, bgc = colors.white, colors.black
  local c = color and term.isColor()
  local bgcl, tcl, t = {}, {}, {}
  local blinking, visible = false,true
  blit = function(text, myTc, myBgc)
   for i = 0, #text do
	  local char=string.sub(text,i,i)
	  if char == '\n' then
		y = y+1
		if y>h then
		  y = h
		  focusedLine = focusedLine+1
		  if not t[y+focusedLine] then
			t[y+focusedLine] = {}
			bgcl[y+focusedLine] = {}
			tcl[y+focusedLine] = {}
			for i2 = 1, l do
			  t[y+focusedLine][i2] = ' '
			  bgcl[y+focusedLine][i2] = bgc
			  tcl[y+focusedLine][i2]=tc
			end
		  end
		end
		x = 1
	  else
		if char ~= '' then
		  tcl[y+focusedLine][x-1] = tHex[string.sub(myTc, i, i)]
		  bgcl[y+focusedLine][x-1] = tHex[string.sub(myBgc, i, i)]
		  t[y+focusedLine][x-1] = char
		  x = x+1
		end
	  end
	end
	if visible then update() end
  end
  local hex = function(color)
	local val = "e"
	for k, v in pairs(tHex) do
	  if v == color then val = k end
	end
	return val
  end
  update = function()
	parent.setCursorBlink(false)
	for i = 1, h do
	  local text = ""
	  local textc = ""
	  local textbg = ""
	  for i2 = 1, l do
		textc = textc..hex(tcl[i+focusedLine][i2] or tc)
		textbg = textbg..hex(bgcl[i+focusedLine][i2] or bgc)
		if t[i+focusedLine][i2] == '' then
		 t[i+focusedLine][i2] = " "
		end
		text = text..(t[i+focusedLine][i2] or " ")
	  end
	  parent.setCursorPos(Cx+1, Cy +i)
	  parent.blit(text, textc, textbg)
	end
	parent.setCursorPos(x-1, y)
	parent.setCursorBlink(blinking)
  end
  for i = 1, h+focusedLine do
	t[i] = {}
	bgcl[i] = {}
	tcl[i] = {}
	for i2 = 1,l do
	  t[i][i2]=' '
	  bgcl[i][i2]=bgc
	  tcl[i][i2]=tc
	end
  end
  local invalidC = function()
	if not c then
	  printError('Exception reached at NyanOS.luac.term')
	  os.pullEvent('mouse_click')
	  os.reboot()
	end
  end
  local function colorStatus()
	return c
  end
  return {
	term.native,
	term.current,
	isColor = colorStatus,
	isColour = colorStatus,
	getSize = function()
	  return l, h
	end,
	getCursorPos = function()
	  return x, y
	end,
	getBackgroundColour = function()
	  return bgc
	end,
	getBackgroundColor = function()
	  return bgc
	end,
	getTextColour = function()
	  return tc
	end,
	getTextColor = function()
	  return tc
	end,
	write = function(text)
	  text  = tostring(text)
	  if (not text) or text == '' then
		return
	  end
	  blit(
		text,
		hex(tc):rep(#text),
		hex(bgc):rep(#text)
	  )
	end,
	setCursorPos = function(cx, cy)
	  x = cx+1
	  y = cy
	  if visible then update() end
	end,
	setTextColor = function(k)
	  tc = k
	  invalidC()
	end,
	setBackgroundColor = function(k)
	   bgc = k
	   invalidC()
	end,
	 setTextColour = function(k)
	   tc = k
	   invalidC()
	end,
	setBackgroundColour = function(k)
	   bgc = k
	   invalidC()
	end,
	scroll = function(scr)
	  focusedLine = focusedLine+scr
	  for i2 = 0, focusedLine+h do
		if not t[i2+h] then
		 t[y+i2] = {}
		 bgcl[y+i2] = {}
		 tcl[y+i2] = {}
		 for i = 1, l do
		 t[h+i2][i]=' '
		 bgcl[h+i2][i]=bgc
		 tcl[h+i2][i]=tc
		 end
	   end
	 end
	  if visible then update() end
	end,
	clear = function(color)
	  for i = 1, #t do
		t[i] = {}
		bgcl[i] = {}
		tcl[i] = {}
		for i2 = 1,l do
		  t[i][i2]=' '
		  bgcl[i][i2]=color or bgc
		  tcl[i][i2]=tc
		end
	  end
	  if visible then update() end
	end,
	clearLine = function(myY, color)
	  if not myY then
	   myY = y
	  end
	  y = myY
	  t[y+focusedLine] = {}
	  bgcl[y+focusedLine] = {}
	  tcl[y+focusedLine] = {}
	  for i = 1, l do
		t[y+focusedLine][i]=' '
		bgcl[y+focusedLine][i]=color or bgc
		tcl[y+focusedLine][i]=tc
	  end
	  if visible then update() end
	end,
	setCursorBlink = function(bool)
	  blinking = bool
	  if visible then update() end
	end,
	setVisible = function(bool)
	  visible = bool
	  if bool then
	   update()
	  else
	   parent.setCursorBlink(false)
	  end
	end,
	blit = blit,
  }
end
local l, h = term.getSize()
M = create(term.native(), 1, 1, l, h, true)
term.redirect(M)
shell.run('rom/programs/shell')


It is very laggy when I run it with a repetitive function such as write.
As you can see, I removed all original os.pullEvent and coroutine.yield s in attempt to reduce lag.
Why does it lag and how do I fix it?
Edited on 24 June 2016 - 06:53 PM
Bomb Bloke #2
Posted 26 June 2016 - 07:59 AM
The most glaring issue is that any time anything is written to your buffer, you redraw the whole thing onto the screen - not just the bit that needs to be updated. You'd be better off rigging the blit function to do its own drawing if the window is "visible".

In the update function, it'd be faster to make use of table.concat() to merge line contents in a single go, rather than concatenating over and over again within a loop.

In your blit function, you've got a loop starting from 0 when it should start from 1. The regular blit function doesn't handle line breaks, either - nothing in the term API does. At some point you'll also have to think about what to do if the cursor is ever out of bounds.
EveryOS #3
Posted 07 July 2016 - 08:18 PM
thx