n00b-questions ^_^

BlitzMax Forums/BlitzMax Beginners Area/n00b-questions ^_^

How do I free-up an image? (or anything else for that matter)

i=LoadImage(somefile)
Release i

(Or more specific, in my case, i is a member of a type..)

..leads to a major crash here.. (bmax1.14)

if you're new to bmx then have a look at http://www.blitzbasic.com/Community/posts.php?topic=41179 for some key differences. One of these is the garbage collection. Since 1.14 garbage collection has become more transparent to the programmer. That is you don't notice it, don't have to call it and don't have to worry (so much) about releasing things. There are a few guidelines to stick to though.

Try using strict mode.
When loading images, etc, use local newImage:Timage=loadimage("etc")
instead of local newImage=loadimage("etc")

this way your image will be "managed" by the garbage collector when it does its rounds. To answer your question you can "release" an image by simply removing any reference to it from your program. So, in this quick example of a program you can see it in action:
Strict

Type example
	Field image:Timage
	Field x,y,r
End Type

Graphics 640,480,0


Local i:example=New example
	i.image=LoadImage("B-Max.png")
	i.x=300
	i.y=200
	i.r=Rand(360)

		
' now draw our image
SetRotation i.r
DrawImage i.image,i.x,i.y
SetRotation 0
Flip
WaitKey

' now we get rid of any reference to it.
i.image = Null

' when the garbage collector does its rounds (every loop? Not sure when)
' it'll see that there are no more pointers, refernces or "connections"
' to the image we previously loaded. 
' That is to say nowhere in your code can you make a reference to it.
' Since i.image is null then it's basically gone.

Rem
Type example
	Field image:Timage
	Field another:Timage
	Field x,y,r
End Type

Graphics 640,480,0

Local i:example=New example
	i.image=LoadImage("B-Max.png")
	i.x=300
	i.y=200
	i.r=Rand(360)
	' make another connection/reference to the image
	i.another=i.image
	
' now draw our image
SetRotation i.r
DrawImage i.image,i.x,i.y
SetRotation 0

' now we get rid of any reference to it.
i.image = Null

' now, in the first example the image would be effectively gone/released
' but we made another reference to it with the .another.
' bmx still has a connection/reference to it so it won't get released

i.another = Null

EndRem


If you don't see an immediate change in GCMemAlloced() it's because bmx frees and reallocates the memory in a strange/fast way.

Hope it helps!

i:timage=LoadImage(somefile)
i = null

oops, to slow :)

Heh. I forgot to add a Strict to the top of my code. it's alright dave, you're my wife now.

Dave, my wife would like to use your toilet.

Dave, my wife says there is a blockage in your toilet.... I've fixed it now.

ah thx! I'll have a look/test ..

Dunno if I like this high-level resource-management tho.

Ahwell, can't be as bad as my cat bringing a mouse into my studio. ^_^

if you do this:


bank:TBank=createbank(100)
bank=null
bank:TBank=createbank(10)

Does the first bank get deleted by the GC then?

You shouldn't need the bank=Null statement, although it does no harm.

When you assign another value to bank with the second CreateBank there is no longer a reference to the first TBank. The garbage collector will, eventually, reclaim that memory.

behold
Strict

'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
Type IButton
	Field canvas:TGadget
	Field image:Timage
	Field width:Int
	Field height:Int
	Field state:Byte
	Field ID:String
	
	Rem
		state:
			0	off, normal
			1	off, mousemove
			2	on,  normal
			3	on,  mousemove
	EndRem
	
	Method ev()
		If EventSource()=canvas
			If EventID()=EVENT_MOUSEENTER
				state:+1
				update()
			EndIf
			If EventID()=EVENT_MOUSELEAVE
				state:-1
				update()
			EndIf
			If EventID()=EVENT_GADGETPAINT
				update()
			EndIf
			If EventID()=EVENT_MOUSEDOWN
				If EventData()=1
					If state<2
						state:+2
					Else
						state:-2
					EndIf
					update()
				EndIf
			EndIf
		EndIf
	End Method
	
	Method update()
		SetGraphics CanvasGraphics(canvas)
			DrawImage image,-state*(ImageWidth(image)/4),0
		Flip
	End Method
	
End Type

Function CreateIButton:IButton(x:Short, y:Short, w:Byte, h:Byte, ID$, img:Timage, parent:Tgadget, state:Byte=0)

	Local a:IButton=New IButton
		
	a.canvas=CreateCanvas(x,y,w,h,parent)
	a.image=img
	a.state=state

