• Welcome to Jose's Read Only Forum 2023.
 

OpenGL 3.1+ : Simple example

Started by Petr Schreiber, August 14, 2009, 11:10:30 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Petr Schreiber

OpenGL 3.x series are quickly jumping forward, making maybe too big steps for someone.

They provide basically two modes:
- old features + new features (compatibility)
- new designed "core" (forward compatible context)

That's the reason I provide here simple example on using OpenGL 3.1 in forward compatible context, completely getting rid of legacy stuff.
The example below shows you how to:

  • Create forward compatible OpenGL 3.1 context
  • Define geometry using Vertex Array Objects + Vertex Buffer Objects
  • Setup materials via GLSL shaders

The code is heavily based on OpenGL 3.1 sample on OpenGL wiki.
My work consisted just in making PB adaptation of code, providing GLSL shader class as a bonus.

Program needs PB/WIN 9 and latest WinHeaders 1.14 with updated glext.inc.

You will of course need OpenGL 3.1 capable 3D card with latest drivers, which means GeForce 8 and up or Radeon HD series.


' -- Basic introduction to OpenGL 3.1 forward compatible context,
' -- world where lot has changed since 2.1

' -- This code takes most of its parts from tutorial at:
' -- http://www.opengl.org/wiki/Tutorial:_OpenGL_3.1_The_First_Triangle_%28C%2B%2B/Win%29
' -- but it is not 1:1 conversion

' -- Petr Schreiber, 2009

#COMPILE EXE
#DIM ALL
#INCLUDE "GLEXT.INC"
#INCLUDE "WGLEXT.INC"

#INCLUDE "SHADER_GLSL.inc"

$WindowCaption = "OpenGL 3.1 Basic Example"

%GL_WINDOWWIDTH  = 640         ' Window width
%GL_WINDOWHEIGHT = 480         ' Window height
%GL_BITSPERPEL   = 32          ' Color resolution in bits per pixel
%GL_DEPTHBITS    = 16          ' Depth of the depth (z-axis) buffer

GLOBAL hDC AS LONG             ' Device context handle
GLOBAL m_vaoID() AS DWORD
GLOBAL m_vboID() AS DWORD

global m_pProgram  as iShaderProgram_GLSL
global m_pVertSh   as iShader_GLSL
global m_pFragSh   as iShader_GLSL
global PrimitivesPrepaired as long

macro GLfloat = single
' =======================================================================================
' Preparing primitives
' =======================================================================================
SUB PreparePrimitives ()

  DIM m_vaoID(2)
  DIM m_vboID(3)

  ' First simple object
  DIM VertexData(8) AS SINGLE         ' vertex array
  DIM ColorData(8) AS SINGLE          ' color array

  array assign VertexData() = -0.3, 0.5, -1.0, _
                              -0.8,-0.5, -1.0, _
                               0.2,-0.5, -1.0

  array assign ColorData() = 1.0, 0.0, 0.0, _
                             0.0, 1.0, 0.0, _
                             0.0, 0.0, 1.0

  ' Second simple object
  DIM VertexData2(8) AS SINGLE  ' vertex array
  array assign VertexData2() = -0.2, 0.5, -1.0, _
                                0.3,-0.5, -1.0, _
                                0.8, 0.5, -1.0

  ' Two VAOs allocation
  glGenVertexArrays(2, m_vaoID(0))

  ' First VAO setup
  glBindVertexArray(m_vaoID(0))

  glGenBuffers(2, m_vboId(0))

  glBindBuffer(%GL_ARRAY_BUFFER, m_vboID(0))

  ' 9 items * size of SINGLE
  glBufferData(%GL_ARRAY_BUFFER, (9 * 4), VertexData(0), %GL_STATIC_DRAW)
  glVertexAttribPointer(0, 3, %GL_FLOAT, %GL_FALSE, 0, byval 0)
  glEnableVertexAttribArray(0)

  glBindBuffer(%GL_ARRAY_BUFFER, m_vboID(1))
  glBufferData(%GL_ARRAY_BUFFER, (9 * 4), ColorData(0), %GL_STATIC_DRAW)
  glVertexAttribPointer(1, 3, %GL_FLOAT, %GL_FALSE, 0, byval 0)
  glEnableVertexAttribArray(1)

  ' Second VAO setup
  glBindVertexArray(m_vaoID(1))

  glGenBuffers(1, m_vboID(2))

  glBindBuffer(%GL_ARRAY_BUFFER, m_vboID(2))
  glBufferData(%GL_ARRAY_BUFFER, (9 * 4), VertexData2(0), %GL_STATIC_DRAW)
  glVertexAttribPointer(0, 3, %GL_FLOAT, %GL_FALSE, 0, byval 0)
  glEnableVertexAttribArray(0)

  glBindVertexArray(0)

  PrimitivesPrepaired = %TRUE

END SUB

' =======================================================================================
' All the setup goes here
' =======================================================================================
SUB SetupScene (BYVAL hwnd AS DWORD, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)

  glClearColor (1.0, 1.0, 1.0, 0.0)

  m_pProgram  = class "cShader_Program_GLSL"
  m_pVertSh   = class "cShader_Vertex_GLSL"
  m_pFragSh   = class "cShader_Fragment_GLSL"

  m_pVertSh.Load(exe.path$+"minimal.vert")
  m_pFragSh.Load(exe.path$+"minimal.frag")

  m_pVertSh.Compile()
  m_pFragSh.Compile()

  m_pProgram.AttachShader(m_pVertSh)
  m_pProgram.AttachShader(m_pFragSh)

  m_pProgram.BindAttribLocation(0, "in_Position")
  m_pProgram.BindAttribLocation(1, "in_Color")

  m_pProgram.Link()
  m_pProgram.Enable()

  PreparePrimitives()

END SUB
' =======================================================================================

' =======================================================================================
' Resize the scene
' =======================================================================================
SUB ResizeScene (BYVAL hwnd AS DWORD, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)

   ' Prevent divide by zero making height equal one
   IF nHeight = 0 THEN nHeight = 1
   ' Reset the current viewport
   glViewport 0, 0, nWidth, nHeight
   ' Select the projection matrix

END SUB
' =======================================================================================

' =======================================================================================
' Draw the scene
' =======================================================================================
SUB DrawScene (BYVAL hwnd AS DWORD, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG)

  glClear(%GL_COLOR_BUFFER_BIT)

  glBindVertexArray(m_vaoID(0))       ' select first VAO
  glDrawArrays(%GL_TRIANGLES, 0, 3)   ' draw first object

  glBindVertexArray(m_vaoID(1))       ' select second VAO
  glVertexAttrib3f(1, 1.0, 0.0, 0.0)  ' set constant color attribute
  glDrawArrays(%GL_TRIANGLES, 0, 3)   ' draw second object

  glBindVertexArray(0)

  glFlush ()

