Simple Windowed OpenGL Framework - for OpenGL beginners

Developed or developing a new product in PureBasic? Tell the world about it.
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Post by Baldrick »

luis wrote:Updated for 4.30 (beta). :wink:
Seems to be not quite right here Luis. The included exe is crashing on startup & all the Pb files I have tried so far seem to be missing constants. :(
Have you maybe forgotten to include a constants pbi or something?
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Baldrick wrote: Seems to be not quite right here Luis. The included exe is crashing on startup & all the Pb files I have tried so far seem to be missing constants. :(
Here works. XP x32 SP3.

Did you extracted the zip keeping the directory structure ?

The only .pb file you need to open to compile the program is "Simple OpenGL Framework.pb".

About the missing constants, you probably opened the files in the demos directory. They are INCLUDED in the main program and they need the framework the main program provides (constants included).

Scroll the main source until there:

Code: Select all

; *************************************
; Your demo code can be included here 
; *************************************

IncludePath "include"

IncludeFile "DEMO_MACROS.pbi" ; support macros used by demos
IncludeFile "DEMO_BINARIES.pbi" ; binaries data used by demos

IncludePath "demos"

; nice, any new demo can be simply added here

IncludeFile "Demo_Polygons.pb"
IncludeFile "Demo_Shading_Rotation.pb"
IncludeFile "Demo_Solids.pb"
IncludeFile "Demo_Texture_1D.pb"
IncludeFile "Demo_Texture_2D.pb"
IncludeFile "Demo_Blending.pb"
IncludeFile "Demo_WaveFlag.pb"
IncludeFile "Demo_FogListSphere.pb"
IncludeFile "Demo_Bolt.pb"
IncludeFile "Demo_Sprite.pb"

If you kept the dirs and opened the correct main file, you should be able to compile it.

About the crashing exe, all is possible. The program is in source form because it's a kind of "tutorial by examples" or a collection of answers to "how could I do this kind of opengl thing with PB" type of question.

It's not written to try to go everywhere. In fact I tried to get it running on my system to learn the basics (no pun intended) on opengl.

BUT with the source you should be able to fix any problem it might encounter on your system.

If you still have problem, ask but please give me some more detailed info, what you did, what the compiler told you, etc.

For example, I don't even know your OS :)

And remember, it was written not considering 64 bit os at all.
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Post by Baldrick »

Did you extracted the zip keeping the directory structure ?
Yes, std exatraction from the zip file
About the missing constants, you probably opened the files in the demos directory.
Oops :oops: Yes I was doing that. I did however try your main "Simple OpenGL Framework.pb", which is unfortunately throwing Macro errors at me.
For the life of me, I cannot see any problem with your macro's either. for example:

Code: Select all

Macro U2B(x) 
 (Round(x * 255,0))
EndMacro

Just throws a syntax error at me no matter how I change it, until I remove everything from it & just leave it as "x" :?
So once the compiler runs past this macro with inncorrect function, it then stops at the next macro:

Code: Select all

Macro DEG2RAD (x)
 (x / 180.0 * #PI)
EndMacro
with an error saying "endles recusivity detected in the macro"

I am running x86 hardware with P4 HTT cpu @ 3Ghz, 512MB RAM, Graphics accelerator is GeForce Fx5200 with 128MB RAM
OS is Win Xp Sp3
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Hi Baldrick, this is strange indeed. We'll try to discover what's happening ok ? :)
Baldrick wrote:Just throws a syntax error at me no matter how I change it, until I remove everything from it & just leave it as "x" :?
Do you mean, until you reduced it to this ?

Code: Select all

Macro U2B (x) 
 x
EndMacro

1) If you paste this code on a new file and try to compile it, it gives you a syntax error there too ? Where exactly ?

Code: Select all

Macro U2B (x) ; unity to byte
 (Round(x * 255, 0))
EndMacro

Macro DEG2RAD (x)
 (x / 180.0 * #PI)
EndMacro

Debug U2B (0.5)


1b) If gives you a syntax error, try to every instance of "x" with something else, for example "myvar". Try to change U2B with another name too. Just to try to avoid a conflict if it's there for a reason I don't know at the moment.

2) Your PB 4.3 b2 (are you using the b2 right?) installation has something added to the standard install ? userlibraries, additional residents, etc.
If that's the case, can you try it on a fresh, parallel installation ?

