Problem with TImagefont in MAXGUI+OpenB3D combination

Started by Krischan, October 22, 2017, 21:48:00

Previous topic - Next topic

Krischan

I have another problem, perhaps somebody knows how to fix this. In my current project I'm using the OpenB3D framework, a MaxGUI window with two canvases and a custom OTF font loaded using TImagefont. There is an interesting problem with the second canvas (depends on which one is activated): the font doesn't work correct in either the first or the second canvas. I've even tried to fix the BeginMax2D/EndMax2D functions but this didn't work. I've reduced the problem to a small demo (here using the Arial TTF from the OS instead of a custom OTF, makes no difference), press SPACE to switch between the MAXGUI BeginMax2D command and a fixed Begin2D command.

I must have two different canvases in MaxGUI (one uses 2D only, one 2D+3D) and they should be updated separately as they are organized in tabs in my application, with an additional third tab which contains a textfield for debug output. Everything works in the second canvas but the font in the first only shows a "filled" version of the font. beside that I'm absolutely unsure about if I've implemented the Hook/Mainloop and the Timer/Paint events correct. It's a real showstopper for my project, a tiny tool for Explorers in the game Elite Dangerous :(

EDIT: oh and by the way - does somebody know how to get Bruceys wx.mod running on BlitzMaxOS? It compiled but I only get errors when I try to run an example. I'm not very happy with MAXGUI and would like to change to a more customizable GUI.

Code (Blitzmax) Select
SuperStrict

Framework openb3d.b3dglgraphics

Import MaxGui.Drivers
Import brl.Timer
Import brl.EventQueue
Import BRL.freetypefont

SetGraphicsDriver GLMax2DDriver()

' MAXGUI stuff
Global width:Int = 320
Global Height:Int = 240
Global wx:Int = (ClientWidth(Desktop()) - width) / 2
Global wy:Int = (ClientHeight(Desktop()) - Height) / 2
Global Window1:TGadget = CreateWindow("First Canvas", wx, wy, width, Height, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
Global canvas1:TGadget = CreateCanvas(0, 0, 320, 240, Window1)
Global window2:TGadget = CreateWindow("Second Canvas", wx * 1.25, wy * 1.25, width, Height, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
Global canvas2:TGadget = CreateCanvas(0, 0, 320, 240, window2)
ActivateGadget(canvas2)

' load font
Global Font:TImageFont = LoadImageFont(getenv_("WINDIR") + "/Fonts/Arial.ttf", 32)

Global switch:Int = 0
Global switchtext:String[] = ["MAX2D", "MAX2D fixed"]

' OpenB3D stuff
SetGraphics CanvasGraphics(canvas1)
Graphics3D width, Height, 0, 2, 60, -1, True
Global cam:TCamera = CreateCamera()
Global mesh:TMesh = CreateCube()
Global light:TLight = CreateLight(1)
AmbientLight 0, 0, 0
PositionEntity mesh, 0, 0, 3

CreateTimer 60

' hook
AddHook EmitEventHook, LoopHook

' main loop
Repeat

WaitEvent()

Forever

End

' ----------------------------------------------------------------------------
' Loop Hook
' ----------------------------------------------------------------------------
Function LoopHook:Object(id:Int, data:Object, context:Object)

Local Event:TEvent = TEvent(data)
If Event = Null Then Return Event

Select Event.id

Case EVENT_TIMERTICK

TurnEntity mesh, 0.5, 1, 0.5

RedrawGadget canvas1
RedrawGadget canvas2

Case EVENT_GADGETPAINT

Select Event.source

Case canvas1

SetGraphics CanvasGraphics(canvas1)

Cls

RenderWorld

If switch Then Begin2D() Else BeginMax2D()

SetBlend ALPHABLEND
SetColor(255, 0, 0)
SetImageFont Font
DrawText switchtext[switch], 0, 0

If switch Then End2D() Else EndMax2D()

Flip False

Case canvas2

SetGraphics CanvasGraphics(canvas2)

Cls

RenderWorld

If switch Then Begin2D() Else BeginMax2D()

SetBlend ALPHABLEND
SetColor(0, 255, 0)
SetImageFont Font
DrawText switchtext[switch], 0, 0

If switch Then End2D() Else EndMax2D()

Flip false

End Select

Case EVENT_KEYDOWN

Select Event.data

Case KEY_SPACE

switch = 1 - switch

End Select

Case EVENT_WINDOWCLOSE

FreeGadget canvas1
FreeGadget canvas2
End

Case EVENT_APPTERMINATE

End

End Select

End Function

' Fixed BeginMax2D()
Function Begin2D()

Local x:Int, y:Int, w:Int, h:Int
GetViewport(x, y, w, h)

glDisable(GL_LIGHTING)
glDisable(GL_DEPTH_TEST)
glDisable(GL_SCISSOR_TEST)
glDisable(GL_FOG)
glDisable(GL_CULL_FACE)

glMatrixMode GL_TEXTURE
glLoadIdentity

glMatrixMode GL_PROJECTION
glLoadIdentity
glOrtho 0, width, Height, 0, -1, 1

glMatrixMode GL_MODELVIEW
glLoadIdentity

SetViewport x, y, w, h

Local MaxTex:Int
glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))

