Simple PCX to video mode 3 tiles converter tool

Topics on software tools like TileStudio, comments on documentation and tutorials (or the lack of) should go here.
Post Reply
User avatar
Janka
Posts: 214
Joined: Fri Sep 21, 2012 10:46 pm
Location: inside Out

Simple PCX to video mode 3 tiles converter tool

Post by Janka »

I know there's gconvert, but I don't need its advanced features like duplicates removal, they get into my way to program. :geek: Plus, I abhor hand-written XML (no offense).:mrgreen:. Plus, as I found out, Gimp's raw output plugin has some glitches with indexed files; it always outputs 3 planes regardless of indexed mode and has problems with planes >16K. And, I'm bugged by the need always to fill out the save dialog everytime I want to save a raw file.

So I decide to write my own little tool, which takes a PCX file as input and outputs a nicely formatted tiles.inc suitable for uzebox' SetTileTable(). The tool is a Tcl script, so you need a Tcl interpreter to run it. Linux and Mac users will easily find one in their distributions, users of MS Windows should look for ActiveState Tcl.

Code: Select all

#!/usr/bin/tclsh
#
#  pcxtotiles.tcl - a minimalist PCX to tiles converter for uzebox video mode 3.
#
#  PCX must be 8 bits per pixel/1 plane, like needed for uzebox.
#  A palette given in the file is ignored as uzebox has a fixed palette.
#  Pixels per line and number of lines must be a multiple of 8.
#  The image may have any number of tiles per line you find useful.
# 
# (C)2012 Janka <jjj@gmx.de>, use and distribute under the terms of GNU GPLv3 or any later version. 
#


## Binary input.
fconfigure stdin -translation binary

## Read and decode PCX header.
binary scan [read stdin 128] @3c@6s@10s@65cs bpp umg lmg ncp nbs
set nbs [expr $nbs & 0xffff]
set lines [expr ($lmg & 0xffff - $umg & 0xffff)/8]

## Reject non-8 bpp/1 plane files.
if {($bpp != 8) || ($ncp != 1)} {
	puts stderr "Uzebox requires an 8 bpp 1 plane indexed PCX file as source for tiles."
	exit
}

## Output header.
puts "const char Tiles\[\] PROGMEM={"

## Read until all tile lines are read.
set linenumber 0
while {$linenumber<=$lines} {
	## Read 8 scanlines into one line of tiles.
	set line {}
	set i [expr 8*$nbs]
	while {$i>0} {
		set byte [read stdin 1]
		binary scan $byte c value
		set value [expr $value & 0xff]

		## RLE byte?
		if {$value >= 192} {
			## Yes. Get next byte for actual pixel value.
			set byte [read stdin 1]

			## Repeat pixel.
			for {} {$value>192} {incr value -1} {
				## Store pixel value.
				append line $byte

				## Next pixel.
				incr i -1
			}
		} {
			## No. Store pixel value.
			append line $byte

			## Next pixel.
			incr i -1
		}
	}

	## Go through all tiles in that line.
	for {set tile 0} {$tile<[expr $nbs/8]} {incr tile} {
		## Arrange tile.
		puts -nonewline "/* Tile #[expr $linenumber*$nbs/8+$tile] ($linenumber|$tile) */\n\t"
		for {set y 0} {$y<8} {incr y} {
				binary scan [string range $line [expr $nbs*$y+8*$tile] [expr $nbs*$y+8*$tile+7]] c8 VALUES
				foreach VALUE $VALUES {
					puts -nonewline "0x[format %02x [expr $VALUE & 0xff]], "
				}
				puts -nonewline "\n\t"
		}
		puts ""
	}

	## Next tile line
	incr linenumber
}

## Output footer.
puts "};"

Usage:

Code: Select all

$ pcxtotiles.tcl <mytiles.pcx >tiles.inc
Have fun!
Post Reply