'	a.width=ImageWidth(img/4) ' try #1
'	a.height=ImageHeight(img)

'	a.width=ImageWidth(a.image/4) ' try #2
'	a.height=ImageHeight(a.image)

	Return a
End Function
'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>




Local testimage:Timage=CreateImage(32*4,32)
Local x,y,r,g,b,i:Byte
Local map:TPixmap=LockImage(testimage)
	For i=0 To 3
		For y=0 To 31
			For x=0 To 31
				r=Rnd(0,i*32+31)
				g=Rnd(0,i*32+31)
				b=Rnd(0,i*32+31)
				WritePixel map,i*32+x,y,$ff000000|b+256*g+65536*r
			Next
		Next
	Next
UnlockImage testimage
map=Null



Local window:Tgadget=CreateWindow("^_^",32,32,640,480)

Local ib1:IButton=CreateIButton(4,4,32,32,"dog",testimage,window,0)
Local ib2:IButton=CreateIButton(104,4,32,32,"cat",testimage,window,0)



OnEnd Quit

Repeat
	WaitEvent()
	If EventID()=EVENT_WINDOWCLOSE End
	
	ib1.ev()
	ib2.ev()
Forever

Function Quit()
End Function



I'm learning bmax by doing this.. :D

two questions:

1 why can't I get the imagewidth/height in that function?
(some error I get..)

2 can I somehow automate that .ev thing in the mainloop? So that upon creation of a gadget like this, things happen automatically?

1 why can't I get the imagewidth/height in that function?
Since a TImage contains .width and .height fields you can do this:

Print a.image.width

2 can I somehow automate that .ev thing in the mainloop? So that upon creation of a gadget like this, things happen automatically?

See new example here. I've removed width/height fields and replaced them with image.width etc..
Also, I added 'IButton.Ev()'. This calls a function in the IButton type which iterates through a TList (called IButtonList). The list contains references to all the buttons created. Every time you add a new button it is automatically added to the list thanks to the New() method (also present in the IButton type):
'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

Global IButtonList:TList=New TList

Type IButton
	Field canvas:TGadget
	Field image:Timage
	Field state:Byte
	Field ID:String
	
	Rem
		state:
			0	off, normal
			1	off, mousemove
			2	on,  normal
			3	on,  mousemove
	EndRem
	
	Function ev()
		For Local ib:IButton=EachIn IButtonList
			If EventSource()=ib.canvas
				If EventID()=EVENT_MOUSEENTER
					ib.state:+1
					ib.update()
				EndIf
				If EventID()=EVENT_MOUSELEAVE
					ib.state:-1
					ib.update()
				EndIf
				If EventID()=EVENT_GADGETPAINT
					ib.update()
				EndIf
				If EventID()=EVENT_MOUSEDOWN
					If EventData()=1
						If ib.state<2
							ib.state:+2
						Else
							ib.state:-2
						EndIf
						ib.update()
					EndIf
				EndIf
		EndIf
		Next
	End Function
	Method New()
		IButtonList.AddLast Self
	End Method
	Method update()
		SetGraphics CanvasGraphics(canvas)
			DrawImage image,-state*(image.width/4),0
		Flip
	End Method
End Type

Function CreateIButton:IButton(x:Short, y:Short, ID$, img:Timage, parent:Tgadget, state:Byte=0)
	Local a:IButton=New IButton
	a.canvas=CreateCanvas(x,y,img.width/4,img.height,parent)
	a.image=img
	a.state=state
	Return a
End Function
'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
'<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>




Local testimage:Timage=CreateImage(32*4,32)
Local x,y,r,g,b,i:Byte
Local map:TPixmap=LockImage(testimage)
	For i=0 To 3
		For y=0 To 31
			For x=0 To 31
				r=Rnd(0,i*32+31)
				g=Rnd(0,i*32+31)
				b=Rnd(0,i*32+31)
				WritePixel map,i*32+x,y,$ff000000|b+256*g+65536*r
			Next
		Next
	Next
UnlockImage testimage
map=Null



Local window:Tgadget=CreateWindow("^_^",32,32,640,480)

'Local ib.IButton
Local ib1:IButton=CreateIButton(4,4,"dog",testimage,window,0)
Local ib2:IButton=CreateIButton(104,4,"cat",testimage,window,0)
Local ib3:IButton=CreateIButton(50,40,"mouse",testimage,window,0)



