add sprites library and Xmas demo
This commit is contained in:
parent
def08c6c94
commit
d22baa3f36
5 changed files with 699 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,6 +5,7 @@ tests/*.s
|
|||
examples/*.s
|
||||
!runtime.s
|
||||
!stdlibwrap.s
|
||||
!sprites.s
|
||||
*.o
|
||||
*.exe
|
||||
*.bin
|
||||
|
|
|
|||
5
examples/sprites.inc
Normal file
5
examples/sprites.inc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
type SpritePixels = array[0..31] of integer;
|
||||
type BackgroundPixels = array[0..31999] of integer;
|
||||
|
||||
procedure PutSprite(x,y:integer; var sprite: SpritePixels); external;
|
||||
procedure UndrawSprite(x,y:integer; var background: BackgroundPixels); external;
|
||||
363
examples/sprites.s
Normal file
363
examples/sprites.s
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
.EQU SPRITE_HEIGHT 16
|
||||
|
||||
.EQU WORDS_PER_LINE 80
|
||||
.EQU FB_RA $900
|
||||
.EQU FB_WA $901
|
||||
.EQU FB_IO $902
|
||||
.EQU FB_PS $903
|
||||
|
||||
; calculate mask for a word of pixels
|
||||
; args: word of pixels with four bits per pixel
|
||||
; returns: value that masks out all pixels that are set
|
||||
CALC_MASK:
|
||||
LOADC $F ; pixel mask
|
||||
C_M_L0:
|
||||
SWAP ; swap mask and pixels value
|
||||
AND.S1.X2Y ; isolate one pixel, keep args
|
||||
CBRANCH.Z C_M_L1 ; if pixel is zero, dont set mask bits
|
||||
OVER ; copy current mask
|
||||
OR ; or into pixels value
|
||||
C_M_L1:
|
||||
SWAP ; swap back, ToS is now mask bits
|
||||
SHL 2 ; shift mask for next pixel to the left
|
||||
SHL 2
|
||||
|
||||
DUP
|
||||
CBRANCH.NZ C_M_L0 ; if mask is zero, we are done
|
||||
DROP ; remove mask bits
|
||||
NOT ; invert result
|
||||
RET
|
||||
|
||||
; calculate vmem address from coordinates
|
||||
; args: x,y
|
||||
; returns: vmem word number
|
||||
CALC_VMEM_ADDR:
|
||||
; only works if WORDS_PER_LINE is 80
|
||||
; and pixels per word is 8
|
||||
|
||||
DUP
|
||||
; y
|
||||
SHL 2
|
||||
SHL 2
|
||||
SHL 2 ; * 64
|
||||
|
||||
SWAP
|
||||
; + y
|
||||
SHL 2
|
||||
SHL 2 ; * 16
|
||||
ADD
|
||||
|
||||
SWAP
|
||||
; word offset = X/8
|
||||
SHR
|
||||
SHR
|
||||
SHR
|
||||
ADD
|
||||
|
||||
RET
|
||||
|
||||
; put a sprite on screen
|
||||
; arg: x,y pointer to sprite data
|
||||
.EQU PS_VMEM_ADDR 0
|
||||
.EQU PS_SPRITE_DATA 4
|
||||
.EQU PS_SPRITE_LINES 8
|
||||
.EQU PS_X 12
|
||||
.EQU PS_Y 16
|
||||
.EQU PS_SHIFT_C 20
|
||||
.EQU PS_SPILL 24
|
||||
.EQU PS_FS 28
|
||||
PUTSPRITE:
|
||||
FPADJ -PS_FS
|
||||
STORE PS_SPRITE_DATA
|
||||
STORE PS_Y
|
||||
STORE PS_X
|
||||
|
||||
; calculate vmem address
|
||||
LOAD PS_X
|
||||
LOAD PS_Y
|
||||
LOADCP CALC_VMEM_ADDR
|
||||
CALL
|
||||
STORE PS_VMEM_ADDR
|
||||
|
||||
LOAD PS_X ; shift count = x mod 8
|
||||
LOADC 7
|
||||
AND
|
||||
STORE PS_SHIFT_C
|
||||
|
||||
LOADC SPRITE_HEIGHT
|
||||
STORE PS_SPRITE_LINES
|
||||
|
||||
; loop over each line of the sprite
|
||||
PS_LOOP1:
|
||||
; set read and write address
|
||||
; in the vga controller
|
||||
LOADC FB_RA ; read address register
|
||||
LOAD PS_VMEM_ADDR
|
||||
STOREI 1 ; use autoincrement to get to the next register
|
||||
LOAD PS_VMEM_ADDR
|
||||
STOREI
|
||||
DROP
|
||||
|
||||
LOAD PS_SPRITE_DATA ; address of sprite data
|
||||
DUP
|
||||
INC 4 ; increment pointer
|
||||
STORE PS_SPRITE_DATA ; and store it again
|
||||
LOADI ; load word from orig. address
|
||||
|
||||
|
||||
LOADC 0
|
||||
STORE PS_SPILL
|
||||
|
||||
; loop to shift pixel data to right
|
||||
LOAD PS_SHIFT_C ; load shift count
|
||||
PS_LOOP2:
|
||||
DUP ; test it for zero
|
||||
CBRANCH.Z PS_LOOP2_X
|
||||
|
||||
SWAP ; swap count with pixels
|
||||
|
||||
; save the pixel that is shifted out
|
||||
LOADC $F ; mask the four bits
|
||||
AND.S0 ; keep original value on stack
|
||||
BROT ; and move them to MSB
|
||||
BROT
|
||||
BROT
|
||||
SHL 2
|
||||
SHL 2 ; shift by 28 in total
|
||||
|
||||
LOAD PS_SPILL ; load spill bits
|
||||
SHR ; shift by four to make space
|
||||
SHR
|
||||
SHR
|
||||
SHR
|
||||
OR ; or with orig value
|
||||
STORE PS_SPILL ; store new value
|
||||
|
||||
SHR ; shift pixels right
|
||||
SHR ; four bits per pixel
|
||||
SHR
|
||||
SHR
|
||||
|
||||
SWAP ; swap back, count now ToS
|
||||
DEC 1
|
||||
BRANCH PS_LOOP2
|
||||
PS_LOOP2_X:
|
||||
DROP ; remove shift count, shifted pixels now in ToS
|
||||
|
||||
DUP
|
||||
LOADCP CALC_MASK ; calculate sprite mask for this word
|
||||
CALL
|
||||
|
||||
LOADCP FB_IO ; address of the i/o register
|
||||
LOADI ; read word from video mem
|
||||
|
||||
AND ; and word with mask
|
||||
|
||||
OR ; OR sprite data with original pixels
|
||||
|
||||
LOADCP FB_IO
|
||||
SWAP
|
||||
STOREI ; store result into i/o reg
|
||||
DROP
|
||||
|
||||
;
|
||||
; process spilled bits and right half of sprite data
|
||||
;
|
||||
|
||||
; put spill bits on stack for later
|
||||
LOAD PS_SPILL
|
||||
|
||||
LOAD PS_SPRITE_DATA ; address of sprite data
|
||||
DUP
|
||||
INC 4 ; increment pointer
|
||||
STORE PS_SPRITE_DATA ; and store it again
|
||||
LOADI ; load word from orig. address
|
||||
|
||||
; reset spill bits
|
||||
LOADC 0
|
||||
STORE PS_SPILL
|
||||
|
||||
; shift pixel data to right
|
||||
LOAD PS_SHIFT_C ; load shift count
|
||||
PS_LOOP3: ; test it for zero
|
||||
DUP
|
||||
CBRANCH.Z PS_LOOP3_X
|
||||
|
||||
SWAP ; swap count with pixels
|
||||
|
||||
; save the pixel that is shifted out
|
||||
LOADC $F ; mask the four bits
|
||||
AND.S0 ; keep original value on stack
|
||||
BROT ; and move them to MSB
|
||||
BROT
|
||||
BROT
|
||||
SHL 2
|
||||
SHL 2 ; shift by 28 in total
|
||||
|
||||
LOAD PS_SPILL ; load spill bits
|
||||
SHR ; shift by four to make space
|
||||
SHR
|
||||
SHR
|
||||
SHR
|
||||
OR ; or with orig value
|
||||
STORE PS_SPILL ; store new value
|
||||
|
||||
SHR ; shift pixels right
|
||||
SHR ; four bits per pixel
|
||||
SHR
|
||||
SHR
|
||||
|
||||
SWAP ; swap back, count now ToS
|
||||
DEC 1
|
||||
BRANCH PS_LOOP3
|
||||
PS_LOOP3_X:
|
||||
DROP ; remove shift count, shifted pixels now in ToS
|
||||
|
||||
OR ; or together with spill bits
|
||||
|
||||
DUP
|
||||
LOADCP CALC_MASK ; calculate sprite mask
|
||||
CALL
|
||||
|
||||
LOADCP FB_IO ; load original pixels
|
||||
LOADI
|
||||
|
||||
AND ; and with mask
|
||||
|
||||
OR ; or together with original pixels
|
||||
|
||||
LOADCP FB_IO
|
||||
SWAP
|
||||
STOREI
|
||||
DROP
|
||||
|
||||
; write spilled bits into next vmem word
|
||||
LOAD PS_SPILL ; get spill bits
|
||||
DUP
|
||||
LOADCP CALC_MASK ; calculate sprite mask for spill bits
|
||||
CALL
|
||||
|
||||
LOADCP FB_IO
|
||||
LOADI ; load next vmem word
|
||||
AND ; apply sprite mask
|
||||
|
||||
OR ; OR in spill bits
|
||||
|
||||
LOADCP FB_IO
|
||||
SWAP ; swap pixels and addr
|
||||
STOREI ; write back
|
||||
DROP
|
||||
|
||||
LOAD PS_SPRITE_LINES ; decrement lines count
|
||||
DEC 1
|
||||
DUP
|
||||
CBRANCH.Z PS_L_XT ; exit if zero
|
||||
STORE PS_SPRITE_LINES
|
||||
; prepare next line
|
||||
LOAD PS_VMEM_ADDR
|
||||
LOADC WORDS_PER_LINE ; increment to next screen line
|
||||
ADD
|
||||
STORE PS_VMEM_ADDR
|
||||
BRANCH PS_LOOP1
|
||||
PS_L_XT:
|
||||
DROP
|
||||
|
||||
FPADJ PS_FS
|
||||
RET
|
||||
|
||||
; undraw a sprite, i.e. draw background data
|
||||
; over a sprite location
|
||||
; args: x,y, ptr to background data
|
||||
.EQU UD_S_X 0
|
||||
.EQU UD_S_Y 4
|
||||
.EQU UD_S_PXS 8
|
||||
.EQU UD_S_BGDATA 12
|
||||
.EQU UD_S_OFFSET 16
|
||||
.EQU UD_S_BGORIG 20
|
||||
.EQU UD_S_FS 24
|
||||
UNDRAWSPRITE:
|
||||
FPADJ -UD_S_FS
|
||||
STORE UD_S_BGORIG
|
||||
STORE UD_S_Y
|
||||
STORE UD_S_X
|
||||
|
||||
; calculate pixel shift
|
||||
LOAD UD_S_X
|
||||
LOADC $7
|
||||
AND
|
||||
STORE UD_S_PXS
|
||||
|
||||
; calculate vmem offset
|
||||
LOAD UD_S_X
|
||||
LOAD UD_S_Y
|
||||
LOADCP CALC_VMEM_ADDR
|
||||
CALL
|
||||
|
||||
DUP
|
||||
STORE UD_S_OFFSET
|
||||
|
||||
; calculate background data address from offset
|
||||
SHL 2
|
||||
LOAD UD_S_BGORIG
|
||||
ADD
|
||||
STORE UD_S_BGDATA
|
||||
|
||||
LOADC SPRITE_HEIGHT ; line count
|
||||
UD_S_L1:
|
||||
; store vmem offset into write addr reg
|
||||
LOADCP FB_WA
|
||||
LOAD UD_S_OFFSET
|
||||
STOREI 1 ; ugly but fast: reuse addr
|
||||
; with postincrement to
|
||||
; get to FB_IO for STOREI below
|
||||
|
||||
; load a word of background data
|
||||
LOAD UD_S_BGDATA
|
||||
LOADI
|
||||
; and write it to vmem
|
||||
STOREI
|
||||
; reuse addr from STOREI
|
||||
|
||||
; load 2nd word of background data
|
||||
LOAD UD_S_BGDATA
|
||||
INC 4
|
||||
DUP
|
||||
STORE UD_S_BGDATA
|
||||
LOADI
|
||||
STOREI ; and write it to vmem
|
||||
DROP
|
||||
|
||||
; if pixel shift is zero, no 3rd word
|
||||
LOAD UD_S_PXS
|
||||
CBRANCH.Z UD_S_L2
|
||||
|
||||
; load 3rd word of background data
|
||||
LOADCP FB_IO
|
||||
LOAD UD_S_BGDATA
|
||||
INC 4
|
||||
DUP
|
||||
STORE UD_S_BGDATA
|
||||
LOADI
|
||||
STOREI ; and write it to vmem
|
||||
DROP
|
||||
|
||||
UD_S_L2:
|
||||
LOAD UD_S_OFFSET
|
||||
LOADCP WORDS_PER_LINE
|
||||
ADD
|
||||
DUP
|
||||
STORE UD_S_OFFSET
|
||||
SHL 2
|
||||
LOAD UD_S_BGORIG
|
||||
ADD
|
||||
STORE UD_S_BGDATA
|
||||
|
||||
DEC 1 ; decrement counter
|
||||
DUP
|
||||
CBRANCH.NZ UD_S_L1 ; check for zero
|
||||
|
||||
DROP ; remove counter
|
||||
|
||||
FPADJ UD_S_FS
|
||||
RET
|
||||
|
||||
220
examples/xmas.pas
Normal file
220
examples/xmas.pas
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
program XmasAnimation;
|
||||
uses sprites;
|
||||
|
||||
type PictData = record
|
||||
magic, mode:integer;
|
||||
palette: array [0..15] of integer;
|
||||
pixeldata: array [0..31999] of integer;
|
||||
end;
|
||||
|
||||
Sprite = record
|
||||
x,y:integer;
|
||||
oldX,oldY:integer;
|
||||
xdelta,ydelta:integer;
|
||||
curFrame:integer;
|
||||
frameCount:integer;
|
||||
frameTime:integer;
|
||||
frameLeft:integer;
|
||||
changed:boolean;
|
||||
frame:array [0..3] of SpritePixels;
|
||||
end;
|
||||
|
||||
var pic:PictData;
|
||||
filename:string;
|
||||
infile:file;
|
||||
ch:char;
|
||||
santaSprite: Sprite;
|
||||
deerSprite: Sprite;
|
||||
ohDeerSprite: Sprite;
|
||||
rudolfSprite: Sprite;
|
||||
smokeSprite: Sprite;
|
||||
|
||||
procedure WaitVSync; external;
|
||||
|
||||
procedure loadPalette(var pic:PictData);
|
||||
var i:integer;
|
||||
begin
|
||||
for i := 0 to 15 do
|
||||
setpalette(i, pic.palette[i]);
|
||||
end;
|
||||
|
||||
procedure showPic(var pic:PictData);
|
||||
begin
|
||||
PutScreen(pic.pixeldata);
|
||||
end;
|
||||
|
||||
procedure loadSpriteFrame(var aSprite:Sprite;spriteIndex:integer;
|
||||
var sheetFile:file;sheetIndex:integer);
|
||||
begin
|
||||
seek(sheetFile, 8 + sheetIndex * 128);
|
||||
read(sheetFile, aSprite.frame[spriteIndex]);
|
||||
if aSprite.frameCount <= spriteIndex then
|
||||
aSprite.frameCount := spriteIndex + 1;
|
||||
|
||||
aSprite.curFrame := 0;
|
||||
writeln('loaded sprite frame ', spriteIndex, ' from ', sheetIndex);
|
||||
end;
|
||||
|
||||
procedure animateSprite(var aSprite:Sprite);
|
||||
var frameIndex:integer;
|
||||
frameTime,frameLeft:integer;
|
||||
ydelta:integer;
|
||||
oldX,oldY:integer;
|
||||
begin
|
||||
ydelta := aSprite.ydelta;
|
||||
frameIndex := aSprite.curFrame;
|
||||
frameTime := aSprite.frameTime;
|
||||
frameLeft := aSprite.frameLeft;
|
||||
oldX := aSprite.x; oldY := aSprite.y;
|
||||
aSprite.oldX := oldX; aSprite.oldY := oldY;
|
||||
|
||||
frameLeft := frameLeft - 1;
|
||||
if frameLeft <= 0 then
|
||||
begin
|
||||
frameIndex := frameIndex + 1;
|
||||
frameLeft := aSprite.frameTime;
|
||||
aSprite.frameLeft := frameLeft;
|
||||
aSprite.curFrame := frameIndex;
|
||||
if frameIndex >= aSprite.frameCount
|
||||
then
|
||||
aSprite.curFrame := 0;
|
||||
|
||||
if frameIndex = 1 then
|
||||
begin
|
||||
ydelta := - ydelta;
|
||||
aSprite.ydelta := ydelta;
|
||||
end;
|
||||
aSprite.y := aSprite.y + ydelta;
|
||||
end;
|
||||
|
||||
aSprite.frameLeft := frameLeft;
|
||||
|
||||
aSprite.x := aSprite.x + aSprite.xdelta;
|
||||
if aSprite.x > 620 then aSprite.x := 0;
|
||||
end;
|
||||
|
||||
procedure animate;
|
||||
var i:integer;
|
||||
ydelta:integer;
|
||||
frameIndex:integer;
|
||||
frameTime:integer;
|
||||
oldX,oldY:integer;
|
||||
begin
|
||||
santaSprite.x := 0;
|
||||
santaSprite.y := 60;
|
||||
santaSprite.frameTime := 10;
|
||||
santaSprite.xdelta := 2;
|
||||
santaSprite.ydelta := 1;
|
||||
|
||||
smokeSprite.x := 434;
|
||||
smokeSprite.y := 252;
|
||||
smokeSprite.frameTime := 20;
|
||||
|
||||
deerSprite.x := 18;
|
||||
deerSprite.y := 60;
|
||||
deerSprite.frameTime := 10;
|
||||
deerSprite.xdelta := 2;
|
||||
deerSprite.ydelta := 1;
|
||||
|
||||
ohDeerSprite.x := 33;
|
||||
ohDeerSprite.y := 61;
|
||||
ohDeerSprite.frameTime := 10;
|
||||
ohDeerSprite.xdelta := 2;
|
||||
ohDeerSprite.ydelta := 1;
|
||||
|
||||
rudolfSprite.x := 49;
|
||||
rudolfSprite.y := 60;
|
||||
rudolfSprite.frameTime := 10;
|
||||
rudolfSprite.xdelta := 2;
|
||||
rudolfSprite.ydelta := 1;
|
||||
|
||||
ydelta := 1;
|
||||
|
||||
frameTime := santaSprite.frameTime;
|
||||
|
||||
while not ConAvail do
|
||||
begin
|
||||
frameIndex := santaSprite.curFrame;
|
||||
oldX := santaSprite.x; oldY := santaSprite.y;
|
||||
PutSprite(oldX, oldY, santaSprite.frame[frameIndex]);
|
||||
i := i + 1;
|
||||
frameTime := frameTime - 1;
|
||||
if frameTime = 0 then
|
||||
begin
|
||||
frameTime := santaSprite.frameTime;
|
||||
santaSprite.curFrame := frameIndex + 1;
|
||||
if frameIndex >= santaSprite.frameCount
|
||||
then
|
||||
santaSprite.curFrame := 0;
|
||||
|
||||
if frameIndex = 0 then ydelta := - ydelta;
|
||||
santaSprite.y := santaSprite.y + ydelta;
|
||||
end;
|
||||
santaSprite.x := santaSprite.x + 2;
|
||||
if santaSprite.x > 620 then santaSprite.x := 0;
|
||||
|
||||
PutSprite(deerSprite.x, deerSprite.y,
|
||||
deerSprite.frame[deerSprite.curFrame]);
|
||||
|
||||
PutSprite(ohDeerSprite.x, ohDeerSprite.y,
|
||||
ohDeerSprite.frame[ohDeerSprite.curFrame]);
|
||||
|
||||
PutSprite(rudolfSprite.x, rudolfSprite.y,
|
||||
rudolfSprite.frame[rudolfSprite.curFrame]);
|
||||
|
||||
PutSprite(smokeSprite.x, smokeSprite.y,
|
||||
smokeSprite.frame[smokeSprite.curFrame]);
|
||||
|
||||
animateSprite(deerSprite);
|
||||
animateSprite(ohDeerSprite);
|
||||
animateSprite(rudolfSprite);
|
||||
animateSprite(smokeSprite);
|
||||
|
||||
Delay(10);
|
||||
WaitVSync;
|
||||
|
||||
UndrawSprite(oldX, oldY, pic.pixeldata);
|
||||
UndrawSprite(deerSprite.oldX, deerSprite.oldY, pic.pixeldata);
|
||||
UndrawSprite(ohDeerSprite.oldX, ohDeerSprite.oldY, pic.pixeldata);
|
||||
UndrawSprite(rudolfSprite.oldX, rudolfSprite.oldY, pic.pixeldata);
|
||||
UndrawSprite(smokeSprite.oldX, smokeSprite.oldY, pic.pixeldata);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
filename := 'background.pict';
|
||||
open(infile, filename, ModeReadonly);
|
||||
read(infile, pic);
|
||||
close(infile);
|
||||
|
||||
writeln('magic: ', pic.magic, ' mode:', pic.mode);
|
||||
|
||||
loadPalette(pic);
|
||||
showPic(pic);
|
||||
|
||||
open(infile, 'sprites.sprt', ModeReadOnly);
|
||||
loadSpriteFrame(santaSprite, 0, infile, 0);
|
||||
loadSpriteFrame(santaSprite, 1, infile, 1);
|
||||
|
||||
loadSpriteFrame(deerSprite, 0, infile, 5);
|
||||
loadSpriteFrame(deerSprite, 1, infile, 6);
|
||||
loadSpriteFrame(deerSprite, 2, infile, 7);
|
||||
|
||||
loadSpriteFrame(ohDeerSprite, 0, infile, 7);
|
||||
loadSpriteFrame(ohDeerSprite, 1, infile, 5);
|
||||
loadSpriteFrame(ohDeerSprite, 2, infile, 6);
|
||||
|
||||
loadSpriteFrame(rudolfSprite, 0, infile, 3);
|
||||
loadSpriteFrame(rudolfSprite, 1, infile, 4);
|
||||
loadSpriteFrame(rudolfSprite, 2, infile, 2);
|
||||
|
||||
loadSpriteFrame(smokeSprite, 0, infile, 8);
|
||||
loadSpriteFrame(smokeSprite, 1, infile, 9);
|
||||
loadSpriteFrame(smokeSprite, 2, infile, 10);
|
||||
loadSpriteFrame(smokeSprite, 3, infile, 11);
|
||||
|
||||
close(infile);
|
||||
|
||||
animate;
|
||||
end.
|
||||
110
utils/png2pict.py
Normal file
110
utils/png2pict.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/python3
|
||||
import sys
|
||||
import png
|
||||
|
||||
def process_pixdata(outfile, pixdata, frameindex = 0, pix_w=640, pix_h=400):
|
||||
|
||||
pixmask = 15
|
||||
y = pix_h * frameindex
|
||||
max_y = y + pix_h - 1
|
||||
|
||||
while y <= max_y:
|
||||
x = 0
|
||||
max_x = pix_w - 1
|
||||
pixline = pixdata[y]
|
||||
while x <= max_x:
|
||||
px1 = pixline[x+0] & pixmask
|
||||
px2 = pixline[x+1] & pixmask
|
||||
px3 = pixline[x+2] & pixmask
|
||||
px4 = pixline[x+3] & pixmask
|
||||
px5 = pixline[x+4] & pixmask
|
||||
px6 = pixline[x+5] & pixmask
|
||||
px7 = pixline[x+6] & pixmask
|
||||
px8 = pixline[x+7] & pixmask
|
||||
vmem_word = (px1 << 28) | (px2 << 24) | (px3 << 20) | (px4 << 16) | \
|
||||
(px5 << 12) | (px6 << 8) | (px7 << 4) | px8
|
||||
|
||||
outfile.write(vmem_word.to_bytes(4, 'big'))
|
||||
x += 8
|
||||
y += 1
|
||||
|
||||
|
||||
def process_palette(outfile, palette):
|
||||
for r,g,b in palette:
|
||||
r4 = r >> 4
|
||||
g4 = g >> 4
|
||||
b4 = b >> 4
|
||||
c12 = r4 << 8 | g4 << 4 | b4
|
||||
|
||||
outfile.write(c12.to_bytes(4, 'big'))
|
||||
|
||||
|
||||
def write_header(outfile):
|
||||
magic = b'PIct'
|
||||
mode = 1
|
||||
outfile.write(magic);
|
||||
outfile.write(mode.to_bytes(4, 'big'))
|
||||
|
||||
|
||||
def write_sprite_header(outfile):
|
||||
magic = b'SPRT'
|
||||
mode = 1
|
||||
outfile.write(magic);
|
||||
outfile.write(mode.to_bytes(4, 'big'))
|
||||
|
||||
|
||||
def write_pict_file(width, height, px, metadata, outfile):
|
||||
print("processing as PICT file...")
|
||||
if width != 640:
|
||||
print("width must be 640, aborting")
|
||||
sys.exit(1)
|
||||
pixdata = list(px)
|
||||
palette = metadata['palette']
|
||||
|
||||
if len(palette) != 16:
|
||||
print("palette must have 16 colors, aborting")
|
||||
sys.exit(0)
|
||||
|
||||
with open(outfile,'wb') as f:
|
||||
write_header(f)
|
||||
process_palette(f, palette)
|
||||
process_pixdata(f, pixdata)
|
||||
|
||||
|
||||
def write_sprite_file(width, height, px, metadata, outfile):
|
||||
sprite_height=16
|
||||
|
||||
print("processing as SPRT file with {} sprites...".format(height//sprite_height))
|
||||
if width != 16:
|
||||
print("width must be 16, aborting")
|
||||
sys.exit(1)
|
||||
pixdata = list(px)
|
||||
palette = metadata['palette']
|
||||
|
||||
if len(palette) != 16:
|
||||
print("palette must have 16 colors, aborting")
|
||||
sys.exit(0)
|
||||
|
||||
with open(outfile,'wb') as f:
|
||||
write_sprite_header(f)
|
||||
process_pixdata(f, pixdata, pix_w=16, pix_h=height)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: {} <infile> <outfile>".format(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
infile = sys.argv[1]
|
||||
outfile = sys.argv[2]
|
||||
|
||||
r = png.Reader(infile)
|
||||
p = r.read()
|
||||
width, height, px, metadata = p
|
||||
if width == 640:
|
||||
write_pict_file(width, height, px, metadata, outfile)
|
||||
elif width == 16:
|
||||
write_sprite_file(width, height, px, metadata, outfile)
|
||||
else:
|
||||
print("Can't handle this file, need a width of\n640 or 16 pixels with 16 color palette.")
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue