wxMax and Irrlitcht Engine

BlitzMax Forums/BlitzMax Programming/wxMax and Irrlitcht Engine

PhotonTom(Posted 2012) [#1]
Hi,
Is it possible to run irrlitcht in a canvas of wxmax? I've been looking into it and I can't find anyone that's tried it and I'm a noob with irrlitcht and graphics. Any code or help would be much appreciated.


Chapman7(Posted 2012) [#2]
This is the code I used for wxMax and MiniB3D:

SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxPanel
Import wx.wxGLCanvas
Import sidesign.minib3d


Global Cube:TMesh
Global old_ms:Int=MilliSecs()
Global renders:Int
Global fps:Int

Global prog:MyApp = New MyApp
prog.Run()

Type MyApp Extends wxAppMain
	Field frame:wxFrame
	Field panel:wxPanel
	Field canvas:TMiniB3D
	Global shouldExit:Int = False
	Method OnInit:Int()
		frame = New wxFrame.Create(,,"MiniB3d Sample", 0, 0, 512, 512)
		frame.Center()
		panel = New wxPanel.Create(frame, wxID_ANY, 0, 0, 512, 512)
		canvas = TMiniB3D(New TMiniB3D.Create(panel, wxID_ANY, GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER, 0, 0, 512, 512))
		frame.show()				
		Return True
	End Method
	Method MainLoop:Int()
		While True
		While Not Pending() And ProcessIdle() ; Wend
		While Pending()
			If Not Dispatch() Then
				shouldExit = True
				Exit
			End If
		Wend
		If shouldExit Then
			While pending() 
				dispatch() 
			Wend
			Return 0
		End If

		TurnEntity cube, 0, 1, 0
		RenderWorld
		renders=renders+1
		If MilliSecs()-old_ms>=1000
			old_ms=MilliSecs()
			fps=renders
			renders=0
		EndIf
		Text 0, 0, "FPS: "+fps
		Flip

		Wend
	EndMethod
End Type

Type TMiniB3D Extends wxGLCanvas
	Field init:Int = 0
	Method OnPaint(event:wxPaintEvent)
		If init = 0 Then		
			SetGraphics CanvasGraphics( Self )
			TGlobal.width = 512
			TGlobal.height = 512
			TGlobal.depth = 16
			TGlobal.mode = 0
			TGlobal.GraphicsInit()
			init = 1		
			Local Camera:TCamera = CreateCamera()
			PositionEntity Camera, 0, 0, -10
			
			Local Light:TLight = CreateLight(1)
			cube:TMesh=CreateCube()
			Local sphere:TMesh=CreateSphere()
			Local cylinder:TMesh=CreateCylinder()
			Local cone:TMesh=CreateCone() 
			
			PositionEntity cube,-6,0,0
			PositionEntity sphere,-2,0,0
			PositionEntity cylinder,2,0,0
			PositionEntity cone,6,0,0
			RenderWorld
		End If
	End Method
End Type



It shouldn't be too hard to swap out MiniB3D with the Irrlitcht Wrapper.


PhotonTom(Posted 2012) [#3]
I've had a look and the problem is SetGraphics CanvasGraphics( Self ) , irrlicht doesn't have a similar function. All I can find is ib3d_Graphics3DParams( params :SIrrlichtCreationParameters ) and then creating params with setWindowId(hwnd:Int) but wxmax using Self.GetHandle() gives window hwnd as byte ptr so that was a dead end too. I also tryed Self.GetID() but that resulted in all irrlicht objects returning null so can't of been correct.

I found an example of irrlicht working with maxgui and tested and it works perfectly:
' this is an example showing how to display Irrlicht in a panel on a MaxGUI form.  i have modified it a bit
' by adding an eventreceiver to the Irrlicht instance to show how MaxGUI and Irrlicht events can coexist.
' it is important to note that there still is probably some issues to work out, but for now this works.
'
' NOTE: press the 'w' key to toggle wireframe

Strict 
Framework Irrlicht.Core
Import brl.eventqueue

Import BRL.Basic
Import maxgui.maxgui
Import maxgui.win32maxguiex

Local window:TGadget
Local panel:TGadget

Local windowWidth:Int = 640
Local windowHeight:Int = 380

window=CreateWindow("Irrlicht Win32 BlitzMax window example",100,100,windowWidth,windowHeight,Null,WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS | WINDOW_HIDDEN)

' create window To put irrlicht in
Local hIrrlichtWindow:TGadget=CreatePanel(50,80,320,220,window,PANEL_ACTIVE|PANEL_BORDER)

Local HTMLWindow:TGadget=CreateHTMLView(380,80,250,220,window)

' create ok button
Local Ok:TGadget=CreateButton("OK - Close",windowWidth - 160,windowHeight - 40,150,30,window)

Local go:TGadget=CreateButton("GO URL",windowWidth - 320,windowHeight - 40,150,30,window)

' this is not in the original, but is here to show you can have a textbox and enter into it
' without the events posting to Irrlicht
Local tb:TGadget=CreateTextField(windowWidth - 260,windowHeight - 70,250,20,window)

' create some text
CreateLabel("This is Irrlicht running inside a Win32 MaxGUI window.",20,20,400,40,window)
    
Local param:SIrrlichtCreationParameters=SIrrlichtCreationParameters.create()
param.setWindowId(QueryGadget(hIrrlichtWindow,QUERY_HWND))
param.setDriverType(EDT_OPENGL)

' create the device from the params object
Local device:IrrlichtDevice= ..
    IrrlichtDevice.createFromParams(param)

' the original does not have this.  this is just to show that you can mix events between MaxGUI and Irrlicht.
Type MyEventReceiver Extends IEventReceiver

    Field box:ISceneNode

    Method setBox(b:ISceneNode)
        box=b
    EndMethod

    Method OnEvent:Int(event:SEvent)

        ' check If user presses the key 'W'
        If event.getEventType()=EET_KEY_INPUT_EVENT And event.getKeyPressedDown()=False
        
            Local key:Int=event.getKeyInputKey()

            Select key
                ' switch wire frame mode
                Case EKEY_KEY_W  
                    box.setMaterialFlag(EMF_WIREFRAME, box.getMaterial(0).getWireframe()=False)
                    Return True    
            EndSelect            
        EndIf
        
        Return False
    EndMethod

    ' we must override the generate function in order for instantiation to work properly
    ' must return IEventReceiver
    Function generate:IEventReceiver()
        Return New MyEventReceiver
    EndFunction
EndType

' setup a simple 3d scene

Local smgr:ISceneManager=device.getSceneManager()
Local Driver:IVideoDriver=device.getVideoDriver()

Local cam:ICameraSceneNode=smgr.addCameraSceneNode();
cam.setTarget(_VECTOR3DF(0,0,0))

Local anim:ISceneNodeAnimator=smgr.createFlyCircleAnimator(_VECTOR3DF(0,10,0),30.0)
cam.addAnimator(anim)
anim.drop()

Local cube:ISceneNode=smgr.addCubeSceneNode(25)
cube.setMaterialTexture(0,Driver.getTexture("../media/rockwall.bmp"))
cube.setMaterialFlag(EMF_LIGHTING,False)

smgr.addSkyBoxSceneNode( ..
    Driver.getTexture("../media/irrlicht2_up.jpg"), ..
    Driver.getTexture("../media/irrlicht2_dn.jpg"), ..
    Driver.getTexture("../media/irrlicht2_lf.jpg"), ..
    Driver.getTexture("../media/irrlicht2_rt.jpg"), ..
    Driver.getTexture("../media/irrlicht2_ft.jpg"), ..
    Driver.getTexture("../media/irrlicht2_bk.jpg"))

' create the event receiver that toggles wireframe
Local receiver:IEventReceiver=IEventReceiver.create(MyEventReceiver.generate)
MyEventReceiver(receiver).setBox(cube)
device.setEventReceiver(receiver)

' show And execute dialog
ShowGadget(window)

' do message queue

' Instead of this, you can also simply use your own message loop
' using GetMessage, DispatchMessage And whatever. Calling
' Device->run() will cause Irrlicht To dispatch messages internally too. 
' You need Not call Device->run() If you want To do your own message 
' dispatching loop, but Irrlicht will Not be able To fetch
' user Input Then And you have To do it on your own using the BlitzMax
' event mechanism.

While(device.run())

    Driver.beginScene(True, True)
    smgr.drawAll()
    Driver.endScene()

    If PeekEvent() Then 
        PollEvent()
        Select EventID()
            Case EVENT_WINDOWCLOSE
                Exit
            Case EVENT_GADGETACTION
                If EventSource()=Ok
                    PostEvent(CreateEvent(EVENT_WINDOWCLOSE,Ok))
                ElseIf EventSource()=go
                    Local url:String
                    If GadgetText(tb)<>"" Then url=GadgetText(tb) Else url="http://www.blitzmax.com"
                    HtmlViewGo( HTMLWindow,url )                
                ElseIf EventSource()=tb
                    'Print "textbox"
                Else ' pass it on to Irrlicht
                    ' you would need to determine the event and pass it on
                    Local event:SEvent=SEvent.create()
                    event.setEventType(EET_KEY_INPUT_EVENT)
                    event.setKeyInputKey(EKEY_KEY_W)
                    device.postEventFromUser(event)                
                EndIf
            Default
                'PostEvent(CreateEvent(EventID()),True)
If EventID()=EVENT_KEYDOWN
    Local event:SEvent=SEvent.create()
    event.setEventType(EET_KEY_INPUT_EVENT)
    event.setKeyInputKey(EventData())
    device.postEventFromUser(event)                
EndIf
        End Select
    End If        
    
Wend

' the alternative, own message dispatching loop without Device->run() would
' look like this:

Rem
While True
    If PeekEvent() Then 
        PollEvent()
        Select EventID()
        Case EVENT_WINDOWCLOSE
            Exit
        Case EVENT_GADGETACTION        
            If EventSource()=Ok
                PostEvent(CreateEvent(EVENT_WINDOWCLOSE,Ok))
            End If
        End Select
    End If        
    '// advance virtual time
    device.GetTimer().Tick()
    '// draw engine picture
    driver.beginScene(True, True, 0)
    smgr.drawAll()
    driver.endScene()
Wend
EndRem

device.closeDevice()
device.drop()


This is my attempt to combine wxmax and irrlicht, it doesn't work.
SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxTimer
Import wx.wxPanel
Import wx.wxglmax2D
Import Irrlicht.Core

Const Menu_Exit:Int = 100


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 Driver:IVideoDriver
	Field smgr:ISceneManager
	Field device:IrrlichtDevice
	
	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)
		
		
Local param:SIrrlichtCreationParameters=SIrrlichtCreationParameters.Create()
param.setWindowId(Self.GetID())
param.setDriverType(EDT_OPENGL)

' setup a simple 3d scene

device:IrrlichtDevice= ..
    IrrlichtDevice.createFromParams(param)

smgr:ISceneManager=device.getSceneManager()
Driver:IVideoDriver=device.getVideoDriver()

Local cam:ICameraSceneNode=smgr.addCameraSceneNode();
cam.setTarget(_VECTOR3DF(0,0,0))

Local anim:ISceneNodeAnimator=smgr.createFlyCircleAnimator(_VECTOR3DF(0,10,0),30.0)
cam.addAnimator(anim)
anim.drop()

Local cube:ISceneNode=smgr.addCubeSceneNode(25)
cube.setMaterialTexture(0,Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/rockwall.bmp"))
cube.setMaterialFlag(EMF_LIGHTING,False)

smgr.addSkyBoxSceneNode( ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_up.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_dn.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_lf.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_rt.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_ft.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_bk.jpg"))
		

	End Method
	Method OnPaint(event:wxPaintEvent)
		Render()
	End Method
	Method Render()
	    Driver.beginScene(True, True)
	    smgr.drawAll()
	    Driver.endScene()
	End Method
	Function OnTick(event:wxEvent)
		wxWindow(event.parent).Refresh()
	End Function

End Type



Chapman7(Posted 2012) [#4]
What's the error that you get?


PhotonTom(Posted 2012) [#5]
Using param.setWindowId(Self.GetID()) resulted in all irrlicht objects returning null so can't of been correct. and using param.setWindowId(Self.GetHandle()) gives cannot convert byte ptr into int


Chapman7(Posted 2012) [#6]
param.setWindowId(Int(Self.GetHandle()))

Does that do the trick?


PhotonTom(Posted 2012) [#7]
It fixed one problem, it now outputs the scene to the window, except now there is another problem it wont load the textures properly. It loads the texture and returns true BUT it just displays white.
It must be something todo with the wxGLCanvas because the exact same code works fine with maxgui but fails when loaded into a canvas.

New Code:
SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxTimer
Import wx.wxPanel
Import WX.wxglmax2D
Import Irrlicht.Core

Const Menu_Exit:Int = 100


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 Driver:IVideoDriver
	Field smgr:ISceneManager
	Field device:IrrlichtDevice
	Field tex:ITexture
	
	Method OnInit()
		'SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		Timer = New wxTimer.Create(Self)
		ConnectAny(wxEVT_TIMER, OnTick)
		Timer.Start(10)

		' **********
		Local width:Int, height:Int
		GetSize(width , height)
		
		
Local param:SIrrlichtCreationParameters=SIrrlichtCreationParameters.Create()
param.setWindowId(Int(Self.GetHandle()))
param.setDriverType(EDT_OPENGL)

' setup a simple 3d scene

device:IrrlichtDevice= ..
    IrrlichtDevice.createFromParams(param)




smgr:ISceneManager=device.getSceneManager()
Driver:IVideoDriver=device.getVideoDriver()

Local cam:ICameraSceneNode=smgr.addCameraSceneNode();
cam.setTarget(_VECTOR3DF(0,0,0))

Local anim:ISceneNodeAnimator=smgr.createFlyCircleAnimator(_VECTOR3DF(0,10,0),30.0)
cam.addAnimator(anim)
anim.drop()

Local cube:ISceneNode = smgr.addCubeSceneNode(25)
'tex = Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_up.jpg")
tex = Driver.getTexture("Z:\new.bmp")
Print cube.setMaterialTexture(1,tex)
Print cube.setMaterialFlag(EMF_LIGHTING , False)
Print cube.getmaterialcount()
Print Driver.getTextureCount()
'cube.render()

smgr.addSkyBoxSceneNode( ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_up.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_dn.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_lf.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_rt.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_ft.jpg"), ..
    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_bk.jpg"))
		
		'SetGraphics CanvasGraphics2D( Self )
		
		
	End Method
	Method OnPaint(event:wxPaintEvent)
		Render()
	End Method
	Method Render()
		device.run()
		Driver.beginScene(True , true)
	    	smgr.drawAll()
	    	Driver.endScene()
	End Method
	Function OnTick(event:wxEvent)
		'Print "tick"
		wxWindow(event.parent).Refresh()
	End Function

End Type



Chapman7(Posted 2012) [#8]
Okay this is were I ended up finding something weird with wxMax. Using OnInit() method for the GLCanvas actually does not work entirely and you need to make your own Init thing within the OnPaint() method. I am not sure exactly why you need to do it like this, but this should do the trick: (I am running blind here since I don't have Irrlicht but if you still have issues after this, it should be fairly easy to hammer out).

Type WinCanvas Extends wxGLCanvas
	Field Timer:wxTimer
	Field Driver:IVideoDriver
	Field smgr:ISceneManager
	Field device:IrrlichtDevice
	Field tex:ITexture
	
	Field Init:Int = 0
	
	Method OnPaint(event:wxPaintEvent)
		If Init = 0 Then
		'SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		Timer = New wxTimer.Create(Self)
		ConnectAny(wxEVT_TIMER, OnTick)
		Timer.Start(10)
		' **********
		Local width:Int, height:Int
		GetSize(width , height)
		
		Local param:SIrrlichtCreationParameters=SIrrlichtCreationParameters.Create()
		param.setWindowId(Int(Self.GetHandle()))
		param.setDriverType(EDT_OPENGL)
		' setup a simple 3d scene
		device:IrrlichtDevice= ..
		    IrrlichtDevice.createFromParams(param)
		
		smgr:ISceneManager=device.getSceneManager()
		Driver:IVideoDriver=device.getVideoDriver()
		
		Local cam:ICameraSceneNode=smgr.addCameraSceneNode();
		cam.setTarget(_VECTOR3DF(0,0,0))
		
		Local anim:ISceneNodeAnimator=smgr.createFlyCircleAnimator(_VECTOR3DF(0,10,0),30.0)
		cam.addAnimator(anim)
		anim.drop()
		
		Local cube:ISceneNode = smgr.addCubeSceneNode(25)
		'tex = Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples\media/irrlicht2_up.jpg")
		tex = Driver.getTexture("Z:\new.bmp")
		Print cube.setMaterialTexture(1,tex)
		Print cube.setMaterialFlag(EMF_LIGHTING , False)
		Print cube.getmaterialcount()
		Print Driver.getTextureCount()
		'cube.render()
		
		smgr.addSkyBoxSceneNode( ..
		    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_up.jpg"), ..
		    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_dn.jpg"), ..
		    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_lf.jpg"), ..
		    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_rt.jpg"), ..
		    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_ft.jpg"), ..
		    Driver.getTexture("C:\Program Files (x86)\Blitzmax-SVN\mod\irrlicht.mod\examples/media/irrlicht2_bk.jpg"))
				
		'SetGraphics CanvasGraphics( Self )
		'!!!!!!!!!!!!!!!!!!!!!!!YOU MIGHT HAVE TO UNCOMMENT THAT!!!!!!!!!!!!!!!!!!!!!!!!!!!'
		Init = 1
		EndIf
		
		device.run()
		Driver.beginScene(True , True)
	    smgr.drawAll()
	    Driver.endScene()
	End Method
	Function OnTick(event:wxEvent)
		'Print "tick"
		wxWindow(event.parent).Refresh()
	End Function

End Type


Just copy that whole type over your old GLCanvas type and hopefully it will work for you

Last edited 2012


Chapman7(Posted 2012) [#9]
Hey I realized I totally spaced and forgot Init = 1 so it doesn't run through it again xD Code above is fixed


PhotonTom(Posted 2012) [#10]
I tried your code and got some very interesting results. With Init = 1 in, it was exactly the same as before, no textures.
But when init = 1 wasn't in, when it reloaded the whole engine and textures for every frame, it displayed correctly, well apart from it being really slow and the animation resetting every frame. So this leads me to believe either wxmax or irrlicht is cleaning up the textures after the first frame, does anyone have an idea about what could be causing this?