MiniB3D and wxMax

BlitzMax Modules Forums/MiniB3D/MiniB3D and wxMax

Does anyone have any tutorials on how to integrate MiniB3D into wxMax instead of MaxGUI? I have been working on this for a couple days and still have not found any luck.

SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxTimer
Import wx.wxPanel
Import wx.wxglmax2D
Import "MiniB3D.bmx"

Const Menu_Exit:Int = 100

SetGraphicsDriver wxGLGraphicsDriver(),GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER
New Window.run()

Type Window Extends wxApp
	Field Frame:WinFrame
	Method OnInit:Int()
		Frame = WinFrame(New WinFrame.Create(Null, -1, "Terrain Editor", , , 800, 600))
		Frame.show(True)
		SetTopWindow(Frame)
		Return True
	End Method
End Type

Type WinFrame Extends wxFrame
	Field Canvas:WinCanvas
	Method OnInit()
		Local FileMenu:wxMenu = wxMenu.CreateMenu()
		Local MenuBar:wxMenuBar = wxMenuBar.CreateMenuBar()
		Local Panel:wxPanel = New wxPanel.Create( Self )
		Canvas = WinCanvas(New WinCanvas.Create(Panel, -1, GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER,0,0,800,600))
		ConnectAny(wxEVT_CLOSE, OnClose)
		FileMenu.Append(Menu_Exit, "Exit~tAlt-X", "Quit this program")
		MenuBar.Append(FileMenu, "&File")
		SetMenuBar(MenuBar)
		CreateStatusBar(1)
		SetStatusText("Terrain Editor")
	End Method
	Function OnClose(event:wxEvent)
		WinFrame(event.parent).Canvas.timer.Stop()
		event.Skip()
	End Function
End Type

Type WinCanvas Extends wxGLCanvas
	Field Timer:wxTimer
	Method OnInit()
		SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		Timer = New wxTimer.Create(Self)
		ConnectAny(wxEVT_TIMER, OnTick)
		Timer.Start(100)
	End Method
	Method OnPaint(event:wxPaintEvent)
		Render()
	End Method
	Method Render()
		SetGraphics CanvasGraphics2D( Self )
		SetClsColor(0, 0, 0)
		SetColor(0, 0, 0)
		Cls
		Draw()
		Flip
	End Method
	Function OnTick(event:wxEvent)
		wxWindow(event.parent).Refresh()
	End Function
	Method Draw()
		TGlobal.width = 400
		TGlobal.height = 300
		TGlobal.GraphicsInit()
		Local cam:TCamera=CreateCamera()
		Local light:TLight=CreateLight(1)
		Local cube:TMesh=CreateCube()
		Local sphere:TMesh=CreateSphere()
		Local cylinder:TMesh=CreateCylinder()
		Local cone:TMesh=CreateCone()
		PositionEntity cam,0,0,-10
		PositionEntity cube,-6,0,0
		PositionEntity sphere,-2,0,0
		PositionEntity cylinder,2,0,0
		PositionEntity cone,6,0,0
		TurnEntity cube,0,1,0
		RenderWorld
	End Method
End Type


I have that so far, still need help. I do not know what I should change it to instead of Max2D

Okay... this is your example with modifications based partly on the maxgui example :
SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxTimer
Import wx.wxPanel
Import wx.wxglmax2D
'Import "MiniB3D.bmx"
Import sidesign.minib3d

Const Menu_Exit:Int = 100

SetGraphicsDriver wxGLGraphicsDriver(),GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER
New Window.run()

Type Window Extends wxApp
	Field Frame:WinFrame
	Method OnInit:Int()
		Frame = WinFrame(New WinFrame.Create(Null, -1, "Terrain Editor", , , 800, 600))
		Frame.show(True)
		SetTopWindow(Frame)
		Return True
	End Method
End Type

Type WinFrame Extends wxFrame
	Field Canvas:WinCanvas
	Method OnInit()
		Local FileMenu:wxMenu = wxMenu.CreateMenu()
		Local MenuBar:wxMenuBar = wxMenuBar.CreateMenuBar()
		Local Panel:wxPanel = New wxPanel.Create( Self )
		Canvas = WinCanvas(New WinCanvas.Create(Panel, -1, GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER,0,0,800,600))
		
		
		
		ConnectAny(wxEVT_CLOSE, OnClose)
		FileMenu.Append(Menu_Exit, "Exit~tAlt-X", "Quit this program")
		MenuBar.Append(FileMenu, "&File")
		SetMenuBar(MenuBar)
		CreateStatusBar(1)
		SetStatusText("Terrain Editor")
	End Method
	Function OnClose(event:wxEvent)
		WinFrame(event.parent).Canvas.timer.Stop()
		event.Skip()
	End Function
