You should be able to customize this code to your needs more easily.
Remember you should not use anymore the ".l" variables as I used them here (use defaults integer instead).
Code: Select all
EnableExplicit
#OGLF_TITLE = "Multisample sample (doh!) for Violet"
#WIN_MAIN = 0
; these are the same include I used originally in SWOF, I don't repeat them in this post
IncludePath "include"
IncludeFile "GL.pbi" ; The two includes we need to interface with the OpenGL library
IncludeFile "GL_IMPORTS.pbi" ; ...
IncludeFile "GLEXT.pbi" ; These two are required for multisample
IncludeFile "WGLEXT.pbi" ; ...
; some globals to keep things simple, you can certainly avoid these
Global G_hWnd, G_hDC, G_hRC
Global G_lCurrWinSizeX.l, G_lCurrWinSizeY.l, G_lDeskTopDepth.l, G_lMultisampleNumSamples.l
; multisample vars
Global G_flgMultiSampleAvailable, G_lARB_MultisampleFormat, G_lWantedSamples.l, G_lMultisampleNumSamples.l
Global Dim G_alMultiSamples.l (3,1) ; multisample AA, 1 in (x,1) if that setting is available
G_alMultiSamples(0,0) = 16 ; 16 AA
G_alMultiSamples(1,0) = 8 ; 8 AA
G_alMultiSamples(2,0) = 4 ; 4 AA
G_alMultiSamples(3,0) = 2 ; 2 AA
; GL_Info() stuff
#GL_INFO_LOAD = 0
#GL_INFO_RESET = 1
#GL_INFO_EXTENSIONS_COUNT = 2
#GL_INFO_EXTENSIONS_CHECK = 3
Structure T_LIST ; used for linked lists navigation
*Next.Element
*Prev.Element
EndStructure
Structure T_OPENGL_INFO ; used by GL_Info()
GL_VENDOR.s
GL_RENDERER.s
GL_VERSION.s
*GL_EXTENSIONS.T_LIST
EndStructure: Global G_tOPENGL_INFO.T_OPENGL_INFO
NewList lstGL_Extensions.s() ; used by GL_Info()
Prototype.l P_wglChoosePixelFormatARB (hDC.l, *iAttributes, *fAttributes, nMaxFormats.l, *pixelFormat, *numFormats)
Prototype.l P_wglSwapIntervalEXT (nInterval.l)
Declare.l HandleError (lResult.l, sCallingProc.s, sMessage.s)
Declare.l GL_Set_VSync(lInterval.l)
Declare.l GL_VSync_Supported()
Declare SetPixelFormat (lColorDepth.l, *tPFD.PIXELFORMATDESCRIPTOR)
Declare GL_ResizeScene (lcWidth.l, lcHeight.l)
Declare GL_Init ()
Declare.l GL_Multisample_Supported()
Declare.l GL_Info (enOperation.l = #GL_INFO_LOAD, sParam.s = "")
Declare GL_KillWindow ()
Declare GL_CreateWindow (iNumWin, sTitle.s, lxPos.l, lyPos.l, lcWinWidth.l, lcWinHeight.l, lColorDepth.l, lWinFlags.l)
Declare GL_RenderScene ()
Declare WinMain()
Procedure.l HandleError (lResult.l, sCallingProc.s, sMessage.s) ; handle the functions return values and quit the program in case of fatal error
If lResult = #False
MessageRequester(#OGLF_TITLE , sCallingProc + " - " + sMessage)
End
Else
ProcedureReturn lResult
EndIf
EndProcedure
Procedure.l GL_Set_VSync(lInterval.l) ; enable or disable the VSync
; call it *AFTER* you have checked the vsync control is supported by your driver with GL_VSync_Supported()
Protected wglSwapIntervalEXT_.P_wglSwapIntervalEXT = wglGetProcAddress_("wglSwapIntervalEXT")
ProcedureReturn wglSwapIntervalEXT_(lInterval) ; #True if successful
EndProcedure
Procedure.l GL_VSync_Supported() ; check if VSync control is supported by this driver
ProcedureReturn GL_Info(#GL_INFO_EXTENSIONS_CHECK, "WGL_EXT_swap_control")
EndProcedure
Procedure SetPixelFormat (lColorDepth.l, *tPFD.PIXELFORMATDESCRIPTOR) ; set the desired pixel format
Protected PixelFormat.l ; the selected pixel format matching our request
; The next section of code describes a pixel format.
; We choose a format that supports OpenGL and double buffering, along with RGBA (red, green, blue, alpha channel).
; We try to find a pixel format that matches the bits we decided on (16bit,24bit,32bit).
; Finally we set up a 16bit Z-Buffer.
With *tPFD
\nSize = SizeOf(PIXELFORMATDESCRIPTOR);
\nVersion = 1 ; version
\dwFlags = #PFD_DRAW_TO_WINDOW | #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER ; must support draw to window, OpenGL, double buffering
\iPixelType = #PFD_TYPE_RGBA ; request an RGBA format
\cColorBits = lColorDepth ; color depth
\cRedBits = 0 ; color bits ignored
\cRedShift = 0 ; ...
\cGreenBits = 0 ; ...
\cGreenShift = 0 ; ...
\cBlueBits = 0 ; ...
\cBlueShift = 0 ; ...
\cAlphaBits = 0 ; no alpha buffer
\cAlphaShift = 0 ; shift bit ignored
\cAccumBits = 0 ; no accumulation buffer
\cAccumRedBits = 0 ; accumulation bits ignored
\cAccumGreenBits = 0 ; ...
\cAccumBlueBits = 0 ; ...
\cAccumAlphaBits = 0 ; ...
\cDepthBits = 16 ; z-buffer depth
\cStencilBits = 0 ; no stencil buffer
\cAuxBuffers = 0 ; no auxiliary buffer
\iLayerType = 0 ;
\bReserved = 0 ; reserved
\dwLayerMask = #PFD_MAIN_PLANE ; main drawing layer
\dwLayerMask = 0 ; layer mask ignored
\dwVisibleMask = 0 ;
\dwDamageMask = 0 ;
EndWith
If (G_flgMultiSampleAvailable = #False)
; get a matching pixel format (using GDI32 API)
PixelFormat = HandleError (ChoosePixelFormat_(G_hDC, *tPFD), "SetPixelFormat()", "Cannot get a valid pixel format.")
Else
PixelFormat = G_lARB_MultisampleFormat
EndIf
; set the pixel format for the specified device context
HandleError (SetPixelFormat_ (G_hDC, PixelFormat, *tPFD), "SetPixelFormat()", "Cannot set the desired pixel format.")
EndProcedure
Procedure GL_ResizeScene (lcWidth.l, lcHeight.l) ; resize scene at start and on every window resize
glViewport_(0, 0, lcWidth, lcHeight) ; reset the vurrent viewport
glMatrixMode_(#GL_PROJECTION) ; select the projection matrix
glLoadIdentity_() ; reset the projection matrix
gluPerspective_(30.0, Abs(lcWidth / lcHeight), 0.1, 500.0) ; set the perspective / calculate the aspect ratio
glMatrixMode_(#GL_MODELVIEW) ; select the modelview matrix
glLoadIdentity_() ; reset the modelview matrix
EndProcedure
Procedure GL_Init () ; the setup for our OpenGL scene goes here
HandleError (wglMakeCurrent_(G_hDC, G_hRC), "GL_Init()", "Cannot associate the OpenGL rendering context to the current thread.")
GL_ResizeScene(G_lCurrWinSizeX, G_lCurrWinSizeY) ; set up our perspective OpenGL screen
glShadeModel_ (#GL_SMOOTH) ; enable smooth shading
glClearColor_ (1.0, 1.0, 1.0, 1.0) ; background
glClearDepth_(1.0) ; depth buffer setup
glEnable_(#GL_DEPTH_TEST) ; enables depth testing
glDepthFunc_(#GL_LESS) ; type of depth testing to do
glHint_ (#GL_PERSPECTIVE_CORRECTION_HINT, #GL_NICEST) ; really nice perspective calculations
; we want to enable VSync, if possible, right ?
If GL_VSync_Supported()
GL_Set_VSync(1)
EndIf
EndProcedure
Procedure.l GL_Multisample_Supported() ; check if multisample is supported by this driver and if we can obtain a compatible pixelformat
Protected lFormats.l, lPixelFormat.l, lcIndex.l
; query for the required extension
If GL_Info(#GL_INFO_EXTENSIONS_CHECK, "GL_ARB_multisample") = #False ; try this one
If GL_Info(#GL_INFO_EXTENSIONS_CHECK, "GLX_ARB_multisample") = #False ; maybe this one
If GL_Info(#GL_INFO_EXTENSIONS_CHECK, "WGL_ARB_multisample") = #False ; ok, last try
ProcedureReturn #False ; no need to continue, it's not even supported by the driver
EndIf
EndIf
EndIf
; ok, so this function should be available
Protected wglChoosePixelFormatARB_.P_wglChoosePixelFormatARB = wglGetProcAddress_("wglChoosePixelFormatARB")
; is it not ?
If (wglChoosePixelFormatARB_ = #Null)
ProcedureReturn #False ; ok, I give up, no multisample
EndIf
Protected Dim faAttributes.f (0,1)
faAttributes(0,0) = 0.0
faAttributes(0,1) = 0.0
Dim laAttributes.l (10,1)
laAttributes(0,0) = #WGL_DRAW_TO_WINDOW_ARB
laAttributes(0,1) = #GL_TRUE
laAttributes(1,0) = #WGL_SUPPORT_OPENGL_ARB
laAttributes(1,1) = #GL_TRUE
laAttributes(2,0) = #WGL_ACCELERATION_ARB
laAttributes(2,1) = #WGL_FULL_ACCELERATION_ARB
laAttributes(3,0) = #WGL_COLOR_BITS_ARB
laAttributes(3,1) = G_lDeskTopDepth
laAttributes(4,0) = #WGL_ALPHA_BITS_ARB
laAttributes(4,1) = 8
laAttributes(5,0) = #WGL_DEPTH_BITS_ARB
laAttributes(5,1) = 16
laAttributes(6,0) = #WGL_STENCIL_BITS_ARB
laAttributes(6,1) = 0
laAttributes(7,0) = #WGL_DOUBLE_BUFFER_ARB
laAttributes(7,1) = #GL_TRUE
laAttributes(8,0) = #WGL_SAMPLE_BUFFERS_ARB
laAttributes(8,1) = #GL_TRUE
laAttributes(9,0) = #WGL_SAMPLES_ARB
laAttributes(9,1) = 0 ; we'll write the desired num of samples here
laAttributes(10,0) = 0
laAttributes(10,1) = 0
G_lMultisampleNumSamples = 0
For lcIndex = 0 To 3 ; load the available AA settings
laAttributes(9,1) = G_alMultiSamples(lcIndex, 0)
If wglChoosePixelFormatARB_(G_hDC, laAttributes(), faAttributes(), 1, @lPixelFormat, @lFormats) And lFormats >= 1
G_alMultiSamples(lcIndex , 1) = 1 ; available
EndIf
Next
For lcIndex = 0 To 3 ; we ask for G_lWantedSamples if possible... down to 2AA
If (G_alMultiSamples(lcIndex ,0) <= G_lWantedSamples) And (G_alMultiSamples(lcIndex , 1) = 1)
laAttributes(9,1) = G_alMultiSamples(lcIndex ,0)
wglChoosePixelFormatARB_(G_hDC, laAttributes(), faAttributes(), 1, @lPixelFormat, @lFormats)
G_lARB_MultisampleFormat = lPixelFormat
G_lMultisampleNumSamples = G_alMultiSamples(lcIndex ,0)
ProcedureReturn #True
EndIf
Next
ProcedureReturn #False
EndProcedure
Procedure.l GL_Info (enOperation.l = #GL_INFO_LOAD, sParam.s = "") ; retrieve some infos for our OpenGL context, see the related enumeration for details
; OpenGL requires this procedure to be called AFTER the creation of the rendering contest
Protected lResult.l
Shared lstGL_Extensions()
If G_hRC
Select enOperation
Case #GL_INFO_LOAD ; load the G_OPENGL_INFO structure with various infos
Protected sWork.s
Protected lcIndex.l, lcCount.l
G_tOPENGL_INFO\GL_VENDOR = PeekS(glGetString_(#GL_VENDOR))
G_tOPENGL_INFO\GL_RENDERER = PeekS(glGetString_(#GL_RENDERER))
G_tOPENGL_INFO\GL_VERSION = PeekS(glGetString_(#GL_VERSION))
sWork = PeekS(glGetString_(#GL_EXTENSIONS))
lcCount = CountString(sWork, Space(1)) + 1
ClearList(lstGL_Extensions())
For lcIndex = 1 To lcCount
HandleError (AddElement(lstGL_Extensions()), "GL_Info()", "Out of memory while loading the GL Extensions list.")
lstGL_Extensions() = StringField(sWork, lcIndex, Space(1))
Next
lResult = lcCount
Case #GL_INFO_RESET ; reposition the pointer *GL_EXTENSIONS to the first element
; make the pointer in the struct point to the first element of the list
G_tOPENGL_INFO\GL_EXTENSIONS = FirstElement(lstGL_Extensions()) - SizeOf(T_LIST)
lResult = 0
Case #GL_INFO_EXTENSIONS_COUNT ; return the number of OpenGL extensions supported
lResult = ListSize(lstGL_Extensions())
Case #GL_INFO_EXTENSIONS_CHECK ; check if the specified extension is supported
FirstElement(lstGL_Extensions())
lResult = #False
ForEach lstGL_Extensions()
If lstGL_Extensions() = sParam
lResult = #True
Break
EndIf
Next
EndSelect
Else
HandleError(#False, "GL_Info()", "Rendering context not initialized.")
EndIf
ProcedureReturn lResult
EndProcedure
Procedure GL_KillWindow () ; properly kill the OpenGL window
If G_hDC
; are we able to release the DC ?
HandleError (ReleaseDC_(G_hWnd, G_hDC), "GL_KillWindow()", "Release of device context failed.")
G_hDC = #Null ; set DC to NULL (well, not really needed now but just in case)
EndIf
EndProcedure
Procedure GL_CreateWindow (iNumWin, sTitle.s, lxPos.l, lyPos.l, lcWinWidth.l, lcWinHeight.l, lColorDepth.l, lWinFlags.l)
; create a OpenGL window inside our window and set a suitable pixel format
Protected PFD.PIXELFORMATDESCRIPTOR
; open the main window
G_hWnd = HandleError (OpenWindow (iNumWin, lxPos, lyPos, lcWinWidth, lcWinHeight, sTitle, lWinFlags | #PB_Window_Invisible), "GL_CreateWindow()", "Cannot open the main window.")
; get the device context for that window (using Win32 API)
G_hDC = HandleError (GetDC_(G_hWnd), "GL_CreateWindow()", "Cannot get a device context for the Window.")
; set the desired pixel format
SetPixelFormat(lColorDepth, @PFD)
; creates a new OpenGL rendering context, which is suitable for drawing on the device referenced by hDC
G_hRC = HandleError (wglCreateContext_(G_hDC), "GL_CreateWindow()", "Cannot create the OpenGL rendering context.")
; associate temporarly the DC to this thread
HandleError (wglMakeCurrent_(G_hDC, G_hRC), "GL_CreateWindow()", "Cannot associate the OpenGL rendering context to the current thread.")
GL_Info() ; now we can get the OpenGL vendor, renderer, version and extensions
; if multisample flag is #False, let's try once to enable it
If G_flgMultiSampleAvailable = #False
If G_lWantedSamples > 0
If GL_Multisample_Supported ()
G_flgMultiSampleAvailable = #True ; we can have it ! (one time recursion guaranteed by setting the flg to #True)
GL_KillWindow()
GL_CreateWindow (iNumWin, sTitle.s, lxPos, lyPos, lcWinWidth, lcWinHeight, lColorDepth, lWinFlags) ; * one time only recursion *
EndIf
EndIf
EndIf
; dispose the previously created association
wglMakeCurrent_(#Null,#Null)
HideWindow(#WIN_MAIN, #False) ; show the window
EndProcedure
Procedure GL_RenderScene ()
Static rot.f = 0
Static z.f = 6.0
Static zinc.f = 0.01
glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
glLoadIdentity_() ; reset the current modelview matrix
glTranslatef_(0.0, 0.0, -z) ; move into the screen
glRotatef_(rot, 0.0, 0.0, 1.0) ; rotate the triangle on the Z axis
glColor3f_(0.0, 0.0, 0.0)
glBegin_(#GL_QUADS) ; draw a quad
glVertex3f_(-1.0, 1.0, 0.0) ; top left
glVertex3f_( 1.0, 1.0, 0.0) ; top right
glVertex3f_( 1.0,-1.0, 0.0) ; bottom right
glVertex3f_(-1.0,-1.0, 0.0) ; bottom left
glEnd_() ; fnished
rot + 0.5
z + zinc
If rot > 360.0 : rot = 0.0 : EndIf
If Abs(z) > 10.0 : zinc = -zinc : EndIf
If Abs(z) < 6 :zinc = -zinc : EndIf
SwapBuffers_(G_hDC)
EndProcedure
Procedure WinMain()
; Tested on nVidia 9800 GTX, OpenGL 2.1
; Be sure to have the quality settings in the control panel to "Let the 3d application decide"
; or the multisample settings could be overridden by that
Protected lEvent.l
Protected flgMainLoop = #True
G_lCurrWinSizeX = 800
G_lCurrWinSizeY = 600
; 2, 4, 8, 16
G_lWantedSamples = 0 ; the samples we would like to have (0 to disable multisample)
ExamineDesktops(): G_lDeskTopDepth = DesktopDepth(0)
; define the constant for the window attributes
#WIN_MAIN_ATTRIBUTES = #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered
; create the window
GL_CreateWindow (#WIN_MAIN, "", 0, 0, G_lCurrWinSizeX, G_lCurrWinSizeY , G_lDeskTopDepth, #WIN_MAIN_ATTRIBUTES)
; the samples we were actually able to obtain from the driver are in G_lMultisampleNumSamples
SetWindowTitle(#WIN_MAIN, #OGLF_TITLE + " ( " + Str(G_lMultisampleNumSamples) + " samples )")
GL_Init()
While flgMainLoop = #True
Repeat
lEvent = WindowEvent()
Select lEvent
Case 0 ; give away some time
Delay(1)
Case #PB_Event_CloseWindow
flgMainLoop = #False
EndSelect
Until lEvent = 0
GL_RenderScene()
Wend
GL_KillWindow()
EndProcedure
WinMain()