Display problem with multiple canvases in blitzMax MaxGui

Started by Midimaster, July 28, 2023, 10:12:08

Previous topic - Next topic

Midimaster

I have a 20.000 code lines app to display music notes (sheet music). It was always a single window where I displayed the notes. Now I want to expand this to multiple windows, each showing different music content: scrolling notes and at the same time an editor, where you can work on the next pieces of music, etc...

My problem is now, that the notes are displayed with graphical bugs, when I opened a second window. On one window it is always displayed perfect, but the second window show garbage: rects instead of notes, or even letters. (strange: no letters are in my NOTEN.PNG)

To have all different notes together I use the 18 frames of a TAnimImage NOTEN.PNG. Each contains a single note type: Quarters, Eights, Rests, Keys, etc... So the class TDisplay and TNote put together a complete sheet with position informations and from those 18 frame.

The NOTEN.PNG was a GLOBAL inside type TNote. Both windows used the same method and the same image to display the notes.

Derron already told me, that OpenGL cannot share content (TIMAGEs) and so it comes to this bugs. As a workaround I now load two NOTEN.PNGs and switch them each time the SetGraphics() changes. This indeed removed the problems, but is this really the best way?


In the main loop:
Function RefreshDisplay
    SetGraphics CanvasGraphics(mdi.Canvas)
    TNote.SwitchCanvas 1   ' <--- HERE IS THE WORKAROUND ********
    Cls
    MDI.DrawNoten
    Flip 0
           
    ..
    SetGraphics CanvasGraphics(Assistent.Canvas)
    TNote.SwitchCanvas 2   ' <--- HERE IS THE WORKAROUND ********
    Cls
    Assistent.DrawNoten
    Flip 0
End Function

In the type TNote
Type TNote    
        Global Noten_GAME:TImage, Noten_EDIT:TImage, Noten_TEMP:TImage,
        ' 18 frames and 2 images for both canvases  *********
        Noten_GAME = LoadAnimImage("Noten.png",60,140,0,18)
        Noten_EDIT = LoadAnimImage("Noten.png",60,140,0,18)
        ...

        '  NEW WORKAROUND SWITCH THE IMAGE: ***********
        Function SwitchCanvas(SwitchTo:Int)
            Global OldCanvas:Int = -1
            If SwitchTo=OldCanvas Return
            OldCanvas = SwitchTo

            If OldCanvas=1
                Noten_TEMP = Noten_GAME
            Else
                Noten_TEMP = Noten_EDIT
            EndIf
        End Function
...






Here is a very reduced symbolic example code (not runable, not showing the problem)

SuperStrict
Import MaxGUI.Drivers
CreateTimer 60

MDI.FormLoad
TNote.StartUp

Assistent.FormLoad

While WaitEvent()
   Select EventID()
      Case EVENT_TIMERTICK
            Game.BuildNoten
            RefreshDisplay
       Case EVENT_APPTERMINATE
            End
    End Select
Wend


Function RefreshDisplay()
    Local Fenster:TGraphics=CanvasGraphics(mdi.Canvas)
    SetGraphics Fenster
    TNote.SwitchCanvas 1
    Cls
    MDI.DrawNoten
    Flip 0
           
    If ActiveGadget()=Assistent.Window
            SetGraphics CanvasGraphics(Assistent.Canvas)
            TNote.SwitchCanvas 2
            Cls
            Assistent.DrawNoten
            Flip 0
    EndIf
End Function


Type MDI
        Global Window:TGadget , Canvas:TGadget
       
        Function FormLoad()
                Window= CreateWindow("MAIN ", 100 , 100 , 1920 , 1080 , Null , WINDOW_DEFAULT|WINDOW_CLIENTCOORDS)
                Canvas=CreateCanvas(0 , 0 , GadgetWidth(Desktop()), GadgetHeight(Desktop()) , Window)
                SetGadgetLayout Canvas , 1,1,1,1
        End Function
       
       
        Function DrawNoten()
            Game.Draw
        End Function 
End Type   


Type Assistent
        Global Window:TGadget , Canvas:TGadget
       
        Global EditorNoten:TDisplay

        Function FormLoad()
            Window=CreateWindow("EDITOR",0,0,800,440, mdi.Window , WINDOW_TITLEBAR|WINDOW_CLIENTCOORDS|WINDOW_CENTER|WINDOW_TOOL)
            SetGadgetLayout Window,1,1,1,1

            Canvas=CreateCanvas(3 , 3 , 790, 380 , Window)
            SetGadgetLayout Canvas , 1,1,1,1
        End Function

       
        Function DrawNoten()
                EditorNoten.Draw
        End Function
       
       
        Function BuildNoten()       
            EditorNoten= TDisplay.CreateIt()       
            For Local i%= 0 To 9
                    EditorNoten.AddNote i
            Next
        End Function
End Type


Type Game
        Global GameNoten:TDisplay
       
        Function Draw()
                GameNoten.Draw
        End Function
       
       
        Function BuildNoten()       
            GameNoten = TDisplay.CreateIt()       
            For Local i%= 0 To 9
                    GameNoten.AddNote i
            Next
        End Function
End Type


Type TDisplay      
        Field Liste:TList
       
        Function CreateIt:TDisplay()
            Local loc:TDisplay = New TDisplay
            loc.Liste = New TList
            Return loc
        End Function

       
        Method AddNote(i%)
            Local loc:TNote = New TNote
            loc.Frame = i
            Liste.AddLast loc
        End Method


        Method Draw()
            For Local loc:TNote = EachIn Liste
                loc.DrawOne
            Next       
        End Method
End Type


Type TNote
    Global Noten_GAME:TImage, Noten_EDIT:TImage, Noten_TEMP:TImage
    Field Frame:Int
       
    Function StartUp()
        ' 18 frames and 2 images for both canvases
        Noten_GAME = LoadAnimImage("Noten.png",60,140,0,18)
        Noten_EDIT = LoadAnimImage("Noten.png",60,140,0,18)
    End Function
      

    Function SwitchCanvas(SwitchTo:Int)
        Global OldCanvas:Int = -1
        If SwitchTo=OldCanvas Return
        OldCanvas = SwitchTo
        If OldCanvas=1
            Noten_TEMP = Noten_GAME
        Else
            Noten_TEMP = Noten_EDIT
        EndIf
    End Function

       
        Method DrawOne()
            DrawImage Noten_TEMP, 0 ,0 ,Frame
        End Method
End Type



...back from North Pole.

Derron

Just to add: OpenGL "can" share textures between contexts. Max2D and brl.glgraphics just do not provide an option to configure it that way.

when not sharing it means that a texture is defined in the one context - but in the other it is just ... "random memory". If at this point in the memory by luck is the same texture you might not see it. It might even have a little part of the screen there which it has rendered before - so it looks like you just "offset" your image wrong and all this stuff.
At the end it is similar to not using "CLS" and hoping that on the next "flip" the last rendered buffer is still 100% intact (similar to how you did "dirty rects" >30yrs ago).


Anyways. I think we should check if we could (cross-platform/cross-backend) enable a way to share textures between graphic contexts.


bye
Ron