Code archives/Graphics/TileWiper V1.2

This code has been declared by its author to be Public Domain code.

Download source code

TileWiper V1.2 by Popstar2002
This was my first Blitz Basic program... I have used it (successfully) on two commercial products for the Game Boy Color...

The program looks at each tile in the image and compares it to all other tiles. If several tiles look alike within a certain threshold, the best tile will be used multiple times, thus reducing the number of tiles.

Feel free to make a GUI interface or whatever you like. If you do, please let me know. :)

Due to the Game Boy Color's hardware, the program also flips the tiles on X and Y if it can.
;----------------------------;
;      TileWiper V1.2        ;
;----------------------------;
;My first Blitz Basic Program;
;      Latest version:       ;
;    January 8th - 2002      ;
;----------------------------;
;          Made by           ;
;    Laust Palbo Nielsen     ;
;----------------------------;
;  This program was made to  ;
;optimize the amount of tiles;
;  used in a tilemap on all  ;
; tilebased sytems that can  ;
;        flip tiles          ;
;                            ;
; If you use this program as ;
;part of the development of a;
; commercial product, please ;
;send a copy of the finished ;
;       product to me.       ;
;                            ;
;   Current address can be   ;
;   obtained by mailing me   ;
;      @ laust@palbo.dk      ;
;----------------------------;

AppTitle "TileWiper V1.2"

Global TileOne, TileTwo, Changeflag, TileSizeX, TileSizeY, TileSize, TilesX, TilesY, MapSize, PicWidth, PicHeight, MaxLoss#, Tiles
Global Width, Height, OffSetX, OffSetY, Threshold#, Image$

Global Counter

Global SumRed, SumGreen, SumBlue, Sum#, Percent#
Global SumRedFlipX, SumGreenFlipX, SumBlueFlipX, SumFlipX#, PercentFlipX#
Global SumRedFlipY, SumGreenFlipY, SumBlueFlipY, SumFlipY#, PercentFlipY#
Global SumRedFlipXY, SumGreenFlipXY, SumBlueFlipXY, SumFlipXY#, PercentFlipXY#

Global ColorDifRed, ColorDifGreen, ColorDifBlue
Global ColorDifRedFlipX, ColorDifGreenFlipX, ColorDifBlueFlipX
Global ColorDifRedFlipY, ColorDifGreenFlipY, ColorDifBlueFlipY
Global ColorDifRedFlipXY, ColorDifGreenFlipXY, ColorDifBlueFlipXY

Global ColorTwoGreen, ColorOneBlue, ColorTwoBlue
Global ColorTwoRedFlipX, ColorTwoGreenFlipX, ColorTwoBlueFlipX
Global ColorTwoRedFlipY, ColorTwoGreenFlipY, ColorTwoBlueFlipY
Global ColorTwoRedFlipXY, ColorTwoGreenFlipXY, ColorTwoBlueFlipXY

Global Dist#, DistFlipX#, DistFlipY#, DistFlipXY#

Width=352 : Height=420

Graphics3D Width, Height, 32, 2
ClsColor 128,128,196
Cls

Color 255, 255, 255

;-----------------------------------;
;         Start the Program         ;
;-----------------------------------;

;Get the user information via inputs

Image$=Input$ ("Source image: ") If Image$="" Then Image$="background.bmp"
Loss#=Input ("Loss (1-100) - Press Enter for 100 : ") If Loss#=0 Then Loss#=100
Thres#=Loss# ;Input ("Threshold (1-100): ") If Thres#=0 Then Thres#=5
TileSizeX=Input ("Tile size X - Press Enter for 8 : ") If TileSizeX=0 Then TileSizeX=8
TileSizeY=Input ("Tile size Y - Press Enter for 8 : ") If TileSizeY=0 Then TileSizeY=8

ImgSize=LoadImage (Image$)
PicWidth=ImageWidth (ImgSize)
PicHeight=ImageHeight (ImgSize)
TileSize=TileSizeX*TileSizeY

FreeImage (ImgSize)

;Now that the user has typed in this information, get the last variables

MaxLoss#=Loss#*195.075*TileSize
Threshold#=Thres#*195.075*(TileSize/20)

;Get the number of tiles on the X and Y Axis

TilesX=PicWidth/TileSizeX
TilesY=PicHeight/TileSizeY

;Get the number of tiles in all

MapSize=(TilesX*TilesY)

;Get the starttime so we can see how long it takes

StartTime=MilliSecs()

;Change the screenmode if the picture is too large

Width=Picwidth+32
Height=PicHeight+260

If Width<352 Then Width=352
If Height<420 Then Height=420

Graphics3D Width, Height, 32 ,2
ClsColor 128,128,196

;Clear the screen and start working

Cls

OptimizedImage=CreateImage (PicWidth, PicHeight)

;Set the offsets so the pictures will be centered on the screen

OffsetX=(Width-PicWidth)/2
OffsetY=(Height-PicHeight)/4

Dim NewMap						(MapSize)			;This is where the final map will be stored
Dim FlipMap						(MapSize)			;This map stores the data of which way a tile is flipped
Dim PercentMap#					(Mapsize)			;This map stores the current % information of each tile

Dim TileSetRed					(TileSize, MapSize)	;These three arrays store the standard tile colors
Dim TileSetGreen				(TileSize, MapSize)
Dim TileSetBlue					(TileSize, MapSize)

Dim TileSetRedFlipX				(TileSize, MapSize)	;These three arrays store the tile colors of tiles flipped
Dim TileSetGreenFlipX			(TileSize, MapSize)	;on the X-axis
Dim TileSetBlueFlipX			(TileSize, MapSize) 

Dim TileSetRedFlipY				(TileSize, MapSize)	;These three arrays store the tile colors of tiles flipped
Dim TileSetGreenFlipY			(TileSize, MapSize)	;on the Y-axis
Dim TileSetBlueFlipY			(TileSize, MapSize)

Dim TileSetRedFlipXY			(TileSize, MapSize)	;These three arrays store the tile colors of tiles flipped
Dim TileSetGreenFlipXY			(TileSize, MapSize)	;on the X and Y-axis
Dim TileSetBlueFlipXY			(TileSize, MapSize)

Dim CountArray					(MapSize)			;This array is used at the end to count the amount of unique tiles

;Setup the NewMap and PercentMap arrays so all the tiles that aren't changed will still be drawn

Setup ()

;Load the Tilemap

Tiles=LoadAnimImage (Image$, TileSizeX, TileSizeY, 0, MapSize)

PreCalculate ()

SetBuffer FrontBuffer()								;Now that we're done, go to the frontbuffer
Cls													;and clear the screen

PreCalcTimeEnd=MilliSecs()

;DrawSource ()
DrawDestination ()

Color 255, 255, 255

Text Width/2, OffsetY-20, "Precalculation done in "+((PreCalcTimeEnd-StartTime)/1000)+" seconds", 1, 0

;Main Program
;----------------------------

Main ()

;Compare
;--------------------------------

For Count=MapSize-1 To 0 Step -1		;Go through the entire map backwards
	Compare=NewMap(Count)				;Compare gets the tilenumber that has been used in NewMap(Count)
	If Compare<>Newmap(Compare)			;If the tile on the position that equals Compare does npt itself equal Compare,
		NewMap(Compare)=Compare			;then put it back in its original position
		FlipMap(Compare)=0				;and make sure that it is not flipped.
	End If
Next


;Draw the last changes
;--------------------------------

SetBuffer ImageBuffer(OptimizedImage)

FlipTiles ()

SetBuffer FrontBuffer()

DrawImage (OptimizedImage, OffsetX, OffsetY)


;Check to see how many different tiles are left.
;--------------------------------

For Count=0 To MapSize-1
	Intermediate=NewMap(Count)
	For Reading=Count+1 To MapSize-1
		If Intermediate=Newmap(Reading)
			CountArray(Reading)=0
		End If
	Next
Next


;Check to see how many of these tiles are flipped.
;--------------------------------

FinalCount=0
FlipXsum=0
FlipYsum=0
FlipXYsum=0

For Count=0 To MapSize-1
	FinalCount=FinalCount+CountArray(Count)
	If FlipMap(Count)>0
		If FlipMap(Count)=1 Then FlipXsum=FlipXsum+1
		If FlipMap(Count)=2 Then FlipYsum=FlipYsum+1
		If FlipMap(Count)=3 Then FlipXYsum=FlipXYsum+1
	End If
Next


;Prepare a TileSet from NewMap
;--------------------------------
;!!!Note: This is where I should create a binary file to store the map information!!!

TileSet ()


;Print the final results
;--------------------------------

Color 128,128,196										;Set the color to the background color
Rect (Width/2)-60, 20, 120, 20, 1					;Remove what we displayed last time
Color 255, 255, 255									;Set the color to white

StopTime=MilliSecs()

Text Width/2, 20, "Done in "+((StopTime-StartTime)/1000)+" seconds", 1, 0
Text 8, Height-180, " # of Tiles: "+MapSize
Text 8, Height-160, " Unique Tiles: "+FinalCount
Text 8, Height-120, " Tiles Flipped X: "+FlipXsum
Text 8, Height-100, " Tiles Flipped Y: "+FlipYsum
Text 8, Height-80, " Tiles Flipped XY: "+FlipXYsum

Text 8, Height-40, " Press 'S' to save optimized BMP image."
Text 8, Height-20, " Press ESC to quit."


;Wait for the final user interaction
;--------------------------------

Repeat

	If KeyDown(1)=1 Then End						;If user presses ESC then end the program
	If KeyDown(31)=1								;If user presses 'S' then save the images and end the program
		SaveImage (OptimizedImage, "TW_"+Image$)
		End
	End If

Forever

End








;!!!!----------------------------------------------------Functions------------------------------------------------------!!!!

Function Setup ()

	For Count=0 To MapSize-1
		NewMap(Count)=Count
		PercentMap#(Count)=MaxLoss#
		CountArray(Count)=1
	Next

End Function

;------------------------------

Function PreCalculate()

;Store all colors of all tiles in four sets of arrays: TileSet

	Text width/2, 0, "Precalculating!", 1, 0 			;Tell the user why 'nothing' is happening
													
	For PreCalc=0 To MapSize-1

		SetBuffer BackBuffer()							;Do all the drawing in the backbuffer so it doesn't look weird onscreen
	
		DrawBlock (tiles, 0, 0, PreCalc)
		PreCalcCount=0
		CounterX=0
		CounterY=0
	
		For Y=0 To TileSizeY-1
			For X=0 To TileSizeX-1
				GetColor X, Y

				TileSetRed			(PreCalcCount, PreCalc)=ColorRed()	;Store R, G and B values of the source tiles
				TileSetGreen		(PreCalcCount, PreCalc)=ColorGreen()
				TileSetBlue			(PreCalcCount, PreCalc)=ColorBlue()

				FlipXOne=(TileSizeX-1)-X								;Flip X-values
				FlipYOne=(Y)											;Y is normal
				FlipX=FlipXOne+(TileSizeX*FlipYOne)						;Calculate the FlipX value

				TileSetRedFlipX		(FlipX, PreCalc)=ColorRed()			;Store R, G and B values of tiles flipped
				TileSetGreenFlipX	(FlipX, PreCalc)=ColorGreen()		;on the X-axis
				TileSetBlueFlipX	(FlipX, PreCalc)=ColorBlue()

				FlipXOne=(X)											;X is normal
				FlipYOne=(TileSizeY-1)-Y								;Flip Y-values
				FlipY=FlipXOne+(TileSizeX*FlipYOne)						;Calculate the FlipX value
			
				TileSetRedFlipY		(FlipY, PreCalc)=ColorRed()			;Store R, G and B values of tiles flipped
				TileSetGreenFlipY	(FlipY, PreCalc)=ColorGreen()		;on the Y-axis
				TileSetBlueFlipY	(FlipY, PreCalc)=ColorBlue()

				FlipXOne=(TileSizeX-1)-X								;Flip X-values
				FlipYOne=(TileSizeY-1)-Y								;Flip Y-valus
				FlipXY=FlipXOne+(TileSizeX*FlipYOne)					;Calculate the FlipXY value
			
				TileSetRedFlipXY	(FlipXY, PreCalc)=ColorRed()		;Store R, G and B values of tiles flipped
				TileSetGreenFlipXY	(FlipXY, PreCalc)=ColorGreen()		;on the X and Y-axis
				TileSetBlueFlipXY	(FlipXY, PreCalc)=ColorBlue()

				PreCalcCount=PreCalcCount+1

			Next
		Next

		If KeyDown(1)=1 Then End
	
		SetBuffer FrontBuffer()							;Go back to the frontbuffer and show the user that something is actually happening
		Color 128,128,196									;Set the color to the background color
		Rect (Width/2)-60, 20, 120, 20, 1				;Remove what we displayed last time
		Color 255, 255, 255								;Set the color to white
		Text Width/2, 20, (PreCalc+1)+"/"+MapSize, 1, 0	;Show how far we've come
							
	Next

End Function

;------------------------------

Function Main ()

	Color 0, 255, 128
	RectX=0 : RectY=0

	For TileOne=0 To MapSize-1

		If RectX=PicWidth 
			RectX=0
			RectY=RectY+TileSizeY
		End If

		If PercentMap#(TileOne)<>-1							;Only check if the tile hasn't been locked.

			Color 128,128,196									;Set the color to the background color
			Rect (Width/2)-60, 20, 120, 20, 1				;Remove what we displayed last time
			Color 255, 255, 255								;Set the color to white
			Text Width/2, 20, TileOne+"/"+MapSize, 1, 0		;Show how far we've come

;			For TileTwo=TileOne+1 To MapSize-1
			For TileTwo=0 To MapSize-1
						
				If PercentMap#(TileTwo)<>-1 And TileTwo<>TileOne

					Color 128, 0, 128
					Rect OffSetX+RectX, OffSetY+RectY, TileSizeX, TileSizeY, 1
			
					CompareTiles ()

				End If

			Next

			;If there has been any changes to NewMap (ChangeFlag is set to 1) then redraw NewMap

			If ChangeFlag=1
				DrawDestination ()
				ChangeFlag=0
			End If

		End If

		RectX=RectX+TileSizeX

	Next

End Function

;------------------------------

Function DrawSource ()

	Frame=0	

	For y=0 To TilesY-1
		For x=0 To TilesX-1
			DrawBlock (Tiles, (X*TileSizeX)+OffsetX-1, (Y*TileSizeY+OffsetY), Frame)
			Frame=Frame+1
		Next
	Next

End Function

;------------------------------

Function DrawDestination ()

	Frame=0	

	For y=0 To TilesY-1
		For x=0 To TilesX-1
			DrawBlock (Tiles, (X*TileSizeX)+OffsetX, (Y*TileSizeY+OffsetY), NewMap(Frame))
			Frame=Frame+1
		Next
	Next
	
End Function

;------------------------------

Function CompareTiles ()

	Counter=0

	SumRed=0
	SumGreen=0
	SumBlue=0

	Sum#=0

	SumRedFlipX=0
	SumGreenFlipX=0
	SumBlueFlipX=0

	SumFlipX#=0

	SumRedFlipY=0
	SumGreenFlipY=0
	SumBlueFlipY=0

	SumFlipY#=0

	SumRedFlipXY=0
	SumGreenFlipXY=0
	SumBlueFlipXY=0

	SumFlipXY#=0
	
	Dist#=0
	DistFlipX#=0
	DistFlipY#=0
	DistFlipXY#=0

	For Counter=0 To TileSize-1 

		GetRGBValues ()
		
		GetSums ()

	Next

	;Since most of the time is spent in this loop, the user can exit it here by pressing 'Esc.'
				
	If KeyDown(1)=1 Then End
	
	If Sum#=0 Or Sum#<Threshold# And PercentMap(TileTwo)<>-1
		NewMap(TileTwo)=TileOne
		PercentMap#(TileTwo)=-1
		FlipMap(TileTwo)=0
		ChangeFlag=1
	End If

	If SumFlipX#=0 Or SumFlipX#<Threshold# And PercentMap(TileTwo)<>-1
		NewMap(TileTwo)=TileOne
		PercentMap#(TileTwo)=-1
		FlipMap(TileTwo)=1
		ChangeFlag=1
	End If

	If SumFlipY#=0 Or SumFlipY#<Threshold# And PercentMap(TileTwo)<>-1
		NewMap(TileTwo)=TileOne
		PercentMap#(TileTwo)=-1
		FlipMap(TileTwo)=2
		ChangeFlag=1
	End If

	If SumFlipXY#=0 Or SumFlipXY#<Threshold# And PercentMap(TileTwo)<>-1
		NewMap(TileTwo)=TileOne
		PercentMap#(TileTwo)=-1
		FlipMap(TileTwo)=3
		ChangeFlag=1
	End If

	DoSums ()

