Small cross-platform OpenGL demo

Share your advanced PureBasic knowledge/code with the community.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Small cross-platform OpenGL demo

Post by Shardik »

After studying the fantastic Simple Windowed OpenGL framework from
luis and the snippet from d.j.peters demonstrating how to render OpenGL
on a window in Linux
I decided to strip down a bare bones code example
which works in Windows, Linux and even MacOS. This example simply
displays a triangle with a color gradient.

I tested it successfully on these operating systems with PB 4.61:

Windows
- Windows 98 SE
- Windows XP SP3
- Windows 7 x86
- Windows 7 SP1 x86
- Windows 7 x64

Linux
- Kubuntu 10.04 x86
- Kubuntu 11.10 x86
- Kubuntu 12.04 x86
- Kubuntu 12.04 x64
- Linux Mint 11 x86
- Linux Mint 12 x86
- Linux Mint 13 Cinnamon x86
- OpenSuSE 11.4 x86
- OpenSuSE 12.1 x86
- Ubuntu 10.04 x86
- Ubuntu 11.04 x86
- Ubuntu 12.04 Gnome 2 x86
- Ubuntu 12.04 Gnome 2 x64
- Ubuntu 12.04 Unity x86
- Ubuntu 12.04 Unity x64
- Xubuntu 10.04 x86
- Xubuntu 11.10 x86
- Xubuntu 12.04 x86

MacOS
- MacOS X 10.6.8 (Snow Leopard)
- MacOS X 10.7.4 (Lion)
- MacOS X 10.8.0 (Mountain Lion)

Code: Select all

EnableExplicit

#AGL_RGBA         =  4
#AGL_DOUBLEBUFFER =  5
#AGL_DEPTH_SIZE   = 12
#AGL_PIXEL_SIZE   = 50

#GL_COLOR_BUFFER_BIT = $00004000
#GL_DEPTH_BUFFER_BIT = $00000100
#GL_MODELVIEW  = $1700
#GL_PROJECTION = $1701
#GL_TRIANGLES = 4

Define RenderingContext.I

