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

Text and Colour Image Format

Started by oeed, 07 March 2013 - 06:03 PM
oeed #1
Posted 07 March 2013 - 07:03 PM
Is there an image format that, inaddition to being able to set the background colour, you can set the text and text colour? I am needing this functionality for a project and if there is such a format it would save me the time of making one :P/>
theoriginalbit #2
Posted 07 March 2013 - 07:52 PM
I have a method that NeverCast and I used in CCTube to store 2 colours, in one byte of data (best results were with 2 numbers of 65535 (which is 2 bytes each, 4 bytes of data total, still went to 1 byte of data) … but obviously it doesn't support text too. it was just colours in 1 byte.
oeed #3
Posted 07 March 2013 - 08:23 PM
I was thinking of something along the lines of that. I could have two bytes per pixel I guess, but I don't know of a way to fit all three in a byte.
theoriginalbit #4
Posted 07 March 2013 - 08:34 PM
It would just have to be. 2 colours cant go any lower than 1 byte, then ASCII is one byte. so yeh 2 bytes per pixel is really all u could do id say.

if you want the code we did for the colours, just ask, less for you to do :P/>
Mads #5
Posted 07 March 2013 - 09:05 PM
You can just create one. Very simple, just store a table with all of the data.
Exerro #6
Posted 08 March 2013 - 10:10 AM
I made this already, if I understand what you mean…an image format that supports text and text colour as well as background colour. Would you like me to release it?
oeed #7
Posted 08 March 2013 - 11:09 AM
I made this already, if I understand what you mean…an image format that supports text and text colour as well as background colour. Would you like me to release it?

Yes, that would be great.
Sammich Lord #8
Posted 08 March 2013 - 12:53 PM
Your could do it pretty easily actually. You can have 1 char for each var:

abo
So that would be on pixel. Then 'a' would be the text on the pixel, 'b' would be the color and 'o' would be the background. Then just have the view take the 3 chars and have each of them mean something. So like, 'b' would be black, 'a' would be green, etc.
oeed #9
Posted 08 March 2013 - 01:34 PM
Your could do it pretty easily actually. You can have 1 char for each var:

abo
So that would be on pixel. Then 'a' would be the text on the pixel, 'b' would be the color and 'o' would be the background. Then just have the view take the 3 chars and have each of them mean something. So like, 'b' would be black, 'a' would be green, etc.

That would be the easiest way, but in terms of efficient storage its not the best.
Pharap #10
Posted 08 March 2013 - 01:50 PM
I'd like to see the different proposals for an image format as I have a 2D texture renderer with a runtime format but no storage format yet, so it'd be interesting making a loader/unloader for the textures.
oeed #11
Posted 08 March 2013 - 02:42 PM
If I don't find a suitable one in the next few days, I'll probably just make one, it won't be too hard.
tesla1889 #12
Posted 08 March 2013 - 03:16 PM
wouldn't a markup language be more efficient?

<b=f><t=0>some white text with black background</t><t=9>some cyan text with black background</t></b><b=0><t=f>some black text with white background</t></b>
or something like that?
Pharap #13
Posted 08 March 2013 - 03:45 PM
wouldn't a markup language be more efficient?

<b=f><t=0>some white text with black background</t><t=9>some cyan text with black background</t></b><b=0><t=f>some black text with white background</t></b>
or something like that?

Markup is good, but an xml style markup would waste space. I'd say treating it a bit more like binary would be more applicable.
That way it's 1byte to mark the start of a block, 1 byte for the background, 1 byte for the foreground and then keep reading until another one of the block starters is hit, or the end of the file, whichever comes first. Purely for the sake of saving space. The block starter would just be a generally unused ascii code eg startheader or maybe just null (/0).

The advantage of this is that you could implement a function similar to readline, but with /0 instead of CRLF. I believe /0 is already an escapable character in lua anyway so it wouldn't be hard to append. In fact you could turn the system on it's head, have an initial /0 to mark the start, then from then on every block ends in /0 and you know the first two of those bytes are the colours.

Another advantage to this beyond the 'read to null' thing is that you can easily stream the file byte by byte.
Simply, a program that reads the next byte, checks if it's a null (/0), if it isn't, writes the byte as a char, if it is, notifies itself to read the next two bytes as colour swaps before carrying on with its usual reading. This way, the file will be the size of the text it contains +3 bytes for each colour swap, which isn't too bad for a rich text format.

That's just how I'd handle a richtext format though, some people might prefer XML style for readability.
oeed #14
Posted 08 March 2013 - 04:13 PM
–snip snip–
The advantage of this is that you could implement a function similar to readline, but with /0 instead of CRLF. I believe /0 is already an escapable character in lua anyway so it wouldn't be hard to append. In fact you could turn the system on it's head, have an initial /0 to mark the start, then from then on every block ends in /0 and you know the first two of those bytes are the colours.

Another advantage to this beyond the 'read to null' thing is that you can easily stream the file byte by byte.
Simply, a program that reads the next byte, checks if it's a null (/0), if it isn't, writes the byte as a char, if it is, notifies itself to read the next two bytes as colour swaps before carrying on with its usual reading. This way, the file will be the size of the text it contains +3 bytes for each colour swap, which isn't too bad for a rich text format.

That's just how I'd handle a richtext format though, some people might prefer XML style for readability.

Rather than having it on lines, which wastes space, the idea in my head is that the image has a header that stores the width and height of the image removing the need to have lines.


wouldn't a markup language be more efficient?

<b=f><t=0>some white text with black background</t><t=9>some cyan text with black background</t></b><b=0><t=f>some black text with white background</t></b>
or something like that?

XML might be possible, however it wouldn't be as effective when there are large blocks of colours. I might look in to it though.

At this point it looks like I will just make this format myself depending on how good awsumben13's is. I'm not really aiming for readability, just use a program for that.
Pharap #15
Posted 08 March 2013 - 04:19 PM
Rather than having it on lines, which wastes space, the idea in my head is that the image has a header that stores the width and height of the image removing the need to have lines.

Now you're saying image. Is this image or richtext?
If it's an image, it makes more sense to just make the file a stream of tuples, If it's richtext the readtonull approach makes more sense.

Might as well have both and make them interchangeable. Of course the tuples thing doesn't account for if a cluster of panels share the same colour formatting, but if each panel is different, defining how long the colour lasts would introduce more data than needed, so it depends if the format is aimed at little variance or high variance.

Also it's not technically lines, the only new lines would be the ones in the text. What I mean is have a function that reads to the next /0 in the same what readline reads to the next new line character (which is usually CRLF - 10,13 if I'm not mistaken, which I might be).
nitrogenfingers #16
Posted 08 March 2013 - 06:34 PM
I designed NFT for this, though that was more designed for ASCII art rather than coloured text. It uses two control characters, 0030 and 0031 for background and text colour, with the proceeding hex character informing what the new text or background colour should be. The one benefit I guess it has is people usually don't type out 0030 and 0031 so you don't lose a character- working with the same principle used in changing the appearance of text when writing in books in Vanilla Minecraft (that weird S thing).

