Linux Screen3DMousePatch

Everything related to 3D programming
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Linux Screen3DMousePatch

Post by mk-soft »

The mouse functions for the Engine3D do not work for me under Linux (Virtual Machine).
This had bothered me for a long time and so I wrote a patch for Linux.

With full screen, RestoreMouse must be called at the end, otherwise the mouse cursor for the desktop is destroyed.

Also runs on Linux host system (Tested on Raspberry PI)

Features:
- Auto scrolling for mouse delta at the edge of the screen
- Changing the mouse cursor on the screen
- Changing the mouse cursor for mouse release mode

Update v1.02.2
- Added: FrameDelay for save cpu usage (Needs only with OpenWindowedScreen)

Update v1.03.1
- Bugfix mouse delta direction and menu height

Update v1.03.2
- Limit windowed screen mouse position to screen size (auto scroll area now inside screen)

Screen3DMousePatch.pb

Code: Select all

;-TOP 
; Comment : Linux Screen3DMousePatch
; Author  : mk-soft
; Version : v1.03.2
; Create  : 02.09.2022
; Update  : 10.09.2022
; Link    : https://www.purebasic.fr/english/viewtopic.php?t=79766

; Info:
;
; - Call InitWindowMouse after OpenScreen or OpenWindowedScreen
; - Call RestoreMouse at end of program to restore desktop mouse cursor (Needs only with OpenScreen)
; - Call FrameDelay for save cpu usage (Needs only with OpenWindowedScreen)

