PDA

View Full Version : OpenGL



José Roca
08-06-2011, 20:02
The next update of my headers will have several pleasant surprises. There are two that will please Petr: an wrapper class for OpenGL extensions with 1938 methods updated to OpenGL 4.1 and a resizable, scrollable, stretchable, persistent, flicker free OpenGL control that supports mixing GDI, GDI+ and OpenGL.

Being an standard Windows control, you can have multiple instances of it in your application, and you can have menus, toolbars and any other control.

This code produces the attached zipped executable.



' ########################################################################################
' Microsoft Windows
' File: GLCTX_SpinningTriangle.bas
' Contents: OpenGL example
' Description: Renders a spinning colored triangle controlled with both the TIMER function and the mouse.
' This version uses the CWindow class and the GlCtx graphic control
' Compilers: PBWIN 10+, PBCC 6+
' Headers: Windows API headers 2.02+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from ogl_primitive_types.cpp, by Kevin Harris, 1 Feb 2005,
' downloadable at http://www.codesampler.com/oglsrc/oglsrc_1.htm#ogl_primitive_types
' ########################################################################################

#COMPILE EXE
#DIM ALL
%UNICODE = 1

' // Header files for imported files
%USEGLCTX = 1
#INCLUDE ONCE "CWindow.inc" ' // CWindow class
#INCLUDE ONCE "GlCtx.inc" ' // OpenGL control

$WindowCaption = "OpenGL - Spinning Triangle"

%IDC_GLCTX = 1001

GLOBAL pGL AS ISpinningTrianle

' =======================================================================================
' Spinning triangle class
' =======================================================================================
CLASS CSpinningTrianle

INTERFACE ISpinningTrianle : INHERIT IUnknown

' ====================================================================================
' All the setup goes here
' ====================================================================================
METHOD SetupScene
' // Specify clear values for the color buffers
glClearColor 0.0!, 0.0!, 0.0!, 0.0!
END METHOD
' ====================================================================================

' ====================================================================================
' Resizes the scene
' ====================================================================================
METHOD ResizeScene (BYVAL hCtl AS DWORD)
' // Get the dimensions of the window
LOCAL nWidth, nHeight AS LONG
AfxGetWindowSize(hCtl, nWidth, nHeight)
' // 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
glMatrixMode %GL_PROJECTION
' // Reset the projection matrix
glLoadIdentity
' // Calculate the aspect ratio of the window
gluPerspective 65.0!, nWidth / nHeight, 1.0!, 100.0!
' // Select the model view matrix
glMatrixMode %GL_MODELVIEW
' // Reset the model view matrix
glLoadIdentity
END METHOD
' ====================================================================================

' ====================================================================================
' Draws the scene
' ====================================================================================
METHOD DrawScene (BYVAL hCtl AS DWORD)

' // Get the dimensions of the window
LOCAL nWidth, nHeight AS LONG
AfxGetWindowSize(hCtl, nWidth, nHeight)

LOCAL pt AS POINTAPI
LOCAL t AS DOUBLE

GetCursorPos pt
t = TIMER

glClear %GL_COLOR_BUFFER_BIT

' // Select and setup the modelview matrix
glMatrixMode %GL_MODELVIEW
glLoadIdentity
gluLookAt 0.0!, 1.0!, 0.0!, _ ' Eye-position
0.0!, 20.0!, 0.0!, _ ' View-point
0.0!, 0.0!, 1.0! ' Up-vector

' // Draw a rotating colorful triangle
glTranslatef 0.0!, 14.0!, 0.0!
glRotatef 0.3! * pt.x + t * 100.0!, 0.0!, 0.0!, 1.0!
glBegin %GL_TRIANGLES
glColor3f 1.0!, 0.0!, 0.0!
glVertex3f -5.0!, 0.0!, -4.0!
glColor3f 0.0!, 1.0!, 0.0!
glVertex3f 5.0!, 0.0!, -4.0!
glColor3f 0.0!, 0.0!, 1.0!
glVertex3f 0.0!, 0.0!, 6.0!
glEnd