NPaintPro has the implementation for it's encoding, you can see it there if you're curious.
Pharap #17
Posted 09 March 2013 - 10:58 AM
I designed NFT for this, though that was more designed for ASCII art rather than coloured text. It uses two control characters, 0030 and 0031 for background and text colour, with the proceeding hex character informing what the new text or background colour should be. The one benefit I guess it has is people usually don't type out 0030 and 0031 so you don't lose a character- working with the same principle used in changing the appearance of text when writing in books in Vanilla Minecraft (that weird S thing).

NPaintPro has the implementation for it's encoding, you can see it there if you're curious.

My suggestion of null (/0) is for the same reason as 030 and 031, but null seems easier since there's the escape code for it and it can't be interpreted as a colour code since 0 is not counted as a colour. (though it suddenly occurs to me I may have made a miscalculation in my idea thinking more about how fitting 16 colours into 1 byte would work).

I see no reason why there shouldn't be several formats anyway. Sure it's best to have one as a most common, but people should be free to chose what they think works. As long as a converter or two get made at some point, everything should run smoothly.
MysticT #18
Posted 09 March 2013 - 11:30 AM
This is a library/api I made for my os:
Spoiler

-- MysticOS Image Library

-- Colors

local tColorLookup = {}
for i = 1, 16 do
	tColorLookup[string.byte("0123456789abcdef", i, i)] = 2 ^ (i - 1)