; - Enumeration of cursor type: 
;   * Link:  "https://docs.gtk.org/gdk3/enum.CursorType.html"
;   * Blank: -2
;
; - ScrollRange:
;   * Auto scrolling range for mouse delta

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  
  ImportC ""
    gtk_widget_get_window(widget)
    gdk_get_default_root_window()
    gdk_window_get_cursor(window)
  EndImport
  
  Structure udtMouseData
    IsWindow.i
    Window.i
    WindowID.i
    WindowGDK.i
    IsMenu.i
    CursorDefault.i
    CursorScreen.i
    CursorState.i
    x.l
    y.l
    lastX.l
    lastY.l
    deltaX.l
    deltaY.l
    menuHeight.l
    scrollRange.l
    screenWidth.l
    screenHeight.l
  EndStructure
  
  Global MyMouseData.udtMouseData
  
  Procedure InitWindowMouse(Window = 0, CursorDefault = 0, CursorScreen = 130, ScrollRange = 25)
    Protected PosX.l, PosY.l
    With MyMouseData
      ; Get Window Data
      If IsWindow(Window)
        \IsWindow = #True
        \Window = Window
        \WindowID = WindowID(Window)
        \WindowGDK = gtk_widget_get_window(\WindowID)
        If IsMenu(0)
          \IsMenu = #True
          \menuHeight = MenuHeight()
        EndIf
      Else
        \WindowGDK = gdk_get_default_root_window()
      EndIf
      ; Define Cursor Data
      If CursorDefault
        \CursorDefault = gdk_cursor_new_(CursorDefault)
      Else
        \CursorDefault = gdk_window_get_cursor(\WindowGDK)
      EndIf
      \CursorScreen = gdk_cursor_new_(CursorScreen); Blank = -2
      gdk_window_set_cursor_(\WindowGDK, \CursorScreen)
      ; Scroll Range
      \scrollRange = ScrollRange
      \screenWidth = ScreenWidth()
      \screenHeight = ScreenHeight()
      ; Get Positions
      If IsWindow(Window)
        gtk_widget_get_pointer_(\WindowID, @PosX, @PosY)
        \lastX = PosX
        \lastY = PosY
      Else
        \x = DesktopMouseX()
        \y = DesktopMouseY()
        \lastX = \x
        \lastY = \y
      EndIf
    EndWith
    ProcedureReturn #True
  EndProcedure
  
  Procedure RestoreMouse()
    Protected window, cursor
    If OpenWindow(0, 0, 0, 0, 0, "Restore Mouse Cursor", #PB_Window_Invisible)
      window = gdk_get_default_root_window()
      cursor = gdk_cursor_new_(68)
      If window
        gdk_window_set_cursor_(window, cursor)
      EndIf
    EndIf
  EndProcedure
  
  ; ----
  
  Procedure.f MyMouseX()
    ProcedureReturn MyMouseData\x
  EndProcedure
  
  Procedure.f MyMouseY()
    ProcedureReturn MyMouseData\y
  EndProcedure
  
  Procedure.f MyMouseDeltaX()
    ProcedureReturn MyMouseData\deltaX
  EndProcedure
  
  Procedure.f MyMouseDeltaY()
    ProcedureReturn MyMouseData\deltaY
  EndProcedure
  
  Procedure MyReleaseMouse(State)
    With MyMouseData
      \CursorState = State
      If \WindowGDK
        If State
          gdk_window_set_cursor_(\WindowGDK, \CursorDefault)
        Else
          gdk_window_set_cursor_(\WindowGDK, \CursorScreen)
        EndIf
      EndIf
    EndWith
  EndProcedure
  
  Procedure MyExamineMouse()
    Protected PosX.l, PosY.l
    
    With MyMouseData
      If \IsWindow
        gtk_widget_get_pointer_(\WindowID, @PosX, @PosY)
        If \IsMenu
          PosY - \menuHeight
        EndIf
        If PosX < 0
          PosX = 0
        ElseIf PosX >= \screenWidth
          PosX = \screenWidth - 1
        EndIf
        If PosY < 0
          PosY = 0
        ElseIf PosY >= \screenHeight
          PosY = \screenHeight - 1
        EndIf
      Else
        PosX = DesktopMouseX()
        PosY = DesktopMouseY()
      EndIf
      
      \x = PosX
      \y = PosY
      
      If \CursorState
        \deltaX = 0
        \deltaY = 0
      Else
        \deltaX = PosX - \lastX
        \deltaY = PosY - \lastY
      EndIf
      \lastX = PosX
      \lastY = PosY
      
      If PosX < \scrollRange
        \lastX = \scrollRange
        If \deltaX > \scrollRange
          \deltaX = \scrollRange
        EndIf
      ElseIf PosX > \screenWidth - \scrollRange
        \lastX = \screenWidth - \scrollRange
        If \deltaX < -\scrollRange
          \deltaX = -\scrollRange
        EndIf
      Else
        \lastX = PosX
      EndIf
      If PosY < \scrollRange
        \lastY = \scrollRange
        If \deltaY > \scrollRange
          \deltaY = \scrollRange
        EndIf
      ElseIf PosY > \screenHeight - \scrollRange
        \lastY = \screenHeight - \scrollRange
        If \deltaY < -\scrollRange
          \deltaY = -\scrollRange
        EndIf
      Else
        \lastY = PosY
      EndIf
    EndWith
    ProcedureReturn #True
    
  EndProcedure
  
  ;-- Macros
  Macro MouseX()
    MyMouseX()
  EndMacro
  
  Macro MouseY()
    MyMouseY()
  EndMacro
  
  Macro MouseDeltaX()
    MyMouseDeltaX()
  EndMacro
  
  Macro MouseDeltaY()
    MyMouseDeltaY()
  EndMacro
  
  Macro ReleaseMouse(State)
    MyReleaseMouse(State)
  EndMacro
  
  Macro ExamineMouse()
    MyExamineMouse()
  EndMacro
  
CompilerElse
  Procedure InitWindowMouse(Window = 0, CursorDefault = 0, CursorScreen = 130, ScrollRange = 25)
    ; do nothing
  EndProcedure
  
  Procedure RestoreMouse()
    ; do nothing
  EndProcedure
CompilerEndIf

Procedure FrameDelay(Frames = 30)
  Static time
  Protected diff_time, delay_time
  If time
    diff_time = ElapsedMilliseconds() - time
    delay_time = (1000 / Frames) - diff_time
    If delay_time > 0
      Delay(delay_time)
    EndIf
  EndIf
  time = ElapsedMilliseconds()
EndProcedure

;-- End
Last edited by mk-soft on Sat Sep 10, 2022 12:19 pm, edited 10 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Linux Screen3DMousePatch

Post by mk-soft »

Example:

Code: Select all

;
; ------------------------------------------------------------
;
;   PureBasic - Billboard
;
;    (c) Fantaisie Software
;
; ------------------------------------------------------------
;

#CameraSpeed = 2

IncludeFile #PB_Compiler_Home + "examples/3d/Screen3DRequester.pb"
IncludeFile #PB_Compiler_Home + "examples/3d/Screen3DMousePatch.pb"

Define.f KeyX, KeyY, MouseX, MouseY

If InitEngine3D()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
  If Screen3DRequester()
    
    ; Init own windowed mouse
    InitWindowMouse()
  
    Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
    Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Models", #PB_3DArchive_FileSystem)
    Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts", #PB_3DArchive_FileSystem)
    Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Packs/skybox.zip", #PB_3DArchive_Zip)
    Parse3DScripts()
    
    ; First create materials
    ;
    
    GrassMaterial = CreateMaterial(#PB_Any, TextureID(LoadTexture(#PB_Any,"grass1.png")))
    MaterialBlendingMode(GrassMaterial, #PB_Material_AlphaBlend)
    DirtMaterial = CreateMaterial(#PB_Any, TextureID(LoadTexture(#PB_Any,"Dirt.jpg")))
    
    
    ; Then create the billboard group and use the previous material
    ;
    ;-Billboard
    
    Billboard = CreateBillboardGroup(#PB_Any, MaterialID(GrassMaterial), 96, 96, 0, 0, 0, -1, 1)
    BillboardGroupCommonDirection(Billboard, 0, 1, 0)
        
    For i = 0 To 600
      AddBillboard(Billboard, Random(2000)-1000, Random(18) + 30, Random(2000) - 1000)
    Next i

    ; create ground
    
    MeshPlane = CreatePlane(#PB_Any, 2000, 2000, 40, 40, 4, 4)
    CreateEntity(#PB_Any, MeshID(MeshPlane), MaterialID(DirtMaterial))
    
    ; Add house
    MeshHouse = LoadMesh(#PB_Any, "tudorhouse.mesh")
    House = CreateEntity(#PB_Any, MeshID(MeshHouse), #PB_Material_None, 0, 280, 0)
    ScaleEntity(House, 0.5, 0.5, 0.5)
    
    ; SkyBox
    SkyBox("stevecube.jpg")
    
    ; create camera
    Camera = CreateCamera(#PB_Any, 0, 0, 100, 100)
    MoveCamera(Camera, 200, 400, 900, #PB_Absolute)
    CameraLookAt(Camera, 0, 100, 0)
    
    Repeat
      
      Screen3DEvents()
      
      If ExamineMouse()
        MouseX = -MouseDeltaX() * #CameraSpeed * 0.05
        MouseY = -MouseDeltaY() * #CameraSpeed * 0.05
      EndIf
      
      If MouseButton(#PB_MouseButton_Left) And Not fm_button
        fm_button = 1
        If toggle
          toggle = 0
        Else 
          toggle = 1
        EndIf
        ReleaseMouse(toggle)
      EndIf
      fm_button = MouseButton(#PB_MouseButton_Left)
      
      If Screen3DRequester_FullScreen = 0
        info.s = "X = " + MouseX() + " / Y = " + MouseY()
        info.s + " / Button L = " + MouseButton(#PB_MouseButton_Left)
        info.s + " - M = " + MouseButton(#PB_MouseButton_Middle)
        info.s + " - R = " + MouseButton(#PB_MouseButton_Right)
        SetWindowTitle(0, info)
      EndIf
      
      If ExamineKeyboard()
        
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = #CameraSpeed
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = #CameraSpeed
        Else
          KeyY = 0
        EndIf
        
      EndIf
      
      RotateCamera(Camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera  (Camera, KeyX, 0, KeyY)
      
      RenderWorld()
      Screen3DStats()
      FlipBuffers()
      
      ; Save cpu usage
      FrameDelay(30)
      
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
    
    RestoreMouse()
    
  EndIf
  
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf

End
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Linux Screen3DMousePatch

Post by mk-soft »

Update v1.03.2
- Limit windowed screen mouse position to screen size (auto scroll area now inside screen)
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
useful
Enthusiast
Enthusiast
Posts: 402
Joined: Fri Jul 19, 2013 7:36 am

Re: Linux Screen3DMousePatch

Post by useful »

Ubuntu 22.04 xfce Virtualbox(VBoxSVGA) gtk2 PB 6.03B3
The program 'purebasic_compilation0.out' received an X Window System error.
This probably reflects a bug in the program.
The error was 'GLXBadContextTag'.
(Details: serial 33 error_code 162 request_code 151 minor_code 16)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the --sync command line
option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)
===========
p.s. In the case of gtk3, it works both without a patch and with a patch.
Dawn will come inevitably.
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Linux Screen3DMousePatch

Post by mk-soft »

It's because of the VirtualBox graphics driver. For me it works with Parallels opengl graphics driver.
I don't know if VirtualBox also has an OpenGL graphics driver. Or try another graphics driver.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply