PureBasic Forum
https://www.purebasic.fr/english/

Trackball Camera for OpenGLGadget()
https://www.purebasic.fr/english/viewtopic.php?f=36&t=65829
Page 1 of 1

Author:  StarBootics [ Sun May 29, 2016 11:40 pm ]
Post subject:  Trackball Camera for OpenGLGadget()

Hello everyone,

I would to say this a 100% working trackball camera but it's not the case. From time to time the rotation stop event if the mouse left button is hold down. I don't understand why, if someone find a solution let me know.

Edit 1 : Thanks to Demivec for the hint about #PB_OpenGL_WheelDelta, now the zoom function work fine.
I have also deleted my Feature request since it was complete useless. (I should learn how to read :oops: )

Edit 2 : Some optimization, renaming IncrementDistance() --> Zooming(), removing unused procedures.

Edit 3 : Change the far value for gluPerspective_() the cube no longer disappear behind the camera far plane

Best regards
StarBootics
Code:
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : Trackball Camera for OpenGLGadget()
; File Name : Camera - Module.pb
; File version: 0.9.9
; Programming : OK +/-
; Programmed by : StarBootics
; Date : 29-05-2016
; Last Update : 29-05-2016
; PureBasic code : V5.42 LTS
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
; This code is free to be use where ever you like
; but you use it at your own risk.
;
; The author can in no way be held responsible
; for data loss, damage or other annoying
; situations that may occur.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule Camera
 
  Declare.d GetMotionSensitivity()
  Declare.d GetScrollSensitivity()
  Declare.d GetDistance()
  Declare.d GetMinDistance()
  Declare SetMotionSensitivity(P_MotionSensitivity.d)
  Declare SetScrollSensitivity(P_ScrollSensitivity.d)
  Declare SetDistance(P_Distance.d)
  Declare SetMinDistance(P_MinDistance.d)
  Declare Initialize()
  Declare Reset()
  Declare PerspectiveView()
  Declare FrontView()
  Declare BackView()
  Declare RightView()
  Declare LeftView()
  Declare TopView()
  Declare BottomView()
  Declare TrackBallLookAt()
  Declare Zooming(P_Direction.d)
  Declare StartRotation(P_x.l, P_y.l)
  Declare StopRotation()
  Declare TrackRotation(P_x.l, P_y.l)
 
EndDeclareModule

