From 5fa756996028fc7ce6be943f3e47c10231dbed0d Mon Sep 17 00:00:00 2001
From: ubq323 <ubq323@ubq323.website>
Date: Sat, 6 Aug 2022 22:56:33 +0100
Subject: img

---
 img/better_disp.dat |   1 +
 img/better_disp.lua | 121 ++++++++++++++++++++++++++++++++++++++++++++++------
 img/disp_common.lua | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++
 img/driver.dat      |   2 +-
 img/shitty_disp.dat |   1 +
 img/shitty_disp.lua | 116 ++-----------------------------------------------
 6 files changed, 233 insertions(+), 127 deletions(-)
 create mode 100644 img/better_disp.dat
 create mode 100644 img/disp_common.lua
 create mode 100644 img/shitty_disp.dat

(limited to 'img')

diff --git a/img/better_disp.dat b/img/better_disp.dat
new file mode 100644
index 0000000..797cd18
--- /dev/null
+++ b/img/better_disp.dat
@@ -0,0 +1 @@
+dep img/disp_common
diff --git a/img/better_disp.lua b/img/better_disp.lua
index d7b59c1..1d36f7a 100644
--- a/img/better_disp.lua
+++ b/img/better_disp.lua
@@ -1,3 +1,5 @@
+local disp_common = require("disp_common")
+
 -- a vlorb consists of six gromlings[A
 -- 1  2
 -- 4  8
@@ -22,10 +24,102 @@ local function vlorb(onc,offc, g1,g2,g3,g4,g5,g6)
 	return textc,bgc,string.char(vlorbchar)
 end
 
-local function should_be_on(col)
-	return col[1]+col[2]+col[3] > 1.5
+local function all_palette_distances(R)
+	local out = {}
+	for a=0,15 do
+		for b = 0,15 do
+			local ia=2^a
+			local ib=2^b
+			local ca = R.getPaletteColor(ia)
+			local cb = R.getPaletteColor(ib)
+			local dist = disp_common.color_dist(ca,cb)
+			out[ia][ib] = dist
+		end
+	end
+	return out
+end
+
+local function list_contains(list,val)
+	for _,v in ipairs(list) do
+		if v == val then return true end
+	end
+	return false
 end
 
+-- R, lPx_gromlings, l_pdists  -> lCx_gromlings
+local function adjust_to_2_colors(R,gromlings,pdists)
+	-- gromlings goes 1 2 3 4 5 6
+	-- compress the 6 pixels to just 2 colors
+	-- return the list of cidxs
+	local gromling_colors = {}
+	for i,c in ipairs(gromlings) do
+		gromling_colors[i] = disp_common.closest_palette_color(R,c)
+	end
+
+	local all_current_colors = {}
+	local ncolors = 0
+	for _,cidx in ipairs(gromling_colors) do
+		all_current_colors[cidx] = true
+		ncolors = ncolors+1
+	end
+	
+	while ncolors > 2 do
+		-- merge closest two colors until there are only 2 distinct ones left
+		local best_dist = 9999
+		local best_a = nil
+		local best_b = nil
+		for a in pairs(all_current_colors) do
+			for b in pairs(all_current_colors) do
+				if a ~= b then
+					local dist = pdists[a][b]
+					if dist < best_dist then
+						best_dist = dist
+						best_a = a
+						best_b = b
+					end
+				end
+			end
+		end
+
+		-- todo: be cleverer when deciding whether to merge a into b, or b into a
+		-- currently just merge b into a
+		assert(best_a and best_b and best_a ~= best_b)
+		all_current_colors[best_b] = false
+		ncolors=ncolors-1
+		for gidx,col in ipairs(gromling_colors) do
+			if col == best_b then gromling_colors[gidx] = best_a end
+		end
+	end
+
+	return gromling_colors
+end
+
+local function gromling_list_to_vlorb(gromling_colors)
+	-- takes list of cidxs 
+	local ca = nil
+	local cb = nil
+	local gs = {}
+	for i,col in ipairs(gromling_colors) do
+		if col == ca then
+			gs[i] = true
+		elseif col == cb then
+			gs[i] = false
+		else
+			if not ca then
+				ca = col
+				gs[i] = true
+			elseif not cb then
+				cb = col
+				gs[i] = false
+			else
+				error("third gromling color in vlorb")
+			end
+		end
+	end
+	return ca,cb,table.unpack(gs)
+end
+	
+
 -- todo: refactor common stuff into a common file
 local function disp(R,img,scrx,scry,w,h,imgx,imgy)
 	-- w and h are image coords
@@ -36,6 +130,9 @@ local function disp(R,img,scrx,scry,w,h,imgx,imgy)
 	imgx = imgx or 1
 	imgy = imgy or 1
 
+	disp_common.improve_palette(R,img,w,h,imgx,imgy)
+	local pdists=all_palette_distances(R)
+
 	local sw = math.ceil(w/2)
 	local sh = math.ceil(h/3)
 
@@ -44,23 +141,21 @@ local function disp(R,img,scrx,scry,w,h,imgx,imgy)
 			local ioffx=soffx*2
 			local ioffy=soffy*3
 			R.setCursorPos(scrx+soffx,scry+soffy)
-			local gs = {}
+			local lPx_gromlings = {}
 			for goffy=0,2 do
 				for goffx=0,1 do
-					local ic = img[imgy+ioffy+goffy][imgx+ioffx+goffx] or {0,0,0}
-					table.insert(gs,should_be_on(ic))
+					local px = img[imgy+ioffy+goffy][imgx+ioffx+goffx] or {0,0,0}
+					table.insert(lPx_gromlings,px)
 				end
 			end
-			local tc,bc,ch = vlorb(colors.white,colors.black,table.unpack(gs))
-			R.setTextColor(tc)
-			R.setBackgroundColor(bc)
-			R.write(ch)
+
+			local lCx_gromlings = adjust_to_2_colors(lPx_gromlings)
+			local textc,bgc,vlorbchar = vlorb(gromling_list_to_vlorb(lCx_gromlings))
+			R.setTextColor(textc)
+			R.setBackgroundColor(bgc)
+			R.write(vlorbchar)
 		end
 	end
 end
 
-
-	
-	
-
 return {vlorb=vlorb,disp=disp}
diff --git a/img/disp_common.lua b/img/disp_common.lua
new file mode 100644
index 0000000..5c46b94
--- /dev/null
+++ b/img/disp_common.lua
@@ -0,0 +1,119 @@
+local function color_dist(c1,c2)
+	local total = 0
+	for i=1,3 do total = total + (c1[i]-c2[i])^2 end
+	return total
+end
+
+local function closest_palette_color(R,c)
+	local closest = nil
+	local closest_dist = 99999999
+	for i=0,15 do
+		local pc = {R.getPaletteColor(2^i)}
+		local dist = color_dist(pc,c)
+		if dist < closest_dist then
+			closest = 2^i
+			closest_dist = dist 
+		end
+	end
+	return closest
+end
+
+local function average_color(pxlist)
+	local count = #pxlist
+	local tr,tg,tb = 0,0,0
+	for _,px in ipairs(pxlist) do
+		tr = tr + px[1]
+		tg = tg + px[2]
+		tb = tb + px[3]
+	end
+	return {tr/count,tg/count,tb/count}
+end
+
+local function sortby_r(pxlist) table.sort(pxlist,function(a,b) return a[1]<b[1] end) end
+local function sortby_g(pxlist) table.sort(pxlist,function(a,b) return a[2]<b[2] end) end
+local function sortby_b(pxlist) table.sort(pxlist,function(a,b) return a[3]<b[3] end) end
+
+local function median_cut(pxlist,remaining)
+	remaining = remaining or 4
+	if remaining <= 0 then
+		return {average_color(pxlist)}
+	end
+	local maxr,maxg,maxb = -1,-1,-1
+	local minr,ming,minb = 999,999,999
+	local max,min = math.max,math.min
+	for _,px in ipairs(pxlist) do
+		maxr = max(maxr,px[1])
+		maxg = max(maxg,px[2])
+		maxb = max(maxb,px[3])
+		minr = min(minr,px[1])
+		ming = min(ming,px[2])
+		minb = min(minb,px[3])
+	end
+	local ranger,rangeg,rangeb = maxr-minr,maxg-ming,maxb-minb
+	if ranger > rangeg then
+		if ranger > rangeb then
+			-- red
+			sortby_r(pxlist)
+		else
+			-- blue
+			sortby_b(pxlist)
+		end
+	else
+		if rangeg > rangeb then
+			-- green
+			sortby_g(pxlist)
+		else
+			-- blue
+			sortby_b(pxlist)
+		end
+	end
+	local count = #pxlist
+	local hcount = math.floor(count/2)
+
+	local lhalf,uhalf = {},{}
+	for i=1,hcount do
+		lhalf[i] = pxlist[i]
+	end
+	for i=hcount+1,count do
+		uhalf[i-hcount] = pxlist[i]
+	end
+	
+	local lcols = median_cut(lhalf,remaining-1)
+	local ucols = median_cut(uhalf,remaining-1)
+
+	for i=1,#ucols do table.insert(lcols,ucols[i]) end
+	return lcols
+end
+
+local function reset_palette(R)
+	for i=0,15 do
+		local cx = 2^i
+		R.setPaletteColor(cx,term.nativePaletteColor(cx))
+	end
+end
+
+local function improve_palette(R,img,w,h,imgx,imgy)
+	local pxlist = {}
+	local idx=1
+	for px=imgx,imgx+w-1 do
+		for py=imgy,imgy+h-1 do
+			pxlist[idx] = img[py][px]
+			idx = idx + 1
+		end
+	end
+	local palette = median_cut(pxlist)
+	assert(#palette==16,#palette.." doesn't equal 16")
+	for i=0,15 do
+		local pc = palette[i+1]
+		R.setPaletteColor(2^i,table.unpack(pc))
+	end
+end
+	
+return {
+	color_dist=color_dist,
+	closest_palette_color=closest_palette_color,
+	average_color=average_color,
+	median_cut=median_cut,
+	reset_palette=reset_palette,
+	improve_palette=improve_palette,
+}
diff --git a/img/driver.dat b/img/driver.dat
index d1e4787..27e1798 100644
--- a/img/driver.dat
+++ b/img/driver.dat
@@ -1,2 +1,2 @@
-dep util img/shitty_disp img/load_pnm
+dep util img/shitty_disp img/load_pnm img/better_disp
 file img/driver.lua img/walter.pnm
diff --git a/img/shitty_disp.dat b/img/shitty_disp.dat
new file mode 100644
index 0000000..797cd18
--- /dev/null
+++ b/img/shitty_disp.dat
@@ -0,0 +1 @@
+dep img/disp_common
diff --git a/img/shitty_disp.lua b/img/shitty_disp.lua
index 8bd1b61..ea9681b 100644
--- a/img/shitty_disp.lua
+++ b/img/shitty_disp.lua
@@ -1,116 +1,6 @@
 -- bad displayment thing
-
-local function color_dist(c1,c2)
-	local total = 0
-	for i=1,3 do total = total + (c1[i]-c2[i])^2 end
-	return total
-end
-
-local function closest_palette_color(R,c)
-	local closest = nil
-	local closest_dist = 99999999
-	for i=0,15 do
-		local pc = {R.getPaletteColor(2^i)}
-		local dist = color_dist(pc,c)
-		if dist < closest_dist then
-			closest = 2^i
-			closest_dist = dist 
-		end
-	end
-	return closest
-end
-
-local function average_color(pxlist)
-	local count = #pxlist
-	local tr,tg,tb = 0,0,0
-	for _,px in ipairs(pxlist) do
-		tr = tr + px[1]
-		tg = tg + px[2]
-		tb = tb + px[3]
-	end
-	return {tr/count,tg/count,tb/count}
-end
-
-local function sortby_r(pxlist) table.sort(pxlist,function(a,b) return a[1]<b[1] end) end
-local function sortby_g(pxlist) table.sort(pxlist,function(a,b) return a[2]<b[2] end) end
-local function sortby_b(pxlist) table.sort(pxlist,function(a,b) return a[3]<b[3] end) end
-
-local function median_cut(pxlist,remaining)
-	remaining = remaining or 4
-	if remaining <= 0 then
-		return {average_color(pxlist)}
-	end
-	local maxr,maxg,maxb = -1,-1,-1
-	local minr,ming,minb = 999,999,999
-	local max,min = math.max,math.min
-	for _,px in ipairs(pxlist) do
-		maxr = max(maxr,px[1])
-		maxg = max(maxg,px[2])
-		maxb = max(maxb,px[3])
-		minr = min(minr,px[1])
-		ming = min(ming,px[2])
-		minb = min(minb,px[3])
-	end
-	local ranger,rangeg,rangeb = maxr-minr,maxg-ming,maxb-minb
-	if ranger > rangeg then
-		if ranger > rangeb then
-			-- red
-			sortby_r(pxlist)
-		else
-			-- blue
-			sortby_b(pxlist)
-		end
-	else
-		if rangeg > rangeb then
-			-- green
-			sortby_g(pxlist)
-		else
-			-- blue
-			sortby_b(pxlist)
-		end
-	end
-	local count = #pxlist
-	local hcount = math.floor(count/2)
-
-	local lhalf,uhalf = {},{}
-	for i=1,hcount do
-		lhalf[i] = pxlist[i]
-	end
-	for i=hcount+1,count do
-		uhalf[i-hcount] = pxlist[i]
-	end
-	
-	local lcols = median_cut(lhalf,remaining-1)
-	local ucols = median_cut(uhalf,remaining-1)
-
-	for i=1,#ucols do table.insert(lcols,ucols[i]) end
-	return lcols
-end
-
-local function reset_palette(R)
-	for i=0,15 do
-		local cx = 2^i
-		R.setPaletteColor(cx,term.nativePaletteColor(cx))
-	end
-end
-
-local function improve_palette(R,img,w,h,imgx,imgy)
-	local pxlist = {}
-	local idx=1
-	for px=imgx,imgx+w-1 do
-		for py=imgy,imgy+h-1 do
-			pxlist[idx] = img[py][px]
-			idx = idx + 1
-		end
-	end
-	local palette = median_cut(pxlist)
-	assert(#palette==16,#palette.." doesn't equal 16")
-	for i=0,15 do
-		local pc = palette[i+1]
-		R.setPaletteColor(2^i,table.unpack(pc))
-	end
-end
-	
+local disp_common = require("disp_common")
+local improve_palette,closest_palette_color = disp_common.improve_palette,disp_common.closest_palette_color
 
 
 local function disp(R,img,scrx,scry,w,h,imgx,imgy)
@@ -134,4 +24,4 @@ local function disp(R,img,scrx,scry,w,h,imgx,imgy)
 	end
 end
 
-return {disp=disp,color_dist=color_dist,closest_palette_color=closest_palette_color,reset_palette=reset_palette}
+return {disp=disp}
-- 
cgit v1.2.3