Global array of types keeps returning Null?

BlitzMax Forums/BlitzMax Programming/Global array of types keeps returning Null?

A little help, if you could spare your time - firstly, a big box o' code:
Strict

Rem
bbdoc: IFF ILBM loader
End Rem
Module HOT.IFFILBMLoader

ModuleInfo "Version: 1.00"
ModuleInfo "Author: Toby Zuijdveld"
ModuleInfo "License: Blitz Shared Source Code"
ModuleInfo "Copyright: Jerry Morrison, Electronic Arts (public domain)"
ModuleInfo "Modserver: n/a"

ModuleInfo "History: 1.00 Release"

Import BRL.Pixmap
Import BRL.EndianStream

Private

Function ReadTag$( stream:TStream )
	Local tag:Byte[4]
	If stream.ReadBytes( tag,4 )<>4 Return
	Return Chr(tag[0])+Chr(tag[1])+Chr(tag[2])+Chr(tag[3])
End Function

Function UStoSI%(a:Short)
	If a>$7FFF Then Return -($8000-(a-$8000)) Else Return a
End Function	' unsigned short to signed integer

Const	cmpNone		= 0
Const	cmpByteRun1	= 1

Type	ColourRegister
	Field	red:Byte
	Field	green:Byte
	Field	blue:Byte	' colour intensities 0..255
End Type	' size = 3 bytes

Global	ColourMap:ColourRegister[]	= Null

Public

Type TPixmapLoaderILBM Extends TPixmapLoader

	Method LoadPixmap:TPixmap(stream:TStream)
		stream=BigEndianStream( stream )
		
		If ReadTag( stream )<>"FORM" Return

		Local	dud%					= stream.Readint()	' length of file after ILBM header

		If ReadTag( stream )<>"ILBM" Return

		Local	cmap%					= 0
		Local	w:Short					= 0
		Local	h:Short					= 0
		Local	x%						= 0
		Local	y%						= 0
		Local	nPlanes:Byte			= 0
		Local	masking:Byte			= 0
		Local	compression:Byte		= 0
		Local	transparentColour:Short	= 0
		Local	xAspect:Byte			= 0
		Local	yAspect:Byte			= 0
		Local	pageWidth%				= 0
		Local	pageHeight%				= 0
		Local	plane%					= 0
		Local	scanline%				= 0
		Local	i%						= 0
		Local	n%						= 0
		Local	nn%						= 0
		Local	pixmap:TPixmap			= Null

		While Not stream.Eof()
			Local blahblah$=ReadTag$(stream)
			Select	blahblah$'Readtag$(stream)
				Case	"BMHD"	' BitMapHeader
					dud					= stream.ReadInt()				' length of BitMapHeader chunk
					w					= stream.ReadShort()
					h					= stream.ReadShort()			' raster width & height in pixels
					x					= UStoSI(stream.ReadShort())
					y					= UStoSI(stream.ReadShort())	' pixel position for this image
					nPlanes				= stream.ReadByte()				' # source bitplanes
					masking				= stream.ReadByte()				' Choice of masking technique.
					compression			= stream.ReadByte()				' Choice of compression algorithm applied to the rows of all source and mask planes. 
					Local	dud2%		= stream.ReadByte()				' unused; for consistency, put 0 here
					transparentColour	= stream.ReadShort()			' transparent "colour number" (sort of)
					xAspect				= stream.ReadByte()
					yAspect				= stream.ReadByte()				' pixel aspect, a ratio width : height
					pageWidth			= UStoSI(stream.ReadShort())
					pageHeight			= UStoSI(stream.ReadShort())	' source "page" size in pixels
					stream.SkipBytes(dud-20)							' extended chunk compatibility
				Case	"CMAP"	' ColorMap
							dud			= stream.ReadInt()				' length of ColourMap chunk
					If ColourMap=Null
						cmap		= dud/3
						ColourMap	= New ColourRegister[cmap+1]		' size = (2^nPlanes)*3 bytes
						For i=1 To cmap
