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

[CC 1.76+] BLittle API

Started by Bomb Bloke, 13 December 2015 - 01:37 PM
Bomb Bloke #1
Posted 13 December 2015 - 02:37 PM
pastebin get ujchRSnU blittle

So ComputerCraft 1.76 (the first build for MineCraft 1.8) offers an expanded fontset, including characters that happen to be fairly convenient for drawing pixel art with. oli's function here provides a great illustration as to how they can be used to plot most any 2x3 pattern of pixels within any given character space.

This here is an API to help automate the process; pass in a paintutils image, and it passes out a little version that can be blitted, reduced using the "smaller pixels" available within the new font. It also offers functions to save/load/draw these images.

You can alternatively generate a "window" that can be treated as a regular term object, which'll automatically shrink anything you "draw" into it.

There's a bit of a catch in that there's the potential for some loss of colour information during the conversion process. It fudges things as best it can, but the less complex your image is, the better the results should be (pure black and white should always be perfect, for example). You'll also have better results if the original image dimensions have a width divisible by two and a height divisible by 3.

For quick reference, a regular ComputerCraft terminal display can effectively display images of up to 102x57 pixels using the new fontset (up from 51x19), whereas external monitors (when built up to full size and with a text scale set to 0.5) can go up to 328x243 (from 164x81).