End Type

Type WinCanvas Extends wxGLCanvas
	Field Timer:wxTimer
	
	Field cam:TCamera
	Field light:TLight
	Field cube:TMesh
	Field sphere:TMesh
	Field cylinder:TMesh
	Field cone:TMesh
	
	Method OnInit()
		SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		Timer = New wxTimer.Create(Self)
		ConnectAny(wxEVT_TIMER, OnTick)
		Timer.Start(17)

		' **********
		Local width:Int, height:Int
		GetSize(width, height)

		SetGraphics CanvasGraphics2D( Self )


		TGlobal.width = width
		TGlobal.height = height

		TGlobal.depth=16
		TGlobal.mode=0
		TGlobal.rate=60

		TGlobal.GraphicsInit()
		' ************

		cam=CreateCamera()
		light=CreateLight(1)
		cube=CreateCube()
		sphere=CreateSphere()
		cylinder=CreateCylinder()
		cone=CreateCone()
	End Method
	Method OnPaint(event:wxPaintEvent)
		Render()
	End Method
	Method Render()
		SetGraphics CanvasGraphics2D( Self )
		Draw()
		Flip
	End Method
	Function OnTick(event:wxEvent)
		wxWindow(event.parent).Refresh()
	End Function
	Method Draw()
		PositionEntity cam,0,0,-10
		PositionEntity cube,-6,0,0
		PositionEntity sphere,-2,0,0
		PositionEntity cylinder,2,0,0
		PositionEntity cone,6,0,0
		TurnEntity cube,0,1,0
		RenderWorld
	End Method
End Type

If you want the 3d canvas to scale with the window you'll probably need to connect the size event and set TGlobal's width and height to match the new values.

Note that there are currently issues using a fullscreen-mode canvas with wxMax, in that input events seem to get lost somewhere. If you are only using it in a Window, it works fine.

I am still not getting any sort of render in the canvas. I will work with it a bit and if I get it, I will post it for others.

Hmm... worked here on Mac (so I assumed it should work for Win32 too)... I'll need some time to set up my Parallels to have the latest everything in order to try it there...

What version of MiniB3D do you have?

Nothing is rendered here...

Windows XP, 3ghz P4 processer, NVIDIA 9600 GT video card

I have fixed the example posted by Brucey by sticking a TGLobal.EnableStates() in the draw method.
It now works on my intel macbook running Windows XP.

This is overkill because it seems EnableStates() only needs to be called once.
I'm not sure where to put it so that it happens once, after init(), but before render()

The modified render method looks like this:

	Method Render()
		SetGraphics CanvasGraphics2D( Self )
		TGlobal.EnableStates()
		Draw()
		Flip
	End Method


You could always wrap it in a global variable test?
	Method Render()
		SetGraphics CanvasGraphics2D( Self )
		Global enabled:int
		If Not enabled Then
			enabled = True
			TGlobal.EnableStates()
		End If
		Draw()
		Flip
	End Method

I've not see EnableStates used before. Where/when would you normally call that?

EnableStates is called during Graphics3D(). I don't think it's ment to be called outside minib3d. It tells opengl to enable different features. Some state settings are missing resulting in garbled output in your original example above.

I found out that in your example it's simply called to early for some implementations. (all windows versions? )

It just needs to be called a little later in the application startup sequence.

it's simply called to early for some implementations.

Quite likely.
Different platforms expect different things to have happened by the time you come to use particular APIs.

I suppose that's what makes cross-platform programming so much fun :-)

Running brucey's example (with fix added) i get a "runtime exception: unhandled memory exception error" on RenderWorld. why?

If i run the first code i'have no errors but no render, only black rect.

Running brucey's example (with fix added) i get a "runtime exception: unhandled memory exception error" on RenderWorld. why?

Try adding TGlobal.GraphicsInit() to the Render method.

By the way, I can't figure out how to render textures. I'm only getting white surfaces.

Thanks! Now i can use minib3d and wxMax. for texturese, same problem here :(

No textures here too...

I got it! :)

The textures have to be loaded after the graphics were initialized, which is after the first run of the Render Method. Also the graphics must be initialized once only.

Field initialized_graphics:Int=False

Method Render()
	
	If Not initialized_graphics Then
		TGlobal.GraphicsInit()
		EntityTexture cube,LoadTexture("path\to\texture.png")
		initialized_graphics=True
	End If
	
	Draw()
	Flip
End Method

Makes sense right?

Yeah, that's it.
Great!
[Edit]
Has anyone tested it with an textured mesh?
My whole screen ist flickering while LoadMesh.

thanks!

My whole screen ist flickering while LoadMesh.