For Local Layer:Int = 0 Until MaxTex

glActiveTexture(GL_TEXTURE0+Layer)

glDisable(GL_TEXTURE_CUBE_MAP)
glDisable(GL_TEXTURE_GEN_S)
glDisable(GL_TEXTURE_GEN_T)
glDisable(GL_TEXTURE_GEN_R)

glDisable(GL_TEXTURE_2D)

Next

glActiveTexture(GL_TEXTURE0)

glViewport(0, 0, width, Height)
glScissor(0, 0, width, Height)

glEnable GL_BLEND
glEnable(GL_TEXTURE_2D)

End Function



' Fixed EndMax2D()
Function End2D()

glDisable(GL_TEXTURE_CUBE_MAP)
glDisable(GL_TEXTURE_GEN_S)
glDisable(GL_TEXTURE_GEN_T)
glDisable(GL_TEXTURE_GEN_R)

glDisable(GL_TEXTURE_2D)
glDisable GL_BLEND

TGlobal.EnableStates()

TGlobal.alpha_enable[0] = 0 ' alpha blending was disabled by Max2d (GL_BLEND)
TGlobal.blend_mode[0] = 1 ' force alpha blending
TGlobal.fx1[0] = 0 ' full bright/surface normals was enabled by EnableStates (GL_NORMAL_ARRAY)
TGlobal.fx2[0] = 1 ' vertex colors was enabled by EnableStates (GL_COLOR_ARRAY)

glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)

glClearDepth(1.0)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)

glAlphaFunc(GL_GEQUAL, 0.5)

For Local cam:TCamera=EachIn TCamera.cam_list

' active camera - was if cam.hide[0]=0
If cam = TGlobal.camera_in_use

' fog with Max2d fix
cam.UpdateFog()
Exit

EndIf

Next

End Function
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Derron

wx.mod: works here (linux).

For Windows it is always a matter of using the right MinGW ... I think I was using TDM 4.6 to do the job - so you might give it a try.
Of course error lines would help (blitzmax errors or gcc errors?).


@ font error
cannot try it now but did you check if it works with 2 max2d-canvases only? Maybe openb3d is changing a opengl-variable (matrix, modes,....) which disturbs the font rendering?

bye
Ron

RonTek

I remember doing Max2D and OpenB3D and have to do the Max2D Begin and End functions. I think you also need to play around with the AlphaBlend settings and if I'm not mistaken there's a fix/patch that you need to apply to make it work, though I'm not sure and I have to dig it up when I get a chance.

I have not tried using MaxGUI and OpenB3D, but there's a demo on both provided in the download or repo.

MaxGUI
https://github.com/markcwm/openb3d.mod/blob/master/examples/minib3d/maxgui.bmx

Max2D
https://github.com/markcwm/openb3d.mod/blob/master/examples/minib3d/max2d.bmx

Krischan

Hmm, without OpenB3D it works, but only when I comment the SetGraphicsDriver GLMax2DDriver() line, uncommented the same error occurs.

For the wx problem, I'm using BlitzMaxOS with MinGW 5.1.0.2 here. I'm only getting a fatal error (see attachment), the modules compiles without any errors, the program too (in Debug and Release mode). But it just crashes. Does it work with 5.1 or only with 4.x? This would be too bad and I must stay with MAXGUI then. And is it normal that a simple demo like aboutbox takes 10MB space? Huh?

I'll take a look at the OpenB3D examples later, my wife is hungry and she shouldn't wait for the cook ;)

Code (Blitzmax) Select
SuperStrict

Import maxgui.Drivers
Import brl.Timer
Import brl.EventQueue
Import BRL.freetypefont