END SUB
' =======================================================================================

' =======================================================================================
' Cleanup
' =======================================================================================
SUB Cleanup (BYVAL hwnd AS DWORD)

  if PrimitivesPrepaired then
    glBindBuffer(%GL_ARRAY_BUFFER, 0)
    glBindBuffer(%GL_ELEMENT_ARRAY_BUFFER, 0)
    glDeleteBuffers(3, m_vboID(0))

    glBindVertexArray(0)
    glDeleteVertexArrays(2, m_vaoID(0))

    m_pProgram.DetachShader(m_pVertSh)
    m_pProgram.DetachShader(m_pFragSh)

    m_pProgram = nothing

    m_pVertSh = nothing
    m_pFragSh = nothing
  end if
END SUB
' =======================================================================================

' =======================================================================================
' Processes keystrokes
' Parameters:
' * hwnd = Window hande
' * vKeyCode = Virtual key code
' * bKeyDown = %TRUE if key is pressed; %FALSE if it is released
' =======================================================================================
SUB ProcessKeystrokes (BYVAL hwnd AS DWORD, BYVAL vKeyCode AS LONG, BYVAL bKeyDown AS LONG)

   SELECT CASE AS LONG vKeyCode

      CASE %VK_ESCAPE
         ' Quit if Esc key pressed
         SendMessage hwnd, %WM_CLOSE, 0, 0

   END SELECT

END SUB
' =======================================================================================

' =======================================================================================
' Processes mouse clicks and movement
' Parameters:
' * hwnd      = Window hande
' * wMsg      = Windows message
' * wKeyState = Indicates whether various virtual keys are down.
'               MK_CONTROL    The CTRL key is down.
'               MK_LBUTTON    The left mouse button is down.
'               MK_MBUTTON    The middle mouse button is down.
'               MK_RBUTTON    The right mouse button is down.
'               MK_SHIFT      The SHIFT key is down.
'               MK_XBUTTON1   Windows 2000/XP: The first X button is down.
'               MK_XBUTTON2   Windows 2000/XP: The second X button is down.
' * x         = x-coordinate of the cursor
' * y         = y-coordinate of the cursor
' =======================================================================================
SUB ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wKeyState AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG)

   SELECT CASE wMsg

      CASE %WM_LBUTTONDOWN

      CASE %WM_LBUTTONUP

      CASE %WM_MOUSEMOVE

   END SELECT

END SUB
' =======================================================================================


MACRO OpenGL_CreateContext_Legacy( deviceHandle ) = wglCreateContext(deviceHandle)

FUNCTION OpenGL_CreateContext_3Plus( deviceHandle AS LONG, majorRevision AS LONG, minorRevision AS LONG ) AS LONG

  DIM attributes(5) AS LOCAL LONG  ' 0..5

  ARRAY ASSIGN attributes() = %WGL_CONTEXT_MAJOR_VERSION_ARB, majorRevision, _
                              %WGL_CONTEXT_MINOR_VERSION_ARB, minorRevision, _
                                                           0,             0

  FUNCTION = wglCreateContextAttribsARB(hDC, 0, attributes(0))
END FUNCTION

FUNCTION OpenGL_CreateContext_3_1_ForwardCompatible( deviceHandle AS LONG ) AS LONG

  DIM attributes(6) AS LOCAL LONG  ' 0..6

  ARRAY ASSIGN attributes() = %WGL_CONTEXT_MAJOR_VERSION_ARB, 3, _
                              %WGL_CONTEXT_MINOR_VERSION_ARB, 1, _
                              %WGL_CONTEXT_FLAGS_ARB          , %WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, _
                              0

  FUNCTION = wglCreateContextAttribsARB(hDC, 0, attributes(0))
END FUNCTION

' =======================================================================================

' =======================================================================================
' Main
' =======================================================================================
FUNCTION WINMAIN (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   LOCAL  hwnd        AS DWORD
   LOCAL  wcex        AS WNDCLASSEX
   LOCAL  szClassName AS ASCIIZ * 256
   LOCAL  szCaption   AS ASCIIZ * 256
   LOCAL  msg         AS tagMSG
   LOCAL  rc          AS RECT
   LOCAL  bDone       AS LONG
   LOCAL  nLeft       AS LONG
   LOCAL  nTop        AS LONG
   LOCAL  nWidth      AS LONG
   LOCAL  nHeight     AS LONG
   LOCAL  dwStyle     AS DWORD
   LOCAL  dwStyleEx   AS DWORD
   STATIC vKeyCode    AS LONG
   STATIC bKeyDown    AS LONG
   LOCAL  t           AS DOUBLE
   LOCAL  t0          AS DOUBLE
   LOCAL  fps         AS DOUBLE
   LOCAL  nFrames     AS LONG
   LOCAL  dm          AS DEVMODE
   LOCAL  bFullScreen AS LONG
   LOCAL  lResult     AS LONG

   ' Register the window class
   szClassName        = "PBOPENGL"
   wcex.cbSize        = SIZEOF(wcex)
   wcex.style         = %CS_HREDRAW OR %CS_VREDRAW OR %CS_OWNDC
   wcex.lpfnWndProc   = CODEPTR(WndProc)
   wcex.cbClsExtra    = 0
   wcex.cbWndExtra    = 0
   wcex.hInstance     = hInstance
   wcex.hCursor       = LoadCursor (%NULL, BYVAL %IDC_ARROW)
   wcex.hbrBackground = %NULL
   wcex.lpszMenuName  = %NULL
   wcex.lpszClassName = VARPTR(szClassName)
   wcex.hIcon         = LoadIcon (%NULL, BYVAL %IDI_APPLICATION) ' Sample, if resource icon: LoadIcon(hInst, "APPICON")
   wcex.hIconSm       = LoadIcon (%NULL, BYVAL %IDI_APPLICATION) ' Remember to set small icon too..
   RegisterClassEx wcex

  ' Ask the user which screen mode he prefers
  lResult = MessageBox(%NULL, "Would you like to run in fullscreen mode?", _
             "Start fullScreen?", %MB_YESNOCANCEL OR %MB_ICONQUESTION)
   SELECT CASE lResult
      CASE %IDCANCEL : EXIT FUNCTION
      CASE %IDYES    : bFullScreen = %TRUE
      CASE %IDNO     : bFullScreen = %FALSE
   END SELECT

   ' Window size
   nWidth  = %GL_WINDOWWIDTH
   nHeight = %GL_WINDOWHEIGHT

   IF bFullScreen THEN
      ' Change display settings
      dm.dmSize       = SIZEOF(dm)
      dm.dmPelsWidth  = nWidth
      dm.dmPelsHeight = nHeight
      dm.dmBitsPerPel = %GL_BITSPERPEL
      dm.dmFields     = %DM_BITSPERPEL OR %DM_PELSWIDTH OR %DM_PELSHEIGHT
      IF ChangeDisplaySettings(dm, %CDS_FULLSCREEN) = 0 THEN ShowCursor %FALSE
   END IF

   ' Window caption
   szCaption = $WindowCaption

   ' Window styles
   IF ISFALSE bFullScreen THEN
      dwStyle = %WS_OVERLAPPEDWINDOW
      dwStyleEx = %WS_EX_APPWINDOW OR %WS_EX_WINDOWEDGE
   ELSE
      dwStyle = %WS_POPUP
      dwStyleEx = %WS_EX_APPWINDOW
   END IF

   ' Create the window
   hwnd = CreateWindowEx( _
            dwStyleEx, _                      ' extended styles
            szClassName, _                    ' window class name
            szCaption, _                      ' window caption
            dwStyle, _                        ' window style
            nLeft, _                          ' initial x position
            nTop, _                           ' initial y position
            nWidth, _                         ' initial x size
            nHeight, _                        ' initial y size
            %NULL, _                          ' parent window handle
            0, _                              ' window menu handle
            hInstance, _                      ' program instance handle
            BYVAL %NULL)                      ' creation parameters

   ' Retrieve the coordinates of the window's client area
   GetClientRect hwnd, rc
   ' Initialize the new OpenGl window
   SetupScene hwnd, rc.nRight - rc.nLeft, rc.nBottom - rc.nTop

   ' Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   DO UNTIL bDone

      ' Windows message pump
      DO WHILE PeekMessage(msg, %NULL, 0, 0, %PM_REMOVE)
         IF msg.message = %WM_QUIT THEN
            bDone = %TRUE
         ELSE
            IF msg.message = %WM_KEYDOWN THEN
               vKeyCode = msg.wParam
               bKeyDown = %TRUE
            ELSEIF msg.message = %WM_KEYUP THEN
               vKeyCode = msg.wParam
               bKeyDown = %FALSE
            END IF
            TranslateMessage msg
            DispatchMessage msg
         END IF
      LOOP

      IF ISFALSE bFullScreen THEN
         ' Get time and mouse position
         t = INT(TIMER)
         ' Calculate and display FPS (frames per second)
         IF t > t0 OR nFrames = 0 THEN
            fps = nFrames \ (t - t0)
            wsprintf szCaption, $WindowCaption & " (%i FPS)", BYVAL fps
            SetWindowText hwnd, szCaption
            t0 = t
            nFrames = 0
         END IF
         nFrames = nFrames + 1
      END IF

      ' Draw the scene
      DrawScene hwnd, nWidth, nHeight
      ' Exchange the front and back buffers
      SwapBuffers hDC

      ' Process the keystrokes
      IF vKeyCode THEN
         ProcessKeystrokes hwnd, vKeyCode, bKeyDown
         vKeyCode = 0
      END IF

   LOOP

   ' Retore defaults
   IF bFullScreen THEN
      ChangeDisplaySettings BYVAL %NULL, 0
      ShowCursor %TRUE
   END IF

   FUNCTION = msg.wParam

END FUNCTION
' =======================================================================================

' =======================================================================================
' Main window procedure
' =======================================================================================
FUNCTION WndProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   LOCAL  pf  AS LONG
   LOCAL  pfd AS PIXELFORMATDESCRIPTOR
   LOCAL  hRCLegacy AS LONG
   STATIC hRC AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND

         ' Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION

         ' Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_CREATE

         ' Retrieve the device context handle
         hDC = GetDC(hwnd)

         ' Fill the PIXELFORMATDESCRIPTOR structure
         pfd.nSize           = SIZEOF(PIXELFORMATDESCRIPTOR)   ' Size of the structure
         pfd.nVersion        = 1                               ' Version number
         pfd.dwFlags         = %PFD_DRAW_TO_WINDOW _           ' Format must support window
                               OR %PFD_SUPPORT_OPENGL _        ' Format must support OpenGL
                               OR %PFD_DOUBLEBUFFER            ' Format must support double buffering
         pfd.iPixelType      = %PFD_TYPE_RGBA                  ' Request an RGBA format
         pfd.cColorBits      = %GL_BITSPERPEL                  ' Number of color bitplanes in each color buffer
         pfd.cRedBits        = 0                               ' Number of red bitplanes in each RGBA color buffer.
         pfd.cRedShift       = 0                               ' Shift count for red bitplanes in each RGBA color buffer.
         pfd.cGreenBits      = 0                               ' Number of green bitplanes in each RGBA color buffer.
         pfd.cGreenShift     = 0                               ' Shift count for green bitplanes in each RGBA color buffer.
         pfd.cBlueBits       = 0                               ' Number of blue bitplanes in each RGBA color buffer.
         pfd.cBlueShift      = 0                               ' Shift count for blue bitplanes in each RGBA color buffer.
         pfd.cAlphaBits      = 0                               ' Number of alpha bitplanes in each RGBA color buffer
         pfd.cAlphaShift     = 0                               ' Shift count for alpha bitplanes in each RGBA color buffer.
         pfd.cAccumBits      = 0                               ' Total number of bitplanes in the accumulation buffer.
         pfd.cAccumRedBits   = 0                               ' Number of red bitplanes in the accumulation buffer.
         pfd.cAccumGreenBits = 0                               ' Number of gree bitplanes in the accumulation buffer.
         pfd.cAccumBlueBits  = 0                               ' Number of blue bitplanes in the accumulation buffer.
         pfd.cAccumAlphaBits = 0                               ' Number of alpha bitplanes in the accumulation buffer.
         pfd.cDepthBits      = %GL_DEPTHBITS                   ' Depth of the depth (z-axis) buffer.
         pfd.cStencilBits    = 0                               ' Depth of the stencil buffer.
         pfd.cAuxBuffers     = 0                               ' Number of auxiliary buffers.
         pfd.iLayerType      = %PFD_MAIN_PLANE                 ' Ignored. Earlier implementations of OpenGL used this member, but it is no longer used.
         pfd.bReserved       = 0                               ' Number of overlay and underlay planes.
         pfd.dwLayerMask     = 0                               ' Ignored. Earlier implementations of OpenGL used this member, but it is no longer used.
         pfd.dwVisibleMask   = 0                               ' Transparent color or index of an underlay plane.
         pfd.dwDamageMask    = 0                               ' Ignored. Earlier implementations of OpenGL used this member, but it is no longer used.

         ' Find a matching pixel format
         pf = ChoosePixelFormat(hDC, pfd)
         IF ISFALSE pf THEN
            MessageBox hwnd, "Can't find a suitable pixel format", _
                       "Error", %MB_OK OR %MB_ICONEXCLAMATION
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

         ' Set the pixel format
         IF ISFALSE SetPixelFormat(hDC, pf, pfd) THEN
            MessageBox hwnd, "Can't set the pixel format", _
                       "Error", %MB_OK OR %MB_ICONEXCLAMATION
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

         ' Create a new OpenGL rendering context
         hRCLegacy = OpenGL_CreateContext_Legacy(hDC)
         IF ISFALSE hRCLegacy THEN
            MessageBox hwnd, "Can't create an OpenGL Legacy rendering context", _
                       "Error", %MB_OK OR %MB_ICONEXCLAMATION
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

         ' Make it current
         IF ISFALSE wglMakeCurrent(hDC, hRCLegacy) THEN
            MessageBox hwnd, "Can't activate the OpenGL rendering context", _
                       "Error", %MB_OK OR %MB_ICONEXCLAMATION
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

         hRC = OpenGL_CreateContext_3_1_ForwardCompatible(hDC)
         IF ISFALSE hRC THEN
            MessageBox hwnd, "Can't create an OpenGL 3.1 rendering context", _
                       "Error", %MB_OK OR %MB_ICONEXCLAMATION
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

         ' Kill old, legacy context
         ' Release the device and rendering contexts
         wglMakeCurrent hDC, 0
         ' Make the rendering context no longer current
         wglDeleteContext hRCLegacy

         ' Make it current
         IF ISFALSE wglMakeCurrent(hDC,hRC) THEN
            MessageBox hwnd, "Can't activate the OpenGL rendering context", _
                       "Error", %MB_OK OR %MB_ICONEXCLAMATION
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

         EXIT FUNCTION

      CASE %WM_DESTROY
         ' Clear resources
         Cleanup hwnd
         ' Release the device and rendering contexts
         wglMakeCurrent hDC, 0
         ' Make the rendering context no longer current
         IF hRCLegacy THEN
           wglDeleteContext hRCLegacy
         ELSE
           wglDeleteContext hRC
         END IF
         ' Release the device context
         ReleaseDC hwnd, hDC
         ' Post an WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

      CASE %WM_SIZE
         ResizeScene hwnd, LO(WORD, lParam), HI(WORD, lParam)
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         ProcessMouse hwnd, wMsg, wParam, LO(WORD, lParam), HI(WORD, lParam)
         EXIT FUNCTION

   END SELECT

   ' Call the default window procedure to process unhandled messages
   FUNCTION = DefWindowProc(hwnd, wMsg, wParam, lParam)

END FUNCTION



' -- CLASS to manage GLSL shaders

#INCLUDE ONCE "glext.inc"

' -- Vertex shader
class cShader_Vertex_GLSL
  instance shaderHandle as dword

  class method Create()
    shaderHandle = glCreateShader(%GL_VERTEX_SHADER)
  end method

  class method Destroy()
    glDeleteShader(shaderHandle)
  end method

  interface iShader_GLSL
    inherit IUnknown

    method Load(byref fName as string)
      local f       as integer
      local sBuffer as string
      f = freefile

      try
        open fName for binary as #f
          get$ #f, lof(f), sBuffer
      catch
        msgbox "File "+fName+":"+error$(err)
      finally
        close #f
      end try

      glShaderSource(shaderHandle, 1, sBuffer, byval %NULL)
    end method

    method Compile()
      glCompileShader(shaderHandle)
    end method

    property get Handle() as dword
      property = shaderHandle
    end property

  end interface
end class

' -- Fragment shader
class cShader_Fragment_GLSL
  instance shaderHandle as dword

  class method Create()
    shaderHandle = glCreateShader(%GL_FRAGMENT_SHADER)
  end method

  class method Destroy()
    glDeleteShader(shaderHandle)
  end method

  interface iShader_GLSL
    inherit IUnknown

    method Load(byref fName as string)
      local f       as integer
      local sBuffer as string
      f = freefile

      open fName for binary as #f
        get$ #f, lof(f), sBuffer
      close #f

      glShaderSource(shaderHandle, 1, sBuffer, byval %NULL)
    end method

    method Compile()
      glCompileShader(shaderHandle)
    end method

    property get Handle() as dword
      property = shaderHandle
    end property

  end interface
end class

' -- Shader program ( can combine vertex with fragment etc.)
class cShader_Program_GLSL
  instance programHandle as dword

  class method Create()
    programHandle = glCreateProgram()
  end method

  class method Destroy()
    glDeleteProgram(programHandle)
  end method

  interface iShaderProgram_GLSL
    inherit IUnknown

    method AttachShader(byval shader as iShader_GLSL)
      glAttachShader(programHandle, shader.handle)
    end method

    method DetachShader(byval shader as iShader_GLSL)
      glDetachShader(programHandle, shader.handle)
    end method

    method Link()
      glLinkProgram(programHandle)
    end method

    method BindAttribLocation(byval index as long, byref sname as string)
      glBindAttribLocation(programHandle, index, sname)
    end method

    method Enable()
      glUseProgram(programHandle)
    end method

    method Disable()
      glUseProgram(%NULL)
    end method

  end interface
end class


Please downlad the attached ZIP from below, which contains all files necessary ( program+GLSL class+fragment shader+vertex shader )


Petr

EDIT: Added version for PB/Win 10, but you need to use Josés Windows API Headers III v.1.04 or newer
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Petr Schreiber

Updated link to fixed glExt header.

With latest José's Windows headers and updates to it I can confirm the example works as it should with PB/WIN 9.02.
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Patrice Terrier

#2
Petr,

While working myself on GLSL, i did try your code to see what could be the difference with my own, but so far i couldn't get your ZIP file to run with the current set of José's include files,  because all the glextension sub/function are missing.

Here is the my own code, with some of the missing sub/function, however i couldn't get it to work because of mysterious "syntax error, unexpected $end at token "<EOF>".

#COMPILE EXE "GLSL.exe"

#INCLUDE "Win32API.inc"
#INCLUDE "glext.inc"

%SHADER_BLINN_PHONG    = 1
%SHADER_NORMAL_MAPPING = 2

GLOBAL g_nSupportsProgrammablePipeline AS LONG
GLOBAL g_nSupportsProgrammablePipeline AS LONG
GLOBAL g_nBlinnPhongShader AS LONG

GLOBAL g_nNullTexture AS LONG
GLOBAL g_nNormalMappingShader AS LONG
GLOBAL g_rMaxAnisotrophy AS SINGLE

GLOBAL g_hWnd, g_hDC, g_hRC AS DWORD

SUB glUseProgram(BYVAL program AS DWORD)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glUseProgram")
    IF pProc THEN CALL DWORD pProc USING glUseProgram(program)
END SUB

SUB glActiveTexture (BYVAL dwTexture AS DWORD)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glActiveTexture")
    IF pProc THEN CALL DWORD pProc USING glActiveTexture(dwTexture)
END SUB

FUNCTION glCreateShader (BYVAL dwShadertype AS DWORD) AS DWORD
    LOCAL pProc AS DWORD, nRet AS DWORD
    pProc = wglGetProcAddress("glCreateShader")
    IF pProc THEN CALL DWORD pProc USING glCreateShader(dwShadertype) TO nRet
    FUNCTION = nRet
END FUNCTION

SUB glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF szSource AS ASCIIZ, BYREF nLength AS LONG)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glShaderSource")
    IF pProc THEN CALL DWORD pProc USING glShaderSource(dwShader, nCount, szSource, nLength)