What exactly do you mean? Your screen shouldn't refresh at all while executing a LoadMesh call (except you do it in a separate thread). The mesh I tried (.b3d) worked well.

Besides of that I noticed that all meshes must be created after the GraphicsInit() or they'll get overwritten by other meshes.

My whole screen, not just the WxFrame, flashed black and white
and the app freezed under Vista.

that all meshes must be created after the GraphicsInit() or they'll get overwritten by other meshes

This was the point. ALL meshes.
Not just overwritten, it caused some more serious errors.

The cube, sphere and cylinder were created in OnInit().
The other mesh was loaded in Render()
If I move them in Render() after the second "TGlobal.GraphicsInit()"
then it works. Don't know why..

My failing Code:
SuperStrict
' WARNING Code FAILS!! 
Framework wx.wxApp
Import wx.wxFrame
Import wx.wxTimer
Import wx.wxPanel
Import wx.wxglmax2D
Import sidesign.minib3d

Const Menu_Exit:Int = 100

SetGraphicsDriver wxGLGraphicsDriver(),GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER
New Window.run()

Type Window Extends wxApp
	Field Frame:WinFrame
	Method OnInit:Int()
		Frame = WinFrame(New WinFrame.Create(Null, -1, "Terrain Editor", , , 800, 600))
		Frame.show(True)
		SetTopWindow(Frame)
		Return True
	End Method
End Type

Type WinFrame Extends wxFrame
	Field Canvas:WinCanvas
	Method OnInit()
		Local FileMenu:wxMenu = wxMenu.CreateMenu()
		Local MenuBar:wxMenuBar = wxMenuBar.CreateMenuBar()
		Local Panel:wxPanel = New wxPanel.Create( Self )
		Canvas = WinCanvas(New WinCanvas.Create(Panel, -1, GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER,0,0,800,600))
		
		
		
		ConnectAny(wxEVT_CLOSE, OnClose)
		FileMenu.Append(Menu_Exit, "Exit~tAlt-X", "Quit this program")
		MenuBar.Append(FileMenu, "&File")
		SetMenuBar(MenuBar)
		CreateStatusBar(1)
		SetStatusText("Terrain Editor")
	End Method
	Function OnClose(event:wxEvent)
		WinFrame(event.parent).Canvas.timer.Stop()
		event.Skip()
	End Function
End Type

Type WinCanvas Extends wxGLCanvas
	Field Timer:wxTimer
	
	Field cam:TCamera
	Field light:TLight
	Field cube:TMesh
	Field sphere:TMesh
	Field cylinder:TMesh
	Field cone:TMesh
	Field hd:TMesh
	'
	Field initialized_graphics:Int = False

	Method OnInit()
		SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		Timer = New wxTimer.Create(Self)
		ConnectAny(wxEVT_TIMER, OnTick)
		Timer.Start(17)

		' **********
		Local width:Int, height:Int
		GetSize(width, height)

		SetGraphics CanvasGraphics2D( Self )


		TGlobal.width = width
		TGlobal.height = height

		TGlobal.depth=16
		TGlobal.mode=0
		TGlobal.rate=60

		TGlobal.GraphicsInit()
		' ************

		cam=CreateCamera()
		light=CreateLight(1)
		cube=CreateCube()
		sphere=CreateSphere()
		cylinder=CreateCylinder()
		cone = CreateCone()
	End Method
	Method OnPaint(event:wxPaintEvent)
		Render()
	End Method
	Method Render()
		If Not initialized_graphics Then	
			TGlobal.GraphicsInit()

			Local ufo:TMesh = LoadMesh ("ufo.b3d")    ' flashing screen; fails under Vista  ************************
			initialized_graphics=True
		End If
		' SetGraphics CanvasGraphics2D(Self)
		Global enabled:int
		If Not enabled Then
			enabled = True
			TGlobal.EnableStates()
		End If
		Draw()
		Flip
	End Method

	Function OnTick(event:wxEvent)
		wxWindow(event.parent).Refresh()
	End Function
	Method Draw()
		PositionEntity cam,0,0,-10
		PositionEntity cube,-6,0,0
		PositionEntity sphere,-2,0,0
		PositionEntity cylinder,2,0,0
		PositionEntity cone,6,0,0
		TurnEntity cube,0,1,0
		RenderWorld
	End Method
End Type


Nice to hear it worked.

I'm not familiar with OpenGL but the problem seems to be that with the second GraphicsInit() the previous setup gets lost but isn't freed up properly as the graphics are never finished correctly, so some objects and settings still reside in the memory and interfere the rendering.

By the way, the first GraphicsInit() (at OnInit()) isn't necessary if you're anyways reinitializing the graphics in the Render method.