Module Camera
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Déclaration de la Structure <<<<<
 
  Structure Instance
   
    MotionSensitivity.d
    ScrollSensitivity.d
    Distance.d
    MinDistance.d
    RotationX.d
    RotationY.d
    MouseLeftButtonHold.b
    MouseX.l
    MouseY.l
   
  EndStructure
 
  Global Instance.Instance
 
  Procedure.f WrapAngleDeg(angle.f)
   
    ; <- wraps a value into [0,360) fringe
   
    ; Author : Psychophanta
   
    !fild dword[@f] ; <- now i have 360 into st0
    !fld dword[p.v_angle]
    !fprem
    !fadd st1,st0
    !fldz
    !fcomip st1
    !fcmovnbe st0,st1
    !fstp st1
    ProcedureReturn
    !@@:dd 360
  EndProcedure
 
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Les observateurs <<<<<
 
  Procedure.d GetMotionSensitivity()
   
    ProcedureReturn Instance\MotionSensitivity
  EndProcedure
 
  Procedure.d GetScrollSensitivity()
   
    ProcedureReturn Instance\ScrollSensitivity
  EndProcedure
 
  Procedure.d GetDistance()
   
    ProcedureReturn Instance\Distance
  EndProcedure
 
  Procedure.d GetMinDistance()
   
    ProcedureReturn Instance\MinDistance
  EndProcedure
 
  Procedure.d GetRotationX()
   
    ProcedureReturn Instance\RotationX
  EndProcedure
 
  Procedure.d GetRotationY()
   
    ProcedureReturn Instance\RotationY
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Les mutateurs <<<<<
 
  Procedure SetMotionSensitivity(P_MotionSensitivity.d)
   
    Instance\MotionSensitivity = P_MotionSensitivity
   
  EndProcedure
 
  Procedure SetScrollSensitivity(P_ScrollSensitivity.d)
   
    Instance\ScrollSensitivity = P_ScrollSensitivity
   
  EndProcedure
 
  Procedure SetDistance(P_Distance.d)
   
    Instance\Distance = P_Distance
   
  EndProcedure
 
  Procedure SetMinDistance(P_MinDistance.d)
   
    Instance\MinDistance = P_MinDistance
   
  EndProcedure
 
  Procedure SetRotationX(P_RotationX.d)
   
    Instance\RotationX = P_RotationX
   
  EndProcedure
 
  Procedure SetRotationY(P_RotationY.d)
   
    Instance\RotationY = P_RotationY
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< L'opérateur Initialize <<<<<
 
  Procedure Initialize()
   
    Instance\MotionSensitivity = 1.75
    Instance\ScrollSensitivity = 1.0
    Instance\Distance = 10.0
    Instance\MinDistance = 0.1
    Instance\RotationX = 30.0
    Instance\RotationY = -45.0
    Instance\MouseLeftButtonHold = 0
    Instance\MouseX = 0
    Instance\MouseY = 0
   
  EndProcedure
 
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< L'opérateur Reset <<<<<
 
  Procedure Reset()
   
    Instance\MotionSensitivity = 0.0
    Instance\ScrollSensitivity = 0.0
    Instance\Distance = 0.0
    Instance\MinDistance = 0.0
    Instance\RotationX = 0.0
    Instance\RotationY = 0.0
    Instance\MouseLeftButtonHold = 0
    Instance\MouseX = 0
    Instance\MouseY = 0
   
  EndProcedure
 
  Procedure PerspectiveView()
   
    Instance\RotationX = 30.0
    Instance\RotationY = -45.0
   
  EndProcedure
 
  Procedure FrontView()
   
    Instance\RotationX = 0.0
    Instance\RotationY = 0.0
   
  EndProcedure
 
  Procedure BackView()
   
    Instance\RotationX = 180.0
    Instance\RotationY = 0.0
   
  EndProcedure
 
  Procedure RightView()
   
    Instance\RotationX = 0.0
    Instance\RotationY = -90.0
   
  EndProcedure
 
  Procedure LeftView()
   
    Instance\RotationX = 0.0
    Instance\RotationY = 90.0
   
  EndProcedure
 
  Procedure TopView()
   
    Instance\RotationX = 90.0
    Instance\RotationY = 0.0
   
  EndProcedure
 
  Procedure BottomView()
   
    Instance\RotationX = -90.0
    Instance\RotationY = 0.0
   
  EndProcedure
 
  Procedure TrackBallLookAt()
   
    ;glMatrixMode(#GL_MODELVIEW)
    glLoadIdentity_()
    ; // la caméra regarde le centre (0,0,0) et est sur l'axe Z à une certaine distance du centre donc (0,0, distance)
    gluLookAt_(0, 0, Instance\Distance, 0, 0, 0, 0, 1, 0)
    glRotated_(Instance\RotationX, 1, 0, 0); //la scène est tournée autour de l'axe X
    glRotated_(Instance\RotationY, 0, 1, 0); //la scène est tournée autour de l'axe Y
   
  EndProcedure
 
  Procedure Zooming(P_Direction.d)
   
    Instance\Distance = Instance\Distance + P_Direction * Instance\ScrollSensitivity
   
    If Instance\Distance < Instance\MinDistance
      Instance\Distance = Instance\MinDistance
    EndIf
   
  EndProcedure
 
  Procedure StartRotation(P_x.l, P_y.l)
   
    Instance\MouseLeftButtonHold = #True
    Instance\MouseX = P_x
    Instance\MouseY = P_y
   
  EndProcedure
 
  Procedure StopRotation()
   
    Instance\MouseLeftButtonHold = #False
   
  EndProcedure
 
  Procedure TrackRotation(P_x.l, P_y.l)
   
    If Instance\MouseLeftButtonHold = #True
      Instance\RotationX = WrapAngleDeg(Instance\RotationX + Sign(P_y - Instance\MouseY) * Instance\MotionSensitivity)
      Instance\RotationY = WrapAngleDeg(Instance\RotationY + Sign(P_x - Instance\MouseX) * Instance\MotionSensitivity)
      Instance\MouseX = P_x
      Instance\MouseY = P_y
    EndIf
   
  EndProcedure
 
EndModule

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code généré en : 00.001 secondes (109000.00 lignes/seconde) <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

CompilerIf #PB_Compiler_IsMainFile
 
 
  ; Global RollAxisX.f
  ; Global RollAxisY.f
  ; Global RollAxisZ.f
  ;
  ; Global RotateSpeedX.f = 1.0
  ; Global RotateSpeedY.f
  ; Global RotateSpeedZ.f = 1.0
  ;
  ; Global ZoomFactor.f = 1.0 ; Distance of the camera. Negative value = zoom back
 
  Procedure DrawCube(Gadget)
   
    SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
    Camera::TrackBallLookAt()
   
    glPushMatrix_()                  ; Save the original Matrix coordinates
    glMatrixMode_(#GL_MODELVIEW)
   
    ;   glTranslatef_(0, 0, ZoomFactor)  ;  move it forward a bit
    ;
    ;   glRotatef_ (RollAxisX, 1.0, 0, 0) ; rotate around X axis
    ;   glRotatef_ (RollAxisY, 0, 1.0, 0) ; rotate around Y axis
    ;   glRotatef_ (RollAxisZ, 0, 0, 1.0) ; rotate around Z axis
    ;
    ;   RollAxisX + RotateSpeedX
    ;   RollAxisY + RotateSpeedY
    ;   RollAxisZ + RotateSpeedZ
   
    ; clear framebuffer And depth-buffer
   
    glClear_ (#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
   
    ; draw the faces of a cube
   
    ; draw colored faces
   
    glDisable_(#GL_LIGHTING)
    glBegin_  (#GL_QUADS)
   
    ; Build a face, composed of 4 vertex !
    ; glBegin() specify how the vertexes are considered. Here a group of
    ; 4 vertexes (GL_QUADS) form a rectangular surface.
   
    ; Now, the color stuff: It's r,v,b but with float values which
    ; can go from 0.0 To 1.0 (0 is .. zero And 1.0 is full intensity)
   
    glNormal3f_ (0,0,1.0)
    glColor3f_  (0,0,1.0)
    glVertex3f_ (0.5,0.5,0.5)   
    glColor3f_  (0,1.0,1.0)         
    glVertex3f_ (-0.5,0.5,0.5)
    glColor3f_  (1.0,1.0,1.0)
    glVertex3f_ (-0.5,-0.5,0.5)
    glColor3f_  (0,0,0)
    glVertex3f_ (0.5,-0.5,0.5)
   
    ; The other face is the same than the previous one
    ; except the colour which is nice blue To white gradiant
   
    glNormal3f_ (0,0,-1.0)
    glColor3f_  (0,0,1.0)
    glVertex3f_ (-0.5,-0.5,-0.5)
    glColor3f_  (0,0,1.0)
    glVertex3f_ (-0.5,0.5,-0.5)
    glColor3f_  (1.0,1.0,1.0)
    glVertex3f_ (0.5,0.5,-0.5)
    glColor3f_  (1.0,1.0,1.0)
    glVertex3f_ (0.5,-0.5,-0.5)
   
    glEnd_()
   
    ; draw shaded faces
   
    glEnable_(#GL_LIGHTING)
    glEnable_(#GL_LIGHT0)
    glBegin_ (#GL_QUADS)
   
    glNormal3f_ (   0, 1.0,   0)
    glVertex3f_ ( 0.5, 0.5, 0.5)
    glVertex3f_ ( 0.5, 0.5,-0.5)
    glVertex3f_ (-0.5, 0.5,-0.5)
    glVertex3f_ (-0.5, 0.5, 0.5)
   
    glNormal3f_ (0,-1.0,0)
    glVertex3f_ (-0.5,-0.5,-0.5)
    glVertex3f_ (0.5,-0.5,-0.5)
    glVertex3f_ (0.5,-0.5,0.5)
    glVertex3f_ (-0.5,-0.5,0.5)
   
    glNormal3f_ (1.0,0,0)
    glVertex3f_ (0.5,0.5,0.5)
    glVertex3f_ (0.5,-0.5,0.5)
    glVertex3f_ (0.5,-0.5,-0.5)
    glVertex3f_ (0.5,0.5,-0.5)
   
    glNormal3f_ (-1.0,   0,   0)
    glVertex3f_ (-0.5,-0.5,-0.5)
    glVertex3f_ (-0.5,-0.5, 0.5)
    glVertex3f_ (-0.5, 0.5, 0.5)
    glVertex3f_ (-0.5, 0.5,-0.5)
   
    glEnd_()
   
    glPopMatrix_()
    glFinish_()
   
    SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
  EndProcedure
 
 
  Procedure SetupGL(Width, Height)
   
    glMatrixMode_(#GL_PROJECTION)
    gluPerspective_(45.0, Width/Height, 1.0, 500.0)
   
    ; position viewer
    glMatrixMode_(#GL_MODELVIEW)
   
    glTranslatef_(0, 0, -5.0)
   
    glEnable_(#GL_DEPTH_TEST)   ; Enabled, it slowdown a lot the rendering. It's to be sure than the
                                ; rendered objects are inside the z-buffer.
   
    glEnable_(#GL_CULL_FACE)    ; This will enhance the rendering speed as all the back face will be
                                ; ignored. This works only with CLOSED objects like a cube... Singles
                                ; planes surfaces will be visibles only on one side.
   
    glShadeModel_(#GL_SMOOTH)
  EndProcedure
 
 
  Procedure HandleError (Result, Text$)
    If Result = 0
      MessageRequester("Error", Text$, 0)
      End
    EndIf
  EndProcedure
 
 
  Procedure Reshape()
   
    ResizeGadget(0, #PB_Ignore, #PB_Ignore, WindowWidth(0)-10, WindowHeight(0)-10)
   
    SetGadgetAttribute(0, #PB_OpenGL_SetContext, #True)
    glViewport_(0,0, GadgetWidth(0), GadgetHeight(0))
    glMatrixMode_(#GL_PROJECTION)
    glLoadIdentity_()
    gluPerspective_(30.0, GadgetWidth(0)/GadgetHeight(0), 1.0, 500.0)
    glMatrixMode_(#GL_MODELVIEW)
   
  EndProcedure
 
 
  OpenWindow(0, 0, 0, 800, 600, "OpenGL Gadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
 
  OpenGLGadget(0, 5, 5, 790, 590, #PB_OpenGL_Keyboard)
  SetupGL(790, 590)
  Camera::Initialize()
  Camera::TrackBallLookAt()
  AddWindowTimer(0, 1, 16) ; about 60 fps
 
  Repeat
    Event = WaitWindowEvent()
   
    Select Event
       
      Case #PB_Event_SizeWindow
        Reshape()
       
      Case #PB_Event_Timer
        If EventTimer() = 1
          DrawCube(0)
        EndIf
       
      Case #PB_Event_Gadget
       
        Select EventGadget()
           
          Case 0
           
            Select EventType()
               
              Case #PB_EventType_MouseWheel
                Camera::Zooming(GetGadgetAttribute(0, #PB_OpenGL_WheelDelta)) ;use the wheel delta to drive the zoom
               
              Case #PB_EventType_LeftButtonDown
                Camera::StartRotation(GetGadgetAttribute(0, #PB_OpenGL_MouseX), GetGadgetAttribute(0, #PB_OpenGL_MouseY))
               
              Case #PB_EventType_LeftButtonUp
                Camera::StopRotation()
               
              Case #PB_EventType_MouseMove
                Camera::TrackRotation(GetGadgetAttribute(0, #PB_OpenGL_MouseX), GetGadgetAttribute(0, #PB_OpenGL_MouseY))
               
            EndSelect
           
        EndSelect
       
    EndSelect
   
  Until Event = #PB_Event_CloseWindow
 
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<

Author:  Demivec [ Mon May 30, 2016 4:09 am ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

StarBootics wrote:
I would to say this a 100% working trackball camera but it's not the case. See me Feature Request here : viewtopic.php?f=3&t=65824


Make these changes
Code:
OpenGLGadget(0, 5, 5, 790, 590, #PB_OpenGL_Keyboard) ;declare with this flag for mouse wheel events

;in event loop use
Select EventType()
   Case #PB_EventType_MouseWheel
      Camera::IncrementDistance(GetGadgetAttribute(0, #PB_OpenGL_WheelDelta)) ;use the wheel delta to drive the zoom

Author:  Demivec [ Tue May 31, 2016 12:38 am ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

As an addendum to my previous post, from what I understand, the flag #PB_OpenGL_Keyboard is only needed for the Windows OS. The other OS's should report the wheel events even without focus.

Author:  StarBootics [ Wed Jun 01, 2016 12:08 am ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

Hello everyone,

Is anybody have a continuous rotation of the camera ?

For me, it work, stop working, after several tries work again, out of the sudden stop working again. Very buggy under Ubuntu Gnome 16.04.

What about you guys ?

Best regards
StarBootics

Author:  #NULL [ Wed Jun 01, 2016 11:30 am ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

i can rotate without problem until i release the mouse button, if that's what you mean. (windows 7, pb 5.42)

Author:  StarBootics [ Wed Jun 01, 2016 2:15 pm ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

#NULL wrote:
i can rotate without problem until i release the mouse button, if that's what you mean. (windows 7, pb 5.42)


It work as expected under window.
Buggy under Ubuntu Gnome 16.04
Under Mac OS ???

Thanks for your reply
StarBootics

Author:  IdeasVacuum [ Wed Jun 01, 2016 3:32 pm ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

Windows 7 x86 PB 5.42LTS OpenGL 2.1.2 (old) Graphics Card: GeForce 7900 GT (old) Intel Core 2 CPU 6400 (old)

Both zoom and drag rotate work perfectly on my machine, despite it's age. Perhaps the problems in Ubuntu are Ubuntu settings?

Author:  IdeasVacuum [ Sat Apr 13, 2019 12:55 pm ]
Post subject:  Re: Trackball Camera for OpenGLGadget()

This Module works beautifully in an OpenGL gadget. Has anyone written the same for a Windowed Screen?

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/