end

local function color2str(c)
	local i = math.floor(math.log(c) / math.log(2)) + 1
	if i > 0 and i <= 16 then
		return string.at("0123456789abcdef", i)
	end
	return "0"
end

local function str2color(s, i)
	return tColorLookup[string.byte(s, i or 1)] or 0
end

local function getBgColor(c)
	return 2 ^ bit.band(bit.brshift(c, 4), 0x0F)
end

local function getTxtColor(c)
	return 2 ^ bit.band(c, 0x0F)
end

local function getColorByte(bgColor, txtColor)
	bgColor = math.floor(math.log(bgColor) / math.log(2))
	txtColor = math.floor(math.log(txtColor) / math.log(2))
	return bit.bor(bit.blshift(bgColor, 4), txtColor)
end

-- Image Class

local img = {}

function img:render(target, ox, oy)
	target = target or screen
	ox = ox or 1
	oy = oy or 1
	if target.isColor and target.isColor() then
		for y = 1, self.height do
			target.setCursorPos(ox, oy + y - 1)
			local i = 1
			local txt = self.text[y]
			local sBgColor = self.bgColor[y]
			local sTxtColor = self.txtColor[y]
			while i <= self.width do
				local bgColor = str2color(sBgColor, i)
				local txtColor = str2color(sTxtColor, i)
				j = i
				i = i + 1
				while i <= self.width and bgColor == str2color(sBgColor, i) and
						txtColor == str2color(sTxtColor, i) do
					i = i + 1
				end
				target.setBackgroundColor(bgColor)
				target.setTextColor(txtColor)
				target.write(string.sub(txt, j, i - 1))
			end
		end
	else
		for y = 1, self.height do
			target.setCursorPos(ox, oy + y - 1)
			target.write(self.txt[y])
		end
	end
end

function img:draw(src, ox, oy, x, y, w, h)
	if x <= self.width and y <= self.height then
		local sx, sy = 1, 1
		if x < 1 then
			w = w + x - 1
			sx = -x + 1
			x = 1
		end
		if x + w > self.width then
			w = self.width - x
		end
		if y < 1 then
			h = h + y - 1
			sy = -y + 1
			y = 1
		end
		if y + h > self.height then
			h = self.height - y
		end
		for i = 0, h - 1 do
			self.bgColor[y+i] = string.replace(self.bgColor[y+i], x, x + w - 1, string.sub(src.bgColor[oy+sy+i], ox + sx, ox + sx + w))
			self.txtColor[y+i] = string.replace(self.txtColor[y+i], x, x + w - 1, string.sub(src.txtColor[oy+sy+i], ox + sx, ox + sx + w))
			self.text[y+i] = string.replace(self.text[y+i], x, x + w - 1, string.sub(src.text[oy+sy+i], ox + sx, ox + sx + w))
		end
	end
end