END SUB

SUB glCompileShader (BYVAL dwShader AS DWORD)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glCompileShader")
    IF pProc THEN CALL DWORD pProc USING glCompileShader(dwShader)
END SUB

SUB glGetShaderiv (BYVAL dwShader AS DWORD, BYVAL pname AS DWORD, BYREF params AS LONG)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glGetShaderiv")
    IF pProc THEN CALL DWORD pProc USING glGetShaderiv(dwShader, pname, params)
END SUB

SUB glGetShaderInfoLog (BYVAL dwProgram AS DWORD, BYVAL bufSize AS LONG, BYREF nLength AS LONG, BYREF infoLog AS BYTE)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glGetShaderInfoLog")
    IF pProc THEN CALL DWORD pProc USING glGetShaderInfoLog(dwProgram, bufSize, nLength, infoLog)
END SUB

FUNCTION glCreateProgram () AS DWORD
    LOCAL pProc AS DWORD, nRet AS DWORD
    pProc = wglGetProcAddress("glCreateProgram")
    IF pProc THEN CALL DWORD pProc USING glCreateProgram() TO nRet
    FUNCTION = nRet
END FUNCTION

SUB glAttachShader (BYVAL dwProgram AS DWORD, BYVAL dwShader AS DWORD)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glAttachShader")
    IF pProc THEN CALL DWORD pProc USING glAttachShader(dwProgram, dwShader)