'							ColourMap[i]		= New ColourRegister
							ColourMap[i].red	= stream.ReadByte()
							ColourMap[i].green	= stream.ReadByte()
							ColourMap[i].blue	= stream.ReadByte()
						Next
						If dud & 1 Then stream.SkipBytes(1)				' padded chunk compatibility
					Else
						stream.SkipBytes(dud)							' skip chunk
					EndIf	' ColourMap=Null
				Case	"BODY"	' 
							dud				= stream.ReadInt()			' length of BODY chunk
					Local	row%[w+9]
					Local	buffer%[9]
							pixmap			= TPixmap.Create(w,h,PF_RGB888)
					If 2^nPlanes>cmap Then ColourMap=ColourMap[..(2^nPlanes)+1]
					For Local column%=1 To h
						row			= New Int[w+9]
						Select	compression
							Case	cmpNone
								For plane=1 To nPlanes
									For scanline=1 To w Step 8
										buffer[1]	= stream.ReadByte()
										For dud=2 To 8
											buffer[dud]				= (buffer[1] Shr (dud-1)) & 1
										Next	' dud=2 To 8
										buffer[1]	= buffer[1] & 1
										For dud=1 To 8
											row[scanline+(dud-1)]	= row[scanline+(dud-1)]+(buffer[dud] Shl (plane-1))
										Next	' dud=1 To 8
									Next	' scanline=1 To w Step 8
								Next	' plane=1 To nPlanes
							Case	cmpByteRun1
								For plane=1 To nPlanes
									scanline	= 1
									Repeat
										dud=stream.ReadByte()
										If dud>127 Then dud:-256	' unsigned to signed conversion
										If dud<>-128	' noop
											If dud<0	' replicate the next byte -n+1 times
												dud			= Abs(dud)+1
												n			= stream.ReadByte()
												buffer[1]	= n
												For nn=2 To 8
													buffer[nn]	= (buffer[1] Shr (nn-1)) & 1
												Next	' nn=2 To 8
												buffer[1]								= buffer[1] & 1
												For i=1 To dud
													For nn=1 To 8
														row[scanline+(nn-1)+((i-1)*8)]	= row[scanline+(nn-1)+((i-1)*8)]+(buffer[nn] Shl (plane-1))
													Next	' nn=1 To 8
												Next	' i%=1 To dud
												scanline:+dud
											Else		' copy the next n+1 bytes literally
												For nn=1 To dud+1
													n			= stream.ReadByte()
													buffer[1]	= n
													For nn%=2 To 8
														buffer[nn]						= (buffer[1] Shr (nn-1)) & 1
													Next	' nn=2 To 8
													buffer[1]	= buffer[1] & 1
													For i=1 To 8
														row[scanline+(i-1)]				= row[scanline+(i-1)]+(buffer[i] Shl (plane-1))
													Next	' i=1 To 8
													scanline:+1
												Next	' nn=1 To dud+1
											EndIf
										EndIf
									Until scanline>w
								Next	' plane=1 To nPlanes
							Default	' unsupported compression algorithm
								dud	= 0
								Exit
						End Select	' compression
						debugstop
						If dud=0 Then pixmap			= Null;Exit
						For dud=1 To w
							pixmap.WritePixel dud-1,column-1,(ColourMap[row[dud]].red Shl 16)+(ColourMap[row[dud]].green Shl 8)+ColourMap[row[dud]].blue
						Next	' row=1 To w
					Next	' column=1 To h
					If cmap Then ColourMap	= Null
					Exit
				Default			' unsupported chunks
					stream.SkipBytes(stream.ReadInt())									' skip chunk
			End Select	' ReadTag$(stream)
			
			If pixmap Then Exit
		Wend	' Not stream.EOF()
		
		Return pixmap
	End Method

End Type

New TPixmapLoaderILBM

Don't get too scared about all that, there's only a couple of small sections I need help with : revolving around my use of the ColourMap:ColourRegister[] Global. What I'm trying to do with it, is keep an array of red, green, blue information available to the loader method in between calls. Looking at the code up there it doesn't make any sense to do it this way, but I'll be expanding on that later. If you jump down to the "CMAP" section, what it does is this : If a ColourMap array doesn't exist (ie it's Null), it creates an array of the size of the CMAP chunk (the number of colours in the palette table) - then when it comes time to setting the values in the array, it errors out with 'trying to access field of Null object'.

Which is fine, my head isn't coping very well with all this, but I managed to figure out that each entry in the array needs initialising as well, being that it's a custom type. But if you unRem the ColourMap line in that loop, I still have problems at the bottom of the method - scroll down to the pixmap.WritePixel line. Here, again, I get complaints that I'm referencing a Null object, which I thouroughly don't understand, it was created and set when I processed the CMAP entry - why can't I access it now?

It's supposed to be Global so there shouldn't be any problems from what I can tell. Any ideas would be immensely appreciated.

Oh, if you need an example file to use this on for whatever reason, grab one at http://members.dodo.com.au/~tzuyd/bull.iff - it's a small 5x5 graphic with a palette of 16 colours.

Oh and there's every possibility that even if the ColourMap stuff was working, that the graphic would look completely corrupted, so don't worry about that ;]

