mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-24 12:31:25 +00:00
removed tools/, moved to new repo sehugg/8bit-tools
This commit is contained in:
parent
4480e217f6
commit
5fe9ec29a5
2
Makefile
2
Makefile
@ -34,5 +34,3 @@ tsweb:
|
||||
astrolibre.b64.txt: astrolibre.rom
|
||||
lzg -9 $< | base64 -w 0 > $@
|
||||
|
||||
astdump:
|
||||
clang -Xclang -ast-dump -fsyntax-only tools/galois.c
|
||||
|
@ -1,53 +0,0 @@
|
||||
|
||||
all: binaries
|
||||
|
||||
%.lzg: %
|
||||
lzg -9 $< $@
|
||||
|
||||
binaries: scr2floyd scr2floyd_percept galois
|
||||
|
||||
%-pf.hex: %-pf.pbm p4_to_pfbytes.py
|
||||
python p4_to_pfbytes.py $< > $@
|
||||
|
||||
%-48.hex: %-48.pbm p4_to_48pix.py
|
||||
python p4_to_48pix.py $< > $@
|
||||
|
||||
%-pf.pbm: %.jpg
|
||||
convert $< -resize 40x192\! -colorspace Gray -dither FloydSteinberg $@
|
||||
|
||||
%-48.pbm: %.jpg
|
||||
convert $< -resize 48x192\! -colorspace Gray -dither FloydSteinberg $@
|
||||
|
||||
%.tga: %.png
|
||||
convert $< -resize 192 $<.gif
|
||||
convert $<.gif +dither -type palette -depth 4 -compress RLE -colors 8 -flip $@
|
||||
convert $@ $@.png
|
||||
|
||||
%.pcx: %.png
|
||||
convert $< -format raw -type palette -compress none -colors 15 +dither $@
|
||||
%.rle.pcx: %.png
|
||||
convert $< -format raw -type palette -compress rle -colors 15 +dither $@
|
||||
%.4.pcx: %.png
|
||||
convert $< -format raw -type palette -compress none -colors 4 +dither $@
|
||||
|
||||
ship1.pbm: ship1.png
|
||||
convert ship1.png -negate -flop ship1.pbm
|
||||
|
||||
%.h:
|
||||
cat $* | hexdump -v -e '"\n" 128/1 "0x%02x,"'
|
||||
|
||||
%.prom:
|
||||
cat $* | hexdump -v -e '" \n defb " 32/1 "$$%02x,"' | cut -c 2-134
|
||||
|
||||
%.s:
|
||||
cat $* | hexdump -v -e '" \n .byte " 32/1 "$$%02x,"' | cut -c 2-135
|
||||
|
||||
%.rot.pbm: %.pbm
|
||||
convert $< -transpose -bordercolor white -border 4x4 $@
|
||||
|
||||
baddies-horiz.rot.pbm: baddies-horiz.png
|
||||
convert $< +dither -brightness-contrast 50x50 -fill black -transpose -negate $@
|
||||
convert $@ foo.png
|
||||
|
||||
lfsr.out: lfsrcalc.py
|
||||
pypy lfsrcalc.py | sort -n > lfsr.out
|
25
tools/README
25
tools/README
@ -1,24 +1,3 @@
|
||||
These files have been moved to:
|
||||
|
||||
This directory contains 8bitworkshop tools for bitmap and
|
||||
music conversion.
|
||||
|
||||
Requires ImageMagick (convert) and Python 2.x.
|
||||
MIDI tools require Mido (pip install mido).
|
||||
|
||||
On Ubuntu:
|
||||
|
||||
$ sudo apt update
|
||||
$ sudo apt install python python-pip imagemagick curl
|
||||
$ sudo pip install mido
|
||||
|
||||
To use the tools, go to the appropriate directory and
|
||||
look at the Makefile for each:
|
||||
|
||||
vcs/ Atari 2600/VCS
|
||||
mw8080/ Midway 8080
|
||||
scramble/ Galaxian/Scramble
|
||||
vicdual/ VIC Dual
|
||||
williams/ Williams
|
||||
|
||||
fonts/ Example fonts
|
||||
images/ Example images
|
||||
https://github.com/sehugg/8bit-tools
|
||||
|
@ -1,15 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
|
||||
out = sys.stdout
|
||||
chr = open(sys.argv[1],'rb').read()
|
||||
|
||||
out.write('const unsigned char ARRAY[%d] = {\n' % len(chr))
|
||||
|
||||
for i in range(0,len(chr)):
|
||||
out.write('0x%02x, ' % ord(chr[i]))
|
||||
if (i & 7) == 7:
|
||||
out.write('\n')
|
||||
|
||||
out.write('\n};\n')
|
@ -1,15 +0,0 @@
|
||||
|
||||
import sys,re
|
||||
|
||||
inf = sys.stdin
|
||||
outf = open('a.out','wb')
|
||||
l = inf.readline()
|
||||
while l:
|
||||
l = l.strip()
|
||||
if l[-1] == ',':
|
||||
l = l[0:-1]
|
||||
toks = re.split('[,\s]+', l)
|
||||
toks = list(filter(lambda x: x[0:2]=='0x', toks))
|
||||
arr = [int(x,0) for x in toks]
|
||||
outf.write(bytes(arr))
|
||||
l = inf.readline()
|
@ -1,16 +0,0 @@
|
||||
|
||||
import os,sys,codecs
|
||||
|
||||
for root, dirs, files in os.walk("./presets"):
|
||||
for fn in files:
|
||||
path = root + '/' + fn
|
||||
if fn[-1] == '~':
|
||||
continue
|
||||
try:
|
||||
with open(path,'r') as f:
|
||||
data = f.read()
|
||||
if data[0] != '\n':
|
||||
print((path,'no initial newline'))
|
||||
except:
|
||||
print((path,sys.exc_info()[0]))
|
||||
|
@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
./scr2floyd_percept $1.tga
|
||||
lzg -9 $1.CHR > $1.CHR.lzg
|
||||
lzg -9 $1.CLR > $1.CLR.lzg
|
||||
rm -f $1.s
|
||||
echo "\t.area _CODE" >> $1.s
|
||||
echo "\t.globl _msx_mode2_pattern_lzg" >> $1.s
|
||||
echo "\t.globl _msx_mode2_color_lzg" >> $1.s
|
||||
echo "\n_msx_mode2_pattern_lzg:" >> $1.s
|
||||
cat $1.CHR.lzg | hexdump -v -e '"\n.db " 16/1 ",0x%02x"' | sed "s/n.db,/ .db /" | tail -n +3 >> $1.s
|
||||
echo "\n_msx_mode2_color_lzg:" >> $1.s
|
||||
cat $1.CLR.lzg | hexdump -v -e '"\n.db " 16/1 ",0x%02x"' | sed "s/n.db,/ .db /" | tail -n +3 >> $1.s
|
||||
|
1437
tools/fonts/c64.bdf
1437
tools/fonts/c64.bdf
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@
|
||||
|
||||
/* test of 16-bit Galois LFSR */
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
int n = 100;
|
||||
unsigned short x = 1;
|
||||
for (int i=0; i<n; i++) {
|
||||
int c = x&1;
|
||||
x >>= 1;
|
||||
if (c) x ^= 0xd400; // 0b1101010000000000
|
||||
printf("%4x\n", x);
|
||||
}
|
||||
for (int i=0; i<n; i++) {
|
||||
int c = x&0x8000;
|
||||
x <<= 1;
|
||||
if (c) x ^= 0xa801;
|
||||
printf("%4x\n", x);
|
||||
}
|
||||
return 0;
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,30 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
MAXBITS=16
|
||||
|
||||
print("Period,nbits,feedback,mask")
|
||||
|
||||
for n in range(1,MAXBITS):
|
||||
mask = (1<<n)-1
|
||||
hibit = (1<<(n-1))
|
||||
for i in range(0,1<<n):
|
||||
for invert in [0,1]:
|
||||
x = 1
|
||||
seq = []
|
||||
seen = set()
|
||||
while x and not x in seen:
|
||||
seq.append(x)
|
||||
seen.add(x)
|
||||
feedback = x & hibit
|
||||
x = ((x << 1) & mask)
|
||||
if invert:
|
||||
if not feedback:
|
||||
x ^= i
|
||||
else:
|
||||
if feedback:
|
||||
x ^= i
|
||||
if x:
|
||||
seqindex = seq.index(x)
|
||||
seqlen = len(seq) - seqindex
|
||||
if seqlen>1:
|
||||
print((seqlen, "#(%d,%d'%s,%d)" % (n,n,bin(i)[1:],invert), seqindex))
|
@ -1,42 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var BEST={}
|
||||
|
||||
var MAXBITS=17
|
||||
//MAXBITS=12
|
||||
|
||||
for (var n=1; n<MAXBITS; n++) {
|
||||
var mask = (1<<n)-1;
|
||||
var hibit = (1<<(n-1));
|
||||
for (var i=0; i < (1<<n); i++) {
|
||||
for (var invert=0; invert<2; invert++) {
|
||||
var x = 1;
|
||||
var seq = [];
|
||||
var seen = new Map();
|
||||
while (x && !seen.get(x)) {
|
||||
seq.push(x);
|
||||
seen.set(x, true);
|
||||
var feedback = (x & hibit) != 0;
|
||||
x = ((x << 1) & mask);
|
||||
if (invert && !feedback) x ^= i;
|
||||
if (!invert && feedback) x ^= i;
|
||||
}
|
||||
if (x) {
|
||||
var seqindex = seq.indexOf(x);
|
||||
var seqlen = seq.length - seqindex;
|
||||
if (seqlen > 1 && x == 1) {
|
||||
if (!BEST[seqlen] || n < BEST[seqlen].n) {
|
||||
BEST[seqlen] = {n:n, i:i, invert:invert};
|
||||
//console.log(seqlen + "\t" + n + "\t" + i.toString(2) + "\t" + x.toString(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var seqlen in BEST) {
|
||||
var b = BEST[seqlen];
|
||||
console.log(seqlen+" &\t@"+b.n+"'b"+b.i.toString(2)+","+b.invert+"@ \\\\");
|
||||
}
|
||||
|
@ -1,182 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, string, math, argparse
|
||||
import mido
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-s', '--start', type=int, default=21, help="first MIDI note")
|
||||
parser.add_argument('-n', '--num', type=int, default=21+63, help="number of notes")
|
||||
parser.add_argument('-v', '--voices', type=int, default=3, help="number of voices")
|
||||
parser.add_argument('-T', '--transpose', type=int, default=0, help="transpose by half-steps")
|
||||
parser.add_argument('-t', '--tempo', type=int, default=48, help="tempo")
|
||||
parser.add_argument('-o', '--one', action="store_true", help="one voice per channel")
|
||||
parser.add_argument('-z', '--compress', action="store_true", help="compress song (experimental)")
|
||||
parser.add_argument('-H', '--hex', action="store_true", help="hex output")
|
||||
parser.add_argument('midifile', help="MIDI file")
|
||||
parser.add_argument('midichannels', nargs='?', help="comma-separated list of MIDI channels, or -")
|
||||
args = parser.parse_args()
|
||||
|
||||
min_note = args.start
|
||||
max_note = min_note + args.num
|
||||
max_voices = args.voices
|
||||
one_voice_per_channel = args.one
|
||||
tempo = args.tempo
|
||||
compress = args.compress
|
||||
transpose = args.transpose
|
||||
coutput = not args.hex
|
||||
|
||||
# for 2600
|
||||
#max_voices = 2
|
||||
#coutput = 0
|
||||
# for 2600 wavetable
|
||||
#max_voices = 4
|
||||
#one_voice_per_channel = 0
|
||||
|
||||
fn = args.midifile
|
||||
|
||||
mid = mido.MidiFile(fn)
|
||||
|
||||
def hex1(n):
|
||||
return '%02x'%n
|
||||
def hex2(n):
|
||||
return '0x%02x'%n
|
||||
|
||||
def only_notes(s):
|
||||
for ch in s:
|
||||
if ord(ch) == 0xff:
|
||||
return False
|
||||
return True
|
||||
|
||||
def find_common_substrings(s):
|
||||
results = {}
|
||||
for l in range(64, 6, -1):
|
||||
for i in range(0,len(s)-l*2):
|
||||
match = s[i:i+l]
|
||||
if not only_notes(match):
|
||||
continue
|
||||
count = 0
|
||||
j = i+l
|
||||
while j < len(s):
|
||||
p = s.find(match, j)
|
||||
if p > 0:
|
||||
count += 1
|
||||
j = p+l
|
||||
else:
|
||||
break
|
||||
if count:
|
||||
n = count*(l-1)-1
|
||||
if not results.get(i) or n > results[i][0]:
|
||||
results[i] = (n,l)
|
||||
return results
|
||||
|
||||
def get_best_substring(ss):
|
||||
best = (0,0,0)
|
||||
for k,v in list(ss.items()):
|
||||
if v[0] > best[2]:
|
||||
best = (k,v[1],v[0])
|
||||
return best
|
||||
|
||||
def offset2str(ofs):
|
||||
return chr(ofs & 0xff) + chr((ofs >> 8) & 0xff)
|
||||
#return chr(0xc0 | (ofs & 0x3f)) + chr(0xc0 | ((ofs >> 6) & 0x3f))
|
||||
|
||||
g_code = 0xc1
|
||||
g_subs = []
|
||||
|
||||
def replace_substrings(s, bss):
|
||||
global g_code
|
||||
i,l,n = bss
|
||||
count = (n+1)/(l-1)
|
||||
match = s[i:i+l]
|
||||
print((i,l,n,count,repr(match)))
|
||||
r = s[0:i]
|
||||
while i<len(s):
|
||||
r += chr(g_code)
|
||||
p = s.find(match,i+l)
|
||||
if p < 0:
|
||||
p = len(s)
|
||||
r += s[i+l:p]
|
||||
i = p
|
||||
g_subs.append(match + chr(0xff))
|
||||
g_code += 1
|
||||
print((len(s), len(r)+n+l))
|
||||
assert len(s) == len(r)+n+l
|
||||
return r
|
||||
|
||||
def channels_for_track(track):
|
||||
channels = set()
|
||||
for msg in track:
|
||||
if msg.type == 'note_on':
|
||||
channels.add(msg.channel)
|
||||
return list(channels)
|
||||
|
||||
if not args.midichannels:
|
||||
print(mid)
|
||||
print((mid.length, 'seconds'))
|
||||
for i, track in enumerate(mid.tracks):
|
||||
print(('Track {}: {} ({}) {}'.format(i, track.name, len(track), channels_for_track(track))))
|
||||
#for msg in track:
|
||||
# print(msg)
|
||||
else:
|
||||
gtime = 0
|
||||
curtime = 0
|
||||
nnotes = 0
|
||||
nvoices = 0
|
||||
curchans = 0
|
||||
channels = [int(x) for x in args.midichannels.split(',')]
|
||||
print ('')
|
||||
print(("// %s %s" % (mid, channels)))
|
||||
output = []
|
||||
for msg in mid:
|
||||
gtime += msg.time * tempo
|
||||
if msg.type == 'note_on' and msg.channel in channels:
|
||||
note = msg.note + transpose
|
||||
vel = msg.velocity
|
||||
t = int(math.ceil(gtime))
|
||||
if vel > 0:
|
||||
while curtime < t:
|
||||
dt = min(63, t-curtime)
|
||||
curtime += dt
|
||||
if nnotes > 0:
|
||||
nvoices = 0
|
||||
curchans = 0
|
||||
output.append(dt+128)
|
||||
if note >= min_note and note <= max_note and nvoices < max_voices:
|
||||
if not (one_voice_per_channel and (curchans & (1<<msg.channel))):
|
||||
n = note - min_note
|
||||
output.append(n)
|
||||
nnotes += 1
|
||||
nvoices += 1
|
||||
curchans |= 1<<msg.channel
|
||||
output.append(0xff)
|
||||
if coutput:
|
||||
print((','.join([hex2(x) for x in output])))
|
||||
else:
|
||||
bighex = ''.join([hex1(x) for x in output])
|
||||
for i in range(0,len(bighex)+32,32):
|
||||
print(('\thex', bighex[i:i+32]))
|
||||
if compress:
|
||||
# replace common substrings
|
||||
bout = ''.join(chr(i) for i in output)
|
||||
for iter in range(0,32):
|
||||
ss = find_common_substrings(bout)
|
||||
bss = get_best_substring(ss)
|
||||
print(bss)
|
||||
if bss[1] == 0:
|
||||
break
|
||||
bout = replace_substrings(bout, bss)
|
||||
print((repr(bout)))
|
||||
# build substring table
|
||||
ofs = (len(g_subs)+1)*2
|
||||
zout = offset2str(ofs)
|
||||
ofs += len(bout)
|
||||
for ss in g_subs:
|
||||
ofs += len(ss)
|
||||
zout += offset2str(ofs)
|
||||
# output strings
|
||||
zout += bout
|
||||
for ss in g_subs:
|
||||
zout += ss
|
||||
# print output
|
||||
print((','.join([hex2(ord(x)) for x in zout])))
|
||||
print(("// compressed %d -> %d bytes" % (len(output), len(zout))))
|
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, string, math, argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-l', '--length', type=int, default=64, help="length of note table")
|
||||
parser.add_argument('-u', '--upper', type=int, default=49, help="upper note # to test")
|
||||
parser.add_argument('-f', '--freq', type=float, default=3579545/32.0, help="base frequency (Hz)")
|
||||
parser.add_argument('-b', '--bias', type=float, default=0, help="divisor bias")
|
||||
parser.add_argument('-m', '--maxbits', type=float, default=12, help="max. # of bits")
|
||||
args = parser.parse_args()
|
||||
|
||||
test_notes = args.upper
|
||||
final_notes = args.length
|
||||
basehz = args.freq
|
||||
bias = args.bias
|
||||
maxval = (1<<int(args.maxbits))-1
|
||||
|
||||
results = []
|
||||
|
||||
for a440 in range(4300,4500):
|
||||
error = 0
|
||||
for note in range(1,test_notes):
|
||||
notehz = a440 / 10.0 * math.pow(2.0, (note - 49) / 12.0);
|
||||
period = int(round(basehz / notehz))
|
||||
while period > maxval:
|
||||
period /= 2
|
||||
tonehz = basehz / period
|
||||
error += abs(notehz-tonehz)
|
||||
#print a440,note,notehz,notehz-tonehz,period
|
||||
#if a440 == 4405:
|
||||
# print '%d,%f,%d' % (note,tonehz-notehz,period)
|
||||
results.append((error, a440))
|
||||
|
||||
results.sort()
|
||||
best_error, best_a440 = results[0]
|
||||
best_a440 /= 10.0
|
||||
print('//', args)
|
||||
print('//', best_a440, best_error, test_notes)
|
||||
|
||||
print("const int note_table[%d] = {" % final_notes)
|
||||
for note in range(0,final_notes):
|
||||
notehz = best_a440 * math.pow(2.0, (note - 49) / 12.0);
|
||||
period = int(round(basehz / notehz)) - bias
|
||||
while period > maxval:
|
||||
period /= 2
|
||||
print('%d,' % period, end='')
|
||||
print("};")
|
@ -1,91 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, string, math, argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-l', '--length', type=int, default=64, help="length of note table")
|
||||
parser.add_argument('-u', '--upper', type=int, default=49, help="upper note # to test")
|
||||
args = parser.parse_args()
|
||||
|
||||
test_notes = args.upper
|
||||
final_notes = args.length
|
||||
|
||||
basehz = 15720.0 #4
|
||||
basehz2 = 5240.0 #12
|
||||
basehz3 = 1014.2 #6
|
||||
s = 8
|
||||
|
||||
bittable = [
|
||||
0b00000000,
|
||||
0b00000001,
|
||||
0b00010001,
|
||||
0b01001001,
|
||||
0b01010101,
|
||||
0b10110101,
|
||||
0b11011011,
|
||||
0b11101111,
|
||||
]
|
||||
|
||||
results = []
|
||||
|
||||
for a440 in range(4200,4600):
|
||||
error = 0
|
||||
for note in range(4,test_notes):
|
||||
notehz = a440 / 10.0 * math.pow(2.0, (note - 49) / 12.0);
|
||||
period = round(basehz * s / notehz) / s
|
||||
tonehz = basehz / period
|
||||
if period < s or period > 32*s:
|
||||
tonehz = -10000
|
||||
period2 = round(basehz2 * s / notehz) / s
|
||||
tonehz2 = basehz2 / period
|
||||
if period2 < s or period2 > 32*s:
|
||||
tonehz2 = -10000
|
||||
period3 = round(basehz3 * s / notehz) / s
|
||||
tonehz3 = basehz3 / period
|
||||
if period3 < s or period3 > 32*s:
|
||||
tonehz3 = -10000
|
||||
error += min(abs(notehz-tonehz), abs(notehz-tonehz2), abs(notehz-tonehz3))
|
||||
results.append((error, a440))
|
||||
|
||||
results.sort()
|
||||
best_error, best_a440 = results[0]
|
||||
best_a440 /= 10.0
|
||||
print('//', best_a440, best_error, test_notes)
|
||||
|
||||
periods = []
|
||||
tones = []
|
||||
bits = []
|
||||
|
||||
print("const int note_table[%d] = {" % final_notes)
|
||||
for note in range(0,final_notes):
|
||||
notehz = best_a440 * math.pow(2.0, (note - 49) / 12.0);
|
||||
bestperiod = 255
|
||||
bestscore = 999999
|
||||
besthz = -1
|
||||
for hz in [basehz, basehz2, basehz3]:
|
||||
period = int(round(hz * s / notehz))
|
||||
if period >= s and period <= 32*s:
|
||||
tonehz = hz / period
|
||||
error = notehz - hz
|
||||
if error < bestscore:
|
||||
bestscore = error
|
||||
bestperiod = period
|
||||
besthz = hz
|
||||
|
||||
#print(note, besthz, bestperiod, notehz)
|
||||
print('%d,' % period, end='')
|
||||
periods.append(bestperiod / s - 1)
|
||||
bits.append(bittable[bestperiod & (s-1)])
|
||||
if besthz==basehz:
|
||||
tones.append(4)
|
||||
elif besthz==basehz2:
|
||||
tones.append(12)
|
||||
elif besthz==basehz3:
|
||||
tones.append(6)
|
||||
else:
|
||||
tones.append(0)
|
||||
print("};")
|
||||
|
||||
print(periods)
|
||||
print(bits)
|
||||
print(tones)
|
@ -1,9 +0,0 @@
|
||||
|
||||
d = 16
|
||||
s = 800
|
||||
|
||||
for n in range(0,128):
|
||||
z = n/2+d
|
||||
y = s/z
|
||||
print("%d," % y, end='')
|
||||
print()
|
2
tools/mw8080/.gitignore
vendored
2
tools/mw8080/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*.c
|
||||
*.pbm
|
@ -1,29 +0,0 @@
|
||||
|
||||
all: cp437.mw8080.c c64.mw8080.c baddies-horiz.rot.c scrappy.rot.c
|
||||
|
||||
# convert DOS CP437 font (256 chars)
|
||||
cp437.mw8080.c: ../fonts/cp437-8x8.bdf
|
||||
python ../parsebdf8.py $< -f -r -C > $@
|
||||
|
||||
# convert C64 font (63 chars)
|
||||
c64.mw8080.c: ../fonts/c64.bdf
|
||||
python ../parsebdf8.py $< -f -r -C -s 32 -e 94 > $@
|
||||
|
||||
%.h:
|
||||
cat $* | hexdump -v -e '"\n" 128/1 "0x%02x,"'
|
||||
|
||||
# convert PBM bitmap to C array
|
||||
%.c: %.pbm
|
||||
python ../pbm_to_c.py $< > $@
|
||||
|
||||
#%.rot.pbm: %.pbm
|
||||
# convert $< -transpose -bordercolor white -border 4x4 $@
|
||||
|
||||
# rotate and dither example bitmaps
|
||||
|
||||
baddies-horiz.rot.pbm: ../images/baddies-horiz.png
|
||||
convert $< +dither -brightness-contrast 50x50 -fill black -transpose -negate $@
|
||||
|
||||
scrappy.rot.pbm: ../images/scrappy48x64.pbm
|
||||
convert $< -transpose -bordercolor white -border 4x4 $@
|
||||
|
@ -1,11 +0,0 @@
|
||||
|
||||
all: nametable.dat
|
||||
|
||||
clean:
|
||||
rm -f *.dat road.png
|
||||
|
||||
nametable.dat: road.png
|
||||
makechr -e error.png $< #-b 0000ff
|
||||
|
||||
road.png: road.py
|
||||
python road.py
|
@ -1,102 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Import a library of functions called 'pygame'
|
||||
import pygame
|
||||
import random
|
||||
from math import pi
|
||||
|
||||
# Initialize the game engine
|
||||
pygame.init()
|
||||
|
||||
# Define the colors we will use in RGB format
|
||||
BLACK = ( 0, 0, 0)
|
||||
WHITE = (255, 255, 255)
|
||||
BLUE = ( 0, 0, 255)
|
||||
GREEN = ( 0, 184, 0)
|
||||
|
||||
CURBING = [
|
||||
(136,20,0),
|
||||
(168,16,0),
|
||||
]
|
||||
|
||||
CENLINE = [
|
||||
(124,124,124),
|
||||
(188,188,188),
|
||||
]
|
||||
|
||||
MOUNTAINS = [
|
||||
(80,48,0),
|
||||
(172,124,0)
|
||||
]
|
||||
|
||||
# Set the height and width of the screen
|
||||
size = [512, 240]
|
||||
y0 = 112
|
||||
x0 = 256
|
||||
screen = pygame.display.set_mode(size)
|
||||
|
||||
pygame.display.set_caption("Example code for the draw module")
|
||||
|
||||
#Loop until the user clicks the close button.
|
||||
done = False
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while not done:
|
||||
|
||||
# This limits the while loop to a max of 10 times per second.
|
||||
# Leave this out and we will use all CPU we can.
|
||||
clock.tick(10)
|
||||
|
||||
for event in pygame.event.get(): # User did something
|
||||
if event.type == pygame.QUIT: # If user clicked close
|
||||
done=True # Flag that we are done so we exit this loop
|
||||
|
||||
# All drawing code happens after the for loop and but
|
||||
# inside the main while done==False loop.
|
||||
|
||||
# Clear the screen and set the screen background
|
||||
screen.fill(BLUE)
|
||||
pygame.draw.rect(screen, GREEN, [0, y0, 512, 240-y0])
|
||||
|
||||
# draw the road
|
||||
for y in range(y0,240):
|
||||
i = y-y0
|
||||
rw = i*2
|
||||
cw = rw/4
|
||||
lw = rw/32
|
||||
z = 500.0/(i+1)
|
||||
curbcol = CURBING[int(z) % 2]
|
||||
cencol = CENLINE[int(z) % 2]
|
||||
if i < 16:
|
||||
cencol = BLACK #CENLINE[0]
|
||||
if i < 0:
|
||||
curbcol = BLACK #CURBING[0]
|
||||
pygame.draw.line(screen, BLACK, [x0-rw, y], [x0+rw, y], 1)
|
||||
pygame.draw.line(screen, curbcol, [x0-rw-cw, y], [x0-rw, y], 1)
|
||||
pygame.draw.line(screen, curbcol, [x0+rw, y], [x0+rw+cw, y], 1)
|
||||
pygame.draw.line(screen, cencol, [x0-rw/3-lw, y], [x0-rw/3+lw, y], 1)
|
||||
pygame.draw.line(screen, cencol, [x0+rw/3-lw, y], [x0+rw/3+lw, y], 1)
|
||||
|
||||
# draw mountains
|
||||
h1 = 1
|
||||
h2 = 2
|
||||
for x in range(0,512):
|
||||
pygame.draw.line(screen, MOUNTAINS[0], [x, y0-1], [x, y0-h1], 1)
|
||||
pygame.draw.line(screen, MOUNTAINS[1], [x, y0-1], [x, y0-h2], 1)
|
||||
if random.randint(0,8) > h1:
|
||||
h1 += 1
|
||||
elif h1 > 1:
|
||||
h1 -= 1
|
||||
if random.randint(0,6) > h2:
|
||||
h2 += 1
|
||||
elif h2 > 1:
|
||||
h2 -= 1
|
||||
|
||||
# Go ahead and update the screen with what we've drawn.
|
||||
# This MUST happen after all the other drawing commands.
|
||||
pygame.display.flip()
|
||||
|
||||
pygame.image.save(screen, 'road.png')
|
||||
|
||||
# Be IDLE friendly
|
||||
pygame.quit()
|
@ -1,11 +0,0 @@
|
||||
|
||||
import sys
|
||||
|
||||
chr = open(sys.argv[1],'rb').read()
|
||||
out = open('outsms.bin','wb')
|
||||
for i in range(0,len(chr),16):
|
||||
for y in range(0,8):
|
||||
arr = [ ord(chr[i+y]), ord(chr[i+8+y]), 0, 0 ]
|
||||
out.write(bytearray(arr))
|
||||
out.close()
|
||||
|
@ -1,58 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, struct
|
||||
|
||||
# playfield bytes, one array for each of 6 columns
|
||||
output = [[],[],[],[],[],[]]
|
||||
|
||||
# reverse byte
|
||||
def rev(n):
|
||||
return int('{:08b}'.format(n)[::-1], 2)
|
||||
|
||||
# output bits in given range
|
||||
def out(i, pix, lb, hb, reverse=0, shift=0):
|
||||
x = (pix >> lb) & ((1<<(hb-lb))-1)
|
||||
if reverse:
|
||||
x = rev(x)
|
||||
if shift:
|
||||
x = x << shift
|
||||
assert(x>=0 and x<=255)
|
||||
output[i].append(x)
|
||||
|
||||
# read PBM (binary P4 format) file
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
# read PBM header
|
||||
header = f.readline().strip()
|
||||
assert(header == b'P4')
|
||||
dims = f.readline().strip()
|
||||
if dims[0:1] == b'#':
|
||||
dims = f.readline().strip()
|
||||
width,height = list(map(int, dims.split()))
|
||||
assert(width==48)
|
||||
# read bitmap rows
|
||||
for y in range(0,height):
|
||||
row = bytes(f.read(6) + b'\0\0') # pad to 8 bytes
|
||||
# convert to 64-bit integer
|
||||
pix = struct.unpack('<q',row)[0]
|
||||
#print '%010lx' % pix
|
||||
# generate playfield bytes
|
||||
out(0, pix, 0, 8, 0)
|
||||
out(1, pix, 8, 16, 0)
|
||||
out(2, pix, 16, 24, 0)
|
||||
out(3, pix, 24, 32, 0)
|
||||
out(4, pix, 32, 40, 0)
|
||||
out(5, pix, 40, 48, 0)
|
||||
|
||||
# output bitmap tables
|
||||
for c in range(0,6):
|
||||
print("\talign $100")
|
||||
print(("Bitmap%d" % c))
|
||||
print("\thex 00")
|
||||
s = '\thex '
|
||||
for i in range(0,height):
|
||||
s += '%02x' % output[c][height-i-1]
|
||||
if i % 16 == 15:
|
||||
print(s)
|
||||
s = '\thex '
|
||||
if len(s)>5:
|
||||
print(s)
|
@ -1,60 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, struct
|
||||
|
||||
# playfield bytes, one array for each of 6 columns
|
||||
output = [[],[],[],[],[],[]]
|
||||
|
||||
# reverse byte
|
||||
def rev(n):
|
||||
return int('{:08b}'.format(n)[::-1], 2)
|
||||
|
||||
# output bits in given range
|
||||
def out(i, pix, lb, hb, reverse=0, shift=0):
|
||||
x = (pix >> lb) & ((1<<(hb-lb))-1)
|
||||
if reverse:
|
||||
x = rev(x)
|
||||
if shift:
|
||||
x = x << shift
|
||||
assert(x>=0 and x<=255)
|
||||
output[i].append(x)
|
||||
|
||||
# read PBM (binary P4 format) file
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
# read PBM header
|
||||
header = f.readline().strip()
|
||||
assert(header == b'P4')
|
||||
dims = f.readline().strip()
|
||||
if dims[0:1] == b'#':
|
||||
dims = f.readline().strip()
|
||||
print(dims)
|
||||
width,height = list(map(int, dims.split()))
|
||||
assert(width==40)
|
||||
# read bitmap rows
|
||||
for y in range(0,height):
|
||||
row = bytes(f.read(5) + b'\0\0\0') # pad to 8 bytes
|
||||
# convert bytes from MSB first to LSB first
|
||||
row2 = []
|
||||
for i in range(0,8):
|
||||
row2.append(rev(row[i]))
|
||||
# convert to 64-bit integer
|
||||
pix = struct.unpack('<q',bytes(row2))[0]
|
||||
# generate playfield bytes
|
||||
out(0, pix, 0, 4, 0, 4)
|
||||
out(1, pix, 4, 12, 1)
|
||||
out(2, pix, 12, 20, 0)
|
||||
out(3, pix, 20, 24, 0, 4)
|
||||
out(4, pix, 24, 32, 1)
|
||||
out(5, pix, 32, 40, 0)
|
||||
|
||||
# output bitmap tables
|
||||
for c in range(0,6):
|
||||
print(("PFBitmap%d" % c))
|
||||
s = '\thex '
|
||||
for i in range(0,height):
|
||||
s += '%02x' % output[c][height-i-1]
|
||||
if i % 16 == 15:
|
||||
print(s)
|
||||
s = '\thex '
|
||||
if len(s)>5:
|
||||
print(s)
|
@ -1,71 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys,string
|
||||
|
||||
height = 5
|
||||
lochar = 41
|
||||
hichar = 90
|
||||
|
||||
chars = {}
|
||||
inbitmap = 0
|
||||
with open(sys.argv[1],'r') as f:
|
||||
lines = f.readlines()
|
||||
for l in lines:
|
||||
l = l.strip()
|
||||
toks = l.split()
|
||||
if toks[0] == 'ENCODING':
|
||||
chord = int(toks[1])
|
||||
elif toks[0] == 'BITMAP':
|
||||
inbitmap = True
|
||||
bytes = []
|
||||
elif toks[0] == 'ENDCHAR':
|
||||
inbitmap = False
|
||||
if chord >= lochar and chord <= hichar:
|
||||
while len(bytes) < height:
|
||||
bytes.insert(0,0)
|
||||
assert(len(bytes) == height)
|
||||
bytes.reverse()
|
||||
print((chord,bytes))
|
||||
chars[chord] = bytes
|
||||
elif inbitmap and len(toks) == 1:
|
||||
byte = int(toks[0],16)
|
||||
assert((byte&15)==0)
|
||||
assert((byte&1)==0)
|
||||
byte = byte / 32
|
||||
bytes.append(byte)
|
||||
|
||||
# output font table
|
||||
x = 0
|
||||
output = []
|
||||
outputlo = []
|
||||
outputhi = []
|
||||
for ch in range(lochar,hichar+1):
|
||||
x = 0
|
||||
bytes = chars.get(ch)
|
||||
#bytes = bytes + [0]
|
||||
if not bytes:
|
||||
bytes = [0] * height
|
||||
for b in bytes:
|
||||
if not x:
|
||||
v = b
|
||||
else:
|
||||
v = v | (b<<4)
|
||||
output.append(v)
|
||||
x ^= 1
|
||||
outputlo.append(b)
|
||||
outputhi.append(b<<4)
|
||||
|
||||
def tohex(v):
|
||||
return '%02x'%v
|
||||
def tohex2(v):
|
||||
return '0x%02x'%v
|
||||
def tobin(v):
|
||||
return "bitarray[0][0]=3'b{0:3b};\n".format(v)
|
||||
|
||||
print(('\thex ' + ''.join(map(tohex,output))))
|
||||
print((''.join(map(tohex2,output))))
|
||||
print(('\thex ' + ''.join(map(tohex,outputlo))))
|
||||
print(('\thex ' + ''.join(map(tohex,outputhi))))
|
||||
print((''.join(map(tobin,output))))
|
||||
|
||||
print((len(output),len(outputlo),len(outputhi)))
|
@ -1,65 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys,string,argparse
|
||||
|
||||
#lochar = 0x20 #48
|
||||
#hichar = 0x5e #57
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-s', '--start', type=int, default=0, help="index of first character")
|
||||
parser.add_argument('-e', '--end', type=int, default=255, help="index of last character")
|
||||
parser.add_argument('bdffile', help="BDF bitmap file")
|
||||
args = parser.parse_args()
|
||||
|
||||
lochar = args.start
|
||||
hichar = args.end
|
||||
|
||||
def tohex(v):
|
||||
return '%02x'%v
|
||||
def tohex2(v):
|
||||
return '0x%02x'%v
|
||||
|
||||
chars = {}
|
||||
inbitmap = 0
|
||||
with open(args.bdffile,'r') as f:
|
||||
lines = f.readlines()
|
||||
for l in lines:
|
||||
l = l.strip()
|
||||
toks = l.split()
|
||||
#print l,toks
|
||||
if toks[0] == 'ENCODING':
|
||||
chord = int(toks[1])
|
||||
elif toks[0] == 'BITMAP':
|
||||
inbitmap = True
|
||||
bytes = []
|
||||
elif toks[0] == 'BBX':
|
||||
bbx = [int(x) for x in toks[1:]]
|
||||
elif toks[0] == 'ENDCHAR':
|
||||
inbitmap = False
|
||||
if chord >= lochar and chord <= hichar:
|
||||
#bytes.reverse()
|
||||
#print chord,bytes,bbx
|
||||
width = bbx[0]+1
|
||||
height = bbx[1]
|
||||
output = [(width+1)//2 + (width)*16, height + (height+bbx[3])*16]
|
||||
for y in range(0,height):
|
||||
for x in range(0,width,2):
|
||||
b = 0
|
||||
if bytes[y] & (0x80 >> x):
|
||||
b |= 0xf0
|
||||
if bytes[y] & (0x40 >> x):
|
||||
b |= 0x0f
|
||||
output.append(b)
|
||||
print('const char CH_%d[] = { %s };' % ( chord, ','.join([tohex2(x) for x in output]) ))
|
||||
chars[chord] = 'CH_%d' % chord
|
||||
elif inbitmap and len(toks) == 1:
|
||||
byte = int(toks[0],16)
|
||||
bytes.append(byte)
|
||||
|
||||
print('const char* const FONT_TABLE[%d] = {' % (hichar-lochar+1), end=' ')
|
||||
for ch in range(lochar, hichar+1):
|
||||
if chars.get(ch):
|
||||
print('%s,' % chars[ch], end=' ')
|
||||
else:
|
||||
print('0,', end=' ')
|
||||
print("};")
|
@ -1,120 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys,string,argparse
|
||||
|
||||
#lochar = 0x20 #48
|
||||
#hichar = 0x5e #57
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-s', '--start', type=int, default=0, help="index of first character")
|
||||
parser.add_argument('-e', '--end', type=int, default=255, help="index of last character")
|
||||
parser.add_argument('-H', '--height', type=int, default=8, help="character height")
|
||||
parser.add_argument('-i', '--invert', action="store_true", help="invert bits")
|
||||
parser.add_argument('-r', '--rotate', action="store_true", help="rotate bits")
|
||||
parser.add_argument('-f', '--flip', action="store_true", help="flip bits (vertically)")
|
||||
parser.add_argument('-m', '--mirror', action="store_true", help="mirror bits (horizontally)")
|
||||
outfmtgroup = parser.add_mutually_exclusive_group()
|
||||
outfmtgroup.add_argument("-A", "--asmhex", action="store_true", help="DASM-compatible hex")
|
||||
outfmtgroup.add_argument("-B", "--asmdb", action="store_true", help="Z80ASM-compatible hex")
|
||||
outfmtgroup.add_argument("-C", "--carray", action="store_true", help="Nested C array")
|
||||
outfmtgroup.add_argument("-F", "--flatcarray", action="store_true", help="Flat C array")
|
||||
outfmtgroup.add_argument("-V", "--verilog", action="store_true", help="Verilog-compatible hex")
|
||||
parser.add_argument('bdffile', help="BDF bitmap file")
|
||||
args = parser.parse_args()
|
||||
|
||||
height = args.height
|
||||
lochar = args.start
|
||||
hichar = args.end
|
||||
invert = args.invert
|
||||
flip = args.flip
|
||||
rotate = args.rotate
|
||||
mirror = args.mirror
|
||||
|
||||
chars = {}
|
||||
inbitmap = 0
|
||||
with open(args.bdffile,'r') as f:
|
||||
lines = f.readlines()
|
||||
for l in lines:
|
||||
l = l.strip()
|
||||
toks = l.split()
|
||||
#print l,toks
|
||||
if toks[0] == 'ENCODING':
|
||||
chord = int(toks[1])
|
||||
elif toks[0] == 'BITMAP':
|
||||
inbitmap = True
|
||||
bytes = []
|
||||
elif toks[0] == 'ENDCHAR':
|
||||
inbitmap = False
|
||||
if chord >= lochar and chord <= hichar:
|
||||
while len(bytes) < height:
|
||||
bytes.insert(0,0)
|
||||
assert(len(bytes) == height)
|
||||
bytes.reverse()
|
||||
#print chord,bytes
|
||||
chars[chord] = bytes
|
||||
elif inbitmap and len(toks) == 1:
|
||||
byte = int(toks[0],16)
|
||||
bytes.append(byte)
|
||||
|
||||
def revbits(n):
|
||||
r = 0
|
||||
for i in range(0,8):
|
||||
if (n & (1<<i)):
|
||||
r |= (1<<(7-i))
|
||||
return r
|
||||
|
||||
# output font table
|
||||
x = 0
|
||||
output = []
|
||||
revoutput = []
|
||||
rotoutput = []
|
||||
rot2output = []
|
||||
for ch in range(lochar,hichar+1):
|
||||
bytes = chars.get(ch)
|
||||
if not bytes:
|
||||
bytes = [0] * height
|
||||
if flip:
|
||||
bytes.reverse()
|
||||
if mirror:
|
||||
for i in range(0,height):
|
||||
bytes[i] = revbits(bytes[i])
|
||||
if rotate:
|
||||
rotbytes = [0] * height
|
||||
for x in range(0,height):
|
||||
for y in range(0,height):
|
||||
rotbytes[-1-x] |= (((bytes[-1-y]>>x)&1)<<y)
|
||||
bytes = rotbytes
|
||||
#rotoutput[-7+x] |= (((output[-1-y]>>x)&1)<<y)
|
||||
#rotoutput[-1-x] |= (((output[-1-y]>>x)&1)<<y)
|
||||
#rot2output[-1-x] |= (((output[-7+y]>>x)&1)<<y)
|
||||
for b in bytes:
|
||||
output.append(b)
|
||||
|
||||
def tohex(v):
|
||||
return '%02x'%v
|
||||
def tohex2(v):
|
||||
return '0x%02x'%v
|
||||
def tohexv(v):
|
||||
return "8'h%02x"%v
|
||||
|
||||
for arr in [output]:
|
||||
if args.asmhex:
|
||||
print('\thex ' + ''.join(list(map(tohex,arr))))
|
||||
if args.asmdb:
|
||||
for i in range(0,len(output),height):
|
||||
print('.DB', ','.join(list(map(tohex2,arr[i:i+height]))), ';%d'%(i/height+lochar))
|
||||
if args.carray:
|
||||
print("static char FONT[%d][%d] = {" % (hichar-lochar+1, height))
|
||||
for i in range(0,len(output),height):
|
||||
print('{', ','.join(list(map(tohex2,arr[i:i+height]))), '},', end=' ')
|
||||
print()
|
||||
print("};")
|
||||
if args.flatcarray:
|
||||
print("static char FONT[%d] = {" % ((hichar-lochar+1) * height))
|
||||
print(','.join(list(map(tohex2,arr))))
|
||||
print("}");
|
||||
if args.verilog:
|
||||
j = 0
|
||||
for i in range(0,len(output),height):
|
||||
print(','.join(list(map(tohexv,arr[i:i+height]))) + ", //%d" % (i/height))
|
||||
j += 1
|
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
|
||||
# reverse byte
|
||||
def rev(n):
|
||||
return int('{:08b}'.format(n)[::-1], 2)
|
||||
|
||||
# output bits in given range
|
||||
def out(i, pix, lb, hb, reverse=0, shift=0):
|
||||
x = (pix >> lb) & ((1<<(hb-lb))-1)
|
||||
if reverse:
|
||||
x = rev(x)
|
||||
if shift:
|
||||
x = x << shift
|
||||
assert(x>=0 and x<=255)
|
||||
output[i].append(x)
|
||||
|
||||
# read PBM (binary P4 format) file
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
# read PBM header
|
||||
header = f.readline().strip()
|
||||
assert(header == 'P4')
|
||||
dims = f.readline().strip()
|
||||
while dims[0] == '#':
|
||||
dims = f.readline().strip()
|
||||
width,height = map(int, dims.split())
|
||||
wbytes = (width+7)/8
|
||||
data = f.read()
|
||||
print("{%d,%d," % (wbytes,height), end='')
|
||||
for i in range(0,len(data)):
|
||||
if i>0:
|
||||
sys.stdout.write(",")
|
||||
ofs = i+wbytes-(i%wbytes)*2-1
|
||||
sys.stdout.write( "0x%02x" % ord(data[ofs]) )
|
||||
print("}")
|
||||
|
@ -1,46 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, array, string
|
||||
|
||||
col0 = 0
|
||||
|
||||
def tocolor(x):
|
||||
if x == 0:
|
||||
return 0
|
||||
else:
|
||||
return x + col0
|
||||
|
||||
def tohex2(v):
|
||||
return '0x%02x'%v
|
||||
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
data = array.array('B', f.read())
|
||||
assert data[0] == 0xa
|
||||
assert data[3] == 8
|
||||
|
||||
# palette
|
||||
print("byte palette[16] = {", end='')
|
||||
for i in range(0,16):
|
||||
r = data[16+i*3]
|
||||
g = data[17+i*3]
|
||||
b = data[18+i*3]
|
||||
entry = (r>>5) | ((g>>2)&0x38) | (b&0xc0)
|
||||
print('%s,' % (tohex2(entry)), end='')
|
||||
print("}")
|
||||
|
||||
# image data
|
||||
width = (data[9] << 8) + data[8] + 1
|
||||
height = (data[11] << 8) + data[10] + 1
|
||||
rowlen = (data[0x43] << 8) + data[0x42]
|
||||
print("const byte sprite[] = {")
|
||||
print("%d,%d," % ((width+1)/2,height))
|
||||
for y in range(0,height):
|
||||
ofs = 0x80 + y*rowlen
|
||||
output = []
|
||||
for x in range(0,width,2):
|
||||
b = (tocolor(data[ofs]) << 4) + tocolor(data[ofs+1])
|
||||
output.append(b)
|
||||
ofs += 2
|
||||
print(','.join(map(tohex2,output)) + ',')
|
||||
print("}")
|
||||
|
@ -1,83 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var fs = require('fs'),
|
||||
PNG = require('pngjs').PNG,
|
||||
RgbQuant = require('rgbquant');
|
||||
|
||||
var data = fs.readFileSync(process.argv[2]);
|
||||
var png = PNG.sync.read(data);
|
||||
q = new RgbQuant();
|
||||
q.colors = 4;
|
||||
q.sample(png.data);
|
||||
pal = q.palette(false, true);
|
||||
//console.log(q);
|
||||
|
||||
function readfonttxt(s) {
|
||||
var lines = s.split(/\r?\n/);// TODO
|
||||
}
|
||||
|
||||
function remapBits(x, arr) {
|
||||
if (!arr) return x;
|
||||
var y = 0;
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
var s = arr[i];
|
||||
if (s < 0) {
|
||||
s = -s-1;
|
||||
y ^= 1 << s;
|
||||
}
|
||||
if (x & (1 << i)) {
|
||||
y ^= 1 << s;
|
||||
}
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
function reorder(arrin, remap) {
|
||||
var out = [];
|
||||
for (var i=0; i<arrin.length; i++) {
|
||||
var j = remapBits(i, remap);
|
||||
//console.log(i,j);
|
||||
if (j >= arrin.length) throw i+" -> "+j+" >= "+arrin.length;
|
||||
out.push(arrin[j] | 0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function packbits(arrin, bpp, brev) {
|
||||
var out = new Uint8Array((arrin.length * bpp) >> 3);
|
||||
for (var i=0; i<arrin.length; i++) {
|
||||
var j = (i * bpp) >> 3;
|
||||
var s = (i * bpp) & 7;
|
||||
if (brev) s = 8-bpp-s;
|
||||
out[j] |= arrin[i] << s;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function hex(n) {
|
||||
return (n < 16 ? "0" : "") + n.toString(16);
|
||||
}
|
||||
|
||||
function dump(arr, bpl) {
|
||||
var s = '';
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
if (i % bpl == 0) {
|
||||
s += '\n.byte ';
|
||||
} else {
|
||||
s += ',';
|
||||
}
|
||||
s += '$' + hex(arr[i]);
|
||||
}
|
||||
s += '\n';
|
||||
return s;
|
||||
}
|
||||
|
||||
idximg = q.reduce(png.data, 2);
|
||||
//idximg = idximg.slice(0, 8*16*128);
|
||||
//idximg = idximg.slice(8*16*64);
|
||||
idx2 = reorder(idximg, [0,1,2,3,4,5,6,11,12,13,-8,-9,-10,-11]); // 8x16 font
|
||||
//idx2 = reorder(idximg, [0,1,2,3,5,6,11,12,13,99,-8,-9,-10,-5]); // 8x16 CHR tileset
|
||||
idx3 = packbits(idx2, 2, true);
|
||||
//console.log(idximg.length, idx2.length, idx3.length);
|
||||
console.log(dump(idx3, 8));
|
||||
console.log(";;",idx3.length,"bytes,",pal.length/4,'colors');
|
@ -1,462 +0,0 @@
|
||||
|
||||
/*
|
||||
---------------------------------------------------------------
|
||||
TMSOPT v.0.1 - Eduardo A. Robsy Petrus & Arturo Ragozini 2007
|
||||
Credits to Rafael Jannone for his Floyd-Steinberg implementation
|
||||
---------------------------------------------------------------
|
||||
TGA image converter (24 bpp, uncompressed) to TMS9918 format
|
||||
---------------------------------------------------------------
|
||||
Overview
|
||||
---------------------------------------------------------------
|
||||
Selects the best solution for each 8x1 pixel block
|
||||
Optimization uses the following algorithm:
|
||||
|
||||
(a) Select one 1x8 block, select a couple of colors, apply
|
||||
Floyd-Steinberg within the block, compute the squared error,
|
||||
repeat for all 105 color combinations, keep the best couple
|
||||
of colors.
|
||||
|
||||
(b) Apply Floyd-Steinberg to the current 1x8 block with the best
|
||||
two colors seleted before and spread the errors to the
|
||||
adjacent blocks.
|
||||
|
||||
(c) repeat (a) and (b) on the next 1x8 block, scan all lines.
|
||||
|
||||
(d) Convert the image in pattern and color definitions (CHR & CLR)
|
||||
|
||||
To load in MSX basic use something like this:
|
||||
|
||||
10 screen 2: color 15,0,0
|
||||
20 bload"FILE.CHR",s
|
||||
30 bload"FILE.CLR",s
|
||||
40 goto 40
|
||||
|
||||
---------------------------------------------------------------
|
||||
Compilation instructions
|
||||
---------------------------------------------------------------
|
||||
Tested with GCC/Win32 [mingw]:
|
||||
|
||||
GCC TMSopt.c -oTMSopt.exe -O3 -s
|
||||
|
||||
It is standard C, so there is a fair chance of being portable!
|
||||
NOTE
|
||||
In the current release the name of the C file has become scr2floyd.c
|
||||
---------------------------------------------------------------
|
||||
History
|
||||
---------------------------------------------------------------
|
||||
Ages ago - algorithm created
|
||||
16/05/2007 - first C version (RAW format)
|
||||
17/05/2007 - TGA format included, some optimization included
|
||||
18/05/2007 - Big optimization (200 times faster), support for
|
||||
square errors
|
||||
19/05/2007 - Floyd-Stenberg added, scaling for better rounding
|
||||
24/05/2007 - Floyd-Stenberg included in the color optimization.
|
||||
---------------------------------------------------------------
|
||||
Legal disclaimer
|
||||
---------------------------------------------------------------
|
||||
Do whatever you want to do with this code/program.
|
||||
Use at your own risk, all responsability would be declined.
|
||||
It would be nice if you credit the authors, though.
|
||||
---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Headers!
|
||||
|
||||
#include<stdio.h>
|
||||
#include<time.h>
|
||||
#include<limits.h>
|
||||
#include<stdlib.h>
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define scale 16
|
||||
#define inrange8(t) ((t)<0) ? 0 :(((t)>255) ? 255:(t))
|
||||
#define clamp(t) ((t)<0) ? 0 :(((t)>255*scale) ? 255*scale : (t))
|
||||
|
||||
// Just one function for everything
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
// Vars
|
||||
|
||||
FILE *file,*CHR,*CLR;
|
||||
int bc,bp,i,j,x,y,c,p,k,MAXX,MAXY;
|
||||
uint n,total=0,done=0,size;
|
||||
char *name;
|
||||
short image[512+2][512+2][3],header[18],palette[16][3];
|
||||
|
||||
// TMS9918 RGB palette - approximated 50Hz PAL values
|
||||
uint pal[16][3]= {
|
||||
{ 0,0,0}, // 0 Transparent
|
||||
{ 0,0,0}, // 1 Black 0 0 0
|
||||
{ 33,200,66}, // 2 Medium green 33 200 66
|
||||
{ 94,220,120}, // 3 Light green 94 220 120
|
||||
{ 84,85,237}, // 4 Dark blue 84 85 237
|
||||
{ 125,118,252}, // 5 Light blue 125 118 252
|
||||
{ 212,82,77}, // 6 Dark red 212 82 77
|
||||
{ 66,235,245}, // 7 Cyan 66 235 245
|
||||
{ 252,85,84}, // 8 Medium red 252 85 84
|
||||
{ 255,121,120}, // 9 Light red 255 121 120
|
||||
{ 212,193,84}, // A Dark yellow 212 193 84
|
||||
{ 230,206,128}, // B Light yellow 230 206 128
|
||||
{ 33,176,59}, // C Dark green 33 176 59
|
||||
{ 201,91,186}, // D Magenta 201 91 186
|
||||
{ 204,204,204}, // E Gray 204 204 204
|
||||
{ 255,255,255} // F White 255 255 255
|
||||
};
|
||||
// Scale palette
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
for (k=0;k<3;k++)
|
||||
palette[i][k] = scale*pal[i][k];
|
||||
|
||||
// Get time
|
||||
|
||||
clock();
|
||||
|
||||
// Application prompt
|
||||
|
||||
printf("TMSopt v.0.1 - TGA 24bpp to TMS9918 converter.\nCoded by Eduardo A. Robsy Petrus & Arturo Ragozini 2007.\n\n");
|
||||
printf("Credits to Rafael Jannone for his Floyd-Steinberg implementation.\n \n");
|
||||
|
||||
|
||||
// Guess the name of the image I used for testing
|
||||
#ifdef DEBUG
|
||||
argc = 2;
|
||||
argv[1] = malloc(20);
|
||||
argv[1][0] = 'l';
|
||||
argv[1][1] = 'e';
|
||||
argv[1][2] = 'n';
|
||||
argv[1][3] = 'n';
|
||||
argv[1][4] = 'a';
|
||||
argv[1][5] = '_';
|
||||
argv[1][6] = '.';
|
||||
argv[1][7] = 't';
|
||||
argv[1][8] = 'g';
|
||||
argv[1][9] = 'a';
|
||||
argv[1][10] = 0;
|
||||
#endif
|
||||
|
||||
// Test if only one command-line parameter is available
|
||||
|
||||
if (argc==1)
|
||||
{
|
||||
printf("Syntax: TMSopt [file.tga]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open source image (TGA, 24-bit, uncompressed)
|
||||
|
||||
if ((file=fopen(argv[1],"rb"))==NULL)
|
||||
{
|
||||
printf("cannot open %s file!\n",argv[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Read TGA header
|
||||
|
||||
for (i=0;i<18;i++) header[i]=fgetc(file);
|
||||
|
||||
// Check header info
|
||||
|
||||
for (i=0,n=0;i<12;i++) n+=header[i];
|
||||
|
||||
// I deleted the check on n, was it important ?
|
||||
if ((header[2]!=2)||(header[17])||(header[16]!=24))
|
||||
{
|
||||
printf("Unsupported file format!\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Calculate size
|
||||
|
||||
MAXX=header[12]|header[13]<<8;
|
||||
MAXY=header[14]|header[15]<<8;
|
||||
|
||||
size=((MAXX+7)>>3)*MAXY;
|
||||
|
||||
// Check size limits
|
||||
|
||||
if ((!MAXX)||(MAXX>512)||(!MAXY)||(MAXY>512))
|
||||
{
|
||||
printf("Unsupported size!");
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Load image data
|
||||
|
||||
for (y=MAXY-1;y>=0;y--)
|
||||
for (x=0;x<MAXX;x++)
|
||||
for (k=0;k<3;k++)
|
||||
image[x+1][y+1][2-k]=((short)fgetc(file))*scale; // Scale image
|
||||
|
||||
for (x=0;x<MAXX;x++)
|
||||
for (k=0;k<3;k++)
|
||||
image[x][0][k] = image[x][1][k];
|
||||
|
||||
for (y=0;y<MAXY;y++)
|
||||
for (k=0;k<3;k++)
|
||||
image[0][y][k] = image[1][0][k];
|
||||
|
||||
|
||||
// Close file
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Information
|
||||
|
||||
printf("Converting %s (%i,%i) to TMS9918 format ",argv[1],MAXX,MAXY);
|
||||
printf("in (%i,%i) screen 2 tiles... ",((MAXX+7)>>3),((MAXY+7)>>3));
|
||||
|
||||
|
||||
// Image processing
|
||||
|
||||
for (y=0;y<((MAXY+7)>>3);y++)
|
||||
for (j=0;j<8;j++)
|
||||
for (x=0;x<((MAXX+7)>>3);x++)
|
||||
{
|
||||
// Generate alternatives
|
||||
uchar c1, c2;
|
||||
uchar bc1, bc2;
|
||||
uint bv;
|
||||
uint bs = INT_MAX;
|
||||
|
||||
uint yy = 1+((y<<3)|j);
|
||||
|
||||
for (c1=1;c1<16;c1++)
|
||||
{
|
||||
ushort c1r,c1g,c1b;
|
||||
|
||||
c1r = palette[c1][0];
|
||||
c1g = palette[c1][1];
|
||||
c1b = palette[c1][2];
|
||||
|
||||
for (c2=c1+1;c2<16;c2++)
|
||||
{
|
||||
ushort c2r,c2g,c2b;
|
||||
ushort r,g,b;
|
||||
|
||||
uint cs = 0;
|
||||
uint cv = 0;
|
||||
|
||||
uint xx = 1+(x<<3);
|
||||
|
||||
c2r = palette[c2][0];
|
||||
c2g = palette[c2][1];
|
||||
c2b = palette[c2][2];
|
||||
|
||||
r = clamp(image[xx][yy][0]);
|
||||
g = clamp(image[xx][yy][1]);
|
||||
b = clamp(image[xx][yy][2]);
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
short e10 = (r-c1r);
|
||||
short e11 = (g-c1g);
|
||||
short e12 = (b-c1b);
|
||||
uint mc1 = e10*e10+e11*e11+e12*e12;
|
||||
|
||||
short e20 = (r-c2r);
|
||||
short e21 = (g-c2g);
|
||||
short e22 = (b-c2b);
|
||||
uint mc2 = e20*e20+e21*e21+e22*e22;
|
||||
|
||||
cs += (mc1>mc2) ? mc2 : mc1;
|
||||
|
||||
if (cs>bs) break;
|
||||
|
||||
cv |= ((mc1>mc2)<<i);
|
||||
|
||||
xx++;
|
||||
if (mc1>mc2)
|
||||
{
|
||||
r = clamp(image[xx][yy][0]) + 7*e20/16 ;
|
||||
g = clamp(image[xx][yy][1]) + 7*e21/16 ;
|
||||
b = clamp(image[xx][yy][2]) + 7*e22/16 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = clamp(image[xx][yy][0]) + 7*e10/16 ;
|
||||
g = clamp(image[xx][yy][1]) + 7*e11/16 ;
|
||||
b = clamp(image[xx][yy][2]) + 7*e12/16 ;
|
||||
}
|
||||
}
|
||||
if (cs<bs)
|
||||
{
|
||||
bs = cs;
|
||||
bv = cv;
|
||||
bc1 = c1;
|
||||
bc2 = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Here we have the best colors and the best pattern for line j
|
||||
|
||||
short quant_error;
|
||||
|
||||
uint xx = 1+((x<<3));
|
||||
|
||||
for (i=0;i<8;i++,xx++)
|
||||
for (k=0;k<3;k++)
|
||||
{
|
||||
// Compute the quantization error
|
||||
|
||||
if (bv&(1<<i))
|
||||
{
|
||||
quant_error = (clamp(image[xx][yy][k]) - palette[bc2][k])/16;
|
||||
image[xx][yy][k] = palette[bc2][k];
|
||||
}
|
||||
else
|
||||
{
|
||||
quant_error = (clamp(image[xx][yy][k]) - palette[bc1][k])/16;
|
||||
image[xx][yy][k] = palette[bc1][k];
|
||||
}
|
||||
|
||||
// Spread the quantization error
|
||||
|
||||
short q2 = quant_error<<1;
|
||||
image[xx+1][yy+1][k] = clamp(image[xx+1][yy+1][k])+ quant_error; // 1 *
|
||||
quant_error += q2 ;
|
||||
image[xx-1][yy+1][k] = clamp(image[xx-1][yy+1][k])+ quant_error; // 3 *
|
||||
quant_error += q2 ;
|
||||
image[xx+0][yy+1][k] = clamp(image[xx+0][yy+1][k])+ quant_error; // 5 *
|
||||
quant_error += q2 ;
|
||||
image[xx+1][yy+0][k] = clamp(image[xx+1][yy+0][k])+ quant_error; // 7 *
|
||||
}
|
||||
|
||||
|
||||
// Update status counter
|
||||
|
||||
if (done*100/size<(done+1)*100/size)
|
||||
printf("\b\b\b%2i%%",100*done/size);
|
||||
done++;
|
||||
total++;
|
||||
}
|
||||
|
||||
|
||||
// Conversion done
|
||||
|
||||
printf("\b\b\bOk \n");
|
||||
|
||||
|
||||
// Create TMS output files (CHR, CLR)
|
||||
|
||||
argv[1][strlen(argv[1])-3]='C';
|
||||
argv[1][strlen(argv[1])-2]='H';
|
||||
argv[1][strlen(argv[1])-1]='R';
|
||||
CHR=fopen(argv[1],"wb");
|
||||
|
||||
argv[1][strlen(argv[1])-2]='L';
|
||||
CLR=fopen(argv[1],"wb");
|
||||
|
||||
fputc(0xFE,CLR); // Binary data
|
||||
fputc(0x00,CLR); // Start at 2000h
|
||||
fputc(0x20,CLR);
|
||||
fputc(0xFF,CLR); // Stop at 37FFh
|
||||
fputc(0x37,CLR);
|
||||
fputc(0x00,CLR); // Run
|
||||
fputc(0x00,CLR);
|
||||
|
||||
|
||||
fputc(0xFE,CHR); // Binary data
|
||||
fputc(0x00,CHR); // Start at 0000h
|
||||
fputc(0x00,CHR);
|
||||
fputc(0xFF,CHR); // Stop at 17FFh
|
||||
fputc(0x17,CHR);
|
||||
fputc(0x00,CHR); // Run
|
||||
fputc(0x00,CHR);
|
||||
|
||||
// Save best pattern and colour combination
|
||||
// NOTE1:
|
||||
// THIS PART CAN BE LARGELY CUTTED AND OPTIMIZED REUSING
|
||||
// RESULTS FROM THE PREVIOUS LOOP, BUT WHO CARES?
|
||||
// NOTE2:
|
||||
// This code can be used for conversion without dithering
|
||||
|
||||
for (y=0;y<((MAXY+7)>>3);y++)
|
||||
for (x=0;(x<(MAXX+7)>>3);x++)
|
||||
for (j=0;j<8;j++)
|
||||
{
|
||||
uchar c1,c2;
|
||||
uint bs = INT_MAX;
|
||||
uchar bp = 0, bc = 0;
|
||||
|
||||
uint yy = 1+((y<<3)|j);
|
||||
|
||||
for (c1=1;c1<16;c1++)
|
||||
for (c2=c1+1;c2<16;c2++)
|
||||
{
|
||||
uint cs = 0;
|
||||
uint cp = 0;
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
uint xx = 1+((x<<3)|i);
|
||||
|
||||
short u0 = (palette[c1][0]-image[xx][yy][0]);
|
||||
short u1 = (palette[c1][1]-image[xx][yy][1]);
|
||||
short u2 = (palette[c1][2]-image[xx][yy][2]);
|
||||
uint mc1 = u0*u0+u1*u1+u2*u2;
|
||||
|
||||
short v0 = (palette[c2][0]-image[xx][yy][0]);
|
||||
short v1 = (palette[c2][1]-image[xx][yy][1]);
|
||||
short v2 = (palette[c2][2]-image[xx][yy][2]);
|
||||
uint mc2 = v0*v0+v1*v1+v2*v2;
|
||||
|
||||
cp = (cp<<1) | (mc1>mc2);
|
||||
cs += (mc1>mc2) ? mc2 : mc1;
|
||||
if (cs>bs) break;
|
||||
}
|
||||
if (cs<bs)
|
||||
{
|
||||
bs=cs;
|
||||
bp=cp;
|
||||
bc=c2*16+c1;
|
||||
}
|
||||
}
|
||||
|
||||
fputc(bc,CLR);
|
||||
fputc(bp,CHR);
|
||||
}
|
||||
|
||||
|
||||
fclose(CHR);
|
||||
fclose(CLR);
|
||||
|
||||
// Generate new name
|
||||
|
||||
name = malloc(0x100);
|
||||
argv[1][strlen(argv[1])-4]=0;
|
||||
strcpy(name,argv[1]);
|
||||
strcat(name,"_tms.tga");
|
||||
|
||||
// Save file header
|
||||
|
||||
file=fopen(name,"wb");
|
||||
|
||||
for (i=0;i<18;i++) fputc(header[i],file);
|
||||
|
||||
// Save image data
|
||||
|
||||
for (y=MAXY-1;y>=0;y--)
|
||||
for (x=0;x<MAXX;x++)
|
||||
for (k=0;k<3;k++)
|
||||
fputc(inrange8(image[1+x][1+y][2-k]/scale),file); // Scale to char
|
||||
|
||||
// Close file
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Prompt elapsed time
|
||||
|
||||
printf("%.2f million combinations analysed in %.2f seconds.\n",total/1e6,(float)clock()/(float)CLOCKS_PER_SEC);
|
||||
printf("Note: the .CLR and .CHR files have correct headers only for 256x192 images. \n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,476 +0,0 @@
|
||||
|
||||
/*
|
||||
---------------------------------------------------------------
|
||||
TMSOPT v.0.1 - Eduardo A. Robsy Petrus & Arturo Ragozini 2007
|
||||
Credits to Rafael Jannone for his Floyd-Steinberg implementation
|
||||
---------------------------------------------------------------
|
||||
TGA image converter (24 bpp, uncompressed) to TMS9918 format
|
||||
---------------------------------------------------------------
|
||||
Overview
|
||||
---------------------------------------------------------------
|
||||
Selects the best solution for each 8x1 pixel block
|
||||
Optimization uses the following algorithm:
|
||||
|
||||
(a) Select one 1x8 block, select a couple of colors, apply
|
||||
Floyd-Steinberg within the block, compute the squared error,
|
||||
repeat for all 105 color combinations, keep the best couple
|
||||
of colors.
|
||||
|
||||
(b) Apply Floyd-Steinberg to the current 1x8 block with the best
|
||||
two colors seleted before and spread the errors to the
|
||||
adjacent blocks.
|
||||
|
||||
(c) repeat (a) and (b) on the next 1x8 block, scan all lines.
|
||||
|
||||
(d) Convert the image in pattern and color definitions (CHR & CLR)
|
||||
|
||||
To load in MSX basic use something like this:
|
||||
|
||||
10 screen 2: color 15,0,0
|
||||
20 bload"FILE.CHR",s
|
||||
30 bload"FILE.CLR",s
|
||||
40 goto 40
|
||||
|
||||
---------------------------------------------------------------
|
||||
Compilation instructions
|
||||
---------------------------------------------------------------
|
||||
Tested with GCC/Win32 [mingw]:
|
||||
|
||||
GCC TMSopt.c -oTMSopt.exe -O3 -s
|
||||
|
||||
It is standard C, so there is a fair chance of being portable!
|
||||
NOTE
|
||||
In the current release the name of the C file has become scr2floyd.c
|
||||
---------------------------------------------------------------
|
||||
History
|
||||
---------------------------------------------------------------
|
||||
Ages ago - algorithm created
|
||||
16/05/2007 - first C version (RAW format)
|
||||
17/05/2007 - TGA format included, some optimization included
|
||||
18/05/2007 - Big optimization (200 times faster), support for
|
||||
square errors
|
||||
19/05/2007 - Floyd-Stenberg added, scaling for better rounding
|
||||
24/05/2007 - Floyd-Stenberg included in the color optimization.
|
||||
---------------------------------------------------------------
|
||||
Legal disclaimer
|
||||
---------------------------------------------------------------
|
||||
Do whatever you want to do with this code/program.
|
||||
Use at your own risk, all responsability would be declined.
|
||||
It would be nice if you credit the authors, though.
|
||||
---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Headers!
|
||||
|
||||
#include<stdio.h>
|
||||
#include<time.h>
|
||||
#include<limits.h>
|
||||
#include<stdlib.h>
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define scale 16
|
||||
#define inrange8(t) ((t)<0) ? 0 :(((t)>255) ? 255:(t))
|
||||
#define clamp(t) ((t)<0) ? 0 :(((t)>255*scale) ? 255*scale : (t))
|
||||
|
||||
|
||||
typedef struct {
|
||||
float r, g, b;
|
||||
} RGB;
|
||||
|
||||
float ColourDistance(RGB e1, RGB e2)
|
||||
{
|
||||
float r,g,b;
|
||||
float rmean;
|
||||
|
||||
e1.r/=scale;
|
||||
e1.g/=scale;
|
||||
e1.b/=scale;
|
||||
|
||||
e2.r/=scale;
|
||||
e2.g/=scale;
|
||||
e2.b/=scale;
|
||||
|
||||
rmean = ( (int)e1.r + (int)e2.r ) / 2 ;
|
||||
r = ((int)e1.r - (int)e2.r);
|
||||
g = ((int)e1.g - (int)e2.g);
|
||||
b = ((int)e1.b - (int)e2.b);
|
||||
// return r*r+g*g+b*b;
|
||||
return ((((512+rmean)*r*r)/256) + 4*g*g + (((767-rmean)*b*b)/256));
|
||||
}
|
||||
|
||||
// Just one function for everything
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
// Vars
|
||||
|
||||
FILE *file,*CHR,*CLR;
|
||||
int bc,bp,i,j,x,y,c,p,k,MAXX,MAXY;
|
||||
uint n,total=0,done=0,size;
|
||||
char *name;
|
||||
short image[512+2][512+2][3],header[18],palette[16][3];
|
||||
|
||||
// TMS9918 RGB palette - approximated 50Hz PAL values
|
||||
uint pal[16][3]= {
|
||||
{ 0,0,0}, // 0 Transparent
|
||||
{ 0,0,0}, // 1 Black 0 0 0
|
||||
{ 33,200,66}, // 2 Medium green 33 200 66
|
||||
{ 94,220,120}, // 3 Light green 94 220 120
|
||||
{ 84,85,237}, // 4 Dark blue 84 85 237
|
||||
{ 125,118,252}, // 5 Light blue 125 118 252
|
||||
{ 212,82,77}, // 6 Dark red 212 82 77
|
||||
{ 66,235,245}, // 7 Cyan 66 235 245
|
||||
{ 252,85,84}, // 8 Medium red 252 85 84
|
||||
{ 255,121,120}, // 9 Light red 255 121 120
|
||||
{ 212,193,84}, // A Dark yellow 212 193 84
|
||||
{ 230,206,128}, // B Light yellow 230 206 128
|
||||
{ 33,176,59}, // C Dark green 33 176 59
|
||||
{ 201,91,186}, // D Magenta 201 91 186
|
||||
{ 204,204,204}, // E Gray 204 204 204
|
||||
{ 255,255,255} // F White 255 255 255
|
||||
};
|
||||
// Scale palette
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
for (k=0;k<3;k++)
|
||||
palette[i][k] = scale*pal[i][k];
|
||||
|
||||
// Get time
|
||||
|
||||
clock();
|
||||
|
||||
// Application prompt
|
||||
|
||||
printf("TMSopt v.0.1 - TGA 24bpp to TMS9918 converter.\nCoded by Eduardo A. Robsy Petrus & Arturo Ragozini 2007.\n\n");
|
||||
printf("Credits to Rafael Jannone for his Floyd-Steinberg implementation.\n \n");
|
||||
|
||||
|
||||
// Guess the name of the image I used for testing
|
||||
#ifdef DEBUG
|
||||
argc = 2;
|
||||
argv[1] = malloc(20);
|
||||
argv[1][0] = 'l';
|
||||
argv[1][1] = 'e';
|
||||
argv[1][2] = 'n';
|
||||
argv[1][3] = 'n';
|
||||
argv[1][4] = 'a';
|
||||
argv[1][5] = '_';
|
||||
argv[1][6] = '.';
|
||||
argv[1][7] = 't';
|
||||
argv[1][8] = 'g';
|
||||
argv[1][9] = 'a';
|
||||
argv[1][10] = 0;
|
||||
#endif
|
||||
|
||||
// Test if only one command-line parameter is available
|
||||
|
||||
if (argc==1)
|
||||
{
|
||||
printf("Syntax: TMSopt [file.tga]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open source image (TGA, 24-bit, uncompressed)
|
||||
|
||||
if ((file=fopen(argv[1],"rb"))==NULL)
|
||||
{
|
||||
printf("cannot open %s file!\n",argv[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Read TGA header
|
||||
|
||||
for (i=0;i<18;i++) header[i]=fgetc(file);
|
||||
|
||||
// Check header info
|
||||
|
||||
for (i=0,n=0;i<12;i++) n+=header[i];
|
||||
|
||||
// I deleted the check on n, was it important ?
|
||||
if ((header[2]!=2)||(header[17])||(header[16]!=24))
|
||||
{
|
||||
printf("Unsupported file format!\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Calculate size
|
||||
|
||||
MAXX=header[12]|header[13]<<8;
|
||||
MAXY=header[14]|header[15]<<8;
|
||||
|
||||
size=((MAXX+7)>>3)*MAXY;
|
||||
|
||||
// Check size limits
|
||||
|
||||
if ((!MAXX)||(MAXX>512)||(!MAXY)||(MAXY>512))
|
||||
{
|
||||
printf("Unsupported size!");
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Load image data
|
||||
|
||||
for (y=MAXY-1;y>=0;y--)
|
||||
for (x=0;x<MAXX;x++)
|
||||
for (k=0;k<3;k++)
|
||||
image[x+1][y+1][2-k]=((short)fgetc(file))*scale; // Scale image
|
||||
|
||||
for (x=0;x<MAXX;x++)
|
||||
for (k=0;k<3;k++)
|
||||
image[x][0][k] = image[x][1][k];
|
||||
|
||||
for (y=0;y<MAXY;y++)
|
||||
for (k=0;k<3;k++)
|
||||
image[0][y][k] = image[1][0][k];
|
||||
|
||||
|
||||
// Close file
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Information
|
||||
|
||||
printf("Converting %s (%i,%i) to TMS9918 format ",argv[1],MAXX,MAXY);
|
||||
printf("in (%i,%i) screen 2 tiles... ",((MAXX+7)>>3),((MAXY+7)>>3));
|
||||
|
||||
|
||||
// Image processing
|
||||
|
||||
for (y=0;y<((MAXY+7)>>3);y++)
|
||||
for (j=0;j<8;j++)
|
||||
for (x=0;x<((MAXX+7)>>3);x++)
|
||||
{
|
||||
// Generate alternatives
|
||||
uchar c1, c2;
|
||||
uchar bc1, bc2;
|
||||
uint bv;
|
||||
uint bs = INT_MAX;
|
||||
|
||||
uint yy = 1+((y<<3)|j);
|
||||
|
||||
for (c1=1;c1<16;c1++)
|
||||
{
|
||||
RGB cp1 = {palette[c1][0],palette[c1][1],palette[c1][2]};
|
||||
|
||||
for (c2=c1+1;c2<16;c2++)
|
||||
{
|
||||
RGB cp2 = {palette[c2][0],palette[c2][1],palette[c2][2]};
|
||||
|
||||
uint xx = 1+(x<<3);
|
||||
|
||||
RGB ppp = {clamp(image[xx][yy][0]),clamp(image[xx][yy][1]),clamp(image[xx][yy][2])};
|
||||
|
||||
uint cs = 0;
|
||||
uint cv = 0;
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
short e10 = (ppp.r-cp1.r);
|
||||
short e11 = (ppp.g-cp1.g);
|
||||
short e12 = (ppp.b-cp1.b);
|
||||
long mc1 = ColourDistance(cp1,ppp);
|
||||
|
||||
short e20 = (ppp.r-cp2.r);
|
||||
short e21 = (ppp.g-cp2.g);
|
||||
short e22 = (ppp.b-cp2.b);
|
||||
long mc2 = ColourDistance(cp2,ppp);
|
||||
|
||||
cs += (mc1>mc2) ? mc2 : mc1;
|
||||
|
||||
if (cs>bs) break;
|
||||
|
||||
cv |= ((mc1>mc2)<<i);
|
||||
|
||||
xx++;
|
||||
if (mc1>mc2)
|
||||
{
|
||||
ppp.r = clamp(image[xx][yy][0]) + 7*e20/16;
|
||||
ppp.g = clamp(image[xx][yy][1]) + 7*e21/16;
|
||||
ppp.b = clamp(image[xx][yy][2]) + 7*e22/16;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppp.r = clamp(image[xx][yy][0]) + 7*e10/16;
|
||||
ppp.g = clamp(image[xx][yy][1]) + 7*e11/16;
|
||||
ppp.b = clamp(image[xx][yy][2]) + 7*e12/16;
|
||||
}
|
||||
}
|
||||
if (cs<bs)
|
||||
{
|
||||
bs = cs;
|
||||
bv = cv;
|
||||
bc1 = c1;
|
||||
bc2 = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Here we have the best colors and the best pattern for line j
|
||||
|
||||
short quant_error;
|
||||
|
||||
uint xx = 1+((x<<3));
|
||||
|
||||
for (i=0;i<8;i++,xx++)
|
||||
for (k=0;k<3;k++)
|
||||
{
|
||||
// Compute the quantization error
|
||||
|
||||
if (bv&(1<<i))
|
||||
{
|
||||
quant_error = (clamp(image[xx][yy][k]) - palette[bc2][k])/16;
|
||||
image[xx][yy][k] = palette[bc2][k];
|
||||
}
|
||||
else
|
||||
{
|
||||
quant_error = (clamp(image[xx][yy][k]) - palette[bc1][k])/16;
|
||||
image[xx][yy][k] = palette[bc1][k];
|
||||
}
|
||||
|
||||
// Spread the quantization error
|
||||
|
||||
short q2 = quant_error<<1;
|
||||
image[xx+1][yy+1][k] = clamp(image[xx+1][yy+1][k])+ quant_error; // 1 *
|
||||
quant_error += q2 ;
|
||||
image[xx-1][yy+1][k] = clamp(image[xx-1][yy+1][k])+ quant_error; // 3 *
|
||||
quant_error += q2 ;
|
||||
image[xx+0][yy+1][k] = clamp(image[xx+0][yy+1][k])+ quant_error; // 5 *
|
||||
quant_error += q2 ;
|
||||
image[xx+1][yy+0][k] = clamp(image[xx+1][yy+0][k])+ quant_error; // 7 *
|
||||
}
|
||||
|
||||
|
||||
// Update status counter
|
||||
|
||||
if (done*100/size<(done+1)*100/size)
|
||||
printf("\b\b\b%2i%%",100*done/size);
|
||||
done++;
|
||||
total++;
|
||||
}
|
||||
|
||||
|
||||
// Conversion done
|
||||
|
||||
printf("\b\b\bOk \n");
|
||||
|
||||
|
||||
// Create TMS output files (CHR, CLR)
|
||||
|
||||
argv[1][strlen(argv[1])-3]='C';
|
||||
argv[1][strlen(argv[1])-2]='H';
|
||||
argv[1][strlen(argv[1])-1]='R';
|
||||
CHR=fopen(argv[1],"wb");
|
||||
|
||||
argv[1][strlen(argv[1])-2]='L';
|
||||
CLR=fopen(argv[1],"wb");
|
||||
|
||||
fputc(0xFE,CLR); // Binary data
|
||||
fputc(0x00,CLR); // Start at 2000h
|
||||
fputc(0x20,CLR);
|
||||
fputc(0xFF,CLR); // Stop at 37FFh
|
||||
fputc(0x37,CLR);
|
||||
fputc(0x00,CLR); // Run
|
||||
fputc(0x00,CLR);
|
||||
|
||||
|
||||
fputc(0xFE,CHR); // Binary data
|
||||
fputc(0x00,CHR); // Start at 0000h
|
||||
fputc(0x00,CHR);
|
||||
fputc(0xFF,CHR); // Stop at 17FFh
|
||||
fputc(0x17,CHR);
|
||||
fputc(0x00,CHR); // Run
|
||||
fputc(0x00,CHR);
|
||||
|
||||
// Save best pattern and colour combination
|
||||
// NOTE1:
|
||||
// THIS PART CAN BE LARGELY CUTTED AND OPTIMIZED REUSING
|
||||
// RESULTS FROM THE PREVIOUS LOOP, BUT WHO CARES?
|
||||
// NOTE2:
|
||||
// This code can be used for conversion without dithering
|
||||
|
||||
for (y=0;y<((MAXY+7)>>3);y++)
|
||||
for (x=0;(x<(MAXX+7)>>3);x++)
|
||||
for (j=0;j<8;j++)
|
||||
{
|
||||
uchar c1,c2;
|
||||
uint bs = INT_MAX;
|
||||
uchar bp = 0, bc = 0;
|
||||
|
||||
uint yy = 1+((y<<3)|j);
|
||||
|
||||
for (c1=1;c1<16;c1++)
|
||||
{
|
||||
RGB cp1 = {palette[c1][0],palette[c1][1],palette[c1][2]};
|
||||
for (c2=c1+1;c2<16;c2++)
|
||||
{
|
||||
RGB cp2 = {palette[c2][0],palette[c2][1],palette[c2][2]};
|
||||
uint cs = 0;
|
||||
uint cp = 0;
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
uint xx = 1+((x<<3)|i);
|
||||
RGB ppp = {clamp(image[xx][yy][0]),clamp(image[xx][yy][1]),clamp(image[xx][yy][2])};
|
||||
|
||||
long mc1 = ColourDistance(cp1,ppp);
|
||||
long mc2 = ColourDistance(cp2,ppp);
|
||||
|
||||
cp = (cp<<1) | (mc1>mc2);
|
||||
cs += (mc1>mc2) ? mc2 : mc1;
|
||||
if (cs>bs) break;
|
||||
}
|
||||
if (cs<bs)
|
||||
{
|
||||
bs=cs;
|
||||
bp=cp;
|
||||
bc=c2*16+c1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fputc(bc,CLR);
|
||||
fputc(bp,CHR);
|
||||
}
|
||||
|
||||
|
||||
fclose(CHR);
|
||||
fclose(CLR);
|
||||
|
||||
// Generate new name
|
||||
|
||||
name = malloc(0x100);
|
||||
argv[1][strlen(argv[1])-4]=0;
|
||||
strcpy(name,argv[1]);
|
||||
strcat(name,"_tms.tga");
|
||||
|
||||
// Save file header
|
||||
|
||||
file=fopen(name,"wb");
|
||||
|
||||
for (i=0;i<18;i++) fputc(header[i],file);
|
||||
|
||||
// Save image data
|
||||
|
||||
for (y=MAXY-1;y>=0;y--)
|
||||
for (x=0;x<MAXX;x++)
|
||||
for (k=0;k<3;k++)
|
||||
fputc(inrange8(image[1+x][1+y][2-k]/scale),file); // Scale to char
|
||||
|
||||
// Close file
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Prompt elapsed time
|
||||
|
||||
printf("%.2f million combinations analysed in %.2f seconds.\n",total/1e6,(float)clock()/(float)CLOCKS_PER_SEC);
|
||||
printf("Note: the .CLR and .CHR files have correct headers only for 256x192 images. \n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, zipfile
|
||||
|
||||
OUTFILE = 'scramble.zip'
|
||||
|
||||
ROMS = [
|
||||
( "s1.2d", 0x0000, 0x0800),
|
||||
( "s2.2e", 0x0800, 0x0800),
|
||||
( "s3.2f", 0x1000, 0x0800),
|
||||
( "s4.2h", 0x1800, 0x0800),
|
||||
( "s5.2j", 0x2000, 0x0800),
|
||||
( "s6.2l", 0x2800, 0x0800),
|
||||
( "s7.2m", 0x3000, 0x0800),
|
||||
( "s8.2p", 0x3800, 0x0800),
|
||||
# ROM_REGION( 0x10000, "audiocpu", 0 )
|
||||
( "ot1.5c", 0x0000, 0x0800),
|
||||
( "ot2.5d", 0x0800, 0x0800),
|
||||
( "ot3.5e", 0x1000, 0x0800),
|
||||
# ROM_REGION( 0x1000, "gfx1", 0 )
|
||||
( "c2.5f", 0x4000, 0x0800),
|
||||
( "c1.5h", 0x4800, 0x0800),
|
||||
# ROM_REGION( 0x0020, "proms", 0 )
|
||||
( "c01s.6e", 0x5000, 0x0020),
|
||||
]
|
||||
|
||||
fn = sys.argv[1]
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
print "Read %d bytes of %s" % (len(data), fn)
|
||||
|
||||
with zipfile.ZipFile(OUTFILE, 'w') as zipf:
|
||||
for name,start,length in ROMS:
|
||||
romdata = data[start:start+length]
|
||||
if len(romdata) != length:
|
||||
print "*** No data for %s (offset 0x%x)" % (name,start)
|
||||
romdata = '\0' * length
|
||||
zipf.writestr(name, romdata)
|
||||
else:
|
||||
print 'Wrote %s (%d bytes)' % (name, length)
|
||||
zipf.writestr(name, romdata)
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
|
||||
import math
|
||||
|
||||
#n = 8
|
||||
#m = 127
|
||||
|
||||
n = 32
|
||||
m = 127
|
||||
|
||||
n = 4
|
||||
m = 7
|
||||
|
||||
for i in range(0,n*4):
|
||||
print('%d,' % int(round(math.sin(i*math.pi/2/n)*m)), end='')
|
||||
if i % 16 == 15:
|
||||
print('')
|
@ -1,71 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
from xml.dom import minidom
|
||||
|
||||
def textToFloat(name):
|
||||
if name:
|
||||
return float(name)
|
||||
else:
|
||||
return None
|
||||
|
||||
def textToColor(name,opacity):
|
||||
if name is None or not name[0] == '#':
|
||||
return None
|
||||
color = int(name[1:],16) << 8
|
||||
if opacity:
|
||||
print(('opacity',opacity))
|
||||
return color
|
||||
|
||||
svg_file = sys.argv[1]
|
||||
|
||||
doc = minidom.parse(svg_file) # parseString also exists
|
||||
groups = doc.getElementsByTagName('g')
|
||||
for grp in groups:
|
||||
groupID = grp.getAttribute('id')
|
||||
paths = grp.getElementsByTagName('path')
|
||||
print((groupID,paths))
|
||||
if len(paths):
|
||||
for path in paths:
|
||||
shape = {}
|
||||
d = path.getAttribute('d')
|
||||
styleAttrs = {}
|
||||
style = path.getAttribute('style')
|
||||
sarr = style.split(';')
|
||||
for s in sarr:
|
||||
nvarr = s.split(':', 2)
|
||||
if len(nvarr) == 2:
|
||||
styleAttrs[nvarr[0]] = nvarr[1]
|
||||
print((path,d,styleAttrs))
|
||||
shape['pts'] = []
|
||||
shape['currentColor'] = textToColor(styleAttrs.get("stroke"), styleAttrs.get("stroke-opacity"))
|
||||
shape['currentWidth'] = textToFloat(styleAttrs.get("strokeWidth"))
|
||||
hidden = "none" == styleAttrs.get("display")
|
||||
cmds = d.split(' ')
|
||||
x = 0
|
||||
y = 0
|
||||
i0 = 0
|
||||
start = True
|
||||
for cmd in cmds:
|
||||
print(cmd)
|
||||
ch = cmd[0]
|
||||
if ch == 'm' or ch == 'l':
|
||||
start = True
|
||||
elif ch == 'z':
|
||||
origin = shape['pts'][i0]
|
||||
shape.lineTo(origin.x, origin.y)
|
||||
elif ch == 'c':
|
||||
skip = True
|
||||
else:
|
||||
xy = cmd.split(',')
|
||||
print(xy)
|
||||
x += float(xy[0])
|
||||
y -= float(xy[1])
|
||||
if start or hidden:
|
||||
shape.moveTo(x,y)
|
||||
else:
|
||||
shape.lineTo(x,y)
|
||||
start = False
|
||||
|
||||
|
||||
doc.unlink()
|
@ -1,17 +0,0 @@
|
||||
|
||||
# convert PBM bitmap to playfield bytes
|
||||
%-pf.hex: %-pf.pbm p4_to_pfbytes.py
|
||||
python p4_to_pfbytes.py $< > $@
|
||||
|
||||
# convert PBM bitmap to 48-pixel sprite
|
||||
%-48.hex: %-48.pbm p4_to_48pix.py
|
||||
python p4_to_48pix.py $< > $@
|
||||
|
||||
# convert JPG to pbm
|
||||
|
||||
%-pf.pbm: %.jpg
|
||||
convert $< -resize 40x192\! -colorspace Gray -dither FloydSteinberg $@
|
||||
|
||||
%-48.pbm: %.jpg
|
||||
convert $< -resize 48x192\! -colorspace Gray -dither FloydSteinberg $@
|
||||
|
@ -1,58 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, struct
|
||||
|
||||
# playfield bytes, one array for each of 6 columns
|
||||
output = [[],[],[],[],[],[]]
|
||||
|
||||
# reverse byte
|
||||
def rev(n):
|
||||
return int('{:08b}'.format(n)[::-1], 2)
|
||||
|
||||
# output bits in given range
|
||||
def out(i, pix, lb, hb, reverse=0, shift=0):
|
||||
x = (pix >> lb) & ((1<<(hb-lb))-1)
|
||||
if reverse:
|
||||
x = rev(x)
|
||||
if shift:
|
||||
x = x << shift
|
||||
assert(x>=0 and x<=255)
|
||||
output[i].append(x)
|
||||
|
||||
# read PBM (binary P4 format) file
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
# read PBM header
|
||||
header = f.readline().strip()
|
||||
assert(header == 'P4')
|
||||
dims = f.readline().strip()
|
||||
if dims[0] == '#':
|
||||
dims = f.readline().strip()
|
||||
width,height = map(int, dims.split())
|
||||
assert(width==48)
|
||||
# read bitmap rows
|
||||
for y in range(0,height):
|
||||
row = bytes(f.read(6) + '\0\0') # pad to 8 bytes
|
||||
# convert to 64-bit integer
|
||||
pix = struct.unpack('<q',row)[0]
|
||||
#print '%010lx' % pix
|
||||
# generate playfield bytes
|
||||
out(0, pix, 0, 8, 0)
|
||||
out(1, pix, 8, 16, 0)
|
||||
out(2, pix, 16, 24, 0)
|
||||
out(3, pix, 24, 32, 0)
|
||||
out(4, pix, 32, 40, 0)
|
||||
out(5, pix, 40, 48, 0)
|
||||
|
||||
# output bitmap tables
|
||||
for c in range(0,6):
|
||||
print "\talign $100"
|
||||
print "Bitmap%d" % c
|
||||
print "\thex 00"
|
||||
s = '\thex '
|
||||
for i in range(0,height):
|
||||
s += '%02x' % output[c][height-i-1]
|
||||
if i % 16 == 15:
|
||||
print s
|
||||
s = '\thex '
|
||||
if len(s)>5:
|
||||
print s
|
@ -1,62 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, struct
|
||||
|
||||
# playfield bytes, one array for each of 6 columns
|
||||
output = [[],[],[],[],[],[]]
|
||||
|
||||
# reverse byte
|
||||
def rev(n):
|
||||
return int('{:08b}'.format(n)[::-1], 2)
|
||||
|
||||
# output bits in given range
|
||||
def out(i, pix, lb, hb, reverse=0, shift=0):
|
||||
x = (pix >> lb) & ((1<<(hb-lb))-1)
|
||||
if reverse:
|
||||
x = rev(x)
|
||||
if shift:
|
||||
x = x << shift
|
||||
assert(x>=0 and x<=255)
|
||||
output[i].append(x)
|
||||
|
||||
# read PBM (binary P4 format) file
|
||||
with open(sys.argv[1],'rb') as f:
|
||||
# read PBM header
|
||||
header = f.readline().strip()
|
||||
assert(header == 'P4')
|
||||
dims = f.readline().strip()
|
||||
if dims[0] == '#':
|
||||
dims = f.readline().strip()
|
||||
width,height = map(int, dims.split())
|
||||
assert(width==40)
|
||||
# read bitmap rows
|
||||
for y in range(0,height):
|
||||
row = bytes(f.read(5) + '\0\0\0') # pad to 8 bytes
|
||||
# convert bytes from MSB first to LSB first
|
||||
row2 = ''
|
||||
for i in range(0,8):
|
||||
row2 += chr(rev(ord(row[i])))
|
||||
# convert to 64-bit integer
|
||||
pix = struct.unpack('<q',row2)[0]
|
||||
#print '%010lx' % pix
|
||||
# generate playfield bytes
|
||||
out(0, pix, 0, 4, 0, 4)
|
||||
out(1, pix, 4, 12, 1)
|
||||
out(2, pix, 12, 20, 0)
|
||||
out(3, pix, 20, 24, 0, 4)
|
||||
out(4, pix, 24, 32, 1)
|
||||
out(5, pix, 32, 40, 0)
|
||||
|
||||
# output bitmap tables
|
||||
for c in range(0,6):
|
||||
#print "\talign $100"
|
||||
print "PFBitmap%d" % c
|
||||
#print "\thex 00"
|
||||
s = '\thex '
|
||||
for i in range(0,height):
|
||||
s += '%02x' % output[c][height-i-1]
|
||||
if i % 16 == 15:
|
||||
print s
|
||||
s = '\thex '
|
||||
if len(s)>5:
|
||||
print s
|
@ -1,118 +0,0 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
|
||||
#define P(x,y) ((((x) & 0xF) << 4) | (((y) & 0xF) << 0))
|
||||
#define FONT_UP 0xFE
|
||||
#define FONT_LAST 0xFF
|
||||
|
||||
const byte vecfont[59][8] = {
|
||||
/*' '*/{ FONT_LAST },
|
||||
/*'!'*/{ P(4,0), P(3,2), P(5,2), P(4,0), FONT_UP, P(4,4), P(4,12), FONT_LAST },
|
||||
/*'"'*/{ P(2,10), P(2,6), FONT_UP, P(6,10), P(6,6), FONT_LAST },
|
||||
/*'#'*/{ P(0,4), P(8,4), P(6,2), P(6,10), P(8,8), P(0,8), P(2,10), P(2,2) },
|
||||
/*'$'*/{ P(6,2), P(2,6), P(6,10), FONT_UP, P(4,12), P(4,0), FONT_LAST },
|
||||
/*'%'*/{ P(0,0), P(8,12), FONT_UP, P(2,10), P(2,8), FONT_UP, P(6,4), P(6,2) },
|
||||
/*'&'*/{ P(8,0), P(4,12), P(8,8), P(0,4), P(4,0), P(8,4), FONT_LAST },
|
||||
/*'''*/{ P(0,12), P(8,0), FONT_LAST },
|
||||
|
||||
/*'('*/{ P(6,0), P(2,4), P(2,8), P(6,12), FONT_LAST },
|
||||
/*')'*/{ P(2,0), P(6,4), P(6,8), P(2,12), FONT_LAST },
|
||||
/*'*'*/{ P(0,0), P(4,12), P(8,0), P(0,8), P(8,8), P(0,0), FONT_LAST },
|
||||
/*'+'*/{ P(1,6), P(7,6), FONT_UP, P(4,9), P(4,3), FONT_LAST },
|
||||
/*','*/{ P(2,0), P(4,2), FONT_LAST },
|
||||
/*'-'*/{ P(2,6), P(6,6), FONT_LAST },
|
||||
/*'.'*/{ P(3,0), P(4,0), FONT_LAST },
|
||||
/*'/'*/{ P(0,0), P(8,12), FONT_LAST },
|
||||
|
||||
/*'0'*/{ P(0,0), P(8,0), P(8,12), P(0,12), P(0,0), P(8,12), FONT_LAST },
|
||||
/*'1'*/{ P(4,0), P(4,12), P(3,10), FONT_LAST },
|
||||
/*'2'*/{ P(0,12), P(8,12), P(8,7), P(0,5), P(0,0), P(8,0), FONT_LAST },
|
||||
/*'3'*/{ P(0,12), P(8,12), P(8,0), P(0,0), FONT_UP, P(0,6), P(8,6), FONT_LAST },
|
||||
/*'4'*/{ P(0,12), P(0,6), P(8,6), FONT_UP, P(8,12), P(8,0), FONT_LAST },
|
||||
/*'5'*/{ P(0,0), P(8,0), P(8,6), P(0,7), P(0,12), P(8,12), FONT_LAST },
|
||||
/*'6'*/{ P(0,12), P(0,0), P(8,0), P(8,5), P(0,7), FONT_LAST },
|
||||
/*'7'*/{ P(0,12), P(8,12), P(8,6), P(4,0), FONT_LAST },
|
||||
|
||||
/*'8'*/{ P(0,0), P(8,0), P(8,12), P(0,12), P(0,0), FONT_UP, P(0,6), P(8,6), },
|
||||
/*'9'*/{ P(8,0), P(8,12), P(0,12), P(0,7), P(8,5), FONT_LAST },
|
||||
/*':'*/{ P(4,9), P(4,7), FONT_UP, P(4,5), P(4,3), FONT_LAST },
|
||||
/*';'*/{ P(4,9), P(4,7), FONT_UP, P(4,5), P(1,2), FONT_LAST },
|
||||
/*'<'*/{ P(6,0), P(2,6), P(6,12), FONT_LAST },
|
||||
/*'='*/{ P(1,4), P(7,4), FONT_UP, P(1,8), P(7,8), FONT_LAST },
|
||||
/*'>'*/{ P(2,0), P(6,6), P(2,12), FONT_LAST },
|
||||
/*'?'*/{ P(0,8), P(4,12), P(8,8), P(4,4), FONT_UP, P(4,1), P(4,0), FONT_LAST },
|
||||
|
||||
/*'@'*/{ P(8,4), P(4,0), P(0,4), P(0,8), P(4,12), P(8,8), P(4,4), P(3,6) },
|
||||
/*'A'*/{ P(0,0), P(0,8), P(4,12), P(8,8), P(8,0), FONT_UP, P(0,4), P(8,4) },
|
||||
/*'B'*/{ P(0,0), P(0,12), P(4,12), P(8,10), P(4,6), P(8,2), P(4,0), P(0,0) },
|
||||
/*'C'*/{ P(8,0), P(0,0), P(0,12), P(8,12), FONT_LAST },
|
||||
/*'D'*/{ P(0,0), P(0,12), P(4,12), P(8,8), P(8,4), P(4,0), P(0,0), FONT_LAST },
|
||||
/*'E'*/{ P(8,0), P(0,0), P(0,12), P(8,12), FONT_UP, P(0,6), P(6,6), FONT_LAST },
|
||||
/*'F'*/{ P(0,0), P(0,12), P(8,12), FONT_UP, P(0,6), P(6,6), FONT_LAST },
|
||||
/*'G'*/{ P(6,6), P(8,4), P(8,0), P(0,0), P(0,12), P(8,12), FONT_LAST },
|
||||
|
||||
/*'H'*/{ P(0,0), P(0,12), FONT_UP, P(0,6), P(8,6), FONT_UP, P(8,12), P(8,0) },
|
||||
/*'I'*/{ P(0,0), P(8,0), FONT_UP, P(4,0), P(4,12), FONT_UP, P(0,12), P(8,12) },
|
||||
/*'J'*/{ P(0,4), P(4,0), P(8,0), P(8,12), FONT_LAST },
|
||||
/*'K'*/{ P(0,0), P(0,12), FONT_UP, P(8,12), P(0,6), P(6,0), FONT_LAST },
|
||||
/*'L'*/{ P(8,0), P(0,0), P(0,12), FONT_LAST },
|
||||
/*'M'*/{ P(0,0), P(0,12), P(4,8), P(8,12), P(8,0), FONT_LAST },
|
||||
/*'N'*/{ P(0,0), P(0,12), P(8,0), P(8,12), FONT_LAST },
|
||||
/*'O'*/{ P(0,0), P(0,12), P(8,12), P(8,0), P(0,0), FONT_LAST },
|
||||
|
||||
/*'P'*/{ P(0,0), P(0,12), P(8,12), P(8,6), P(0,5), FONT_LAST },
|
||||
/*'Q'*/{ P(0,0), P(0,12), P(8,12), P(8,4), P(0,0), FONT_UP, P(4,4), P(8,0) },
|
||||
/*'R'*/{ P(0,0), P(0,12), P(8,12), P(8,6), P(0,5), FONT_UP, P(4,5), P(8,0) },
|
||||
/*'S'*/{ P(0,2), P(2,0), P(8,0), P(8,5), P(0,7), P(0,12), P(6,12), P(8,10) },
|
||||
/*'T'*/{ P(0,12), P(8,12), FONT_UP, P(4,12), P(4,0), FONT_LAST },
|
||||
/*'U'*/{ P(0,12), P(0,2), P(4,0), P(8,2), P(8,12), FONT_LAST },
|
||||
/*'V'*/{ P(0,12), P(4,0), P(8,12), FONT_LAST },
|
||||
/*'W'*/{ P(0,12), P(2,0), P(4,4), P(6,0), P(8,12), FONT_LAST },
|
||||
|
||||
/*'X'*/{ P(0,0), P(8,12), FONT_UP, P(0,12), P(8,0), FONT_LAST },
|
||||
/*'Y'*/{ P(0,12), P(4,6), P(8,12), FONT_UP, P(4,6), P(4,0), FONT_LAST },
|
||||
/*'Z'*/{ P(0,12), P(8,12), P(0,0), P(8,0), FONT_UP, P(2,6), P(6,6), FONT_LAST },
|
||||
};
|
||||
|
||||
////
|
||||
|
||||
static int frame = 0;
|
||||
|
||||
void draw_char(char ch) {
|
||||
const byte* p = vecfont[ch - ' '];
|
||||
byte bright = 0;
|
||||
byte x = 0;
|
||||
byte y = 0;
|
||||
byte i;
|
||||
if (ch < ' ' || ch > 'Z') return;
|
||||
printf("const word VECFONT_%d[] = { ", ch);
|
||||
for (i=0; i<8; i++) {
|
||||
byte b = *p++;
|
||||
if (b == FONT_LAST) break; // last move
|
||||
else if (b == FONT_UP) bright = 0; // pen up
|
||||
else {
|
||||
byte x2 = b>>4;
|
||||
byte y2 = b&15;
|
||||
printf("_SVEC(%d,%d,%d), ", (char)(x2-x), (char)(y2-y), bright);
|
||||
bright = 4;
|
||||
x = x2;
|
||||
y = y2;
|
||||
}
|
||||
}
|
||||
printf("_SVEC(%d,%d,%d), _RTSL() };\n", (char)12-x, (char)-y, 0);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
for (int i=' '; i<='Z'; i++) {
|
||||
draw_char(i);
|
||||
}
|
||||
printf("const word* const VECFONT[] = { ");
|
||||
for (int i=' '; i<='Z'; i++) {
|
||||
printf("VECFONT_%d,", i);
|
||||
}
|
||||
printf(" };\n");
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
|
||||
all: cp437.vicdual.c c64.vicdual.c
|
||||
|
||||
clean:
|
||||
rm -f cp437.vicdual.c c64.vicdual.c
|
||||
|
||||
# convert DOS CP437 font (256 chars)
|
||||
cp437.vicdual.c: ../fonts/cp437-8x8.bdf
|
||||
python ../parsebdf8.py $< -r -C > $@
|
||||
|
||||
# convert C64 font (256 chars, some unused)
|
||||
c64.vicdual.c: ../fonts/c64.bdf
|
||||
python ../parsebdf8.py $< -r -C > $@
|
||||
|
||||
%.h:
|
||||
cat $* | hexdump -v -e '"\n" 128/1 "0x%02x,"'
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys, zipfile
|
||||
|
||||
OUTFILE = 'carnival.zip'
|
||||
|
||||
ROMS = [
|
||||
( "epr-651.u33", 0x0000, 0x0400 ),
|
||||
( "epr-652.u32", 0x0400, 0x0400 ),
|
||||
( "epr-653.u31", 0x0800, 0x0400 ),
|
||||
( "epr-654.u30", 0x0c00, 0x0400 ),
|
||||
( "epr-655.u29", 0x1000, 0x0400 ),
|
||||
( "epr-656.u28", 0x1400, 0x0400 ),
|
||||
( "epr-657.u27", 0x1800, 0x0400 ),
|
||||
( "epr-658.u26", 0x1c00, 0x0400 ),
|
||||
( "epr-659.u8", 0x2000, 0x0400 ),
|
||||
( "epr-660.u7", 0x2400, 0x0400 ),
|
||||
( "epr-661.u6", 0x2800, 0x0400 ),
|
||||
( "epr-662.u5", 0x2c00, 0x0400 ),
|
||||
( "epr-663.u4", 0x3000, 0x0400 ),
|
||||
( "epr-664.u3", 0x3400, 0x0400 ),
|
||||
( "epr-665.u2", 0x3800, 0x0400 ),
|
||||
( "epr-666.u1", 0x3c00, 0x0400 ),
|
||||
( "316-633", 0x4000, 0x0020 ),
|
||||
( "epr-412", 0x4040, 0x0400 ),
|
||||
( "316-0206.u14", 0x4020, 0x0020 )
|
||||
]
|
||||
|
||||
fn = sys.argv[1]
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
print "Read %d bytes of %s" % (len(data), fn)
|
||||
|
||||
with zipfile.ZipFile(OUTFILE, 'w') as zipf:
|
||||
for name,start,length in ROMS:
|
||||
romdata = data[start:start+length]
|
||||
if len(romdata) != length:
|
||||
print "*** No data for %s (offset 0x%x)" % (name,start)
|
||||
romdata = '\0' * length
|
||||
zipf.writestr(name, romdata)
|
||||
else:
|
||||
zipf.writestr(name, romdata)
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
|
||||
all: baddies.c badspacerobots.tga tom-thumb.c swave.c.rom.h
|
||||
|
||||
clean:
|
||||
rm -f baddies.[ch] *.gif *.tga *.tga.png tom-thumb.c swave.c.rom.h
|
||||
|
||||
%.h: %
|
||||
cat $* | hexdump -v -e '"\n" 128/1 "0x%02x,"' > $@
|
||||
|
||||
# convert PCX (or PNG) file to Williams C sprite
|
||||
%.c: %.pcx
|
||||
python3 ../pcx2will.py $< > $@
|
||||
|
||||
# convert PNG into RLE-encoded TGA bitmap
|
||||
%.tga: %.png
|
||||
convert $< -resize 192 $<.gif
|
||||
convert $<.gif +dither -type palette -depth 4 -compress RLE -colors 8 -flip $@
|
||||
convert $@ $@.png
|
||||
|
||||
# convert PNG to 15-color PCX
|
||||
%.pcx: %.png
|
||||
convert $< -format raw -type palette -compress none -colors 15 +dither $@
|
||||
|
||||
#%.4.pcx: %.png
|
||||
# convert $< -format raw -type palette -compress none -colors 4 +dither $@
|
||||
|
||||
# convert BDF font file to definitions
|
||||
%.c: ../fonts/%.bdf
|
||||
python3 ../parsebdf4bit.py -s 33 -e 97 $< > $@
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 122 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user