3) If you still have the pb 4.2 final, can you try to download and compile in it the SWOF for the 4.2 (swof.zip in the first post) and tell me the result ?
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Post by Baldrick »

Baldrick wrote:
Just throws a syntax error at me no matter how I change it, until I remove everything from it & just leave it as "x"
Do you mean, until you reduced it to this ?
Code:
Macro U2B (x)
x
EndMacro
>> Yes that how I mean. I even tried changing the macro to a procedure with no success.

1) If you paste this code on a new file and try to compile it, it gives you a syntax error there too ? Where exactly ?
Code:
Macro U2B (x) ; unity to byte
(Round(x * 255, 0))
EndMacro
Macro DEG2RAD (x)
(x / 180.0 * #PI)
EndMacro
Debug U2B (0.5)
>> Works correctly as we both would expect. (including the DEG2RAD macro )

1b) If gives you a syntax error, try to every instance of "x" with something else, for example "myvar". Try to change U2B with another name too. Just to try to avoid a conflict if it's there for a reason I don't know at the moment.
>> Yes, already tried that without success. e.g. myU2B(myvar)

2) Your PB 4.3 b2 (are you using the b2 right?) installation has something added to the standard install ? userlibraries, additional residents, etc.
If that's the case, can you try it on a fresh, parallel installation ?
>> Yes I am on a full 4.30B2 install. I have removed all user libs, etc. still no difference.

3) If you still have the pb 4.2 final, can you try to download and compile in it the SWOF for the 4.2 (swof.zip in the first post) and tell me the result ?
>> I have a copy of 4.2 which I have run in portable mode from MyDocuments directory & your demo for 4.2 works brilliantly. :D
(1 small mistake with a linked list SelectElelment() on line 661 which is a simple fix of adding -1 to the selection )

btw. The 4.2 demo you have here has convinced me I need to learn OpenGl. I really like it. :mrgreen:
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Based on your answers I must admit I'm stuck :shock:

Considering that macro is the first code the compiler encounter (if we exclude 1 constant at the top and the directive enableexplicit) I don't know what suggest.

In your place, I would try to copy/paste from my source some lines at the time in a brand new file, starting with

Code: Select all

#BUILD_RELEASE = 1

the comments and

EnableExplicit  

