SPR File Decoder / Loader
This example decodes null byte compressed palette mapped sprites from constructor into a series of regular RGB images. The convertor doesn't include a palette decoder, since that data isn't stored within the sprite file, it's housed else where. But the format is just IFF so loading them is trivial, I just don't have the required file, so haven't bothered.
Info on the sprite format can be found here
https://github.com/shlainn/game-file-formats/wiki/Constructor-.SPR-files
[pbcode]
; File to decode
file$="Location_Of_File_Here.spr"
// ---------------------------------------------------------
// Here we're building a shaded palette in whatever colour we want
// since sprite files don't actually contain the palette data in them
// the palette is stored in a different file.
// Link to a SPR format dizzy
// https://github.com/shlainn/game-file-formats/wiki/Constructor-.SPR-files
// ---------------------------------------------------------
Dim Palette(255)
For lp =0 to 255
Palette(lp)=rgbalphamult(rgb(lp,lp,lp),$ffffff)
next
// Load the Sprite file into a bank
Bank=LoadFileToBank(file$)
// DIm the array that will hold the converted frames
Dim Sprites(0)
// Decode the raw frames
Sprites()=Decode_Sprites(Bank,Palette())
// The bank is no longer needed so delete it
deleteBank Bank
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
; -[ MAIN LOOP ]-------------------------------------------------------
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
SetFps 60
Frame=1
Maxframes=GetArrayElements(Sprites())
Do
;clear screen to black
Cls
; check for up arrow
if upkey() and Frame>1
Frame--
endif
; check for down arrow
if downkey() and Frame<MaxFrames
Frame++
endif
; get the image of this frame
ThisImage=Sprites(Frame)
if ThisIMage
Width#=GetImageWidth(ThisImage)
Height#=GetImageWidth(ThisImage)
drawRotatedimage ThisIMage,400,300,0,2,2,Width#/-2,Height#/-2,false
endif
print "Sprite frame#"+str$(frame)+" of #"+str$(MaxFrames)
sync
loop
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
; -[ Decode Sprites ]-------------------------------------------------------
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
Function Decode_Sprites(SpriteBank,Palette())
Dim Frames(0)
if GetBankStatus(SpriteBank)
SpriteBankSize=GetBankSize(SpriteBank)
if SpriteBankSize>4
NumberOfFrames = PeekBankInt(SpriteBank, 0 ) ; read integer from mem block at offset 0
DIm Frames(NumberOfFrames)
print NumberOfFrames
// -------------------------------------
// decode frames
// -------------------------------------
For framelp=0 to NumberOfFrames-1
// Get the offset with the mem block of where this frame starts
FrameDataOffset = PeekBankInt(SpriteBank, 4+(FrameLp*4) )
// does this frame have any data ?
if FrameDataOffset<>0
#print FrameDataOffset
// --------------------------------------------------------------------------------
// decompress frame, here i'm assuming the frame offset is relative to the start
// of the file, it might be relative to it's position it the sprite table
// --------------------------------------------------------------------------------
// Grab the info about the sprite from it's header.
FrameWidth=PeekBankWORD(SpriteBank, FrameDataOffset + 4 )
FrameHeight=PeekBankWORD(SpriteBank, FrameDataOffset + 6 )
// calc current /start offset of the compressed pixel data for this frame
PixelDataAddress =FrameDataOffset + 8
// Alloc a bank to store the temp pixel data.
// it's probably a good idea to pad this, just in case :)
DecompressedBank = NewBank( (FrameWidth+1) * FrameHeight)
#print FrameWidth
#print FrameHeight
#print DecompressedBank
#print ""
// --------------------------------------------------------------------------------
// decode the pixel data that makes up to this frame into the temp bank
// --------------------------------------------------------------------------------
MaxPixelCount = FrameWidth * FrameHeight
PixelCount =0
repeat
// read the pixel
ThisPixel = PeekBankByte(SpriteBank, PixelDataAddress)
// is pixel zero ??
if ThisPixel=0
// decode run length fragment (restore run of zeros)
RunSize = PeekBankByte(SpriteBank, PixelDataAddress+1)
For WriteLP=1 to RunSize
POkeBankByte DecompressedBank,PixelCount,ThisPixel
Inc PixelCount
next
// step src offset/pointer forward
PixelDataAddress=PixelDataAddress+2
else
// write the pixel to output bank
POkeBankByte DecompressedBank,PixelCount,ThisPixel
inc PixelDataAddress
Inc PixelCount
endif
// check if we're reached the end of sprite
until PixelCount=>MaxPixelCount
ThisImage=NewIMage(FrameWidth,FrameHeight,2)
rendertoimage ThisIMage
PixelCount =0
lockbuffer
ThisPixel=point(0,0)
For ylp=0 to FrameHeight-1
For xlp=0 to FrameWidth-1
// Get this pixel index
ThisPixel=PeekBankByte(DecompressedBank,PixelCount)
// Convert the palette map index into the output RGB colour & draw this dot
Fastdot Xlp,ylp,Palette(ThisPixel)
PixelCount++
next
next
unlockbuffer
Frames(framelp)=ThisImage
deletebank DecompressedBank
endif
rendertoscreen
if Frames(framelp)
cls 0
print "Decoding Frame#"+str$(framelp)
sync
endif
next
endif
endif
EndFunction Frames()
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
; -[ Load File to Bank ]-------------------------------------------------------
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
Function LoadFileToBank(file$)
if Fileexist(file$)
size=filesize(File$)
ThisBank=NewBank(Size)
fh=ReadnewFile(File$)
if fh
ReadMemory fh,GetBankPtr(ThisBank),Size
closefile fh
endif
endif
EndFunction ThisBank
[/pbcode]
Related Articles:
* C64 Styled Sprite Rendering Example (http://www.underwaredesign.com/forums/index.php?topic=4022.0)
* Palette Mapped / Raster Bar Examples (http://www.underwaredesign.com/forums/index.php?topic=4060.0)
* LowRES PlayBASIC - 8bit Retro Graphics Library (https://www.underwaredesign.com/forums/index.php?topic=4725.0)
* Challenge #27 - Learn binary operations through Retro Computer Graphics (http://www.underwaredesign.com/forums/index.php?topic=4147.0)