(Technically this is NG issue, but I am assuming it is the same in "vanilla" BMax)
So I was wanting to automate the process of building a palette library for a bunch of sprite images (so I can later simplify the images and also do some code-based palette swapping etc)
but I ran into some issues with trying to make a list of the pixel values, as the TList commands refer to Object arguments.
Usually, Strings and whatever can simply recast as "Object" but not Integers it seems:::
Here's a simplified example:
Global Palette:TList
Local Image:TPixmap=LoadPixmap("Test.png")
For Local Y:Int= 0 Until Image.height
For Local X:Int= 0 Until Image.width
Local Pixel:Int=ReadPixel(Image,X,Y)
If ( Not (ExistInPalette(Pixel))) Then AddToPalette(Pixel)
Next
Next
DebugLog("Found "+Palette.Count()+" colours")
Function ExistInPalette:Byte(Pixel:Int)
If (Palette=Null) Then Return False
Return Palette.Contains(Pixel)
End Function
Function AddToPalette(Pixel:Int)
If (Palette=Null) Then Palette=New TList
Palette.AddLast(Pixel)
End Function
Working with an array may be easier, iterating through each array item, but I don't know how big the array may need to be in advance...
You might be better off with an IntMap rather than a List:
https://blitzmax.org/docs/en/api/brl/brl.map/tintmap/
You could use the Int pixel values as keys (the actual value the key returns wouldn't really matter -- a string representation of the key would be my choice). You can check for a key before adding via Contains(), then at the end of the process get a collection of all the keys with Keys(), which would be your entire palette.
It's a bit of a weird case for a Map because the keys themselves are the values that you care about, but hey ho!
Local Image:TPixmap=LoadPixmap("Test.png")
For Local Y:Int= 0 Until Image.height
For Local X:Int= 0 Until Image.width
Local Pixel:Int=ReadPixel(Image,X,Y)
TPalette.Add Pixel
Next
Next
Type TPalette
Global List:TList= New TList
Field Pixel:Int
Function Add(Pixel:Int)
If Contains(Pixel)=True Then Return
Item:TPalette = New TPalette
Item.Pixel = Pixel
List.AddLast Item
End Function
Function Contains:Int(Pixel)
For Local Item:TPalette = EachIn List
If Item.Pixel=Pixel then Return True
Next
Return False
End Function
End Type
Awesome!
Thanks so much for the qwuick replies :)
@Sledge I am not very familiar with the "Map" types and so was a little intimidated to try and risk overcomplicating and making things a lot worse - but thanks for the explanation - it would certainly be a neater approach!
@Midimaster - Thanks. I guess having the Pixel explicit cast as integer within the type scope and then using a custom iteration "contains" helps the compiler to interpret the Object?
What's funny as I originally wrote a function with similar iteration and equivalence check, but then changed it when I remembered the "contains" method :D
Quote...using a custom iteration "contains" helps the compiler to interpret the Object?...
No it is the
Local x:Type EachIn, that picks only the searched type in a list.
If your list contains objects of different types then the code line...
QuoteFor Local Item:TPalette = EachIn List
... already casts and limits the iteration to only one type.
Got it!
Thanks, Midimaster