END SUB

SUB glDeleteShader (BYVAL dwShader AS DWORD)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glDeleteShader")
    IF pProc THEN CALL DWORD pProc USING glDeleteShader(dwShader)
END SUB

SUB glLinkProgram (BYVAL dwProgram AS DWORD)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glLinkProgram")
    IF pProc THEN CALL DWORD pProc USING glLinkProgram(dwProgram)
END SUB

SUB glGetProgramiv (BYVAL dwProgram AS DWORD, BYVAL pname AS DWORD, BYREF params AS LONG)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glGetProgramiv")
    IF pProc THEN CALL DWORD pProc USING glGetProgramiv(dwProgram, pname, params)
END SUB

SUB glGetProgramInfoLog (BYVAL dwProgram AS DWORD, BYVAL bufSize AS LONG, BYREF nLength AS LONG, BYREF infoLog AS BYTE)
    LOCAL pProc AS DWORD
    pProc = wglGetProcAddress("glGetProgramInfoLog")
    IF pProc THEN CALL DWORD pProc USING glGetProgramInfoLog(dwProgram, bufSize, nLength, InfoLog)
END SUB

SUB GL2GetGLVersion(nMajor AS LONG, nMinor AS LONG)

    STATIC nMajorGL, nMinorGL AS LONG

    IF nMajorGL = 0 AND nMinorGL = 0 THEN
        LOCAL pszVersion AS ASCIIZ PTR, szVersion AS ASCIIZ * 16
        pszVersion = glGetString(%GL_VERSION)
        szVersion = @pszVersion
        nMajorGL = VAL(EXTRACT$(szVersion, ".")): nMinorGL = VAL(REMAIN$(szVersion, "."))
    END IF
    nMajor = nMajorGL
    nMinor = nMinorGL

END SUB

FUNCTION GL2SupportsGLVersion(BYVAL nMajor AS LONG, BYVAL nMinor AS LONG) AS LONG

    STATIC nMajorGL, nMinorGL, nRet AS LONG

    IF nMajorGL = 0 AND nMinorGL = 0 THEN GL2GetGLVersion(nMajorGL, nMinorGL)
    nRet = 0
    IF nMajorGL > nMajor THEN
        nRet = -1
    ELSEIF nMajorGL = nMajor AND nMinorGL >= nMinor THEN
        nRet = -1
    END IF
    FUNCTION = nRet

END FUNCTION

FUNCTION CompileShader(BYVAL nType AS DWORD, sBuffer AS STRING, nLength AS LONG) AS LONG

'   // Compiles the shader given it's source code. Returns the shader object.
'   // A std::string object containing the shader's info log is thrown if the
'   // shader failed to compile.
'   //
'   // 'nType' is either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
'   // 'pszSource' is a C style string containing the shader's source code.
'   // 'nLength' is the nLength of 'pszSource'.

    LOCAL dwShader AS DWORD
    dwShader = glCreateShader(nType)

    IF dwShader THEN
   
        LOCAL compiled AS LONG
        LOCAL szBuffer AS ASCIIZ * 1024
        szBuffer = sBuffer
        glShaderSource(dwShader, 1, szBuffer, nLength)


        glCompileShader(dwShader)
        glGetShaderiv(dwShader, %GL_COMPILE_STATUS, compiled)
msgbox "compiled"+str$(compiled)+str$(dwShader)+$cr+$cr+sBuffer+$cr+str$(nLength)
        IF NOT compiled THEN
            LOCAL infoLogSize AS LONG
            glGetShaderiv(dwShader, %GL_INFO_LOG_LENGTH, infoLogSize)
            LOCAL sInfolog AS STRING
            sInfolog = STRING$(infoLogSize, 0)
            DIM InfoLog(infoLogSize) AS BYTE
            glGetShaderInfoLog(dwShader, infoLogSize, infoLogSize, InfoLog(0))
            MEMORY COPY VARPTR(InfoLog(0)), STRPTR(sInfolog), infoLogSize
            msgbox "shader" +$cr+$cr+sInfolog
        END IF
    END IF

    FUNCTION = dwShader

END FUNCTION

FUNCTION LinkShaders(BYVAL vertShader AS LONG, BYVAL fragShader AS LONG) AS LONG

'   // Links the compiled vertex and/or fragment shaders into an executable
'   // shader nProgram. Returns the executable shader object. If the shaders
'   // failed to link into an executable shader nProgram, then a std::string
'   // object is thrown containing the info log.

    LOCAL nProgram AS LONG
    nProgram = glCreateProgram()

    IF nProgram THEN
   
        LOCAL linked AS LONG

        IF vertShader THEN glAttachShader(nProgram, vertShader)

        IF fragShader THEN glAttachShader(nProgram, fragShader)

        glLinkProgram(nProgram)
        glGetProgramiv(nProgram, %GL_LINK_STATUS, linked)

