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 )
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: Select all
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 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 <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<