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 (http://www.opengl.org/wiki/Tutorial:_OpenGL_3.1_The_First_Triangle_%28C%2B%2B/Win%29).
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 (http://www.jose.it-berater.org/smfforum/index.php?topic=3189.msg10178#msg10178) with updated glext.inc (http://www.jose.it-berater.org/smfforum/index.php?topic=3189.msg10815#msg10815).
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 )
PetrEDIT: Added version for PB/Win 10, but you need to use Josés Windows API Headers III v.1.04 or newer
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.
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
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.
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.incQuote
SUB glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF szSource AS STRING, BYREF nLength AS LONG)
cglext.incQuote
' =====================================================================================
' 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
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.
...
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
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.incQuote
DECLARE SUB glShaderSource (BYVAL dwShader AS DWORD, BYVAL nCount AS LONG, BYREF szSource AS STRING, BYREF nLength AS LONG)
In cglext.incQuote
' =====================================================================================
' 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
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 ...
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.
:)
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
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.)
Hi Patrice,
very nice! The thing is whether to focus on GLSL as main shading language, or use CG (http://developer.nvidia.com/cg-toolkit), which is both for OpenGL and Direct3D + thanks to various profiles scales better for Intel based GPUs.
Petr
For those like myself, who prefer to use the Flat API, see the full GLEXT.inc inside of the attached ZIP file.
...
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
' =====================================================================================
Patrice, the class allows to check OBJRESULT to know if the call has succeeded. It returns ERROR_PROC_NOT_FOUND (&H8007007F&) if the extension does not exist. Using SUBs, you can't return an error code and you need to check if the exten sion exists before calling it.
José
I am also checking if the extension exist with the Flat API, but i am not returning an error, because i check first for the requested OpenGL version.
...
Thank you very much José!
Petr