This shows how to cast stencil shadows.
Press Arrows to rotate object, U,I,O,J,K,L Keys to move light, Numpad 7,8,9,4,5,6 Keys to move object, Q,W,E,A,S,D Keys to move sphere.
You can get the "Object2.txt", "Object.txt", "Object1.txt", "SimpleObject.txt" from the "lesson27.zip" here:
http://nehe.gamedev.net/data/lessons/vc/lesson27.zip
Last edited on 20 Feb 2007.
Code: Select all
;Banu Octavian & NeHe's Shadow Casting Tutorial (Lesson 27)
;http://nehe.gamedev.net
;Credits: Nico Gruener, Dreglor, traumatic
;Author: hagibaba
;Date: 12 Jan 2007
;Note: up-to-date with PB v4.02 (Windows)
;Note: requires a vertex data text file in path "Data/Object2.txt"
;Alternative files to try "Object.txt", "Object1.txt", "SimpleObject.txt"
;Section for standard constants, structures, macros and declarations
XIncludeFile #PB_Compiler_Home+"Examples\Sources - Advanced\OpenGL Cube\OpenGL.pbi" ;include the gl.h constants
;wingdi.h constants
#DM_BITSPERPEL=$40000
#DM_PELSWIDTH=$80000
#DM_PELSHEIGHT=$100000
;winuser.h constants
#CDS_FULLSCREEN=4
#DISP_CHANGE_SUCCESSFUL=0
#SC_MONITORPOWER=$F170
Procedure.w LoWord(value.l) ;windef.h macro
ProcedureReturn (value & $FFFF)
EndProcedure
Procedure.w HiWord(value.l) ;windef.h macro
ProcedureReturn ((value >> 16) & $FFFF)
EndProcedure
Import "glu32.lib"
gluPerspective(fovy.d,aspect.d,zNear.d,zFar.d) ;sets up a perspective projection matrix
gluSphere(*qobj,radius.d,slices.l,stacks.l) ;draws a sphere
EndImport
Import "opengl32.lib"
glClearDepth(depth.d) ;specifies the clear value for the depth buffer
EndImport
;Start of Lesson 27
XIncludeFile "3dobject.pb" ;Include File For 3D Object Handling
Global hDC.l ;Private GDI Device Context
Global hRC.l ;Permanent Rendering Context
Global hWnd.l ;Holds Our Window Handle
Global hInstance.l ;Holds The Instance Of The Application
Global Dim keys.b(256) ;Array Used For The Keyboard Routine
Global active.b=#True ;Window Active Flag Set To TRUE By Default
Global fullscreen.b=#True ;Fullscreen Flag Set To Fullscreen Mode By Default
Global obj.SHADOWEDOBJECT ;Object
Global xrot.f=0,xspeed.f=0 ;X Rotation & X Speed
Global yrot.f=0,yspeed.f=0 ;Y Rotation & Y Speed
Global Dim LightPos.f(4) ;Light Position
LightPos(0)= 0.0 : LightPos(1)= 5.0 : LightPos(2)=-4.0 : LightPos(3)= 1.0
Global Dim LightAmb.f(4) ;Ambient Light Values
LightAmb(0)= 0.2 : LightAmb(1)= 0.2 : LightAmb(2)= 0.2 : LightAmb(3)= 1.0
Global Dim LightDif.f(4) ;Diffuse Light Values
LightDif(0)= 0.6 : LightDif(1)= 0.6 : LightDif(2)= 0.6 : LightDif(3)= 1.0
Global Dim LightSpc.f(4) ;Specular Light Values
LightSpc(0)=-0.2 : LightSpc(1)=-0.2 : LightSpc(2)=-0.2 : LightSpc(3)= 1.0
Global Dim MatAmb.f(4) ;Material - Ambient Values
MatAmb(0)= 0.4 : MatAmb(1)= 0.4 : MatAmb(2)= 0.4 : MatAmb(3)= 1.0
Global Dim MatDif.f(4) ;Material - Diffuse Values
MatDif(0)= 0.2 : MatDif(1)= 0.6 : MatDif(2)= 0.9 : MatDif(3)= 1.0
Global Dim MatSpc.f(4) ;Material - Specular Values
MatSpc(0)= 0.0 : MatSpc(1)= 0.0 : MatSpc(2)= 0.0 : MatSpc(3)= 1.0
Global Dim MatShn.f(1) ;Material - Shininess
MatShn(0)= 0.0
Global Dim ObjPos.f(3) ;Object Position
ObjPos(0)=-2.0 : ObjPos(1)=-2.0 : ObjPos(2)=-5.0
Global q.l ;Quadratic For Drawing A Sphere
Global Dim SpherePos.f(3) ;Sphere Position
SpherePos(0)=-4.0 : SpherePos(1)=-5.0 : SpherePos(2)=-6.0
Declare.l WndProc(hWnd.l,uMsg.l,wParam.l,lParam.l) ;Declaration For WndProc
Procedure VMatMult(Array M.f(1), Array v.f(1))
Protected Dim res.f(4) ;Hold Calculated Results
res(0)=M( 0)*v(0)+M( 4)*v(1)+M( 8)*v(2)+M(12)*v(3)
res(1)=M( 1)*v(0)+M( 5)*v(1)+M( 9)*v(2)+M(13)*v(3)
res(2)=M( 2)*v(0)+M( 6)*v(1)+M(10)*v(2)+M(14)*v(3)
res(3)=M( 3)*v(0)+M( 7)*v(1)+M(11)*v(2)+M(15)*v(3)
v(0)=res(0) ;Results Are Stored Back In v()
v(1)=res(1)
v(2)=res(2)
v(3)=res(3) ;Homogenous Coordinate
EndProcedure
Procedure ReSizeGLScene(width.l,height.l) ;Resize And Initialize The GL Window
If height=0 : height=1 : EndIf ;Prevent A Divide By Zero Error
glViewport_(0,0,width,height) ;Reset The Current Viewport
glMatrixMode_(#GL_PROJECTION) ;Select The Projection Matrix
glLoadIdentity_() ;Reset The Projection Matrix
gluPerspective(45.0,Abs(width/height),0.001,100.0) ;Calculate The Aspect Ratio Of The Window
glMatrixMode_(#GL_MODELVIEW) ;Select The Modelview Matrix
glLoadIdentity_() ;Reset The Modelview Matrix
EndProcedure
Procedure.l InitGLObjects() ;Initialize Objects
If readObject("Data/Object2.txt",obj)=0 ;Read Object2 Into obj
ProcedureReturn #False ;If Failed Return False
EndIf
setConnectivity(obj) ;Set Face To Face Connectivity
Protected i.l
For i=0 To obj\nFaces-1 ;Loop Through All Object Planes
calculatePlane(obj,i) ;Compute Plane Equations For All Faces
Next
ProcedureReturn #True ;Return True
EndProcedure
Procedure KillGLObjects()
killObject(obj) ;Delete The Object
gluDeleteQuadric_(q) ;Delete The Quadratic
EndProcedure
Procedure.l InitGL() ;All Setup For OpenGL Goes Here
If InitGLObjects()=0 ;Function For Initializing Our Object(s)
ProcedureReturn #False
EndIf
glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
glClearColor_(0.0,0.0,0.0,0.5) ;Black Background
glClearDepth(1.0) ;Depth Buffer Setup
glClearStencil_(0) ;Stencil Buffer Setup
glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
glDepthFunc_(#GL_LEQUAL) ;The Type Of Depth Testing To Do
glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
glLightfv_(#GL_LIGHT1,#GL_POSITION,LightPos()) ;Set Light1 Position
glLightfv_(#GL_LIGHT1,#GL_AMBIENT,LightAmb()) ;Set Light1 Ambience
glLightfv_(#GL_LIGHT1,#GL_DIFFUSE,LightDif()) ;Set Light1 Diffuse
glLightfv_(#GL_LIGHT1,#GL_SPECULAR,LightSpc()) ;Set Light1 Specular
glEnable_(#GL_LIGHT1) ;Enable Light1
glEnable_(#GL_LIGHTING) ;Enable Lighting
glMaterialfv_(#GL_FRONT,#GL_AMBIENT,MatAmb()) ;Set Material Ambience
glMaterialfv_(#GL_FRONT,#GL_DIFFUSE,MatDif()) ;Set Material Diffuse
glMaterialfv_(#GL_FRONT,#GL_SPECULAR,MatSpc()) ;Set Material Specular
glMaterialfv_(#GL_FRONT,#GL_SHININESS,MatShn()) ;Set Material Shininess
glCullFace_(#GL_BACK) ;Set Culling Face To Back Face
glEnable_(#GL_CULL_FACE) ;Enable Culling
glClearColor_(0.1,1.0,0.5,1.0) ;Set Clear Color (Greenish Color)
q=gluNewQuadric_() ;Initialize Quadratic
gluQuadricNormals_(q,#GL_SMOOTH) ;Enable Smooth Normal Generation
gluQuadricTexture_(q,#GL_FALSE) ;Disable Auto Texture Coords
ProcedureReturn #True ;Initialization Went OK
EndProcedure
Procedure DrawGLRoom() ;Draw The Room (Box)
glBegin_(#GL_QUADS) ;Begin Drawing Quads
;Floor
glNormal3f_(0.0, 1.0, 0.0) ;Normal Pointing Up
glVertex3f_(-10.0,-10.0,-20.0) ;Back Left
glVertex3f_(-10.0,-10.0, 20.0) ;Front Left
glVertex3f_( 10.0,-10.0, 20.0) ;Front Right
glVertex3f_( 10.0,-10.0,-20.0) ;Back Right
;Ceiling
glNormal3f_(0.0,-1.0, 0.0) ;Normal Point Down
glVertex3f_(-10.0, 10.0, 20.0) ;Front Left
glVertex3f_(-10.0, 10.0,-20.0) ;Back Left
glVertex3f_( 10.0, 10.0,-20.0) ;Back Right
glVertex3f_( 10.0, 10.0, 20.0) ;Front Right
;Front Wall
glNormal3f_(0.0, 0.0, 1.0) ;Normal Pointing Away From Viewer
glVertex3f_(-10.0, 10.0,-20.0) ;Top Left
glVertex3f_(-10.0,-10.0,-20.0) ;Bottom Left
glVertex3f_( 10.0,-10.0,-20.0) ;Bottom Right
glVertex3f_( 10.0, 10.0,-20.0) ;Top Right
;Back Wall
glNormal3f_(0.0, 0.0,-1.0) ;Normal Pointing Towards Viewer
glVertex3f_( 10.0, 10.0, 20.0) ;Top Right
glVertex3f_( 10.0,-10.0, 20.0) ;Bottom Right
glVertex3f_(-10.0,-10.0, 20.0) ;Bottom Left
glVertex3f_(-10.0, 10.0, 20.0) ;Top Left
;Left Wall
glNormal3f_(1.0, 0.0, 0.0) ;Normal Pointing Right
glVertex3f_(-10.0, 10.0, 20.0) ;Top Front
glVertex3f_(-10.0,-10.0, 20.0) ;Bottom Front
glVertex3f_(-10.0,-10.0,-20.0) ;Bottom Back
glVertex3f_(-10.0, 10.0,-20.0) ;Top Back
;Right Wall
glNormal3f_(-1.0, 0.0, 0.0) ;Normal Pointing Left
glVertex3f_( 10.0, 10.0,-20.0) ;Top Back
glVertex3f_( 10.0,-10.0,-20.0) ;Bottom Back
glVertex3f_( 10.0,-10.0, 20.0) ;Bottom Front
glVertex3f_( 10.0, 10.0, 20.0) ;Top Front
glEnd_() ;Done Drawing Quads
EndProcedure
Procedure.l DrawGLScene() ;Main Drawing Routine
Protected Dim Minv.f(16)
Protected Dim wlp.f(4)
Protected Dim lp.f(4)
;Clear Color Buffer, Depth Buffer, Stencil Buffer
glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT | #GL_STENCIL_BUFFER_BIT);
glLoadIdentity_() ;Reset Modelview Matrix
glTranslatef_( 0.0, 0.0,-20.0) ;Zoom Into Screen 20 Units
glLightfv_(#GL_LIGHT1,#GL_POSITION,LightPos()) ;Position Light1
glTranslatef_(SpherePos(0),SpherePos(1),SpherePos(2)) ;Position The Sphere
gluSphere(q,1.5,32,16) ;Draw A Sphere
;Calculate light's position relative to local coordinate system
;Dunno if this is the best way to do it, but it actually works
glLoadIdentity_() ;Reset Modelview Matrix
glRotatef_(-yrot,0.0,1.0,0.0) ;Rotate By -yrot On Y Axis
glRotatef_(-xrot,1.0,0.0,0.0) ;Rotate By -xrot On X Axis
glGetFloatv_(#GL_MODELVIEW_MATRIX,Minv()) ;Retrieve ModelView Matrix (Stores In Minv)
lp(0)=LightPos(0) ;Store Light Position X In lp[0]
lp(1)=LightPos(1) ;Store Light Position Y In lp[1]
lp(2)=LightPos(2) ;Store Light Position Z In lp[2]
lp(3)=LightPos(3) ;Store Light Direction In lp[3]
VMatMult(Minv(),lp()) ;We Store Rotated Light Vector In 'lp' Array
glTranslatef_(-ObjPos(0),-ObjPos(1),-ObjPos(2)) ;Move Negative On All Axis Based On ObjPos[] Values (X, Y, Z)
glGetFloatv_(#GL_MODELVIEW_MATRIX,Minv()) ;Retrieve ModelView Matrix From Minv
wlp(0)=0.0 ;World Local Coord X To 0
wlp(1)=0.0 ;World Local Coord Y To 0
wlp(2)=0.0 ;World Local Coord Z To 0
wlp(3)=1.0
VMatMult(Minv(),wlp()) ;We Store The Position Of The World Origin Relative To The Local Coord. System In 'wlp' Array
lp(0)+wlp(0) ;Adding These Two Gives Us The
lp(1)+wlp(1) ;Position Of The Light Relative To
lp(2)+wlp(2) ;The Local Coordinate System
glLoadIdentity_() ;Reset Modelview Matrix
glTranslatef_( 0.0, 0.0,-20.0) ;Zoom Into The Screen 20 Units
DrawGLRoom() ;Draw The Room
glTranslatef_(ObjPos(0),ObjPos(1),ObjPos(2)) ;Position The Object
glRotatef_(xrot,1.0,0.0,0.0) ;Spin It On The X Axis By xrot
glRotatef_(yrot,0.0,1.0,0.0) ;Spin It On The Y Axis By yrot
drawObject(obj) ;Procedure For Drawing The Loaded Object
castShadow(obj,lp()) ;Procedure For Casting The Shadow Based On The Silhouette
glColor4f_(0.7,0.4,0.0,1.0) ;Set Color To An Orange
glDisable_(#GL_LIGHTING) ;Disable Lighting
glDepthMask_(#GL_FALSE) ;Disable Depth Mask
glTranslatef_(lp(0),lp(1),lp(2)) ;Translate To Light's Position (Notice We're Still In Local Coordinate System)
gluSphere(q,0.2,16,8) ;Draw A Little Yellow Sphere (Represents Light)
glEnable_(#GL_LIGHTING) ;Enable Lighting
glDepthMask_(#GL_TRUE) ;Enable Depth Mask
xrot+xspeed ;Increase xrot By xspeed
yrot+yspeed ;Increase yrot By yspeed
glFlush_() ;Flush The OpenGL Pipeline
ProcedureReturn #True ;Everything Went OK
EndProcedure
Procedure ProcessKeyboard() ;Process Key Presses
;Spin Object
If keys(#VK_LEFT) And yspeed>-2.5
yspeed-0.1 ;'Arrow Left' Decrease yspeed
EndIf
If keys(#VK_RIGHT) And yspeed<2.5
yspeed+0.1 ;'Arrow Right' Increase yspeed
EndIf
If keys(#VK_UP) And xspeed>-2.5
xspeed-0.1 ;'Arrow Up' Decrease xspeed
EndIf
If keys(#VK_DOWN) And xspeed<2.5
xspeed+0.1 ;'Arrow Down' Increase xspeed
EndIf
;Adjust Light's Position (U,I,O,J,K,L Keys)
If keys(#VK_L)
LightPos(0)+0.05 ;'L' Moves Light Right
EndIf
If keys(#VK_J)
LightPos(0)-0.05 ;'J' Moves Light Left
EndIf
If keys(#VK_I)
LightPos(1)+0.05 ;'I' Moves Light Up
EndIf
If keys(#VK_K)
LightPos(1)-0.05 ;'K' Moves Light Down
EndIf
If keys(#VK_O)
LightPos(2)+0.05 ;'O' Moves Light Toward Viewer
EndIf
If keys(#VK_U)
LightPos(2)-0.05 ;'U' Moves Light Away From Viewer
EndIf
;Adjust Object's Position (Numpad 7,8,9,4,5,6 Keys)
If keys(#VK_NUMPAD6)
ObjPos(0)+0.05 ;'Numpad6' Move Object Right
EndIf
If keys(#VK_NUMPAD4)
ObjPos(0)-0.05 ;'Numpad4' Move Object Left
EndIf
If keys(#VK_NUMPAD8)
ObjPos(1)+0.05 ;'Numpad8' Move Object Up
EndIf
If keys(#VK_NUMPAD5)
ObjPos(1)-0.05 ;'Numpad5' Move Object Down
EndIf
If keys(#VK_NUMPAD9)
ObjPos(2)+0.05 ;'Numpad9' Move Object Toward Viewer
EndIf
If keys(#VK_NUMPAD7)
ObjPos(2)-0.05 ;'Numpad7' Move Object Away From Viewer
EndIf
;Adjust Ball's Position (Q,W,E,A,S,D Keys)
If keys(#VK_D)
SpherePos(0)+0.05 ;'D' Move Ball Right
EndIf
If keys(#VK_A)
SpherePos(0)-0.05 ;'A' Move Ball Left
EndIf
If keys(#VK_W)
SpherePos(1)+0.05 ;'W' Move Ball Up
EndIf
If keys(#VK_S)
SpherePos(1)-0.05 ;'S' Move Ball Down
EndIf
If keys(#VK_E)
SpherePos(2)+0.05 ;'E' Move Ball Toward Viewer
EndIf
If keys(#VK_Q)
SpherePos(2)-0.05 ;'Q' Move Ball Away From Viewer
EndIf
EndProcedure
Procedure KillGLWindow() ;Properly Kill The Window
KillGLObjects()
If fullscreen ;Are We In Fullscreen Mode?
ChangeDisplaySettings_(#Null,0) ;If So Switch Back To The Desktop
ShowCursor_(#True) ;Show Mouse Pointer
EndIf
If hRC ;Do We Have A Rendering Context?
If wglMakeCurrent_(#Null,#Null)=0 ;Are We Able To Release The DC And RC Contexts?
MessageBox_(#Null,"Release Of DC And RC Failed.","SHUTDOWN ERROR",#MB_OK | #MB_ICONINFORMATION)
EndIf
If wglDeleteContext_(hRC)=0 ;Are We Able To Delete The RC?
MessageBox_(#Null,"Release Rendering Context Failed.","SHUTDOWN ERROR",#MB_OK | #MB_ICONINFORMATION)
EndIf
hRC=#Null ;Set RC To NULL
EndIf
If hDC And ReleaseDC_(hWnd,hDC)=0 ;Are We Able To Release The DC
MessageBox_(#Null,"Release Device Context Failed.","SHUTDOWN ERROR",#MB_OK | #MB_ICONINFORMATION)
hDC=#Null ;Set DC To NULL
EndIf
If hWnd And DestroyWindow_(hWnd)=0 ;Are We Able To Destroy The Window?
MessageBox_(#Null,"Could Not Release hWnd.","SHUTDOWN ERROR",#MB_OK | #MB_ICONINFORMATION)
hWnd=#Null ;Set hWnd To NULL
EndIf
If UnregisterClass_("OpenGL",hInstance)=0 ;Are We Able To Unregister Class
MessageBox_(#Null,"Could Not Unregister Class.","SHUTDOWN ERROR",#MB_OK | #MB_ICONINFORMATION)
hInstance=#Null ;Set hInstance To NULL
EndIf
EndProcedure
;This Code Creates Our OpenGL Window. Parameters Are:
;title - Title To Appear At The Top Of The Window
;width - Width Of The GL Window Or Fullscreen Mode
;height - Height Of The GL Window Or Fullscreen Mode
;bits - Number Of Bits To Use For Color (8/16/24/32)
;fullscreenflag - Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)
Procedure.b CreateGLWindow(title.s,width.l,height.l,bits.l,fullscreenflag.b)
Protected PixelFormat.l ;Holds The Results After Searching For A Match
Protected wc.WNDCLASS ;Windows Class Structure
Protected dwExStyle.l ;Window Extended Style
Protected dwStyle.l ;Window Style
Protected WindowRect.RECT ;Grabs Rectangle Upper Left / Lower Right Values
Protected wpos.POINT ;Window position
WindowRect\left=0 ;Set Left Value To 0
WindowRect\right=width ;Set Right Value To Requested Width
WindowRect\top=0 ;Set Top Value To 0
WindowRect\bottom=height ;Set Bottom Value To Requested Height
fullscreen=fullscreenflag ;Set The Global Fullscreen Flag
hInstance=GetModuleHandle_(#Null) ;Grab An Instance For Our Window
wc\style=#CS_HREDRAW | #CS_VREDRAW | #CS_OWNDC ;Redraw On Size, And Own DC For Window
wc\lpfnWndProc=@WndProc() ;WndProc Handles Messages
wc\cbClsExtra=0 ;No Extra Window Data
wc\cbWndExtra=0 ;No Extra Window Data
wc\hInstance=hInstance ;Set The Instance
wc\hIcon=LoadIcon_(#Null,#IDI_WINLOGO) ;Load The Default Icon
wc\hCursor=LoadCursor_(#Null,#IDC_ARROW) ;Load The Arrow Pointer
wc\hbrBackground=#Null ;No Background Required For GL
wc\lpszMenuName=#Null ;We Don't Want A Menu
wc\lpszClassName=@"OpenGL" ;Set The Class Name
If RegisterClass_(wc)=0 ;Attempt To Register The Window Class
MessageBox_(#Null,"Failed To Register The Window Class.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
If fullscreen ;Attempt Fullscreen Mode?
Protected dmScreenSettings.DEVMODE ;Device Mode
dmScreenSettings\dmSize=SizeOf(DEVMODE) ;Size Of The Devmode Structure
dmScreenSettings\dmFields=#DM_BITSPERPEL | #DM_PELSWIDTH | #DM_PELSHEIGHT ;bit flags to specify the members of DEVMODE that were initialized
dmScreenSettings\dmBitsPerPel=bits ;Selected Bits Per Pixel
dmScreenSettings\dmPelsWidth=width ;Selected Screen Width in pixels
dmScreenSettings\dmPelsHeight=height ;Selected Screen Height in pixels
;Try To Set Selected Mode And Get Results. Note: CDS_FULLSCREEN Gets Rid Of Start Bar
If ChangeDisplaySettings_(dmScreenSettings,#CDS_FULLSCREEN)<>#DISP_CHANGE_SUCCESSFUL
;If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode
If MessageBox_(#Null,"The Requested Fullscreen Mode Is Not Supported By"+Chr(10)+"Your Video Card. Use Windowed Mode Instead?","NeHe GL",#MB_YESNO | #MB_ICONEXCLAMATION)=#IDYES
fullscreen=#False ;Windowed Mode Selected. Fullscreen = FALSE
Else
;Pop Up A Message Box Letting User Know The Program Is Closing
MessageBox_(#Null,"Program Will Now Close.","ERROR",#MB_OK | #MB_ICONSTOP)
ProcedureReturn #False
EndIf
EndIf
EndIf
If fullscreen ;Are We Still In Fullscreen Mode?
dwExStyle=#WS_EX_APPWINDOW ;Window Extended Style
dwStyle=#WS_POPUP ;Windows Style
ShowCursor_(#False) ;Hide Mouse Pointer
Else
dwExStyle=#WS_EX_APPWINDOW | #WS_EX_WINDOWEDGE ;Window Extended Style
dwStyle=#WS_OVERLAPPEDWINDOW ;Windows Style
EndIf
AdjustWindowRectEx_(WindowRect,dwStyle,#False,dwExStyle) ;Adjust Window To True Requested Size
If fullscreen=0 ;if not fullscreen mode calculate screen centered window
wpos\x=(GetSystemMetrics_(#SM_CXSCREEN)/2)-((WindowRect\right-WindowRect\left)/2)
wpos\y=(GetSystemMetrics_(#SM_CYSCREEN)/2)-((WindowRect\bottom-WindowRect\top)/2)
EndIf
;CreateWindowEx_(Extended Window Style, Class Name, Window Title, Window Style, Window X Position, Window Y Position, Width, Height, No Parent Window, No Menu, Instance, No Creation Data)
hWnd=CreateWindowEx_(dwExStyle,"OpenGL",title,dwStyle | #WS_CLIPSIBLINGS | #WS_CLIPCHILDREN,wpos\x,wpos\y,WindowRect\right-WindowRect\left,WindowRect\bottom-WindowRect\top,#Null,#Null,hInstance,#Null)
If hWnd=0
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Window Creation Error.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
Protected pfd.PIXELFORMATDESCRIPTOR ;pfd Tells Windows How We Want Things To Be
pfd\nSize=SizeOf(PIXELFORMATDESCRIPTOR) ;Size Of This Structure
pfd\nVersion=1 ;Version Number
pfd\dwFlags=#PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER | #PFD_DRAW_TO_WINDOW ;Format Must Support Window, OpenGL, Double Buffering
pfd\iPixelType=#PFD_TYPE_RGBA ;Request An RGBA Format
pfd\cColorBits=bits ;Select Our Color Depth
pfd\cRedBits=0 ;Color Bits Ignored
pfd\cRedShift=0
pfd\cGreenBits=0
pfd\cGreenShift=0
pfd\cBlueBits=0
pfd\cBlueShift=0
pfd\cAlphaBits=0 ;No Alpha Buffer
pfd\cAlphaShift=0 ;Shift Bit Ignored
pfd\cAccumBits=0 ;No Accumulation Buffer
pfd\cAccumRedBits=0 ;Accumulation Bits Ignored
pfd\cAccumGreenBits=0
pfd\cAccumBlueBits=0
pfd\cAccumAlphaBits=0
pfd\cDepthBits=16 ;16Bit Z-Buffer (Depth Buffer)
pfd\cStencilBits=1 ;Use Stencil Buffer ( * Important * )
pfd\cAuxBuffers=0 ;No Auxiliary Buffer
pfd\iLayerType=#PFD_MAIN_PLANE ;Main Drawing Layer
pfd\bReserved=0 ;Reserved
pfd\dwLayerMask=0 ;Layer Masks Ignored
pfd\dwVisibleMask=0
pfd\dwDamageMask=0
hDC=GetDC_(hWnd)
If hDC=0 ;Did We Get A Device Context?
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Can't Create A GL Device Context.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
PixelFormat=ChoosePixelFormat_(hDC,pfd)
If PixelFormat=0 ;Did Windows Find A Matching Pixel Format?
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Can't Find A Suitable PixelFormat.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
If SetPixelFormat_(hDC,PixelFormat,pfd)=0 ;Are We Able To Set The Pixel Format?
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Can't Set The PixelFormat.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
hRC=wglCreateContext_(hDC)
If hRC=0 ;Are We Able To Get A Rendering Context?
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Can't Create A GL Rendering Context.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
If wglMakeCurrent_(hDC,hRC)=0 ;Try To Activate The Rendering Context
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Can't Activate The GL Rendering Context.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
ShowWindow_(hWnd,#SW_SHOW) ;Show The Window
SetForegroundWindow_(hWnd) ;Slightly Higher Priority
SetFocus_(hWnd) ;Sets Keyboard Focus To The Window
ReSizeGLScene(width,height) ;Set Up Our Perspective GL Screen
If InitGL()=0 ;Initialize Our Newly Created GL Window
KillGLWindow() ;Reset The Display
MessageBox_(#Null,"Initialization Failed.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
ProcedureReturn #False
EndIf
ProcedureReturn #True ;Success
EndProcedure
Procedure.l WndProc(hWnd.l,uMsg.l,wParam.l,lParam.l)
Select uMsg ;Check For Windows Messages
Case #WM_ACTIVATE ;Watch For Window Activate Message
If HiWord(wParam)=0 ;Check Minimization State
active=#True ;Program Is Active
Else
active=#False ;Program Is No Longer Active
EndIf
ProcedureReturn 0 ;Return To The Message Loop
Case #WM_SYSCOMMAND ;Intercept System Commands
Select wParam ;Check System Calls
Case #SC_SCREENSAVE ;Screensaver Trying To Start?
ProcedureReturn 0 ;Prevent From Happening
Case #SC_MONITORPOWER ;Monitor Trying To Enter Powersave?
ProcedureReturn 0 ;Prevent From Happening
EndSelect
Case #WM_CLOSE ;Did We Receive A Close Message?
PostQuitMessage_(0) ;Send A Quit Message
ProcedureReturn 0 ;Jump Back
Case #WM_KEYDOWN ;Is A Key Being Held Down?
keys(wParam)=#True ;If So, Mark It As TRUE
ProcedureReturn 0 ;Jump Back
Case #WM_KEYUP ;Has A Key Been Released?
keys(wParam)=#False ;If So, Mark It As FALSE
ProcedureReturn 0 ;Jump Back
Case #WM_SIZE ;Resize The OpenGL Window
ReSizeGLScene(LoWord(lParam),HiWord(lParam)) ;LoWord=Width, HiWord=Height
ProcedureReturn 0 ;Jump Back
EndSelect
;Pass All Unhandled Messages To DefWindowProc
ProcedureReturn DefWindowProc_(hWnd,uMsg,wParam,lParam)
EndProcedure
Procedure.l WinMain() ;Main Program
Protected msg.MSG ;Windows Message Structure
Protected done.b ;Bool Variable To Exit Loop
;Ask The User Which Screen Mode They Prefer
If MessageBox_(#Null,"Would You Like To Run In Fullscreen Mode?","Start FullScreen?",#MB_YESNO | #MB_ICONQUESTION)=#IDNO
fullscreen=#False ;Windowed Mode
EndIf
If CreateGLWindow("Banu Octavian & NeHe's Shadow Casting Tutorial",640,480,32,fullscreen)=0 ;Create The Window
ProcedureReturn 0 ;Quit If Window Was Not Created
EndIf
While done=#False ;Loop That Runs While done=FALSE
If PeekMessage_(msg,#Null,0,0,#PM_REMOVE) ;Is There A Message Waiting?
If msg\message=#WM_QUIT ;Have We Received A Quit Message?
done=#True ;If So done=TRUE
Else ;If Not, Deal With Window Messages
TranslateMessage_(msg) ;Translate The Message
DispatchMessage_(msg) ;Dispatch The Message
EndIf
Else ;If There Are No Messages
;Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
If (active And DrawGLScene()=0) Or keys(#VK_ESCAPE) ;Active? Was There A Quit Received?
done=#True ;ESC or DrawGLScene Signalled A Quit
Else ;Not Time To Quit, Update Screen
Delay(5)
SwapBuffers_(hDC) ;Swap Buffers (Double Buffering)
ProcessKeyboard() ;Process Key Presses
EndIf
If keys(#VK_F1) ;Is F1 Being Pressed?
keys(#VK_F1)=#False ;If So Make Key FALSE
KillGLWindow() ;Kill Our Current Window
fullscreen=~fullscreen & 1 ;Toggle Fullscreen / Windowed Mode
;Recreate Our OpenGL Window
If CreateGLWindow("Banu Octavian & NeHe's Shadow Casting Tutorial",640,480,32,fullscreen)=0
ProcedureReturn 0 ;Quit If Window Was Not Created
EndIf
EndIf
EndIf
Wend
;Shutdown
KillGLWindow() ;Kill The Window
End ;Exit The Program
EndProcedure
WinMain() ;run the main program