OnEnd Quit

Repeat
	WaitEvent()
	If EventID()=EVENT_WINDOWCLOSE End
	IButton.Ev()
Forever

Function Quit()
End Function


width/height: ok, then why's imagewidth/height in the manual? :P Somehow it looks messy having 2 ways of working in 1 manual..

the list:

I imagined working with a list yeah .. but what I meant was something that looks transparent with the internal gadgets.

So, something that works automatically, just as it does for windows-gadgets.
Something that perhaps creates its own events, so I can have my own codes for my own gadgets..

btw, that 'New' method, is that a constructor actually?

Shouldn't you use...
'	a.width=ImageWidth(img)/4 ' try #1

?
Currently you're trying to divide a timage by 4... I think.

uhm...........

^___________________^


I blame Bmax for it.. I never did such stupidness in B+ :)

new Q:

How do I get the OS's form/gadget color? (like in Windows: typically 160,160,160 for a window)

How do I get the OS's form/gadget color? (like in Windows: typically 160,160,160 for a window)
Try this. The example returns the desktop colour. Just modify to suit your needs:
' API - GetSysColor

Extern "win32"
	Function GetSysColor%(index%)
End Extern


Const COLOR_3DDKSHADOW=21
Const COLOR_3DFACE=15
Const COLOR_3DHIGHLIGHT=20
Const COLOR_3DHILIGHT=20
Const COLOR_3DLIGHT=22
Const COLOR_3DSHADOW=16
Const COLOR_ACTIVEBORDER=10
Const COLOR_ACTIVECAPTION=2
Const COLOR_ADD=712
Const COLOR_ADJ_MAX=100
Const COLOR_ADJ_MIN=-100
Const COLOR_APPWORKSPACE=12
Const COLOR_BACKGROUND=1
Const COLOR_BLUE=708
Const COLOR_BLUEACCEL=728
Const COLOR_BOX1=720
Const COLOR_BTNFACE=15
Const COLOR_BTNHIGHLIGHT=20
Const COLOR_BTNHILIGHT=20
Const COLOR_BTNSHADOW=16
Const COLOR_BTNTEXT=18
Const COLOR_CAPTIONTEXT=9
Const COLOR_CURRENT=709
Const COLOR_CUSTOM1=721
Const COLOR_DESKTOP=1
Const COLOR_ELEMENT=716
Const COLOR_GRADIENTACTIVECAPTION=27
Const COLOR_GRADIENTINACTIVECAPTION=28
Const COLOR_GRAYTEXT=17
Const COLOR_GREEN=707
Const COLOR_GREENACCEL=727
Const COLOR_HIGHLIGHT=13
Const COLOR_HIGHLIGHTTEXT=14
Const COLOR_HOTLIGHT=26
Const COLOR_HUE=703
Const COLOR_HUEACCEL=723
Const COLOR_HUESCROLL=700
Const COLOR_INACTIVEBORDER=11
Const COLOR_INACTIVECAPTION=3
Const COLOR_INACTIVECAPTIONTEXT=19
Const COLOR_INFOBK=24
Const COLOR_INFOTEXT=23
Const COLOR_LUM=705
Const COLOR_LUMACCEL=725
Const COLOR_LUMSCROLL=702
Const COLOR_MATCH_VERSION=$200
Const COLOR_MENU=4
Const COLOR_MENUTEXT=7
Const COLOR_MIX=719
Const COLOR_NO_TRANSPARENT=$FFFFFFFF
Const COLOR_PALETTE=718
Const COLOR_RAINBOW=710
Const COLOR_RED=706
Const COLOR_REDACCEL=726
Const COLOR_SAMPLES=717
Const COLOR_SAT=704
Const COLOR_SATACCEL=724
Const COLOR_SATSCROLL=701
Const COLOR_SAVE=711
Const COLOR_SCHEMES=715
Const COLOR_SCROLLBAR=0
Const COLOR_SOLID=713
Const COLOR_SOLID_LEFT=730
Const COLOR_SOLID_RIGHT=731
Const COLOR_TUNE=714
Const COLOR_WINDOW=5
Const COLOR_WINDOWFRAME=6
Const COLOR_WINDOWTEXT=8


' example

col%=GetSysColor(COLOR_DESKTOP)
r%=col & $ff
g%=col Shr 8 & $ff
b%=col Shr 16 & $ff

Notify "Desktop Color (RGB) = "+r+", "+g+", "+b

End