'SetGraphicsDriver GLMax2DDriver()

' MAXGUI stuff
Global width:Int = 320
Global Height:Int = 240
Global wx:Int = (ClientWidth(Desktop()) - width) / 2
Global wy:Int = (ClientHeight(Desktop()) - Height) / 2
Global Window1:TGadget = CreateWindow("First Canvas", wx, wy, width, Height, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
Global canvas1:TGadget = CreateCanvas(0, 0, 320, 240, Window1)
Global window2:TGadget = CreateWindow("Second Canvas", wx * 1.25, wy * 1.25, width, Height, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
Global canvas2:TGadget = CreateCanvas(0, 0, 320, 240, window2)
ActivateGadget(canvas1)

' load font
Global Font:TImageFont = LoadImageFont(getenv_("WINDIR") + "/Fonts/Arial.ttf", 32)

Global switch:Int = 0
Global switchtext:String[] = ["MAX2D", "MAX2D fixed"]

SetGraphics CanvasGraphics(canvas1)

CreateTimer 60

' hook
AddHook EmitEventHook, LoopHook

' main loop
Repeat

WaitEvent()

Forever

End

' ----------------------------------------------------------------------------
' Loop Hook
' ----------------------------------------------------------------------------
Function LoopHook:Object(id:Int, data:Object, context:Object)

Local Event:TEvent = TEvent(data)
If Event = Null Then Return Event

Select Event.id

Case EVENT_TIMERTICK

RedrawGadget canvas1
RedrawGadget canvas2

Case EVENT_GADGETPAINT

Select Event.source

Case canvas1

SetGraphics CanvasGraphics(canvas1)

Cls

SetBlend ALPHABLEND
SetColor(255, 0, 0)
SetImageFont Font
DrawText switchtext[switch], 0, 0

Flip False

Case canvas2

SetGraphics CanvasGraphics(canvas2)

Cls

SetBlend ALPHABLEND
SetColor(0, 255, 0)
SetImageFont Font
DrawText switchtext[switch], 0, 0

Flip False

End Select

Case EVENT_KEYDOWN

Select Event.data

Case KEY_SPACE

switch = 1 - switch

End Select

Case EVENT_WINDOWCLOSE

FreeGadget canvas1
FreeGadget canvas2
End

Case EVENT_APPTERMINATE

End

End Select

End Function
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Derron

10 megs is because it contains the complete wx library - so even if you only added a button, you compile the code for rich edits etc into the exe. And wx creates everything "on its own", so it does not rely on some simple calls to a windows library.
This explains the 10 mb.

Stripping it might reduce file size a bit.


@ EAV
You might consider trying to build it in "debug" mode and you will see where it errors out...




I then used "GLMax2DDriver()" (as I am running my XP in a VirtualBox and so only have proper access to OpenGL). ... it created two windows but they do not refresh without artifacts (might be my VirtualBox thing...).

So might it be that with D3D (and the blitzmax-implementation) you cannot have 2 canvases?


bye
Ron

Dabz

If I run the app with SetGraphicsDriver GLMax2DDriver() commented, it works a charm here...

If I uncomment it, canvas1 is fine and the text is clear, canvas2 on the other hand, the text is garbage!

Dabz
Intel Core i5 6400 2.7GHz, NVIDIA GeForce GTX 1070 (8GB), 16Gig DDR4 RAM, 256GB SSD, 1TB HDD, Windows 10 64bit

Dabz

Little more detail that I've found...

Right, canvasthing3.png is the one that runs as expected (With SetGraphicsDriver GLMax2DDriver() commented out)...

canvasthing1.png is what I get (When SetGraphicsDriver GLMax2DDriver() isnt commented out) when I click on canvas1 first, then hit Space...

canvasthing2.png on the other hand, is what I get (When SetGraphicsDriver GLMax2DDriver() isnt commented out) when I click on canvas2 first (Bringing it to the front), then hitting Space!

Not a clue whats happening there mind, because as I recall... That did work as expected, and I cannot see nothing wrong with the code!?!

Dabz
Intel Core i5 6400 2.7GHz, NVIDIA GeForce GTX 1070 (8GB), 16Gig DDR4 RAM, 256GB SSD, 1TB HDD, Windows 10 64bit

col

You should be able to create multiple windows with the direct3d drivers too.

I get an EAV on the D3D9Max2DDriver.
I also get the same garbage text that Dabz is getting without bringing in the openb3d module.

Win7 x64.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

col

Without digging deep I *think* the problem is because the font uses textures for the glyphs. The textures are created by an underlying context. That context is different for each window. If I recall correctly you shouldn't share textures across glcontexts ( across windows ) ?? Someone should correct me there. Also isn't there glShareContexts type of function that may be of use?

Creating and using a second font for the second window solves the immediate issue for me.
Not sure what's going with D3D9 though - I haven't looked into that one and I need an early night ;D
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Dabz

Just checked with D3D9Max2DDriver, and, works... I had to check as it's been that long I wasnt sure what BlitzMax defaulted to when you just use Graphics()

Dabz
Intel Core i5 6400 2.7GHz, NVIDIA GeForce GTX 1070 (8GB), 16Gig DDR4 RAM, 256GB SSD, 1TB HDD, Windows 10 64bit

Krischan

#10
GlShareContexts(). That's it, thanks col! But the text only works with my modified Begin2D() / End2D() functions - but that's ok.

    SuperStrict
     
    Framework openb3d.b3dglgraphics
     
    Import MaxGui.Drivers
    Import brl.Timer
    Import brl.EventQueue
    Import BRL.freetypefont
     
    SetGraphicsDriver GLMax2DDriver()

GLShareContexts()
     
    ' MAXGUI stuff
    Global width:Int = 320
    Global Height:Int = 240
    Global wx:Int = (ClientWidth(Desktop()) - width) / 2
    Global wy:Int = (ClientHeight(Desktop()) - Height) / 2
    Global Window1:TGadget = CreateWindow("First Canvas", wx, wy, width, Height, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
    Global canvas1:TGadget = CreateCanvas(0, 0, 320, 240, Window1)
    Global window2:TGadget = CreateWindow("Second Canvas", wx * 1.25, wy * 1.25, width, Height, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS)
    Global canvas2:TGadget = CreateCanvas(0, 0, 320, 240, window2)
    ActivateGadget(canvas2)
     
    ' load font
    Global Font:TImageFont = LoadImageFont(getenv_("WINDIR") + "/Fonts/Arial.ttf", 32)
     
    Global switch:Int = 1
    Global switchtext:String[] = ["MAX2D", "MAX2D fixed"]
     
    ' OpenB3D stuff
    SetGraphics CanvasGraphics(canvas1)
    Graphics3D width, Height, 0, 2, 60, -1, True
    Global cam:TCamera = CreateCamera()
    Global mesh:TMesh = CreateCube()
    Global light:TLight = CreateLight(1)
    AmbientLight 0, 0, 0
    PositionEntity mesh, 0, 0, 3
     
    CreateTimer 60
     
    ' hook
    AddHook EmitEventHook, LoopHook
     
    ' main loop
    Repeat
     
            WaitEvent()
     
    Forever
     
    End
     
    ' ----------------------------------------------------------------------------
    ' Loop Hook
    ' ----------------------------------------------------------------------------
    Function LoopHook:Object(id:Int, data:Object, context:Object)
     
            Local Event:TEvent = TEvent(data)
            If Event = Null Then Return Event
     
            Select Event.id
     
                    Case EVENT_TIMERTICK
     
                            TurnEntity mesh, 0.5, 1, 0.5
                   
                            RedrawGadget canvas1
                            RedrawGadget canvas2
     
                    Case EVENT_GADGETPAINT
     
                            Select Event.source
     
                                    Case canvas1
     
                                                            SetGraphics CanvasGraphics(canvas1)
                                                           
                                                            Cls
                                                           
                                                            RenderWorld
                                                           
                                                            If switch Then Begin2D() Else BeginMax2D()
                                                           
                                                            SetBlend ALPHABLEND
                                                            SetColor(255, 0, 0)
                                                            SetImageFont Font
                                                            DrawText switchtext[switch], 0, 0
                                                           
                                                            If switch Then End2D() Else EndMax2D()
                                                           
                                                            Flip False
           
                                    Case canvas2
           
                                                            SetGraphics CanvasGraphics(canvas2)
                                                           
                                                            Cls
                                                           
                                                            RenderWorld
                                                           
                                                            If switch Then Begin2D() Else BeginMax2D()
                                                           
                                                            SetBlend ALPHABLEND
                                                            SetColor(0, 255, 0)
                                                            SetImageFont Font
                                                            DrawText switchtext[switch], 0, 0
                                                           
                                                            If switch Then End2D() Else EndMax2D()
                                                           
                                                            Flip false
     
                            End Select
                           
                    Case EVENT_KEYDOWN
                   
                            Select Event.data
                           
                                    Case KEY_SPACE
                                   
                                                            switch = 1 - switch
                           
                            End Select
     
                    Case EVENT_WINDOWCLOSE
     
                            FreeGadget canvas1
                            FreeGadget canvas2
                            End
     
                    Case EVENT_APPTERMINATE
     
                            End
     
            End Select
     
    End Function
     
    ' Fixed BeginMax2D()
    Function Begin2D()
     
            Local x:Int, y:Int, w:Int, h:Int
            GetViewport(x, y, w, h)
     
            glDisable(GL_LIGHTING)
            glDisable(GL_DEPTH_TEST)
            glDisable(GL_SCISSOR_TEST)
            glDisable(GL_FOG)
            glDisable(GL_CULL_FACE)
     
            glMatrixMode GL_TEXTURE
            glLoadIdentity
     
            glMatrixMode GL_PROJECTION
            glLoadIdentity
            glOrtho 0, width, Height, 0, -1, 1
     
            glMatrixMode GL_MODELVIEW
            glLoadIdentity
     
            SetViewport x, y, w, h
     
            Local MaxTex:Int
            glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))
     
            For Local Layer:Int = 0 Until MaxTex
     
                    glActiveTexture(GL_TEXTURE0+Layer)
     
                    glDisable(GL_TEXTURE_CUBE_MAP)
                    glDisable(GL_TEXTURE_GEN_S)
                    glDisable(GL_TEXTURE_GEN_T)
                    glDisable(GL_TEXTURE_GEN_R)
     
                    glDisable(GL_TEXTURE_2D)
     
            Next
     
            glActiveTexture(GL_TEXTURE0)
     
            glViewport(0, 0, width, Height)
            glScissor(0, 0, width, Height)
     
            glEnable GL_BLEND
            glEnable(GL_TEXTURE_2D)
     
    End Function
     
     
     
    ' Fixed EndMax2D()
    Function End2D()
     
            glDisable(GL_TEXTURE_CUBE_MAP)
            glDisable(GL_TEXTURE_GEN_S)
            glDisable(GL_TEXTURE_GEN_T)
            glDisable(GL_TEXTURE_GEN_R)
     
            glDisable(GL_TEXTURE_2D)
            glDisable GL_BLEND
     
            TGlobal.EnableStates()
     
            TGlobal.alpha_enable[0] = 0     ' alpha blending was disabled by Max2d (GL_BLEND)
            TGlobal.blend_mode[0] = 1       ' force alpha blending
            TGlobal.fx1[0] = 0                      ' full bright/surface normals was enabled by EnableStates (GL_NORMAL_ARRAY)
            TGlobal.fx2[0] = 1                      ' vertex colors was enabled by EnableStates (GL_COLOR_ARRAY)
     
            glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)
            glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)
     
            glClearDepth(1.0)
            glDepthFunc(GL_LEQUAL)
            glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
     
            glAlphaFunc(GL_GEQUAL, 0.5)
     
            For Local cam:TCamera=EachIn TCamera.cam_list
     
                     ' active camera - was if cam.hide[0]=0
                     If cam = TGlobal.camera_in_use
     
                            ' fog with Max2d fix
                            cam.UpdateFog()
                            Exit
     
                    EndIf
     
            Next
     
    End Function


A question to Qube: the codebox in the forum here converts Tabs to Spaces, is it possible to fix this? See second screenshot.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
Metaverse | Blitzbasic Archive | My Github projects

Derron

Just convert your tabs to spaced before posting here. That way you can define how "deep" your tab-spaces should be (by default it should be 4 or 8).


Also: The line with "GLSharecontexts()" is having a "tab" at the beginning. Maybe it only removes the tabs when doing a code-paste in wysiwyg-mode.




bye
Ron

markcwm

#12
I've used this code as the basis for a multi-canvas example named maxgui2, it works well now but it took me a few days. So thanks Krischan. Also thanks for the improved begin and endmax2d functions, I have replaced the old functions with them and renamed the old functions Begin and EndMini3D (so as not to conflict with your names).

There's a new commit for the wrapper which has a few other fixes; the Graphics3D command flags wouldn't let you override the default settings, LoadMesh now has a usenative=True parameter to choose between library or native loaders (which currently lack animation but are otherwise an improvement). And there's a few new examples. ;)