ReadWrite Bit maps

Blitz3D Forums/Blitz3D Programming/ReadWrite Bit maps

_PJ_(Posted 2015) [#1]
I'm having a problem in trying to convert between bitmap images (where pixel status is only considered 0 or 1) and banks.

The issue seems to be specifically particular with trying to write the Image data to a bank.

I have functions which can read/write accurately from the banks unsing ReadBytes and WriteBytes, so the problem can only be in writing to the banks byte by byte is different somehow (Or I'm missing something glaringly obvious).

The Read/WriteBytes theoretically should simply write bytes in sequence, and I believe this does so in 8 bit bytes regardless.
This would most likely be related as Isuspect that the Endian of long bytes may cause the sequence to be reversed...








Here's a sample of code that highlights the issue:
Graphics 1024,768,32

Const SPRITE_MAX=255
Const UNIT_RESOLUTION=8
Const SPR_BIT_DEPTH=8

;1-8		Sprite Ref	:	Eight Bits	;Maximum
;9-10		Frames		:	Two Bits	;0 or 3 Units should never be used, so +1 to raw data
;11-12		Width		:	Two Bits	;in UNITs - 0 or 3 Units should never be used, so +1 to raw data
;13-14		Height		: 	Two Bits	;in UNITs - 0 or 3 Units should never be used, so +1 to raw data
;15			Reversal	:	One Bit		;if Reverse direction requires additional animation frames

Const SPR_FRAMECOUNT_BYTE_OFFSET=9
Const SPR_FRAMECOUNT_BIT_DEPTH=2
Const SPR_DIMENSIONW_BYTE_OFFSET=11
Const SPR_DIMENSIONW_BIT_DEPTH=2
Const SPR_DIMENSIONH_BYTE_OFFSET=13
Const SPR_DIMENSIONH_BIT_DEPTH=2

Const SPR_ALTREVERSE_BYTE_OFFSET=15	;Whether reverse Direction has separate animations
Const SPR_ALTREVERSE_BIT_DEPTH=1

Const MAX_FRAMES=4

Const Root$="C:\Users\A User\Documents\Some Directory\"


Type SPRITE
	Field Reference
	Field Frames
	Field FrameBank[MAX_FRAMES]
	Field Width
	Field Height
	Field Reversal
End Type


Global Count



MakeSpriteData






























Function MakeSpriteData()
	
	CountSprites
	WriteSprites
	
End Function


Function CountSprites() 
	Count=0
	Local Directory=ReadDir(Root)
	Local File$
	Local Path$
	File=NextFile(Directory)
	While (File<>"")
		Path$=Root+File
		If (FileType(Path)=1)
			If (Right(File,3)="bmp")
				Count=Count+1
			End If
		End If
		File=NextFile(Directory)
	Wend
	
	CloseDir Directory
	
	If (Count>SPRITE_MAX)
		Count=SPRITE_MAX
	End If
	
End Function

Function WriteSprites()
	Local Directory=ReadDir(Root)
	Local File$=NextFile(Directory)
	Local Path$
	
	Local Stream=WriteFile(Root+"Default.spr")
	WriteByte(Stream,Count)
	
	Local counter=0
	While (File<>"") And (counter<=Count)
		Path$=Root+File
		If (FileType(Path)=1)
			If (Right(File,3)="bmp")
				counter=counter+1
				ProcessSpriteFile(Path,Stream)
			End If
		End If
		File=NextFile(Directory)
	Wend
	CloseFile Stream
	CloseDir Directory
End Function

Function ProcessSpriteFile(Path$,Stream)
	Local Bank
	Local S.SPRITE
	
	S=ReadSprite(Path)
	WriteSprite(Stream,S)
	
	
	For Bank=1 To S\Frames
		FreeBank S\FrameBank[Bank-1]
	Next
	
	Delete S
	
End Function

Function ReadSprite.SPRITE(Path$)
	
	Local Name$=GetName(Path)
	Local Flags=GetFlags(Name)
	
	Local S.SPRITE=New SPRITE
	S\Reference=Int(Left(Name,Instr(Name," ")-1))
	S\Width=Left(Str(Flags),1)
	S\Height=Mid(Str(Flags),2,1)
	S\Frames=Mid(Str(Flags),3,1)
	S\Reversal=Int(Right(Str(Flags),1))
	
	Local Frame
	Local Bank
	Local Byte
	Local Buffer
	
	Local Image=LoadAnimImage(Path,S\Width*UNIT_RESOLUTION,S\Height*UNIT_RESOLUTION,0,S\Frames)
	
	For Frame=1 To S\Frames
		Bank=CreateBank(S\Width*S\Height*UNIT_RESOLUTION)
		Byte=BankSize(Bank)
		S\FrameBank[Frame-1]=Bank
		
		BufferToBank(S,ImageBuffer(Image,Frame-1),Bank,S\Width,S\Height)
		
	Next
	
	FreeImage Image
	Return S
	
End Function

Function WriteSprite(Stream,S.SPRITE)
	WriteSpriteToFile(S,Stream)
End Function

Function BufferToBank(S.SPRITE,Buffer,Bank,Width,Height)
	LockBuffer Buffer
	
	Local X
	Local Y
	Local n
	Local W=Width*UNIT_RESOLUTION
	Local H=Height*UNIT_RESOLUTION
	
	Local Byte
	Local Pixel
	
	For Y=0 To H-1
		
		
		Byte=0
		
		
		For X=0 To W-1 Step UNIT_RESOLUTION
			
			
			Pixel=( ReadPixelFast(X+n,Y,Buffer))
			
			If (Pixel=-1)
				Byte=Byte+(1 Shl n)
			End If
			
			PokeFrameLine(S,Bank,Y,Byte)
			
		Next
	Next
	UnlockBuffer Buffer
End Function	

Function GetName$(Path$)
	Return Right(Path,Len(Path)-Len(TrimPath(Path)))
End Function	

Function TrimPath$(FilePath$)
	If (FilePath<>"")
		If (((Right(FilePath,1)=".") Or  (Right(FilePath,1)="\") Or (Right(FilePath,1)="/")))
			Return FilePath
		End If
		
		Local Count
		Local Char$
		Local Length=Len(FilePath)
		
		For Count=Length To 1 Step -1
			Char=Mid(FilePath,Count,1)
			If (Char="\")
				Exit
			End If
		Next
		Return Left(FilePath,Count)
	End If
End Function

Function GetFlags(Name$)
	Local ReferenceEnd=Instr(Name," ")
	
	Return Int(Mid(Name,ReferenceEnd+1,4))
End Function

Function PokeFrameLine(S.SPRITE,bank,Y,Byte)
	Select S\Width
		Case 1:
			PokeByte bank,Y,Byte
		Case 2:
			PokeShort bank,Y*2,Byte		
		Case 4:
			PokeInt bank,Y*4,Byte
		Default:
			RuntimeError "Invalid runlength request: "+S\Width
	End Select
End Function

Function WriteSpriteToFile(S.SPRITE,Stream)
	
	Local UnitWidth=S\Width
	Local BitwiseWidth=(UnitWidth Shr True)
	Local ByteValueWidth=BitwiseWidth Shl (SPR_DIMENSIONW_BYTE_OFFSET-1)
	
	Local UnitHeight=S\Height
	Local BitwiseHeight=(UnitHeight Shr True)
	Local ByteValueHeight=BitwiseHeight Shl (SPR_DIMENSIONH_BYTE_OFFSET-1)
	
	Local Frames=S\Frames
	Local BitwiseFrames=(S\Frames Shr True)
	Local ByteValueFrames=BitwiseFrames Shl (SPR_FRAMECOUNT_BYTE_OFFSET-1)
	
	Local Reversal=S\Reversal Shl (SPR_ALTREVERSE_BYTE_OFFSET-1)
	
	
	WriteShort Stream,S\Reference+ByteValueWidth+ByteValueHeight+ByteValueFrames+Reversal
	
	Local Frame
	Local Bank
	Local Byte
	
	For Frame=1 To Frames
		Bank=S\FrameBank[Frame-1]
		Byte=BankSize(Bank)
		WriteBytes(Bank,Stream,0,Byte)
	Next
	
End Function


Otherwise, when NOT trying to onvert between image files, the Banks can be read and written perfectly with the following:

Function WriteSpritesToFile()
	ChangeDir DATA_STORE_PATH
	Local Path$=DATA_STORE_PATH+MRU_SPRITEFILE+".spr"
	Local Stream=WriteFile(Path)
	Local S.SPRITE
	Local Iter
	
	WriteByte Stream,SPRITE_COUNT
	
;	For Iter=0 To SPRITE_COUNT
;		S=Object.SPRITE(SPRITES[Iter])
	
	For S=Each SPRITE 
		If (S<>Null)
			WriteSpriteToFile(S,Stream)
		End If
	Next
	
;	Next
	
	CloseFile Stream
	
	Local Message$=WRITEFAILUREMESSAGE
	
	If (FileType(Path)=1)
		If (FileSize(Path))
			Message$=WRITESUCCESSMESSAGE
		End If 
	End If
	
	Notify Message
End Function

Function WriteSpriteToFile(S.SPRITE,Stream)
	
	Local UnitWidth=S\Width
	Local BitwiseWidth=(UnitWidth Shr True)
	Local ByteValueWidth=BitwiseWidth Shl (SPR_DIMENSIONW_BYTE_OFFSET-1)
	
	Local UnitHeight=S\Height
	Local BitwiseHeight=(UnitHeight Shr True)
	Local ByteValueHeight=BitwiseHeight Shl (SPR_DIMENSIONH_BYTE_OFFSET-1)
	
	Local Frames=S\Frames
	Local BitwiseFrames=(S\Frames Shr True)
	Local ByteValueFrames=BitwiseFrames Shl (SPR_FRAMECOUNT_BYTE_OFFSET-1)
	
	Local Reversal=S\Reversal Shl (SPR_ALTREVERSE_BYTE_OFFSET-1)
	
	
	WriteShort Stream,S\Reference+ByteValueWidth+ByteValueHeight+ByteValueFrames+Reversal
	
	Local Frame
	Local Bank
	Local Byte
	
	For Frame=1 To Frames
		Bank=S\FrameBank[Frame-1]
		Byte=BankSize(Bank)
		WriteBytes(Bank,Stream,0,Byte)
	Next
	
End Function

Function ImportSpriteFile(FilePath$)
	Local Stream=ReadFile(FilePath)
	If (Stream)
		Local Path$=TrimPath(FilePath)
		Local Name$=Right(FilePath,Len(FilePath)-Len(Path))
		MRU_SPRITEFILE=Left(Name,Len(Name)-4)
		GetSpritesDataFromStream(Stream)
		CloseFile Stream
	End If
End Function

Function GetSpritesDataFromStream(Stream)
	SPRITE_COUNT=ReadByte(Stream)
	GetSpritesFromStream(Stream)
End Function

Function GetSpritesFromStream(Stream)
	Local Count
	For Count=0 To SPRITE_COUNT
		GetSpriteDataFromStream(Stream)
	Next
End Function

Function GetSpriteDataFromStream(Stream)
	Local S.SPRITE=New SPRITE
	
	Local Byte=ReadShort(Stream)
	
	S\Reference=GetSpriteReferenceFromByte(Byte)
	SPRITES[S\Reference]=Handle(S)
	
	S\Width=GetFrameWidthUnitsFromByte(Byte)
	S\Height=GetFrameHeightUnitsFromByte(Byte)
	
	S\Frames=GetFramesFromByte(Byte)
	S\Reversal=GetReversalFlagFromByte(Byte)
	SetSpriteBanksFromStream(S,Stream)
	
End Function	

Function SetSpriteBanksFromStream(S.SPRITE,Stream)
	Local Frame
	Local Bank
	Local Byte
	For Frame=1 To S\Frames
		Bank=CreateBank(S\Width*S\Height*UNIT_RESOLUTION)
		Byte=BankSize(Bank)
		ReadBytes(Bank,Stream,0,Byte)
		S\FrameBank[Frame-1]=Bank
	Next
End Function



Floyd(Posted 2015) [#2]
The issue seems to be specifically particular with trying to write the Image data to a bank.

Just reading the code, not trying to run it...

Writing image data to bank seems to be the BufferToBank function, which contains
		For X=0 To W-1 Step UNIT_RESOLUTION
			
			
			Pixel=( ReadPixelFast(X+n,Y,Buffer))
			
			If (Pixel=-1)
				Byte=Byte+(1 Shl n)
			End If
			
			PokeFrameLine(S,Bank,Y,Byte)
			
		Next

using n as an offset. But n never changes, is always the inital value of zero.