LOCAL infoLogSize AS LONG
glGetProgramiv(nProgram, %GL_INFO_LOG_LENGTH, infoLogSize)
LOCAL sInfolog AS STRING
sInfolog = STRING$(infoLogSize, 0)
DIM InfoLog(infoLogSize) AS BYTE
glGetProgramInfoLog(nProgram, infoLogSize, infoLogSize, InfoLog(0))

'DECLARE SUB CopyMem LIB "KERNEL32.DLL" ALIAS "RtlMoveMemory" (BYVAL Dest AS DWORD, BYVAL Srce AS DWORD, BYVAL nLength AS DWORD)
'                CopyMem(STRPTR(sMemBuffer), pData, dwSize)
MEMORY COPY VARPTR(InfoLog(0)), STRPTR(sInfolog), infoLogSize
msgbox str$(linked)+$cr+sInfolog

        IF NOT linked THEN nProgram = 0

'       // Mark the two attached shaders for deletion. These two shaders aren't
'       // deleted right now because both are already attached to a shader
'       // nProgram. When the shader nProgram is deleted these two shaders will
'       // be automatically detached and deleted.
        IF vertShader THEN glDeleteShader(vertShader)
        IF fragShader THEN glDeleteShader(fragShader)
    END IF

    FUNCTION = nProgram

END FUNCTION

FUNCTION LoadShader(nID AS LONG) AS LONG

    LOCAL nProgram, vertShader, fragShader AS LONG
    LOCAL sBuffer AS STRING

    IF nID = %SHADER_BLINN_PHONG THEN

       sBuffer = "" + $CRLF + _
                 "#version 110" + $CRLF + _
                 "" + $CRLF + _
                 "varying vec3 normal;" + $CRLF + _
                 "" + $CRLF + _
                 "void main()" + $CRLF + _
                 "{" + $CRLF + _
                 "    normal = normalize(gl_NormalMatrix * gl_Normal);" + $CRLF + _
                 "" + $CRLF + _
                 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" + $CRLF + _
                 "    gl_TexCoord[0] = gl_MultiTexCoord0; " + $CRLF + _   
                 "}" + $CRLF + _
                 "" + $CRLF
       vertShader = CompileShader(%GL_VERTEX_SHADER, sBuffer, LEN(sBuffer))

       sBuffer = "" + $CRLF + _
                 "#version 110" + $CRLF + _
                 "" + $CRLF + _
                 "uniform sampler2D colorMap;" + $CRLF + _
                 "uniform float materialAlpha;" + $CRLF + _
                 "" + $CRLF + _
                 "varying vec3 normal;" + $CRLF + _
                 "" + $CRLF + _
                 "void main()" + $CRLF + _
                 "{" + $CRLF + _
                 "    vec3 n = normalize(normal);" + $CRLF + _
                 "" + $CRLF + _
                 "    float nDotL = max(0.0, dot(n, gl_LightSource[0].position.xyz));" + $CRLF + _
                 "    float nDotH = max(0.0, dot(normal, vec3(gl_LightSource[0].halfVector)));" + $CRLF + _
                 "    float power = (nDotL == 0.0) ? 0.0 : pow(nDotH, gl_FrontMaterial.shininess);" + $CRLF + _
                 "" + $CRLF + _
                 "    vec4 ambient = gl_FrontLightProduct[0].ambient;" + $CRLF + _
                 "    vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL;" + $CRLF + _
                 "    vec4 specular = gl_FrontLightProduct[0].specular * power;" + $CRLF + _
                 "    vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse + specular;" + $CRLF + _
                 "" + $CRLF + _
                 "    gl_FragColor = color * texture2D(colorMap, gl_TexCoord[0].st);" + $CRLF + _
                 "    gl_FragColor.a = materialAlpha;" + $CRLF + _
                 "}" + $CRLF + _
                 "" + $CRLF
       fragShader = CompileShader(%GL_FRAGMENT_SHADER, sBuffer, LEN(sBuffer))

    ELSEIF nID = %SHADER_NORMAL_MAPPING THEN
       sBuffer = "" + $CRLF + _
                 "#version 110" + $CRLF + _
                 "" + $CRLF + _
                 "varying vec3 lightDir;" + $CRLF + _
                 "varying vec3 halfVector;" + $CRLF + _
                 "" + $CRLF + _
                 "void main()" + $CRLF + _
                 "{" + $CRLF + _
                 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" + $CRLF + _
                 "    gl_TexCoord[0] = gl_MultiTexCoord0;" + $CRLF + _
                 "    " + $CRLF + _
                 "    vec3 n = normalize(gl_NormalMatrix * gl_Normal);" + $CRLF + _
                 "    vec3 t = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);" + $CRLF + _
                 "    vec3 b = cross(n, t) * gl_MultiTexCoord1.w;" + $CRLF + _
                 "" + $CRLF + _
                 "    mat3 tbnMatrix = mat3(t.x, b.x, n.x," + $CRLF + _
                 "                          t.y, b.y, n.y," + $CRLF + _
                 "                          t.z, b.z, n.z);" + $CRLF + _
                 "" + $CRLF + _
                 "    lightDir = gl_LightSource[0].position.xyz;" + $CRLF + _
                 "    lightDir = tbnMatrix * lightDir;" + $CRLF + _
                 "" + $CRLF + _
                 "    halfVector = gl_LightSource[0].halfVector.xyz;" + $CRLF + _
                 "    halfVector = tbnMatrix * halfVector;" + $CRLF + _
                 "}" + $CRLF + _
                 "" + $CRLF
       vertShader = CompileShader(%GL_VERTEX_SHADER, sBuffer, LEN(sBuffer))

       sBuffer = "" + $CRLF + _
                 "#version 110" + $CRLF + _
                 "" + $CRLF + _
                 "uniform sampler2D colorMap;" + $CRLF + _
                 "uniform sampler2D normalMap;" + $CRLF + _
                 "uniform float materialAlpha;" + $CRLF + _
                 "" + $CRLF + _
                 "varying vec3 lightDir;" + $CRLF + _
                 "varying vec3 halfVector;" + $CRLF + _
                 "" + $CRLF + _
                 "void main()" + $CRLF + _
                 "{" + $CRLF + _
                 "    vec3 n = normalize(texture2D(normalMap, gl_TexCoord[0].st).rgb * 2.0 - 1.0);" + $CRLF + _
                 "    vec3 l = normalize(lightDir);" + $CRLF + _
                 "    vec3 h = normalize(halfVector);" + $CRLF + _
                 "" + $CRLF + _
                 "    float nDotL = max(0.0, dot(n, l));" + $CRLF + _
                 "    float nDotH = max(0.0, dot(n, h));" + $CRLF + _
                 "    float power = (nDotL == 0.0) ? 0.0 : pow(nDotH, gl_FrontMaterial.shininess);" + $CRLF + _
                 "" + $CRLF + _
                 "    vec4 ambient = gl_FrontLightProduct[0].ambient;" + $CRLF + _
                 "    vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL;" + $CRLF + _
                 "    vec4 specular = gl_FrontLightProduct[0].specular * power;" + $CRLF + _
                 "    vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse + specular;" + $CRLF + _
                 "    " + $CRLF + _
                 "    gl_FragColor = color * texture2D(colorMap, gl_TexCoord[0].st);" + $CRLF + _
                 "    gl_FragColor.a = materialAlpha;" + $CRLF + _
                 "}" + $CRLF + _
                 "" + $CRLF
       fragShader = CompileShader(%GL_FRAGMENT_SHADER, sBuffer, LEN(sBuffer))

    END IF

