Bug in RenderWorld

BlitzMax Forums/MiniB3D Module/Bug in RenderWorld

TomToad(Posted 2007) [#1]
here is a program that demonstrates the bug. Press the spacebar to render new cubes. Sometimes it'll crash the first time, sometimes you have to press the spacebar a few times before it crashes.

It is crashing with "Unhandled Exception:Attempt to access field or method of Null object"
It is stopping in TMesh.bmx, line 1510:
red# =brush.red

Edit: Changed resolution in the code to something more reasonable than my native wide-screen resolution :)


klepto2(Posted 2007) [#2]
no bug within minib3d I think, it is more a bug or failure in th Garbage Collector of BMax.
It seems if you remove an Entity this way sometimes the Delete() Method isn't called properly and the reference to other brushes seems to be deleted. As a workaround don't use FreeEntity within the delete() method. Try this instead:
SuperStrict

Import sidesign.minib3d

Type TCube
	Field X:Int
	Field Y:Int
	Field Z:Int
	Field Entity:TEntity
	
	Function create:TCube(x:Int,y:Int,z:Int)
		Local Cube:TCube = New TCube
		Cube.X = X
		Cube.Y = Y
		Cube.Z = Z
		
		Cube.Entity = CreateCube()
		Cube.Entity.Brush = CreateBrush()
		PositionEntity Cube.Entity,X,Y,Z
		Return Cube
	End Function
	
End Type
	
Graphics3D 800,600,32,1

Local Camera:TCamera = CreateCamera()
PositionEntity Camera,0,0,-20
Local Light:TLight = CreateLight()
RotateEntity Light,45,45,0

Local CubeList:TList = CreateList()

For Local x:Int = 1 To 10
	Local Cube:TCube = TCube.Create(Rand(-10,10),Rand(-10,10),Rand(0,10))
	CubeList.AddLast(Cube)
Next

While Not KeyHit(KEY_ESCAPE)
	Cls
	RenderWorld
	Flip
	
	If KeyHit(KEY_SPACE)
		For Local Cube:TCube = EachIn CubeList
			If Rand(1,4) = 1
				FreeEntity(Cube.Entity)
				CubeList.Remove(Cube)
				Local Cube2:TCube = TCube.Create(Rand(-10,10),Rand(-10,10),Rand(0,10))
				CubeList.AddLast(Cube2)
			End If
		Next
	End If
Wend




TomToad(Posted 2007) [#3]
Weird bug. I was hoping to use FreeEntity() in the Delete() method so I could remove a whole block of entities with something like CubeList.Clear(). The only reason why I could see this fail would be if the GC occured during RenderWorld.
I tried putting GCCollect() after the FreeEntity() and still had problems. Then I realized how stupid that was, I was calling the Garbage collector during garbage collection. :D
So then I tried putting it after CubeList.Remove(Cube). That didn't work either, although it took longer for the program to crash.
Is it possible that calling GCCollect() doesn't necessarily collect everything?

So if calling FreeEntity() from a delete method is a bad idea, what would be an easy way to remove all the entities from a list? Or am I stuck iterating through the entire list and calling FreeEntity() on each iteration?


Just thinking, I could write a function like this:
Function RemoveAllEntities(List:TList)
   For Local Cube:TCube = Eachin List
      FreeEntity(Cube.Entity)
   Next
   List.Clear()
End Function

Then I could just pass the list to the function and not need to rewrite the loop 20 times everywhere I want to delete a list of entities in my program.


Dreamora(Posted 2007) [#4]
GCCollect does try to collect but it does not do that instantan, it takes a few moments and if renderworld happens within this, you are doomed

But you could put GCSuspend and GCResume around renderworld