End Function

;--------------------------------

Function GetRGBValues ()

	;Get the RGB values for tiles that aren't flipped.
				
	ColorOneRed=TileSetRed(Counter, TileOne)
	ColorTwoRed=TileSetRed(Counter, TileTwo)
	ColorOneGreen=TileSetGreen(Counter, TileOne)

	;Get the RGB values for the tiles that we are comparing to.
				
	ColorTwoGreen=TileSetGreen(Counter, TileTwo)
	ColorOneBlue=TileSetBlue(Counter, TileOne)
	ColorTwoBlue=TileSetBlue(Counter, TileTwo)

	;Get the RGB values for tiles that are flipped X.
				
	ColorTwoRedFlipX=TileSetRedFlipX(Counter, TileTwo)
	ColorTwoGreenFlipX=TileSetGreenFlipX(Counter, TileTwo)
	ColorTwoBlueFlipX=TileSetBlueFlipX(Counter, TileTwo)

	;Get the RGB values for tiles that are flipped Y.
				
	ColorTwoRedFlipY=TileSetRedFlipY(Counter, TileTwo)
	ColorTwoGreenFlipY=TileSetGreenFlipY(Counter, TileTwo)
	ColorTwoBlueFlipY=TileSetBlueFlipY(Counter, TileTwo)

	;Get the RGB values for tiles that are flipped X and Y.
				
	ColorTwoRedFlipXY=TileSetRedFlipXY(Counter, TileTwo)
	ColorTwoGreenFlipXY=TileSetGreenFlipXY(Counter, TileTwo)
	ColorTwoBlueFlipXY=TileSetBlueFlipXY(Counter, TileTwo)

	Dist#=Dist#+((ColorOneRed-ColorTwoRed)*(ColorOneRed-ColorTwoRed))+((ColorOneGreen-ColorTwoGreen)*(ColorOneGreen-ColorTwoGreen))+((ColorOneBlue-ColorTwoBlue)*(ColorOneBlue-ColorTwoBlue))
	DistFlipX#=DistFlipX#+((ColorOneRed-ColorTwoRedFlipX)*(ColorOneRed-ColorTwoRedFlipX))+((ColorOneGreen-ColorTwoGreenFlipX)*(ColorOneGreen-ColorTwoGreenFlipX))+((ColorOneBlue-ColorTwoBlueFlipX)*(ColorOneBlue-ColorTwoBlueFlipX))
	DistFlipY#=DistFlipY#+((ColorOneRed-ColorTwoRedFlipY)*(ColorOneRed-ColorTwoRedFlipY))+((ColorOneGreen-ColorTwoGreenFlipY)*(ColorOneGreen-ColorTwoGreenFlipY))+((ColorOneBlue-ColorTwoBlueFlipY)*(ColorOneBlue-ColorTwoBlueFlipY))
	DistFlipXY#=DistFlipXY#+((ColorOneRed-ColorTwoRedFlipXY)*(ColorOneRed-ColorTwoRedFlipXY))+((ColorOneGreen-ColorTwoGreenFlipXY)*(ColorOneGreen-ColorTwoGreenFlipXY))+((ColorOneBlue-ColorTwoBlueFlipXY)*(ColorOneBlue-ColorTwoBlueFlipXY))

End Function

;--------------------------------

Function GetSums ()

	;Add it all up and get a final sum for tiles that aren't flipped.
				
	Sum#=Dist#

	SumFlipX#=DistFlipX#

	SumFlipY#=DistFlipY#
				
	SumFlipXY#=DistFlipXY#

;WaitMouse

End Function

;--------------------------------