API Usageblittle.shrink(table paintutils image [, number backgroundColour) => table blittle image
Shrinks a given image. If the image uses transparency, that will be converted to black (or to the backgroundColour value, if specified).

BLittle image structure
{
	["width"] = (number) image width
	["height"] = (number) image height
	
	[1] = {
		[1] = First text row.
		[2] = Second text row.
		-- etc
	},

	[2] = {
		[1] = First textColour row.
		[2] = Second textColour row.
		-- etc
	},

	[3] = {
		[1] = First backgroundColour row.
		[2] = Second backgroundColour row.
		-- etc
	}
}

It's hence possible to blit a given row of the image using term.blit(image[1][row], image[2][row], image[3][row]).

blittle.shrinkGIF(table GIF images [, number backgroundColour) => table blittle images
Accepts a GIF loaded by one of my other APIs. Returns a table filled with BLittle images, each with an additional "delay" key. These can be rendered quite simply, eg:

Spoiler
os.loadAPI("GIF")
os.loadAPI("blittle")

local image = GIF.loadGIF("someGIF.gif")
image = blittle.shrinkGIF(image, image.backgroundCol)

while true do
	for i = 1, #image do
		blittle.draw(image[i])
		sleep(image[i].delay)
	end
end

blittle.draw(table blittle image [, number xPos] [, number yPos] [, table terminal])
Draws the blittle image - either at x1/y1, or at the specified location; uses either the specified terminal, or if none was supplied, the current one.

blittle.save(table blittle image, string filename)
Saves the blittle image to the specified file.

blittle.load(string filename) => table blittle image
Loads a blittle image from the specified file.

blittle.createWindow(table parent terminal, number x position, number y position, number width, number height, boolean visible) => table terminal object
Pretty much identical to window.create() from the window API - you get a term object you can redirect to.

It'll cover the number of characters specified when you define it, but its internal dimensions are two and three times the defined width and height. For example:

local myWindow = blittle.createWindow(term.current(), 1, 1, 10, 10)
print(myWindow.getSize())  --# 20 30

Only the background colours of the characters drawn to it are visible, so you can eg redirect to it and draw stuff with the paintutils API. As with blittle.shrink(), it'll do its best to fudge the results if the art you want it to draw isn't possible to represent using teletext characters.

As with a window from the window API, you'll get better performance if you set it to invisible while drawing stuff into it, and make it visible just at the moment when you're ready to reveal your completed frame.

All of createWindow()'s parameters are optional. If left blank, then they default like so:

blittle.createWindow(term.current(), 1, 1, currentTermWidth, currentTermHeight, true)

Furthermore, here's a simple example script which imports images using my GIF API, and then draws them on an attached monitor:

Example Code
if not fs.exists("package") then shell.run("pastebin get cUYTGbpb package") end
if not fs.exists("GIF") then shell.run("pastebin get 5uk9uRjC GIF") end
if not fs.exists("blittle") then shell.run("pastebin get ujchRSnU blittle") end

os.loadAPI("GIF")
os.loadAPI("blittle")

local fileName, backgroundCol = "someImage.gif", colours.white

local mon = peripheral.find("monitor")
mon.setTextScale(0.5)
mon.setBackgroundColour(backgroundCol)
mon.clear()

local x, y = mon.getSize()

local image = blittle.shrink(GIF.toPaintutils(GIF.loadGIF(fileName)), backgroundCol)

blittle.draw(image, math.floor((x-image.width)/2)+1, math.floor((y-image.height)/2)+1, mon)

And here are some screenshots of what a few loaded images might look like:

Screenshots



Version History2015/12/14
1.0.0
Initial release.

2016/01/31
1.1.0
Added createWindow() and shrinkGIF() functions.

2016/03/22
1.1.1
Sorted out crash bug reported by viluon; BLittle window object should also be a little faster.

2016/03/25
1.1.2
Fixed bug in the colour matcher.

2016/04/04
1.1.3
Fixed bug where window object's lines may've been incomplete when redrawing.

2016/04/29
1.1.4
Fixed crash bug when drawing off the right-hand edge of a window object.

2016/05/15
1.1.5
… and a similar bug involving the left-hand edge.
Edited on 15 May 2016 - 10:44 AM
oli414 #2
Posted 13 December 2015 - 03:21 PM
That's amazing!

Great way of making the new characters more useful.
Creator #3
Posted 13 December 2015 - 03:39 PM
I have to say, great job!
Bomb Bloke #4
Posted 13 December 2015 - 10:31 PM
Thanks guys. :)/>
LDDestroier #5
Posted 13 December 2015 - 11:58 PM
Oh great, now someone has to make Mario using this…

…great job, Bomb Bloke! YOU DID WELL!
Edited on 13 December 2015 - 10:58 PM
Wojbie #6
Posted 14 December 2015 - 03:32 PM
Just dropping it to say my thanks. :D/>
With this, your gif api and package i was able to easily convert termFont.png into new characters.
As i thank you i leave you with sneak peak of api i am working using said file. I call it BigPrint.
Spoiler
Edited on 14 December 2015 - 02:34 PM
Bomb Bloke #7
Posted 15 December 2015 - 12:07 PM
I'm not generally one for memes, but I'll admit it'll be a while before TF2 voice clips get old…

Good to hear you found it useful, Wojbie. :)/> Bet I'll be seeing that font set get a bit of use - it's quite neatly sized!
dan200 #8
Posted 24 December 2015 - 09:27 PM
I used this API in the 1.76 release post :)/>
http://www.computercraft.info/2015/12/24/computercraft-1-76/
Bomb Bloke #9
Posted 24 December 2015 - 10:19 PM
Creepers with Santa hats… Heh, hope none fall down my chimney!
LoganDark #10
Posted 25 December 2015 - 12:58 PM
Creepers with Santa hats… Heh, hope none fall down my chimney!

*hears creeper burning in fireplace*

Soon that will be a problem…
Bomb Bloke #11
Posted 31 January 2016 - 02:36 PM
A belated update.

Two new functions; createWindow() and shrinkGIF(). Names should pretty much speak for themselves.

createWindow() basically acts like window.create() does - for those who aren't familiar, you get a terminal object you can redirect to. After that you can draw in miniature using paintutils or whatever takes your fancy. Note that as with regular windows, you'll get better performance if you render into them while they're invisible (only here the effect is more pronounced).

Here's an example of it being applied to Gopher's 3D engine:

Spoiler
Edited on 10 February 2016 - 10:16 PM
CrazedProgrammer #12
Posted 15 March 2016 - 11:48 AM
That's amazing!
You did a great job for simplifying the use of these smaller pixels so everyone can enjoy them.
I see that the potential for this is huge.
My next program will feature these smaller pixels (in realtime 20FPS I hope) :P/>
Creator #13
Posted 15 March 2016 - 03:18 PM
Why 20 fps? What do these have to do with pixel sizes?
CrazedProgrammer #14
Posted 15 March 2016 - 04:52 PM
Why 20 fps? What do these have to do with pixel sizes?
I will have to optimize the algorithm enough to hit a constant 20FPS (the max ComputerCraft can output due to the way timer events are rounded off by 0.05 seconds).
Edited on 15 March 2016 - 03:52 PM
Lupus590 #15
Posted 15 March 2016 - 05:31 PM
Why 20 fps? What do these have to do with pixel sizes?
I will have to optimize the algorithm enough to hit a constant 20FPS (the max ComputerCraft can output due to the way timer events are rounded off by 0.05 seconds).
Which is due to MineCraft's tick rate being 20 (Ticks Per Second)
Bomb Bloke #16
Posted 16 March 2016 - 12:03 AM
Which is due to MineCraft's tick rate being 20 (Ticks Per Second)

Well, sorta. CC could time things much finer than that, and certainly monitors can already output data much faster than that. But that is likely why Dan chose to limit the timing system in that manner.
ReBraLaCC #17
Posted 17 March 2016 - 04:17 PM
Does this only work on monitors?
Edited on 17 March 2016 - 03:20 PM
CrazedProgrammer #18
Posted 17 March 2016 - 04:36 PM
Does this only work on monitors?
No. It works on all displays.
Bomb Bloke #19
Posted 18 March 2016 - 12:27 AM
Indeed, I used monitors for the screenshots purely because they can provide larger display resolutions. There's an animation of it being used on a regular display in this post.
Cross_Sans #20
Posted 23 March 2016 - 05:42 PM
Wow, that's just amazing, that's a usefull API ! Good work for you !
Selim #21
Posted 18 June 2016 - 02:16 AM
I could be screwing something up weird, but I am getting a "blittle:457: attempt to concatenate nil and string" when executing blittle.createWindow(term.current(),1,1,x,y,true) where x and y is the current terminal size.

Edit: I was right, I was screwing something up weird. That was all on me. Whoops.
Edited on 18 June 2016 - 12:23 AM
Bomb Bloke #22
Posted 18 June 2016 - 02:23 AM
That error is basically me making a mess when trying to report "you called blittle.load() with a file that can't be opened". You won't see it when calling blittle.createWindow(), however.

Speaking of, you could just use blittle.createWindow() (without arguments), as you're specifying all the defaults there.
DerMistkaefer #23
Posted 01 July 2016 - 03:58 PM
When I wont to test your api i get an error:



The same as in programm code:
if not fs.exists("package") then shell.run("pastebin get cUYTGbpb package") end
if not fs.exists("GIF") then shell.run("pastebin get 5uk9uRjC GIF") end
if not fs.exists("blittle") then shell.run("pastebin get ujchRSnU blittle") end
myWindow = blittle.createWindow()
myWindow.setVisible(true)
myWindow.setVisible(false)
myWindow.write("test")

Can you help me?
TheRockettek #24
Posted 01 July 2016 - 06:11 PM
When I wont to test your api i get an error:



The same as in programm code:
if not fs.exists("package") then shell.run("pastebin get cUYTGbpb package") end
if not fs.exists("GIF") then shell.run("pastebin get 5uk9uRjC GIF") end
if not fs.exists("blittle") then shell.run("pastebin get ujchRSnU blittle") end
myWindow = blittle.createWindow()
myWindow.setVisible(true)
myWindow.setVisible(false)
myWindow.write("test")

Can you help me?

You havent loaded the api. Do:

os.loadAPI("blittle")

and for the other ones aswell ;)/>

os.loadAPI lets you use functions from inside a program. So if its like just a text file you dont need to load it as an API (It will most probrably error anyway)
Admicos #25
Posted 09 July 2016 - 08:39 PM
So, i am having some bugs while trying to use blittle. (Code Here)

At the very top, there is a thin blue line which seems to be a copy? of the blue line right next to it. (bottom one is the intended one)
and at the top right corner, the black box (shadow) beneath the white box (window) seems to "leak" into the window.

What should i do to fix them?