function img:write(x, y, txt)
	if x <= self.width and y > 0 and y <= self.height then
		if x < 1 then
			txt = string.sub(txt, -x + 1)
			x = 1
		end
		if x + #txt > self.width then
			txt = string.sub(txt, 1, self.width - x)
		end
		self.bgColor[y] = string.replace(self.bgColor[y], x, x + #txt - 1, string.rep(color2str(self.curBgColor), #txt))
		self.txtColor[y] = string.replace(self.txtColor[y], x, x + #txt - 1, string.rep(color2str(self.curTxtColor), #txt))
		self.text[y] = string.replace(self.text[y], x, x + #txt - 1, txt)
		return #txt
	end
	return 0
end

function img:read(x, y, len)
	if x <= self.width and y > 0 and y <= self.height then
		if x < 1 then
			w = len + x - 1
			x = 1
		end
		return string.sub(self.text[y], x, x + len)
	end
end

function img:clear()
	local sBlank = string.rep(" ", self.width)
	local sBgColor = string.rep(color2str(self.curBgColor), self.width)
	local sTxtColor = string.rep(color2str(self.curTxtColor), self.width)
	for y = 1, self.height do
		self.text[y] = sBlank
		self.bgColor[y] = sBgColor
		self.txtColor[y] = sTxtColor
	end
end

function img:clearLine(y)
	if y > 0 and y <= self.height then
		self.text[y] = string.rep(" ", self.width)
		self.bgColor[y] = string.rep(color2str(self.curBgColor), self.width)
		self.txtColor[y] = string.rep(color2str(self.curTxtColor), self.width)
	end
end

function img:getSize()
	return self.width, self.height
end

function img:getWidth()
	return self.width
end

function img:getHeight()
	return self.height
end

function img:scroll(n)
	n = n or 1
	if n > self.height then
		self:clear()
	else
		for y = 1, self.height - n do
			self.text[y] = self.text[y + n]
			self.bgColor[y] = self.bgColor[y + n]
			self.txtColor[y] = self.txtColor[y + n]
		end
		local sBlank = string.rep(" ", self.width)
		local sBgColor = string.rep(color2str(self.curBgColor), self.width)
		local sTxtColor = string.rep(color2str(self.curTxtColor), self.width)
		for y = (self.height - n) + 1, self.height do
			self.text[y] = sBlank
			self.bgColor[y] = sBgColor
			self.txtColor[y] = sTxtColor
		end
	end
end

function img:setTextColor(c, x, y)
	if x and y then
		if x > 0 and x <= self.width and y > 0 and y <= self.height then
			self.txtColor[y] = string.set(self.txtColor[y], x, color2str(c))
		end
	else
		self.curTxtColor = c
	end
end
img.setTextColour = img.setTextColor

function img:getTextColor(x, y)
	if x and y then
		if x > 0 and x <= self.width and y > 0 and y <= self.height then
			return str2color(string.at(self.txtColor[y], x))
		end
	else
		return self.curTxtColor
	end
end
img.getTextColour = img.getTextColor

function img:setBackgroundColor(c, x, y)
	if x and y then
		if x > 0 and x <= self.width and y > 0 and y <= self.height then
			self.bgColor[y] = string.set(self.bgColor[y], x, color2str(c))
		end
	else
		self.curBgColor = c
	end
end
img.setBackgroundColour = img.setBackgroundColor

function img:getBackgroundColor(x, y)
	if x and y then
		if x > 0 and x <= self.width and y > 0 and y <= self.height then
			return str2color(string.at(self.bgColor[y], x))
		end
	else
		return self.curBgColor
	end
end
img.getBackgroundColour = img.getBackgroundColor

function img:setChar(x, y, c)
	if x > 0 and x <= self.width and y > 0 and y <= self.height then
		self.text[y] = string.set(self.text[y], x, string.at(tostring(c), 1))
	end
end

function getChar(x, y)
	if x > 0 and x <= self.width and y > 0 and y <= self.height then
		return string.at(self.text[y], x)
	end
end

function img:drawChar(x, y, c)
	if x > 0 and x <= self.width and y > 0 and y <= self.height then
		self.bgColor[y] = string.set(self.bgColor[y], x, color2str(self.curBgColor))
		self.txtColor[y] = string.set(self.txtColor[y], x, color2str(self.curTxtColor))
		self.text[y] = string.set(self.text[y], x, string.at(tostring(c), 1))
	end
end

function img:resize(width, height)
	if self.width ~= width or self.height ~= height then
		local h = math.min(self.height, height)
		if width > self.width then
			local diff = width - self.width
			local sBlank = string.rep(" ", diff)
			local sTxtColor = string.rep(color2str(self.curTxtColor), diff)
			local sBackColor = string.rep(color2str(self.curBgColor), diff)
			for y = 1, h do
				self.text[y] = self.text[y]..sBlank
				self.txtColor[y] = self.txtColor[y]..sTxtColor
				self.bgColor[y] = self.bgColor[y]..sBackColor
			end
		else
			for y = 1, h do
				self.text[y] = string.sub(self.text[y], 1, width)
				self.txtColor[y] = string.sub(self.txtColor[y], 1, width)
				self.bgColor[y] = string.sub(self.bgColor[y], 1, width)
			end
		end
		if height > self.height then
			local w = math.max(self.width, width)
			local sBlank = string.rep(" ", w)
			local sTxtColor = string.rep(color2str(self.curTxtColor), w)
			local sBackColor = string.rep(color2str(self.curBgColor), w)
			for y = self.height + 1, height do
				self.text[y] = sBlank
				self.bgColor[y] = sTxtColor
				self.txtColor[y] = sBackColor
			end
		else
			for y = height + 1, self.height do
				self.text[y] = nil
				self.bgColor[y] = nil
				self.txtColor[y] = nil
			end
		end
		self.width = width
		self.height = height
	end
end

-- API

function new(w, h)
	local tImg = {}
	tImg.width = w
	tImg.height = h
	tImg.text = {}
	tImg.bgColor = {}
	tImg.txtColor = {}
	tImg.curBgColor = colors.black
	tImg.curTxtColor = colors.white
	local sBlank = string.rep(" ", w)
	local sColor = string.rep(color2str(colors.black), w)
	for y = 1, h do
		tImg.text[y] = sBlank
		tImg.bgColor[y] = sColor
		tImg.txtColor[y] = sColor
	end
	return setmetatable(tImg, { __index = img })
end

-- Save/Load functions

local function writeHeader(file, tImg)
	file.writeBytes("MIF")
	file.writeUByte(tImg.width)
	file.writeUByte(tImg.height)
	file.writeUByte(getColorByte(tImg.curBgColor, tImg.curTxtColor))
end

local function readHeader(file)
	if file.readString(3) == "MIF" then
		local w = file.readUByte()
		local h = file.readUByte()
		local curColors = file.readUByte()
		local tImg = {}
		tImg.width = w
		tImg.height = h
		tImg.text = {}
		tImg.bgColor = {}
		tImg.txtColor = {}
		tImg.curBgColor = getBgColor(curColors)
		tImg.curTxtColor = getTxtColor(curColors)
		return tImg
	end
end

local function writeImageData(file, tImg)
	for y = 1, tImg.height do
		for x = 1, tImg.width do
			local bgColor = str2color(tImg.bgColor[y], x)
			local txtColor = str2color(tImg.txtColor[y], x)
			file.writeUByte(getColorByte(bgColor, txtColor))
			file.writeChar(string.at(txt, x))
		end
	end
end

local function readImageData(file, tImg)
	for y = 1, h do
		local txt = ""
		local bgColor = ""
		local txtColor = ""
		for x = 1, w do
			local c = file.readUByte()
			bgColor = bgColor..color2str(getBgColor(c))
			txtColor = txtColor..color2str(getTxtColor(c))
			txt = txt..file.readChar()
		end
		tImg.text[y] = txt
		tImg.bgColor[y] = bgColor
		tImg.txtColor[y] = txtColor
	end
end

function img:save(path)
	local file = fs.open(path, "w")
	if file then
		writeHeader(file, self)
		writeImageData(file, self)
		return true
	end
	return false
end

function load(path)
	local file = fs.open(path, "r")
	if file then
		local tImg = readHeader(file)
		if tImg then
			readImageData(file, tImg)
			return setmetatable(tImg, { __index = img })
		end
	end
	return nil
end
I use it to draw the screen, that's why it has some functions like those in term. Also, some of the functions in the lib are from my os, so you would need to change some things or add some functions.
Anyway, the important part (for this topic) is at the end. The file format is pretty easy, it has a header containing some bytes for identification (to know the file is an image with this format) and 2 bytes for the image size (I don't think anyone will make images of more than 255x255 :P/>, but I could easily change that), then the image data is stored in 2 bytes per pixel: first byte contains text and background color, the second is the character. Knowing the width and height, it's easy to make 2 loops to read the image.
Pharap #19
Posted 09 March 2013 - 12:17 PM
I use it to draw the screen, that's why it has some functions like those in term. Also, some of the functions in the lib are from my os, so you would need to change some things or add some functions.
Anyway, the important part (for this topic) is at the end. The file format is pretty easy, it has a header containing some bytes for identification (to know the file is an image with this format) and 2 bytes for the image size (I don't think anyone will make images of more than 255x255 :P/>, but I could easily change that), then the image data is stored in 2 bytes per pixel: first byte contains text and background color, the second is the character. Knowing the width and height, it's easy to make 2 loops to read the image.
They might exceed 255 if someone makes a texture atlas.
"2 bytes per pixel: first byte contains text and background color, the second is the character."<-How do you fit two colours in 1byte whilst keeping them different?
MysticT #20
Posted 09 March 2013 - 01:54 PM
They might exceed 255 if someone makes a texture atlas.
Yeah, I think I'll change it to 2 bytes each, so you get 65535x65535 images. That should be enough.

How do you fit two colours in 1byte whilst keeping them different?
There's 16 different colors, so you only need 4 bits to store a color (2^4 = 16). To get the color from that, you just get the value of the high or low nibble (high is background color, low is text color) and do 2 ^ n (being n the value of the nibble).
So, if you have orange (value 2) as background color, and blue (value 2048) as text color, you get the byte 0x1B = 0001 1011.
And to convert it back: 2 ^ 1 = 2, 2 ^ 11 = 2048
oeed #21
Posted 09 March 2013 - 01:59 PM
Yes, that is the way I was indenting do it. However, you cant have no colour (transparent).
Pharap #22
Posted 09 March 2013 - 02:11 PM
They might exceed 255 if someone makes a texture atlas.
Yeah, I think I'll change it to 2 bytes each, so you get 65535x65535 images. That should be enough.

How do you fit two colours in 1byte whilst keeping them different?
There's 16 different colors, so you only need 4 bits to store a color (2^4 = 16). To get the color from that, you just get the value of the high or low nibble (high is background color, low is text color) and do 2 ^ n (being n the value of the nibble).
So, if you have orange (value 2) as background color, and blue (value 2048) as text color, you get the byte 0x1B = 0001 1011.
And to convert it back: 2 ^ 1 = 2, 2 ^ 11 = 2048

Derp, wasn't thinking. *note to self, go back and reread own tutorial on binary and bytes* lol
Thank god you put the binary, me and hex don't get on yet lol

I did read the 1 byte thing and realise how it would work, then I got thinking about the overall format and got carried away with the big stuff rather than looking at the little.
Obviously for splitting (probably screwed this up too, my brian has gone walkabout today):

--n is stored colour
local low = ((n<<4)>>4)
local high = (n>>4)
--using << and >> instead of the bit library because I can never remember how it works since I rarely use it

Yes, that is the way I was indenting do it. However, you cant have no colour (transparent).
Technically you can't on normal lua anyway, but for supporting it you'd need another file format.
MysticT #23
Posted 09 March 2013 - 02:19 PM
Yes, that is the way I was indenting do it. However, you cant have no colour (transparent).
True, it doesn't support it. But, what would you do in that case? I mean, it would make sense for background color, since you could use the one that's already on the screen, but what about text?

Thank god you put the binary, me and hex don't get on yet lol
I saw the tutorial, and read what you said, that's why I put it in binary too :)/>

Obviously for splitting (probably screwed this up too, my brian has gone walkabout today):

--n is stored colour
local low = ((n<<4)>>4)
local high = (n>>4)
--using << and >> instead of the bit library because I can never remember how it works since I rarely use it
For the low is easier to use a bit mask:

local low = bit.band(n, 0x0F) -- n &amp; 0x0F
theoriginalbit #24
Posted 09 March 2013 - 02:48 PM
This is a library/api I made for my os:
-spoiler snip-
I use it to draw the screen, that's why it has some functions like those in term. Also, some of the functions in the lib are from my os, so you would need to change some things or add some functions.
Anyway, the important part (for this topic) is at the end. The file format is pretty easy, it has a header containing some bytes for identification (to know the file is an image with this format) and 2 bytes for the image size (I don't think anyone will make images of more than 255x255 :P/>, but I could easily change that), then the image data is stored in 2 bytes per pixel: first byte contains text and background color, the second is the character. Knowing the width and height, it's easy to make 2 loops to read the image.
Nice I used a similar technique for the CCTube video format. Had a new encoding for chars, colours, bytes, shorts (1 nibble), large (2 bytes), point (byte containing cursor location) all in the spec, turned out quite nicely.

"2 bytes per pixel: first byte contains text and background color, the second is the character."<-How do you fit two colours in 1byte whilst keeping them different?
Did you not read the second comment? I said that I has done it that way too :P/>

This was the method I used
Spoiler


math.log2 = function(n)
  return math.log(n) / math.log(2)
end

local function compress( fg, bg )
  local low = bit.band(math.log2(bg), 0xF)
  local high = bit.band(math.log2(fg), 0xF)
  local color = bit.bor( bit.blshift(high, 4), low)
  return color
end

local function uncompress( b )
  low = bit.band(b, 0xF)
  high = bit.brshift(b, 0x4)
  return 2^high, 2^low
end
Pharap #25
Posted 09 March 2013 - 04:01 PM
Thank god you put the binary, me and hex don't get on yet lol
I saw the tutorial, and read what you said, that's why I put it in binary too :)/>

Obviously for splitting (probably screwed this up too, my brian has gone walkabout today):

--n is stored colour
local low = ((n<<4)>>4)
local high = (n>>4)
--using << and >> instead of the bit library because I can never remember how it works since I rarely use it
For the low is easier to use a bit mask:

local low = bit.band(n, 0x0F) -- n &amp; 0x0F
Glad to see my tutorial has been noticed lol.

I prefer the bit shifting thing, or at least I would have used a decimal number instead of hex. n &amp; 15 registers better in my brain lol
Main thing I have against bit is that they feel the need to shove a b in front of every function. ie what's wrong with bit.and, why does it have to be bit.band?


"2 bytes per pixel: first byte contains text and background color, the second is the character."<-How do you fit two colours in 1byte whilst keeping them different?
Did you not read the second comment? I said that I has done it that way too :P/>

This was the method I used
Spoiler


math.log2 = function(n)
  return math.log(n) / math.log(2)
end

local function compress( fg, bg )
  local low = bit.band(math.log2(bg), 0xF)
  local high = bit.band(math.log2(fg), 0xF)
  local color = bit.bor( bit.blshift(high, 4), low)
  return color
end

local function uncompress( b )
  low = bit.band(b, 0xF)
  high = bit.brshift(b, 0x4)
  return 2^high, 2^low
end
I didn't go to bed until 4:30 last night (considering I have to get up at about 6:45 on thursday and friday), plus I've been writing a 6 section report all about blender and 3D theory all day, I think my brain's allowed to flip out a bit lol

Binary I can deal with, but nobody teaches logarithms anymore, I've no clue what the hell they are lol
All I know about them is their relation to the Richter scale. I'm guessing they're something related to exponentiation, but damned if I know how.
theoriginalbit #26
Posted 09 March 2013 - 04:04 PM
Binary I can deal with, but nobody teaches logarithms anymore, I've no clue what the hell they are lol
All I know about them is their relation to the Richter scale. I'm guessing they're something related to exponentiation, but damned if I know how.
log2(m) is the reverse of 2^n
Pharap #27
Posted 09 March 2013 - 04:11 PM
Binary I can deal with, but nobody teaches logarithms anymore, I've no clue what the hell they are lol
All I know about them is their relation to the Richter scale. I'm guessing they're something related to exponentiation, but damned if I know how.
log2(m) is the reverse of 2^n
I was close at least lol
I'd guessed there was a way to do that in maths, but 3/5 of my gcse maths teachers were crap. Sadly it was the latter 3.
So I'd guess math.log(n)/math.log(16) would be the reverse of 16^n by that logic, right?
theoriginalbit #28
Posted 09 March 2013 - 04:13 PM
So I'd guess math.log(n)/math.log(16) would be the reverse of 16^n by that logic, right?
Yep… its not quite 100% tho its close. for example 2^8 is 256 … (math.log(256) / math.log(2)) is 7.999999998
Pharap #29
Posted 09 March 2013 - 04:26 PM
So I'd guess math.log(n)/math.log(16) would be the reverse of 16^n by that logic, right?
Yep… its not quite 100% tho its close. for example 2^8 is 256 … (math.log(256) / math.log(2)) is 7.999999998
Reminds me of the fastinvsqrt possible by fiddling with floats and pointers in the C-likes.
MysticT #30
Posted 10 March 2013 - 04:36 AM
Main thing I have against bit is that they feel the need to shove a b in front of every function. ie what's wrong with bit.and, why does it have to be bit.band?
I thought the same the first time I saw it, but when I was writing my own bit api I realized that the reason is that "and" and "or" are reserved keywords, so you can't make a function with those names (well, you could inside the table, but you would need to call it like bit["and"], instead of bit.and). I guess they added the b in front of those, and to be consistent they did the same to the rest of the functions :P/>
nitrogenfingers #31
Posted 10 March 2013 - 04:53 AM
My suggestion of null (/0) is for the same reason as 030 and 031, but null seems easier since there's the escape code for it and it can't be interpreted as a colour code since 0 is not counted as a colour. (though it suddenly occurs to me I may have made a miscalculation in my idea thinking more about how fitting 16 colours into 1 byte would work).

I see no reason why there shouldn't be several formats anyway. Sure it's best to have one as a most common, but people should be free to chose what they think works. As long as a converter or two get made at some point, everything should run smoothly.

Yeah, I was concerned about compatability with other characters and documents-I chose those two characters because they mean literally nothing to anyone in a document, where characters like \0 can mean specific things like the end of a string or a file.
Pharap #32
Posted 10 March 2013 - 09:19 AM
Main thing I have against bit is that they feel the need to shove a b in front of every function. ie what's wrong with bit.and, why does it have to be bit.band?
I thought the same the first time I saw it, but when I was writing my own bit api I realized that the reason is that "and" and "or" are reserved keywords, so you can't make a function with those names (well, you could inside the table, but you would need to call it like bit["and"], instead of bit.and). I guess they added the b in front of those, and to be consistent they did the same to the rest of the functions :P/>
This is one of the things I have against the lowerThenUpper style. If every public value,function and table were capitalised like so: Bit.And (like is the norm in C#) then you could get away with things like Bit.And since and is the keyword, not And. Sure &amp;&amp; or at least &amp; would be a better idea (especially since you could have an optional short-circuit) but it's too late in the game for the creators to go changing things like that, and I'm pretty sure peripherals don't have access to the LVM so you couldn't make a peripheral to do it.
It's times like this I'm thankful for languages that use symbols more than reserved keywords.
Not saying lua's a bad language ofc, capitalising gets around the keyword issue.

Yeah, I was concerned about compatability with other characters and documents-I chose those two characters because they mean literally nothing to anyone in a document, where characters like \0 can mean specific things like the end of a string or a file.

Technically they are the unit separator and record separator, but few people ever know what the non-visible ascii chars are.
I thought it was only C that forced strings to end with \0, what other things do it?
theoriginalbit #33
Posted 10 March 2013 - 03:11 PM
This is one of the things I have against the lowerThenUpper style. If every public value,function and table were capitalised like so: Bit.And (like is the norm in C#) then you could get away with things like Bit.And since and is the keyword, not And.
I hate how C# uses word case. Every other mainstream language is Camel Case, I prefer it that way, its nice and consistent … but typical Windows, copies Java and has to make the syntax more annoying, just like their OS really …
Pharap #34
Posted 10 March 2013 - 04:00 PM
This is one of the things I have against the lowerThenUpper style. If every public value,function and table were capitalised like so: Bit.And (like is the norm in C#) then you could get away with things like Bit.And since and is the keyword, not And.
I hate how C# uses word case. Every other mainstream language is Camel Case, I prefer it that way, its nice and consistent … but typical Windows, copies Java and has to make the syntax more annoying, just like their OS really …

If you're going to start a flame war over people's language and OS choices you can forget it now. That's off topic and frankly not called for.