Function DoSums()

	Percent#=Sum#;/TileSize
	PercentFlipX#=SumFlipX#;/TileSize
	PercentFlipY#=SumFlipY#;/TileSize
	PercentFlipXY#=SumFlipXY#;/TileSize

	;--------------------------------
		
	;If this tile looks more like the original than any other, then use this tile instead.
		
	If Percent#<MaxLoss# And Percent#<=PercentMap#(TileTwo)
		PercentMap#(TileTwo)=Percent#
		NewMap(TileTwo)=TileOne
		FlipMap(TileTwo)=0
		ChangeFlag=1			;By setting ChangeFlag to 1, the NewMap will be redrawn
	End If
		
	;If this tile, flipped X, looks more like the original than any other, then use this tile instead.
		
		
	If PercentFlipX#<MaxLoss# And PercentFlipX#<=PercentMap#(TileTwo)
		PercentMap#(TileTwo)=PercentFlipX#
		NewMap(TileTwo)=TileOne
		FlipMap(TileTwo)=1
		ChangeFlag=1			;By setting ChangeFlag to 1, the NewMap will be redrawn
	End If
		
	;If this tile, flipped Y, looks more like the original than any other, then use this tile instead.
		
		
	If PercentFlipY#<MaxLoss# And PercentFlipY#<=PercentMap#(TileTwo)
		PercentMap#(TileTwo)=PercentFlipY#
		NewMap(TileTwo)=TileOne
		FlipMap(TileTwo)=2
		ChangeFlag=1			;By setting ChangeFlag to 1, the NewMap will be redrawn
	End If
		
	;If this tile, flipped X and Y, looks more like the original than any other, then use this tile instead.
		
	
	If PercentFlipXY#<MaxLoss# And PercentFlipXY#<=PercentMap#(TileTwo)
		PercentMap#(TileTwo)=PercentFlipXY#
		NewMap(TileTwo)=TileOne
		FlipMap(TileTwo)=3
		ChangeFlag=1			;By setting ChangeFlag to 1, the NewMap will be redrawn
	End If

End Function

;--------------------------------

Function FlipTiles ()

	Frame=0

	For Y=0 To TilesY-1
		For X=0 To TilesX-1

			;Draw the NewMap one last time to make sure that the new changes are drawn


			If FlipMap(Frame)=0				;Check the FlipMap to make sure that this tile shouldn't be flipped
				DrawBlock (Tiles, (X*TileSizeX), Y*TileSizeY, NewMap(Frame))
			End If


			;Flip the tiles that need to be flipped

			If FlipMap(Frame)>0				;Check the FlipMap to see if (and how) this tile should be flipped
				
				CountPixel=0				
				
				For PY=0 To TilesizeY-1
					For PX=0 To TilesizeX-1
				
						If FlipMap(Frame)=1 Then Color TileSetRedFlipX(CountPixel, NewMap(Frame)), TileSetGreenFlipX(CountPixel, NewMap(Frame)), TileSetBlueFlipX(CountPixel, NewMap(Frame))
						If FlipMap(Frame)=2 Then Color TileSetRedFlipY(CountPixel, NewMap(Frame)), TileSetGreenFlipY(CountPixel, NewMap(Frame)), TileSetBlueFlipY(CountPixel, NewMap(Frame))
						If FlipMap(Frame)=3 Then Color TileSetRedFlipXY(CountPixel, NewMap(Frame)), TileSetGreenFlipXY(CountPixel, NewMap(Frame)), TileSetBlueFlipXY(CountPixel, NewMap(Frame))
				
					Plot (X*TileSizeX)+PX, (Y*TileSizeY)+PY
				
					CountPixel=CountPixel+1
				
					Next
				Next
		
			End If

			Frame=Frame+1

		Next
	Next

End Function

;--------------------------------

Function TileSet ()

	NewSet=CreateImage (PicWidth, PicHeight)
	SetBuffer ImageBuffer(NewSet)

	DrawBlock (Tiles, 0, 0, 0)
	GetColor 0, 0
	ClsColor ColorRed(), ColorGreen(), ColorBlue()
	Cls

	CounterTwo=0 : X=0 : Y=0
	For Count=0 To FinalCount-1
		Repeat
			If CountArray(CounterTwo)=1
				DrawBlock (Tiles, X*TileSizeX, Y*TileSizeY, NewMap(CounterTwo))
				Flag=1 : X=X+1
				If X=TilesX
					Y=Y+1
					X=0
				End If
			End If
			CounterTwo=CounterTwo+1
		Until Flag=1
		Flag=0
	Next

	SetBuffer FrontBuffer()

End Function

Comments

None.

Code Archives Forum