I believe you need to replace
ColourMap = New ColourRegister[cmap+1]	

with
ColourMap = ColourMap[..cmap+1]

At least that's what I do when I don't know in advance how large an array will be, and it works for me.

Thanks but no thanks Tom, that didn't seem to make a difference =[

Also, since ColourMap is a Global, is there a way to view it in the debug list? I only see the Locals in there... It's probably hiding somewhere that I missed =]

As you write, 'If a ColourMap array exists (ie it isn't Null), it creates an array of the size of the CMAP chunk...'

But when I read the code, I can see that you are doing the other way around.
You check if colormap=null, I don't know if thats the problem.

Woah, I must have been tired. No, that is supposed to read 'if a ColourMap array doesn't exist (ie it is Null)'... no need to create an array if one already exists (which I realise is impossible with the code posted above)...

EDIT : Something is definately amiss here. Either something is not behaving correctly, or there's a concept hidden somewhere that I'm completely failing to grasp. Observe:
Strict

Rem
bbdoc: IFF ILBM loader
End Rem
Module HOT.IFFILBMLoader

Import BRL.Pixmap
Import BRL.EndianStream

Private

Function ReadTag$( stream:TStream )
	Local tag:Byte[4]
	If stream.ReadBytes( tag,4 )<>4 Return
	Return Chr(tag[0])+Chr(tag[1])+Chr(tag[2])+Chr(tag[3])
End Function

Global	ColourMapRed[]
Global	ColourMapGreen[]
Global	ColourMapBlue[]	' dodginess because I couldn't get the previous code to work!

Public

Type TPixmapLoaderILBM Extends TPixmapLoader
	Method LoadPixmap:TPixmap(stream:TStream)
		stream=BigEndianStream( stream )
		
		If ReadTag( stream )<>"FORM" Return

		Local	dud%					= stream.Readint()	' length of file after ILBM header

		If ReadTag( stream )<>"ILBM" Return

		Local	cmap%					= 0
		Local	i%						= 0
		
		While Not stream.Eof()
			Local blahblah$=ReadTag$(stream)
			Select	blahblah$'Readtag$(stream)
				Case	"CMAP"	' ColorMap
							dud			= stream.ReadInt()				' length of ColourMap chunk
Rem
	The next tempthing line fails with the error:
		Identifier 'ColourMapRed' not found
End Rem
					Local tempthing=ColourMapRed[].length
Rem
	If the tempthing line is commented out, this line fails with the error:
		Expecting expression but encountered end=of-line
	If I change it to 'If ColourMapRed[].length=0' the same error as the tempthing line pops up
End Rem
					If ColourMapRed[]
						cmap		= dud/3
						ColourMapRed	= ColourMapRed[..cmap+1]
						ColourMapGreen	= ColourMapGreen[..cmap+1]
						ColourMapBlue	= ColourMapBlue[..cmap+1]
						For i=1 To cmap
							ColourMapRed[i]		= stream.ReadByte()
							ColourMapGreen[i]	= stream.ReadByte()
							ColourMapBlue[i]	= stream.ReadByte()
						Next
						If dud & 1 Then stream.SkipBytes(1)				' padded chunk compatibility
					Else
						stream.SkipBytes(dud)							' skip chunk
					EndIf	' ColourMap=Null
				Default			' unsupported chunks
					stream.SkipBytes(stream.ReadInt())									' skip chunk
			End Select	' ReadTag$(stream)
		Wend	' Not stream.EOF()
	End Method
End Type

New TPixmapLoaderILBM
This is essentially exactly the same code as before, with the bulk of the 'working' code removed. The biggest change is that I've converted from using a global custom type array to 3 seperate global arrays of the standard Int variety. These are supposed to be Globals and empty arrays are supposed to be equal to an array of size 0. So why, then, does it complain 'Identifier not found' when it encounters the above commented lines? Am I essentially in over my head here or is something genuinely not adding up?

Wow, I have no idea how the compiler should be parsing that, I would recomend removing the empty brackets [] from the offending lines.

As you can see from the following a null array and an array of zero elements is the same thing:

Local a[0]
Local b[1]

If Not a Print "a is null"
If Not b Print "b is null"


OK so it obviously comes down to the fact I have no idea. =] Wouldn't removing the brackets denote the array to a lowly variable? I guess that doesn't cause problems when I want to create an array later on then? Anyways, thanks simon.