OpenWindow(0, 270, 100, 640, 480, "Cross-platform OpenGL demo", #PB_Window_SystemMenu | #PB_Window_Invisible)
SetWindowColor(0, 0)

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux

    ImportC "-lGL"
      glBegin_(PrimitiveID.I) As "glBegin"
      glClear_(BuffersToClear.I) As "glClear"
      glColor3f_(Red.F, Green.F, Blue.F) As "glColor3f"
      glEnd_() As "glEnd"
      glLoadIdentity_() As "glLoadIdentity"
      glMatrixMode_(Target.I) As "glMatrixMode"
      glTranslatef_(x.F, y.F, z.F) As "glTranslatef"
      glVertex3f_(x.F, y.F, z.F) As "glVertex3f"
      glViewport_(x.I, y.I, Width.I, Height.I) As "glViewport"
      glXChooseVisual(*Display, ScreenNumber.I, *AttributeArray)
      glXCreateContext(*Display, *XVisualInfo, GLXContext.I, DirectGraphicsConnection.I)
      glXDestroyContext(*Display, GLXContext.I)
      glXMakeCurrent(*Display, GLXDrawable.I, GLXContext.I)
      glXSwapBuffers(*Display, GLXDrawable.I)
    EndImport

    ImportC "-lGLU"
      gluPerspective_(FieldOfViewAngle.D, AspectRatioWidthToHeight.D, DistanceFromViewerToNearPlane.D, DistanceFromViewerToFarPlane.D) As "gluPerspective"
    EndImport

    Define *Widget.GtkWidget
    Define *Window
    Define *X11Display
    Define X11Window.I
    Define *XVisualInfo

    Dim Attributes.L(4)

    Attributes(0) = #AGL_DEPTH_SIZE
    Attributes(1) = 16
    Attributes(2) = #AGL_DOUBLEBUFFER
    Attributes(3) = #AGL_RGBA
    Attributes(4) = 0

    *X11Display = gdk_x11_get_default_xdisplay_()

    Repeat
      Delay(20)
    Until IsWindow(0) <> 0
    
    *Widget.GtkWidget = WindowID(0)
    *Window = *Widget\Window
    X11Window = gdk_x11_drawable_get_xid_(*Window)

    If X11Window
      *XVisualInfo = glXChooseVisual(*X11Display, 0, @Attributes())

      If *XVisualInfo
        RenderingContext = glXCreateContext(*X11Display, *XVisualInfo, 0, #False)

        If RenderingContext
          glXMakeCurrent(*X11Display, X11Window, RenderingContext)
        EndIf
      EndIf
    EndIf
  CompilerCase #PB_OS_MacOS
    ImportC "/System/Library/Frameworks/AGL.framework/AGL"
      aglChoosePixelFormat(*AGLDevice, DeviceCount.L, *AttributeArray)
      aglCreateContext(PixelFormatObject.L, RenderingContext.L)
      aglDestroyContext(AGLContext.L)
      aglDestroyPixelFormat(PixelFormatObject.L)
      aglSetCurrentContext(AGLContext.L)
      aglSetWindowRef(AGLContext.L, WindowRef.L)
      aglSwapBuffers(AGLContext.L)
    EndImport

    ImportC "/System/Library/Frameworks/OpenGL.framework/OpenGL"
      glBegin_(PrimitiveID.I) As "_glBegin"
      glClear_(BuffersToClear.I) As "_glClear"
      glColor3f_(Red.F, Green.F, Blue.F) As "_glColor3f"
      glEnd_() As "_glEnd"
      glLoadIdentity_() As "_glLoadIdentity"
      glMatrixMode_(Target.I) As "_glMatrixMode"
      glTranslatef_(x.F, y.F, z.F) As "_glTranslatef"
      gluPerspective_(FieldOfViewAngle.D, WidthToHeightRatio.D, DistanceToNearPlane.D, DistanceToFarPlane.D) As "_gluPerspective"
      glVertex3f_(x.F, y.F, z.F) As "_glVertex3f"
      glViewport_(x.I, y.I, Width.I, Height.I) As "_glViewport"
    EndImport

    Define PixelFormatObject.I

    Dim Attributes.L(4)

    Attributes(0) = #AGL_DEPTH_SIZE
    Attributes(1) = 16
    Attributes(2) = #AGL_DOUBLEBUFFER
    Attributes(3) = #AGL_RGBA
    Attributes(4) = 0

    PixelFormatObject = aglChoosePixelFormat(0, 0, @Attributes())

    If PixelFormatObject
      RenderingContext = aglCreateContext(PixelFormatObject, 0)

      If RenderingContext
        aglSetWindowRef(RenderingContext, WindowID(0))
        aglSetCurrentContext(RenderingContext)
      EndIf
    EndIf
  CompilerCase #PB_OS_Windows
    Define DeviceContext.I
    Define PFD.PIXELFORMATDESCRIPTOR
    Define PixelFormat.I
    
    DeviceContext = GetDC_(WindowID(0))
    PFD\nSize       = SizeOf(PIXELFORMATDESCRIPTOR)
    PFD\nVersion    = 1
    PFD\dwFlags     = #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER | #PFD_DRAW_TO_WINDOW
    PFD\dwLayerMask = #PFD_MAIN_PLANE
    PFD\iPixelType  = #PFD_TYPE_RGBA
    PFD\cColorBits  = 24
    PFD\cDepthBits  = 16

    PixelFormat = ChoosePixelFormat_(DeviceContext, PFD)

    If PixelFormat
      If SetPixelFormat_(DeviceContext, PixelFormat, PFD)
        RenderingContext = wglCreateContext_(DeviceContext)

        If RenderingContext
          wglMakeCurrent_(DeviceContext, RenderingContext)
        EndIf
      EndIf
    EndIf
CompilerEndSelect

If RenderingContext = 0
  MessageRequester("Error", "Unable to obtain OpenGL context")
  End
EndIf

HideWindow(0, #False)

Repeat
  glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
  glMatrixMode_(#GL_PROJECTION)
  glLoadIdentity_()
  gluPerspective_(30.0, Abs(WindowWidth(0) / WindowHeight(0)), 0.1, 500.0)
  glMatrixMode_(#GL_MODELVIEW)
  glLoadIdentity_()
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  glLoadIdentity_()
  glTranslatef_(0.0, 0.0, -8.0)
  glColor3f_(1.0, 1.0, 1.0)
  glBegin_(#GL_TRIANGLES)      ; Start drawing a triangle
  glColor3f_ ( 1.0,  0.0, 0.0) ; Set top point of triangle to Red
  glVertex3f_( 0.0,  1.0, 0.0) ; First point of the triangle
  glColor3f_ ( 0.0,  1.0, 0.0) ; Set left point of triangle to Green
  glVertex3f_(-1.0, -1.0, 0.0) ; Second point of the triangle
  glColor3f_ ( 0.0,  0.0, 1.0) ; Set right point of triangle to Blue
  glVertex3f_( 1.0, -1.0, 0.0) ; Third point of the triangle
  glEnd_()                     ; Done drawing the triangle 

  ; Swap buffers (double buffering)  

  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      glxSwapBuffers(*X11Display, X11Window)
    CompilerCase #PB_OS_MacOS
      aglSwapBuffers(RenderingContext)
    CompilerCase #PB_OS_Windows
      SwapBuffers_(DeviceContext)            
  CompilerEndSelect
Until WaitWindowEvent() = #PB_Event_CloseWindow

; ---- Delete rendering context

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    glXDestroyContext(*X11Display, RenderingContext)
  CompilerCase #PB_OS_MacOS
    aglDestroyPixelFormat(PixelFormatObject)
    aglDestroyContext(RenderingContext)
  CompilerCase #PB_OS_Windows
    wglDeleteContext_(RenderingContext)
    ReleaseDC_(WindowID(0), DeviceContext)
CompilerEndSelect
Update 1: I removed the unnecessary check in Windows for the selection of
the subsystem OpenGL. Thank you for your hint, luis!
Update 2: I tested the code example even successfully in Windows 98 SE... :P
Update 3: For Linux I changed #True in the line

Code: Select all

RenderingContext = glXCreateContext(*X11Display, *XVisualInfo, 0, #True)
against #False. This option specifies whether rendering is to be done with a
direct connection to the graphics system (#True) or through the X server
(#False). With this option changed to #False the code example even runs
without problems in OpenSuSE 12.1... :twisted:
Update 4: I tested the code example successfully in Ubuntu 12.04 LTS and
MacOS X 10.7.4 (Lion)
Update 5: In order to run successfully on 64 bit Linux distributions the following
modification was necessary:

Code: Select all

Dim Attributes.I(4)
had to be changed from Integer to Long:

Code: Select all

Dim Attributes.L(4)
Furthermore now it is no longer necessary to discriminate between the different
paths to libGL and libGLU like this:

Code: Select all

    CompilerIf #UbuntuFamilyDistro_newer_than_11_04
      #LibGLUPath = "/usr/lib/i386-linux-gnu/libGLU.so"
    CompilerElse
      #LibGLUPath = "/usr/lib/libGLU.so"
    CompilerEndIf
A simple

Code: Select all

ImportC "-lGL"
and

Code: Select all

ImportC "-lGLU"
automagically finds the correct path to these libraries... :wink:
I have modified the above example accordingly.
At last I have tested the example successfully under several further 32 bit and 64 bit
Linux distributions.
Update 6: I tested the code example successfully on OS X 10.8.0 (Mountain Lion).
Last edited by Shardik on Fri Aug 17, 2012 9:01 am, edited 9 times in total.
Polo
Addict
Addict
Posts: 2422
Joined: Tue May 06, 2003 5:07 pm
Location: UK

Re: Small cross-platform OpenGL demo

Post by Polo »

Works nice on OSX Lion, well done!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Small cross-platform OpenGL demo

Post by luis »

I tried only under Windows but it looks nice for everyone interested in cross platform OpenGL built from scratch (not using the opengl subsystem provided by PB).

I guess you forgot to comment this out :wink:

Code: Select all

; CompilerIf #PB_Compiler_OS = #PB_OS_Windows
;   CompilerIf Subsystem("OpenGL") = #False
;     MessageRequester("ERROR", "Please set the subsystem to OpenGL")
;     End
;   CompilerEndIf
; CompilerEndIf
Thanks for sharing it.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
J. Baker
Addict
Addict
Posts: 2181
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

Re: Small cross-platform OpenGL demo

Post by J. Baker »

Very nice, thanks!
www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef


Even the vine knows it surroundings but the man with eyes does not.
User avatar
electrochrisso
Addict
Addict
Posts: 989
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: Small cross-platform OpenGL demo

Post by electrochrisso »

Some good learning, thanks. :)
PureBasic! Purely the best 8)
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Small cross-platform OpenGL demo

Post by IdeasVacuum »

Very nicely done, thank you! :)
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
jace_stknights
User
User
Posts: 13
Joined: Sat Mar 24, 2012 3:50 am

Re: Small cross-platform OpenGL demo

Post by jace_stknights »

Really cool stuff!

Thanx for sharing!

PS: works with OSX Lion 10.7.3!
User avatar
kenmo
Addict
Addict
Posts: 2033
Joined: Tue Dec 23, 2003 3:54 am

Re: Small cross-platform OpenGL demo

Post by kenmo »

Nice example!
luis wrote:I tried only under Windows but it looks nice for everyone interested in cross platform OpenGL built from scratch (not using the opengl subsystem provided by PB).
It works perfectly for me, under XP Pro, on a system which PB's opengl subsystem does NOT work! Interesting.

(When I choose the "opengl" subsystem, all 2D Drawing and Sprites show up as blank white... apparently I'm the only one here with this problem :? )
WriteView
New User
New User
Posts: 4
Joined: Tue Jun 05, 2012 2:43 pm

Re: Small cross-platform OpenGL demo

Post by WriteView »

Really nice!

Is it a big deal to make a square out of it?
I failed since now. Maybe it's easy and somebody can post a code.

Cheers
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Small cross-platform OpenGL demo

Post by Shardik »

WriteView wrote:Is it a big deal to make a square out of it?
I failed since now. Maybe it's easy and somebody can post a code.
It's very easy to display a square:

- add the following constant to the code example of my first posting:

Code: Select all

#GL_QUADS = 7
- replace this code part displaying a triangle

Code: Select all

  glBegin_(#GL_TRIANGLES)      ; Start drawing a triangle
  glColor3f_ ( 1.0,  0.0, 0.0) ; Set top point of triangle to Red
  glVertex3f_( 0.0,  1.0, 0.0) ; First point of the triangle
  glColor3f_ ( 0.0,  1.0, 0.0) ; Set left point of triangle to Green
  glVertex3f_(-1.0, -1.0, 0.0) ; Second point of the triangle
  glColor3f_ ( 0.0,  0.0, 1.0) ; Set right point of triangle to Blue
  glVertex3f_( 1.0, -1.0, 0.0) ; Third point of the triangle
  glEnd_()                     ; Done drawing the triangle 
by the following code part displaying a square

Code: Select all

  glBegin_(#GL_QUADS)         ; Draw a quad
  glColor3f_(1.0, 0.0, 0.0)   ; Set top left point to Red
  glVertex3f_(-1.0, 1.0, 0.0) ; Top left
  glColor3f_(1.0, 1.0, 0.0)   ; Set bottom left point to Yellow
  glVertex3f_(-1.0,-1.0, 0.0) ; Bottom left
  glColor3f_(0.0, 0.0, 1.0)   ; Set bottom right point to Blue
  glVertex3f_( 1.0,-1.0, 0.0) ; Bottom right  
  glColor3f_(0.0, 1.0, 0.0)   ; Set top right point to Green
  glVertex3f_( 1.0, 1.0, 0.0) ; Top right
  glEnd_()                    ; Done drawing the quad    
- and you are done :wink:

I have simply copied both code parts from luis' Demo_Shading_Rotation.pb which
is contained in the zip file swof.zip of his Simple Windowed OpenGL framework...
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Small cross-platform OpenGL demo

Post by Shardik »

Because of difficulties in running my above cross-platform OpenGL example in the new PB 4.70 Beta 1 of the new cocoa-framework based Mac version I further simplified the example by rendering the OpenGL content into a WindowedScreen thus eliminating all the platform-specific code to obtain a rendering context of the window in order to let PureBasic do that work. Only in Windows this new simplified code requires the subsystem to be set to OpenGL in the IDE's menu (Compiler/Compiler Options.../Library Subsystem: OpenGL). This new example runs on Macs with PB 4.61 and PB 4.70 Beta 1.5 in 32 bit and 64 bit mode (cocoa framework) and 32 bit (Subsystem: Carbon) and should of course run in all listed OSes from my first post.

Code: Select all

EnableExplicit

#GL_COLOR_BUFFER_BIT = $00004000
#GL_DEPTH_BUFFER_BIT = $00000100
#GL_MODELVIEW  = $1700
#GL_PROJECTION = $1701
#GL_TRIANGLES = 4

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  CompilerIf Subsystem("OpenGL") = #False
    MessageRequester("Error", "Please set the subsystem to OpenGL")
    End
  CompilerEndIf
CompilerEndIf

If InitSprite() = 0
  MessageRequester("Error", "Can't open screen & sprite environment!")
  End
EndIf

OpenWindow(0, 270, 100, 640, 480, "Cross-platform OpenGL demo", #PB_Window_SystemMenu | #PB_Window_Invisible)
SetWindowColor(0, 0)
OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0), WindowHeight(0), 0, 0, 0)

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    ImportC "-lGL"
      glBegin_(PrimitiveID.I) As "glBegin"
      glClear_(BuffersToClear.I) As "glClear"
      glColor3f_(Red.F, Green.F, Blue.F) As "glColor3f"
      glEnd_() As "glEnd"
      glLoadIdentity_() As "glLoadIdentity"
      glMatrixMode_(Target.I) As "glMatrixMode"
      glTranslatef_(x.F, y.F, z.F) As "glTranslatef"
      glVertex3f_(x.F, y.F, z.F) As "glVertex3f"
      glViewport_(x.I, y.I, Width.I, Height.I) As "glViewport"
      glXChooseVisual(*Display, ScreenNumber.I, *AttributeArray)
      glXCreateContext(*Display, *XVisualInfo, GLXContext.I, DirectGraphicsConnection.I)
      glXDestroyContext(*Display, GLXContext.I)
      glXMakeCurrent(*Display, GLXDrawable.I, GLXContext.I)
      glXSwapBuffers(*Display, GLXDrawable.I)
    EndImport

    ImportC "-lGLU"
      gluPerspective_(FieldOfViewAngle.D, AspectRatioWidthToHeight.D, DistanceFromViewerToNearPlane.D, DistanceFromViewerToFarPlane.D) As "gluPerspective"
    EndImport

    ImportC "-lX11" : EndImport
  CompilerCase #PB_OS_MacOS
    ImportC "/System/Library/Frameworks/OpenGL.framework/OpenGL"
      glBegin_(PrimitiveID.I) As "_glBegin"
      glClear_(BuffersToClear.I) As "_glClear"
      glColor3f_(Red.F, Green.F, Blue.F) As "_glColor3f"
      glEnd_() As "_glEnd"
      glLoadIdentity_() As "_glLoadIdentity"
      glMatrixMode_(Target.I) As "_glMatrixMode"
      glTranslatef_(x.F, y.F, z.F) As "_glTranslatef"
      gluPerspective_(FieldOfViewAngle.D, WidthToHeightRatio.D, DistanceToNearPlane.D, DistanceToFarPlane.D) As "_gluPerspective"
      glVertex3f_(x.F, y.F, z.F) As "_glVertex3f"
      glViewport_(x.I, y.I, Width.I, Height.I) As "_glViewport"
    EndImport
CompilerEndSelect

HideWindow(0, #False)

Repeat
  glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
  glMatrixMode_(#GL_PROJECTION)
  glLoadIdentity_()
  gluPerspective_(30.0, Abs(WindowWidth(0) / WindowHeight(0)), 0.1, 500.0)
  glMatrixMode_(#GL_MODELVIEW)
  glLoadIdentity_()
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  glLoadIdentity_()
  glTranslatef_(0.0, 0.0, -8.0)
  glColor3f_(1.0, 1.0, 1.0)
  glBegin_(#GL_TRIANGLES)      ; Start drawing a triangle
  glColor3f_ ( 1.0,  0.0, 0.0) ; Set top point of triangle to Red
  glVertex3f_( 0.0,  1.0, 0.0) ; First point of the triangle
  glColor3f_ ( 0.0,  1.0, 0.0) ; Set left point of triangle to Green
  glVertex3f_(-1.0, -1.0, 0.0) ; Second point of the triangle
  glColor3f_ ( 0.0,  0.0, 1.0) ; Set right point of triangle to Blue
  glVertex3f_( 1.0, -1.0, 0.0) ; Third point of the triangle
  glEnd_()                     ; Done drawing the triangle

  ; Swap buffers (double buffering) 
  FlipBuffers()
Until WaitWindowEvent() = #PB_Event_CloseWindow
Update: I had to add

Code: Select all

ImportC "-lX11" : EndImport
so that this example also works in OpenSuSE 12.1. Thank you for your hint, Fred.
Last edited by Shardik on Thu Aug 16, 2012 9:15 am, edited 2 times in total.
Fred
Administrator
Administrator
Posts: 18161
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Small cross-platform OpenGL demo

Post by Fred »

Works perfectly !
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: Small cross-platform OpenGL demo

Post by applePi »

Thank you for the example.
i have tried it to rotate the triangle by adding
spin = spin + 3
glRotatef_(spin, 0.0, 0.0, 1.0 )

before
glBegin_(#GL_TRIANGLES)

but the triangle rotate only when we move the mouse or pressing a key continuously
this is on windows xp.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Small cross-platform OpenGL demo

Post by luis »

applePi wrote: but the triangle rotate only when we move the mouse or pressing a key continuously
this is on windows xp.
WindowEvent() does not wait for messages like WaitWindowEvent()
"Have you tried turning it off and on again ?"
A little PureBasic review
gekkonier
User
User
Posts: 78
Joined: Mon Apr 23, 2007 9:42 am

Re: Small cross-platform OpenGL demo

Post by gekkonier »

very nice!
thank you!
Post Reply