' // Required: Force execution of GL commands in finite time
glFlush

' // Required: Force repainting of the control
InvalidateRect hCtl, BYVAL %NULL, %TRUE

END METHOD
' ====================================================================================

' ====================================================================================
' Processes keystrokes
' Parameters:
' * hwnd = Window hande
' * vKeyCode = Virtual key code
' * bKeyDown = %TRUE if key is pressed; %FALSE if it is released
' ====================================================================================
METHOD 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 METHOD
' ====================================================================================

END INTERFACE

END CLASS
' =======================================================================================

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

' // Create an instance of the CWindow class
LOCAL pWindow AS IWindow
pWindow = CLASS "CWindow"
IF ISNOTHING(pWindow) THEN EXIT FUNCTION

' // Create the main window
LOCAL hwnd AS DWORD
hwnd = pWindow.CreateWindow(%NULL, "CWindow with a OpenGL Graphic Control", 0, 0, 600, 400, 0, 0, CODEPTR(WindowProc))
' // Center the window
pWindow.CenterWindow

' // Create an instance of the OpenGL lesson class
pGL = CLASS "CSpinningTrianle"
IF ISNOTHING(pGL) THEN EXIT FUNCTION

' // Add an OpenGL aware graphic control
LOCAL hCtl AS DWORD
hCtl = pWindow.AddGlCtx(hwnd, %IDC_GLCTX, "", 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
GlCtx_SetResizable hCtl, %TRUE ' // Make the control resizable

' // Show the window
ShowWindow hwnd, nCmdShow
UpdateWindow hwnd

' // Process Windows messages
LOCAL bDone AS LONG
LOCAL vKeyCode AS LONG
LOCAL bKeyDown AS LONG
LOCAL msg AS tagMSG

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

' // Calculate and display the number of frames per second
LOCAL t AS DOUBLE
LOCAL t0 AS DOUBLE
LOCAL fps AS DOUBLE
LOCAL nFrames AS LONG
LOCAL szCaption AS WSTRINGZ * 256

t = INT(TIMER)
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

' // Draw the scene
pGL.DrawScene(hCtl)

' // Process the keystrokes
IF vKeyCode THEN
pGL.ProcessKeystrokes(hwnd, vKeyCode, bKeyDown)
vKeyCode = 0
END IF

LOOP

FUNCTION = msg.wParam

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

' ========================================================================================
' Main callback function.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

SELECT CASE uMsg

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

CASE %WM_SIZE
' // If the window isn't minimized, resize it
LOCAL hCtl AS DWORD
hCtl = GetDlgItem(hwnd, %IDC_GLCTX)
IF wParam <> %SIZE_MINIMIZED THEN
' // Resize the control
MoveWindow hCtl, 0, 0, AfxGetWindowClientWidth(hwnd), AfxGetWindowClientHeight(hwnd), %TRUE
' // Resize and render the OpenGL scene
pGL.SetupScene ' // Setup the scene
pGL.ResizeScene(hCtl) ' // Resize the scene
pGL.DrawScene(hCtl) ' // Draw the scene
END IF

CASE %WM_DESTROY
' // End the application
PostQuitMessage 0
EXIT FUNCTION

END SELECT

' // Pass unprocessed messages to Windows
FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

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

Petr Schreiber
08-06-2011, 21:03
José,

you are magician! Thank you very much for your incredible work!


Petr

José Roca
08-06-2011, 21:15
Run the executable and resize it. No flicker, no blackouts, no buffer swapping... I'm using DIBs and double buffering.

Petr Schreiber
08-06-2011, 21:42
It works great and draws fast. I think I have new source for study :drink:

Petr

José Roca
08-06-2011, 22:24
I'm using classes now. It allows to use instance variables instead of globals, which is very useful when using more than one instance of the control. This way, we just need a global, that holds a reference to the class, for each instance of the control.