;{ *** MACROS *****************************************************************

Macro U2B (x) ; unity to byte
 (Round(x * 255, 0))
EndMacro

Macro DEG2RAD (x)
 (x / 180.0 * #PI)
EndMacro

Macro RAD2DEG (x)
 (x * 180.0 / #PI)
EndMacro

Macro UBOUND (array)
 (PeekL(@array - 8) - 1)
EndMacro 

Macro LOWORD (value) 
 (value & $FFFF)
EndMacro

Macro HIWORD (value) 
 ((value >> 16) & $FFFF)
EndMacro
     
... etc
and I would try to compile that adding more code until I encounter a problem.

That should work since you told me pasting only the macro in a new file it's working as expected.

If you get a definitive answer to the "why" it's happening please let me know. :?:
Baldrick wrote: btw. The 4.2 demo you have here has convinced me I need to learn OpenGl. I really like it. :mrgreen:


I'm happy to hear it.

I'm about to start the develop of a mini-engine (probably more like a lot of helper functions) to easy the development of simple opengl projects in pb.

Just for fun. But as usual it will require probably forever to be done.
Baldrick
Addict
Addict
Posts: 860
Joined: Fri Jul 02, 2004 6:49 pm
Location: Australia

Post by Baldrick »

@Luis,
I must admit I have virtually 0 knowledge when it comes to this OGL stuff but as I get some spare time I will tear your project to peices to see if I can get it working on my system. It might be a good way to get me started a little with this stuff. :)
I might actually try doing a full uninstall of 4.3B2 & reinstall from scratch to see if this makes any difference 1st though. ( Although your included precompiled app crashing on startup does seem a little ominous for this having any effect on my system. )
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Edited again for PB 4.30 final.

Well, probably last time I will update this to new PB versions.

It should be easy anyway, if you have problem you can always ask here I guess. Usually the required modifications are really minor.

And remember to drop the habit to use .l (for long) in new programs (unless really needed) !

Cheers.
Violet
Enthusiast
Enthusiast
Posts: 106
Joined: Sun Dec 23, 2007 6:30 pm

Post by Violet »

Just wanted to drop a "Thanks"! I think it was already last summer that I discovered your Framework, it was a great help for me to learn about OpenGL in PureBasic. Just downloading again, because I want to know how the Anti Aliasing (Multisamples) has to be done. :D
best regards,

Violet
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Violet wrote:Just wanted to drop a "Thanks"! I think it was already last summer that I discovered your Framework, it was a great help for me to learn about OpenGL in PureBasic.
Hi Violet, thank you for letting me know.

I hope to have time in the future to go back to OpenGL, because I would like to make some kind of helper libraries for it.

Bye for now !
Violet
Enthusiast
Enthusiast
Posts: 106
Joined: Sun Dec 23, 2007 6:30 pm

Post by Violet »

I got stuck when trying to "isolate" the Anti Aliasing Stuff. But the Code doesn't work. :cry:

I already looked into NeHe Tutorials about this, but I can't see through what's necessary to activate Multisampling... You don't have a simple code, where you apply Multisampling while just drawing a Quad or something like that?

Code: Select all

;--------------------------------------------------------------------------------------------------
; Declarations
;--------------------------------------------------------------------------------------------------

EnableExplicit

XIncludeFile "../OpenGL.pbi"
XIncludeFile "WGLEXT.pbi"

Global ScreenWidth	= 1024
Global ScreenHeight	= 768

Global Title.s = "OpenGL"

Global WindowEvent
Global hDC, hRC, Windownumber, WindowRect.RECT, wpos.POINT, hWnd
Global Windowflags
Global PixelFormat ;Holds The Results After Searching For A Match

;--------------------------------------------------------------------------------------------------

Structure T_LIST ; used for linked lists navigation
 *Next.Element
 *Prev.Element
EndStructure

Prototype.l P_wglChoosePixelFormatARB (hDC.l, *iAttributes, *fAttributes, nMaxFormats.l, *pixelFormat, *numFormats)

Global G_flgMultiSampleAvailable

Global G_lARB_MultisampleFormat

Global G_lWantedSamples = 4

Global G_lMultisampleNumSamples

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
; used by GL_Info() -------------------------------------------------------------------------------

Structure T_OPENGL_INFO ; used by GL_Info()
 GL_VENDOR.s
 GL_RENDERER.s
 GL_VERSION.s 
 *GL_EXTENSIONS.T_LIST
EndStructure

Enumeration
 #GL_INFO_LOAD
 #GL_INFO_RESET
 #GL_INFO_EXTENSIONS_COUNT
 #GL_INFO_EXTENSIONS_CHECK
EndEnumeration

NewList lstGL_Extensions.s()

Global G_tOPENGL_INFO.T_OPENGL_INFO

;--------------------------------------------------------------------------------------------------
; Procedures
;--------------------------------------------------------------------------------------------------

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(Title, sCallingProc + " - " + sMessage)    
    End
    
 Else
 		
    ProcedureReturn lResult
    
 EndIf
 
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 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.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) = 32
 
 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_(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_(hDC, laAttributes(), faAttributes(), 1, @lPixelFormat, @lFormats)
        G_lARB_MultisampleFormat = lPixelFormat
        G_lMultisampleNumSamples = G_alMultiSamples(lcIndex ,0)
        ProcedureReturn #True
    EndIf    
 Next
   
 ProcedureReturn #False
EndProcedure

;--------------------------------------------------------------------------------------------------
; Startup
;--------------------------------------------------------------------------------------------------

WindowRect\left   = 0       ;Set Left Value To 0
WindowRect\right  = ScreenWidth  ;Set Right Value To Requested Width
WindowRect\top    = 0       ;Set Top Value To 0
WindowRect\bottom = ScreenHeight ;Set Bottom Value To Requested Height

Windownumber = OpenWindow(#PB_Any, 0, 0, ScreenWidth, ScreenHeight, Title, #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget)

hWnd = WindowID(Windownumber)

If hWnd = #False
 MessageRequester("Error", "Window Handle is NULL!")
EndIf

Global pfd.PIXELFORMATDESCRIPTOR
pfd\nSize=SizeOf(PIXELFORMATDESCRIPTOR)
pfd\nVersion=1 ;Version Number
pfd\dwFlags=#PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER | #PFD_DRAW_TO_WINDOW ;Format Must Support Window, OpenGL, Double Buffering
pfd\iPixelType=#PFD_TYPE_RGBA
pfd\cColorBits      = 32 ;Select Our Color Depth
pfd\cRedBits        = 0 ;Color Bits Ignored
pfd\cRedShift       = 0
pfd\cGreenBits      = 0
pfd\cGreenShift     = 0
pfd\cBlueBits       = 0
pfd\cBlueShift      = 0
pfd\cAlphaBits      = 0 ;No Alpha Buffer
pfd\cAlphaShift     = 0 ;Shift Bit Ignored
pfd\cAccumBits      = 0 ;No Accumulation Buffer
pfd\cAccumRedBits   = 0 ;Accumulation Bits Ignored
pfd\cAccumGreenBits = 0
pfd\cAccumBlueBits  = 0
pfd\cAccumAlphaBits = 0
pfd\cDepthBits      = 16              ;16Bit Z-Buffer (Depth Buffer)
pfd\cStencilBits    = 0               ;No Stencil Buffer
pfd\cAuxBuffers     = 0               ;No Auxiliary Buffer
pfd\iLayerType      = #PFD_MAIN_PLANE ;Main Drawing Layer
pfd\bReserved       = 0               ;Reserved
pfd\dwLayerMask     = 0               ;Layer Masks Ignored
pfd\dwVisibleMask   = 0
pfd\dwDamageMask    = 0

hDC = GetDC_(hWnd)

If hDC = #False
  MessageBox_(#Null, "Cannot create a OpenGL Device Context!", Title, #MB_OK | #MB_ICONERROR)
  End
EndIf

PixelFormat = ChoosePixelFormat_(hDC, pfd)

If PixelFormat = #False
  MessageBox_(#Null, "Cannot find a suitable PixelFormat!", Title, #MB_OK | #MB_ICONERROR)
  End
EndIf
 
If SetPixelFormat_(hDC, PixelFormat, pfd) = #False
  MessageBox_(#Null, "Cannot set the PixelFormat!", Title, #MB_OK | #MB_ICONERROR)
  End
EndIf
 
hRC = wglCreateContext_(hDC)
 
If hRC = #False
  MessageBox_(#Null, "Cannot Create a OpenGL Rendering Context!", Title, #MB_OK | #MB_ICONERROR)
  End
EndIf
 
If wglMakeCurrent_(hDC, hRC) = #False
  MessageBox_(#Null, "Cannot activate the OpenGL Rendering Context!", Title, #MB_OK | #MB_ICONERROR)
  End
EndIf

ShowWindow_(hWnd, #SW_SHOW) ;Show The Window
SetForegroundWindow_(hWnd) ;Slightly Higher Priority
SetFocus_(hWnd) ;Sets Keyboard Focus To The Window

;--------------------------------------------------------------------------------------------------

; 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)
            ; Set MultiSamples?!
        EndIf       
        
    EndIf
 EndIf
 
;--------------------------------------------------------------------------------------------------

; Set up OpenGL

glShadeModel_(#GL_SMOOTH)
glEnable_(#GL_TEXTURE_2D)

glClearColor_(0.0, 0.25, 0.5, 0.0)

glViewport_(0, 0, ScreenWidth, ScreenHeight)

glMatrixMode_(#GL_PROJECTION)
glLoadIdentity_()

;glOrtho_(0.0, ScreenWidth, ScreenHeight, 0.0, 0.0, 1.0)
gluPerspective_(30.0, ScreenWidth/ScreenHeight, 0.0, 1024.0)

;--------------------------------------------------------------------------------------------------
; Main Loop
;--------------------------------------------------------------------------------------------------

Repeat
	
	Repeat
		
		WindowEvent = WindowEvent()
		
		If WindowEvent = #PB_Event_CloseWindow
			
			End
			
		EndIf
		
	Until WindowEvent = #False
	
	glClear_(#GL_COLOR_BUFFER_BIT)
  glMatrixMode_(#GL_MODELVIEW)
  glLoadIdentity_()
	
	glTranslatef_(0.0, 0.0, -10.0)
	glRotatef_(30.0, 0.0, 0.0, 1.0)
	
	glBegin_(#GL_QUADS)
		
		glVertex3f_(0.0, 0.0, 0.0)
		glVertex3f_(0.0, 1.0, 0.0)
		glVertex3f_(1.0, 1.0, 0.0)
		glVertex3f_(1.0, 0.0, 0.0)
		
	glEnd_()
	
	SwapBuffers_(hDC)
	
ForEver
best regards,

Violet
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Violet wrote: I already looked into NeHe Tutorials about this, but I can't see through what's necessary to activate Multisampling... You don't have a simple code, where you apply Multisampling while just drawing a Quad or something like that?
I'm working on it, I'll try to reduce the code of my framework to a sample with only single threading (unlike the framework) the AA stuff and killing the rest.

Your code is not easily convertible because the big issue is you should have the procedure to create the OGL window "recursive", like in my original framework. The idea is to create an OGL rendering contest, interrogate the OGL driver about the available AA modes (if any), destroy the dummy OGL rendering contest and create a new one with a valid number os samples loaded as param for the #WGL_SAMPLES_ARB attribute, and then call wglChoosePixelFormatARB with that.

Well, recursion is not really needed, but at minimun you must have a proc (to call it twice) and some communication variable. It's a two step process. Recursion make it easier to call (one call) once set up properly.

I'll post the sample as soon as I made it.

EDIT: the NeHe lesson using the same approach is here:
http://nehe.gamedev.net/data/lessons/le ... ?lesson=46
Last edited by luis on Sun Mar 01, 2009 11:09 pm, edited 1 time in total.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

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).

Hope this helps.

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()
Violet
Enthusiast
Enthusiast
Posts: 106
Joined: Sun Dec 23, 2007 6:30 pm

Post by Violet »

Thank you very much for this! :D

First I still couldn't get it working (I'm on a school Computer now). I could force Antialiasing with ATI Catalyst, but if I set the option to let the Application decide, it didn't work. So, after tracking down the real reason why it didn't use Multisamples, I found out that if Unicode Support is activated,

Code: Select all

sWork = PeekS(glGetString_(#GL_EXTENSIONS))
just outputs unreadable Characters. So the fitting Extension was never found, because the name wasn't readable.

Ok, now I know how to continue, thanks again! :D
best regards,

Violet
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post by luis »

Violet wrote: So, after tracking down the real reason why it didn't use Multisamples, I found out that if Unicode Support is activated,

Code: Select all

sWork = PeekS(glGetString_(#GL_EXTENSIONS))
just outputs unreadable Characters. So the fitting Extension was never found, because the name wasn't readable.
Yes, I don't use unicode, but in case you need it you should use something like that

Code: Select all

sWork = PeekS(glGetString_(#GL_EXTENSIONS), -1, #PB_Ascii) 
as you probably alredy did.

Mhhhh, talking about unicode, it seem maybe there is some bug in the way pb calls opengl functions requiring a string (if unicode is enabled).

For example wglGetProcAddress_("wglChoosePixelFormatARB")

shoud still pass an ASCII string to opengl even if the program is compiled in unicode, but I guess isn't doing that.

If I call wglGetProcAddress_("wglChoosePixelFormatARB") in unicode mode, the functions returns 0 instead of the function address (I know the extension is there on my hardware, the same program in ascii mode works).

If I convert with some code (using PokeS) the Unicode string "wglChoosePixelFormatARB" in a Ascii string, the call is successfull in a unicode-compiled program too.

So I guess there is something wrong there.
Post Reply