'   // Now link the vertex and fragment shaders into a shader nProgram.
    IF (vertShader) AND (fragShader) THEN
        nProgram = LinkShaders(vertShader, fragShader)
    END IF

    FUNCTION = nProgram

END FUNCTION

FUNCTION WGLisExtensionSupported(BYVAL sExtToCheck AS STRING) AS LONG

    REGISTER nI AS LONG, nJ AS LONG
    LOCAL pszInfo AS ASCIIZ PTR
    LOCAL sAllExt AS STRING

    ' Get OpenGL extensions
    pszInfo = glGetString(%GL_EXTENSIONS)
    sAllExt = UCASE$( @pszInfo )

    sExtToCheck = UCASE$(sExtToCheck)

    LOCAL n, n2, nFound AS LONG

    n = PARSECOUNT(sExtToCheck, $SPC)
    n2 = PARSECOUNT(sAllExt, $SPC)
    DIM Token(1 TO n) AS STRING
    DIM Exts(1 TO n2) AS STRING

    PARSE sExtToCheck, Token(), $SPC
    PARSE sAllExt, Exts(), $SPC

    FOR nI = 1 TO n
       nFound = 0
       FOR nJ = 1 TO n2
           IF Token(nI) = Exts(nJ) THEN
              nFound = -1
              EXIT, EXIT
           END IF
       NEXT
    NEXT
    FUNCTION = nFound

END FUNCTION

SUB InitGL()

    g_hDC = GetDC(g_hWnd)
    IF g_hDC = 0 THEN MsgBox "GetDC() failed.": EXIT SUB

    LOCAL pf, msaaSamples AS LONG
    LOCAL pfd AS PIXELFORMATDESCRIPTOR
    LOCAL osvi AS OSVERSIONINFO

    pfd.nSize              = SIZEOF(pfd)
    pfd.nVersion           = 1
    pfd.dwFlags            = %PFD_DRAW_TO_WINDOW OR %PFD_SUPPORT_OPENGL OR %PFD_DOUBLEBUFFER
    pfd.iPixelType         = 0 ' PFD_TYPE_RGBA
    pfd.cColorBits         = 32
    pfd.cAlphaBits         = 1
    pfd.cDepthBits         = 16
    pfd.iLayerType         = 0 ' %PFD_MAIN_PLANE

    osvi.dwOSVersionInfoSize = SIZEOF(OSVERSIONINFO)
    IF GetVersionEx(osvi) THEN ' Check for VISTA and above
       IF osvi.dwPlatformId > 1 AND osvi.dwMajorVersion > 5 THEN pfd.dwFlags = pfd.dwFlags OR %PFD_SUPPORT_COMPOSITION
    END IF

    'ChooseBestMultiSampleAntiAliasingPixelFormat(pf, msaaSamples)

    IF pf = 0 THEN pf = ChoosePixelFormat(g_hDC, pfd)

    IF SetPixelFormat(g_hDC, pf, pfd) THEN
       g_hRC = wglCreateContext(g_hDC): IF g_hRC = 0 THEN MsgBox "wglCreateContext error.": EXIT SUB
       IF wglMakeCurrent(g_hDC, g_hRC) = 0 THEN MsgBox "wglMakeCurrent() failed.": EXIT SUB

       g_nSupportsProgrammablePipeline = GL2SupportsGLVersion(2, 0)

'      // Check for GL_EXT_texture_filter_anisotropic support.
       IF WGLisExtensionSupported("GL_EXT_texture_filter_anisotropic") THEN
          glGetFloatv(%GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, g_rMaxAnisotrophy)
       ELSE
          g_rMaxAnisotrophy = 1.0
       END IF

    END IF

END SUB

SUB Cleanup()
    IF (g_hDC) THEN
        IF (g_hRC) THEN
            wglMakeCurrent(g_hDC, 0)
            wglDeleteContext(g_hRC)
            g_hRC = 0
        END IF
        ReleaseDC(g_hWnd, g_hDC)
        g_hDC = 0
    END IF
END SUB

FUNCTION PBMAIN

   ' // Create the dialog
   DIALOG NEW PIXELS, 0, "Test GLSL", , , 300, 200, %WS_OVERLAPPEDWINDOW TO g_hWnd
   InitGL()

''''''''''''''''''''''''''
    g_nSupportsProgrammablePipeline = GL2SupportsGLVersion(2, 0)

    glEnable(%GL_TEXTURE_2D)
    glEnable(%GL_DEPTH_TEST)
    glEnable(%GL_CULL_FACE)
    glEnable(%GL_LIGHTING)
    glEnable(%GL_LIGHT0)