Anavrins #26
Posted 09 July 2016 - 09:11 PM
Simply avoid drawing too near the border, these are artifact from CC screens directly, not from BLittle.
There's also a relevant Github issue about this, https://github.com/d...Craft/issues/51
Edited on 09 July 2016 - 07:12 PM
Admicos #27
Posted 09 July 2016 - 10:30 PM
Simply avoid drawing too near the border, these are artifact from CC screens directly, not from BLittle.
There's also a relevant Github issue about this, https://github.com/d...Craft/issues/51

Oh, ok. Hopefully this will get fixed soon.
Bomb Bloke #28
Posted 10 July 2016 - 03:48 AM
and at the top right corner, the black box (shadow) beneath the white box (window) seems to "leak" into the window.

Regarding this one, that's a result of you trying to cram too many colours into a single character space.

ComputerCraft can assign a foreground colour and a background colour to each character rendered to the screen. The teletext drawing characters BLittle uses each represent a 2x3 pixel pattern, but they're still ultimately just characters being written to the terminal - they have a foreground and a background colour, two in total.

This means that if you try to use more colours than that within a given character's 2x3 "space", BLittle has to "fudge" the results. It does this by picking the "least used" colours within that space and replacing them with the others until it gets something it can draw on-screen.

Here's your screenshot with the terminal's character spacings masked over it:



As you can see, every character contains no more than two colours. So to prevent oddities like up in the top right corner (where you've obviously tried to draw white/blue/black into the one character), try to line things up so that BLittle never has to approximate the image!

The map also makes clear the border Anavrins mentioned - that's filled automatically by ComputerCraft, and each segment always matches the background colour of whatever character has been drawn next to it (you can tell the background colour of a given teletext character by inspecting its lowest-right segment). In my view, that border would ideally either be removed or set to a constant black, though I can see why Dan doesn't like those solutions.
Edited on 10 July 2016 - 01:55 AM
Soulgriever #29
Posted 20 July 2016 - 11:26 PM
I just wanted to say I love all of your api's quick question is there an easy way to use your blittle api and gif api to make an animated image? Im guessing I would have to flatten the image with the gif api but wasnt sure.
Bomb Bloke #30
Posted 04 August 2016 - 04:42 AM
Yes, examples are in the original post. Using blittle.shrinkGIF() is the easiest way.
LDDestroier #31
Posted 04 November 2016 - 08:02 PM
I noticed that thin line that Admicos was talking about, but the top of the screen only has two colors - red and black.
Why is that?



There should be a red rectangle with the logo in the center. What's with the top and left lines?
Bomb Bloke #32
Posted 05 November 2016 - 12:22 AM
The map also makes clear the border Anavrins mentioned - that's filled automatically by ComputerCraft, and each segment always matches the background colour of whatever character has been drawn next to it (you can tell the background colour of a given teletext character by inspecting its lowest-right segment).

Basically, ComputerCraft scripts don't get "direct" control over the border - if you put a character next to it that uses X background colour, than the border at that location will also use X colour. Your image is placed such that the characters next to the border have to use a red background. Your best bet is to move it further away.

Read Anavrins' post for more info.
Edited on 04 November 2016 - 11:35 PM
Xelostar #33
Posted 10 November 2017 - 08:09 PM
Bomb Bloke, as you probably know, I have made it so my 3D renderer can use your blittle API. I've got two questions:
1. I want to put my API up for download. (In a zip file on Mediafire). Is it okay if I include your blittle API into the zip file?
2. Do you pronounce blittle as one word or as b-little?
Edited on 11 November 2017 - 08:39 AM
Bomb Bloke #34
Posted 11 November 2017 - 03:02 AM
1. Sure.

2. Depends on my mood. ;)/>
Xelostar #35
Posted 11 November 2017 - 09:39 AM
Thanks! I hope to get it out soon. :D/>
Xelostar #36
Posted 13 February 2018 - 02:10 PM
Again I'd like to ask permission to include this as a download for my Doom game (CC's first First Person Shooter). Since there are a lot of files, I've decided to put them on Github and use STD from LDDestroier to download everything with a pastebin installer. I've included an MIT license.
Is it okay if I put the BLittle API in there if I credit you in the readme?
Xelostar #37
Posted 13 February 2018 - 03:54 PM
Nevermind. I think I'm able to install it through pastebin =)