''''''''''''''''''''''
    glActiveTexture(%GL_TEXTURE1)
    glEnable(%GL_TEXTURE_2D)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_MAG_FILTER, %GL_LINEAR)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_MIN_FILTER, %GL_LINEAR_MIPMAP_LINEAR)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_WRAP_S, %GL_REPEAT)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_WRAP_T, %GL_REPEAT)

    glActiveTexture(%GL_TEXTURE0)
    glEnable(%GL_TEXTURE_2D)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_MAG_FILTER, %GL_LINEAR)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_MIN_FILTER, %GL_LINEAR_MIPMAP_LINEAR)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_WRAP_S, %GL_REPEAT)
    glTexParameteri(%GL_TEXTURE_2D, %GL_TEXTURE_WRAP_T, %GL_REPEAT)

    IF g_nSupportsProgrammablePipeline THEN
       g_nBlinnPhongShader = LoadShader(%SHADER_BLINN_PHONG)
       IF g_nBlinnPhongShader = 0 THEN MsgBox "Failed to load Blinn-Phong shader."

       g_nNormalMappingShader = LoadShader(%SHADER_NORMAL_MAPPING)
       IF g_nNormalMappingShader = 0 THEN MsgBox "Failed to load normal mapping shader."

    END IF

    Cleanup()

    MsgBox "Done"
END FUNCTION


Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

José Roca

The previous macros were replaced by the class CGLEXT, available in  CGLEXT.INC. I don 't like macros and the only reason I used them was because, at that time, there was not dead code removal.

Petr Schreiber

#4
Hi,

the code still runs fine for me with PB9 and Josés glExt.inc from 7.7.2010, signature below:
Quote
'/* Header file version number, required by OpenGL ABI for Linux */
'/* glext.h last updated $Date: 2010-06-15 23:46:28 -0700 (Tue, 15 Jun 2010) $ */
'/* Current version at http://www.opengl.org/registry/ *

It displays two triangles nicely.

I am porting it to PB10 now, will post once ready, so far I got the new version to compile but it GPFs  :'(

I think the definition for glShader should be this, instead what it is now (changed asciiz to string, in the docs it is char**):
glext.inc
Quote
SUB glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF szSource AS STRING, BYREF nLength AS LONG)   

cglext.inc
Quote
   ' =====================================================================================
   ' Replaces the source code in a shader object.
   ' void glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
   ' =====================================================================================
   METHOD glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF sSource AS STRING, BYREF nLength AS LONG)
      LOCAL pProc AS DWORD
      pProc = wglGetProcAddress("glShaderSource")
      IF pProc = 0 THEN METHOD OBJRESULT = &H8007007F& : EXIT METHOD
      CALL DWORD pProc USING glShaderSource(dwShader, nCount, sSource, nLength)
   END METHOD
   ' =====================================================================================


Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Patrice Terrier

#5
Petr,

The code i have posted, also GPF when using your script, and i couldn't get it to compile when using mine :(

I shall try using PB 9.05 to see if it makes any difference.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Petr Schreiber

Hi Patrice,

I found out the primary GPF reason was the changed glShaderSource definition - I think there should be BYREF STRING as in PB9 instead of BYREF ASCIIZ.

But there are more GPFs later too, examining...


Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Petr Schreiber

#7
Got it working in PB10!

I did some changes to the main code to reflect enhancements by José.
But it is still needed to change glShaderSource definition to make it work:

In glext.inc
Quote
DECLARE SUB glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF szSource AS STRING, BYREF nLength AS LONG)   

In cglext.inc
Quote
' =====================================================================================
   ' Replaces the source code in a shader object.
   ' void glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
   ' =====================================================================================
   METHOD glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF sSource AS STRING, BYREF nLength AS LONG)
      LOCAL pProc AS DWORD
      pProc = wglGetProcAddress("glShaderSource")
      IF pProc = 0 THEN METHOD OBJRESULT = &H8007007F& : EXIT METHOD
      CALL DWORD pProc USING glShaderSource(dwShader, nCount, sSource, nLength)
   END METHOD
   ' =====================================================================================
I attach the code for you.

Tested on GeForce G210M with 301.42 driver (the latest at the time of this post). The drivers are giving me headache with OpenCL lately, this one is good for both OpenGL/OpenCL.


Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Patrice Terrier

Yes, i confirm that there is a problem with the new declaration

using this one:
QuoteDECLARE SUB myglShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, sString AS STRING, nLength AS DWORD)

I am able to compile the shader correctly ...


Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

#9
Petr

Cross post, we both come to the same conclusion (except that i am using dword and you long for the last nLength parameter).

:)

Added:
I am not using Class myself, but full flat API for the GLEXT but the result is the same.
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Petr Schreiber

:)

I am happy. The last parameter shoud be LONG according to OpenGL specification, because you should be able to pass even negative value, see here:
http://www.opengl.org/sdk/docs/man/xhtml/glShaderSource.xml

José, do you think you could add this change to your headers in next release? It would be very much appreciated!


Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Patrice Terrier

#11
Petr

Yes, i agree that the last parameter should be long.

By the way my OBJ model loader is working great now, the last problem i have to solve is how to handle correctly some transparent TGA textures.

See attached screen shot.
(this one is drawn in programmable pipeline mode.)
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Petr Schreiber

Hi Patrice,

very nice! The thing is whether to focus on GLSL as main shading language, or use CG, which is both for OpenGL and Direct3D + thanks to various profiles scales better for Intel based GPUs.


Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Patrice Terrier

For those like myself, who prefer to use the Flat API, see the full GLEXT.inc inside of the attached ZIP file.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

José Roca

In GLExt.inc I have changed:


DECLARE SUB glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF strings AS STRING, BYREF nLength AS LONG)
DECLARE SUB glShaderSourceARB (BYVAL shaderObj AS DWORD, BYVAL nCount AS LONG, BYREF strings AS STRING, BYREF nLength AS LONG)
DECLARE FUNCTION glCreateShaderProgramv(BYVAL dwType AS DWORD, BYVAL dwCount AS DWORD, BYREF strings AS STRING) AS DWORD


and in CGLExt.inc


   ' =====================================================================================
   ' Replaces the source code in a shader object.
   ' void glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
   ' =====================================================================================
   METHOD glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF strings AS STRING, BYREF nLength AS LONG)
      LOCAL pProc AS DWORD
      pProc = wglGetProcAddress("glShaderSource")
      IF pProc = 0 THEN METHOD OBJRESULT = &H8007007F& : EXIT METHOD
      CALL DWORD pProc USING glShaderSource(dwShader, nCount, strings, nLength)
   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' void glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
   ' =====================================================================================
   METHOD glShaderSourceARB (BYVAL shaderObj AS DWORD, BYVAL nCount AS LONG, BYREF strings AS STRING, BYREF nLength AS LONG)
      LOCAL pProc AS DWORD
      pProc = wglGetProcAddress("glShaderSourceARB")
      IF pProc = 0 THEN METHOD OBJRESULT = &H8007007F& : EXIT METHOD
      CALL DWORD pProc USING glShaderSourceARB(shaderObj, nCount, strings, nLength)
   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' GLuint glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar* *strings);
   ' =====================================================================================
   METHOD glCreateShaderProgramv (BYVAL dwType AS DWORD, BYVAL dwCount AS DWORD, BYREF strings AS STRING) AS DWORD
      LOCAL dwRes AS DWORD
      LOCAL pProc AS DWORD
      pProc = wglGetProcAddress("glCreateShaderProgramv")
      IF pProc = 0 THEN METHOD OBJRESULT = &H8007007F& : EXIT METHOD
      CALL DWORD pProc USING glCreateShaderProgramv(dwType, dwCount, strings) TO dwRes
      METHOD = dwRes
   END METHOD
   ' =====================================================================================