Banu Octavian & NeHe's Shadow Tutorial (Lesson 27)

Share your advanced PureBasic knowledge/code with the community.
hagibaba
Enthusiast
Enthusiast
Posts: 170
Joined: Fri Mar 05, 2004 2:55 am
Location: UK
Contact:

Banu Octavian & NeHe's Shadow Tutorial (Lesson 27)

Post by hagibaba »

Code updated for 5.20+

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
Last edited by hagibaba on Sun Jul 01, 2007 11:21 pm, edited 4 times in total.
hagibaba
Enthusiast
Enthusiast
Posts: 170
Joined: Fri Mar 05, 2004 2:55 am
Location: UK
Contact:

Post by hagibaba »

Code updated for 5.20+

This is the "3dobject.pb" file which is an include file for this lesson.

Lasted edited on 14 Feb 2007.

Code: Select all

;Include File For 3D Object Handling (Lesson 27)

;INFINITY For Calculating The Extension Vector For The Shadow Volume
;#INFINITY=100 ;Note: was used in doShadowPass()

Structure POINT3F ;Structure Describing An Object's Vertex
 x.f : y.f : z.f
EndStructure

Structure PLANE ;Structure Describing A Plane
 a.f : b.f : c.f : d.f ;Equation In The Format: ax + by + cz + d = 0
EndStructure

Structure FACE ;Structure Describing An Object's Face
 vert.l[3] ;Index Of Each Vertex That Makes Up The Triangle Of This Face
 normals.POINT3F[3] ;Normals To Each Vertex
 planeEq.PLANE ;Equation Of A Plane That Contains This Triangle
 neigh.l[3] ;Index Of Each Face That Neighbours This One
 visible.b ;Is The Face Visible By The Light?
EndStructure

Structure SHADOWEDOBJECT ;Shadowed Object Structure
 nVerts.l ;Number Of Vertices
 pVerts.l ;Pointer To Vertices, Dynamically Allocated
 nFaces.l ;Number Of Faces
 pFaces.l ;Pointer To Faces, Dynamically Allocated
EndStructure

Procedure.s readstr(f.l) ;Reads A String From File

 Protected string.s
 While Left(string,1)="/" Or Left(string,1)=""
  string=ReadString(f)
 Wend
 ProcedureReturn string
 
EndProcedure

Procedure.l readObject(filename.s,*o.SHADOWEDOBJECT) ;Load Object

 Protected file.l,i.l
 Protected fsize.l,vsize.l,normals.l
 Protected oneline.s,char.s,pos.l,count.l
 
 file=ReadFile(#PB_Any,filename)
 
 If file=0
  ProcedureReturn #False
 EndIf
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 normals=OffsetOf(FACE\normals) ;12
 
 ;Read Vertices
 *o\nVerts=Val(readstr(file))
 *o\pVerts=AllocateMemory((*o\nVerts+1)*vsize)
 For i=1 To *o\nVerts
  oneline=readstr(file)
 
  count=0 : char=""
  For pos=1 To Len(oneline)
   If Mid(oneline,pos,1)<>" " : char=char+Mid(oneline,pos,1) : EndIf
   If Len(char)>0 And (Mid(oneline,pos,1)=" " Or pos=Len(oneline))
    Select count
     Case 0 : PokeF(*o\pVerts+(i*vsize),ValF(char)) ;pVerts[i]\x
     Case 1 : PokeF(*o\pVerts+(i*vsize)+4,ValF(char)) ;pVerts[i]\y
     Case 2 : PokeF(*o\pVerts+(i*vsize)+8,ValF(char)) ;pVerts[i]\z
    EndSelect
    count=count+1 : char=""
   EndIf
  Next
 
 Next
 
 ;Read Faces
 *o\nFaces=Val(readstr(file))
 *o\pFaces=AllocateMemory(*o\nFaces*fsize)
 For i=0 To *o\nFaces-1
  oneline=readstr(file)
 
  count=0 : char=""
  For pos=1 To Len(oneline)
   If Mid(oneline,pos,1)<>" " : char=char+Mid(oneline,pos,1) : EndIf
   If Len(char)>0 And (Mid(oneline,pos,1)=" " Or pos=Len(oneline))
    Select count
     Case 0 : PokeL(*o\pFaces+(i*fsize),Val(char)) ;pFaces[i]\vert[0]
     Case 1 : PokeL(*o\pFaces+(i*fsize)+4,Val(char)) ;pFaces[i]\vert[1]
     Case 2 : PokeL(*o\pFaces+(i*fsize)+8,Val(char)) ;pFaces[i]\vert[2]
     
     Case 3 : PokeF(*o\pFaces+(i*fsize)+normals,ValF(char)) ;pFaces[i]\normals[0]\x
     Case 4 : PokeF(*o\pFaces+(i*fsize)+normals+4,ValF(char)) ;pFaces[i]\normals[0]\y
     Case 5 : PokeF(*o\pFaces+(i*fsize)+normals+8,ValF(char)) ;pFaces[i]\normals[0]\z
     Case 6 : PokeF(*o\pFaces+(i*fsize)+normals+12,ValF(char)) ;pFaces[i]\normals[1]\x
     Case 7 : PokeF(*o\pFaces+(i*fsize)+normals+16,ValF(char)) ;pFaces[i]\normals[1]\y
     Case 8 : PokeF(*o\pFaces+(i*fsize)+normals+20,ValF(char)) ;pFaces[i]\normals[1]\z
     Case 9 : PokeF(*o\pFaces+(i*fsize)+normals+24,ValF(char)) ;pFaces[i]\normals[2]\x
     Case 10 : PokeF(*o\pFaces+(i*fsize)+normals+28,ValF(char)) ;pFaces[i]\normals[2]\y
     Case 11 : PokeF(*o\pFaces+(i*fsize)+normals+32,ValF(char)) ;pFaces[i]\normals[2]\z
    EndSelect
    count=count+1 : char=""
   EndIf
  Next
 
 Next
 
 ProcedureReturn #True
 
EndProcedure

Procedure killObject(*o.SHADOWEDOBJECT) ;Free Object Data

 If *o\pFaces
  FreeMemory(*o\pFaces)
 EndIf
 *o\pFaces=#Null
 *o\nFaces=0
 
 If *o\pVerts
  FreeMemory(*o\pVerts)
 EndIf
 *o\pVerts=#Null
 *o\nVerts=0
 
EndProcedure

Procedure setConnectivity(*o.SHADOWEDOBJECT) ;Connectivity Procedure - Based On Gamasutra's Article

 Protected p1i.l,p2i.l,p1j.l,p2j.l
 Protected cP1i.l,cP2i.l,cP1j.l,cP2j.l
 Protected i.l,j.l,ki.l,kj.l
 Protected fsize.l,neigh.l
 
 fsize=SizeOf(FACE) ;77
 neigh=OffsetOf(FACE\neigh) ;64
 
 For i=0 To (*o\nFaces-1)-1
  For j=i+1 To *o\nFaces-1
   For ki=0 To 3-1
    If PeekL(*o\pFaces+(i*fsize)+neigh+(ki*4))=0 ;pFaces[i]\neigh[ki]
     For kj=0 To 3-1
      p1i=ki
      p1j=kj
      p2i=(ki+1) % 3
      p2j=(kj+1) % 3
     
      p1i=PeekL(*o\pFaces+(i*fsize)+(p1i*4)) ;pFaces[i]\vert[p1i]
      p2i=PeekL(*o\pFaces+(i*fsize)+(p2i*4)) ;pFaces[i]\vert[p2i]
      p1j=PeekL(*o\pFaces+(j*fsize)+(p1j*4)) ;pFaces[j]\vert[p1j]
      p2j=PeekL(*o\pFaces+(j*fsize)+(p2j*4)) ;pFaces[j]\vert[p2j]
     
      cP1i=((p1i+p2i)-Abs(p1i-p2i))/2
      cP2i=((p1i+p2i)+Abs(p1i-p2i))/2
      cP1j=((p1j+p2j)-Abs(p1j-p2j))/2
      cP2j=((p1j+p2j)+Abs(p1j-p2j))/2
     
      If cP1i=cP1j And cP2i=cP2j ;Check If They Are Neighbours - I.E. The Edges Are The Same
       PokeL(*o\pFaces+(i*fsize)+neigh+(ki*4),j+1) ;pFaces[i]\neigh[ki]
       PokeL(*o\pFaces+(j*fsize)+neigh+(kj*4),i+1) ;pFaces[j]\neigh[kj]
      EndIf
     Next
    EndIf
   Next
  Next
 Next
 
EndProcedure

Procedure drawObject(*o.SHADOWEDOBJECT) ;Draw An Object - Simply Draw Each Triangular Face

 Protected i.l,j.l,vi.l
 Protected fsize.l,vsize.l,normals.l
 Protected v.POINT3F
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 normals=OffsetOf(FACE\normals) ;12
 
 glBegin_(#GL_TRIANGLES)
 For i=0 To *o\nFaces-1
  For j=0 To 3-1
   v\x=PeekF(*o\pFaces+(i*fsize)+normals+(j*vsize)) ;pFaces[i]\normals[j]\x
   v\y=PeekF(*o\pFaces+(i*fsize)+normals+(j*vsize)+4) ;pFaces[i]\normals[j]\y
   v\z=PeekF(*o\pFaces+(i*fsize)+normals+(j*vsize)+8) ;pFaces[i]\normals[j]\z
   glNormal3f_(v\x,v\y,v\z)
   vi=PeekL(*o\pFaces+(i*fsize)+(j*4)) ;pFaces[i]\vert[j]
   v\x=PeekF(*o\pVerts+(vi*vsize)) ;pVerts[pFaces[i]\vert[j]]\x
   v\y=PeekF(*o\pVerts+(vi*vsize)+4) ;pVerts[pFaces[i]\vert[j]]\y
   v\z=PeekF(*o\pVerts+(vi*vsize)+8) ;pVerts[pFaces[i]\vert[j]]\z
   glVertex3f_(v\x,v\y,v\z)
  Next
 Next
 glEnd_()
 
EndProcedure

Procedure calculatePlane(*o.SHADOWEDOBJECT,fi.l) ;Function For Computing A Plane Equation Given 3 Points

 Protected Dim v.POINT3F(4)
 Protected i.l,vi.l
 Protected fsize.l,vsize.l,planeEq.l
 Protected plEq.PLANE
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 planeEq=OffsetOf(FACE\planeEq) ;48
 
 For i=0 To 3-1 ;Get Shortened Names For The Vertices Of The Face
  vi=PeekL(*o\pFaces+(fi*fsize)+(i*4)) ;pFaces[fi]\vert[i]
  v(i+1)\x=PeekF(*o\pVerts+(vi*vsize)) ;pVerts[pFaces[fi]\vert[i]]\x
  v(i+1)\y=PeekF(*o\pVerts+(vi*vsize)+4) ;pVerts[pFaces[fi]\vert[i]]\y
  v(i+1)\z=PeekF(*o\pVerts+(vi*vsize)+8) ;pVerts[pFaces[fi]\vert[i]]\z
 Next
 
 plEq\a= v(1)\y*(v(2)\z-v(3)\z) + v(2)\y*(v(3)\z-v(1)\z) + v(3)\y*(v(1)\z-v(2)\z)
 plEq\b= v(1)\z*(v(2)\x-v(3)\x) + v(2)\z*(v(3)\x-v(1)\x) + v(3)\z*(v(1)\x-v(2)\x)
 plEq\c= v(1)\x*(v(2)\y-v(3)\y) + v(2)\x*(v(3)\y-v(1)\y) + v(3)\x*(v(1)\y-v(2)\y)
 plEq\d=-( v(1)\x*(v(2)\y*v(3)\z - v(3)\y*v(2)\z) + v(2)\x*(v(3)\y*v(1)\z - v(1)\y*v(3)\z) + v(3)\x*(v(1)\y*v(2)\z - v(2)\y*v(1)\z) )
 PokeF(*o\pFaces+(fi*fsize)+planeEq,plEq\a) ;pFaces[fi]\planeEq\a
 PokeF(*o\pFaces+(fi*fsize)+planeEq+4,plEq\b) ;pFaces[fi]\planeEq\b
 PokeF(*o\pFaces+(fi*fsize)+planeEq+8,plEq\c) ;pFaces[fi]\planeEq\c
 PokeF(*o\pFaces+(fi*fsize)+planeEq+12,plEq\d) ;pFaces[fi]\planeEq\d
 
EndProcedure

Procedure doShadowPass(*o.SHADOWEDOBJECT, Array lp.f(1)) ;Draw Object's Shadow

 Protected i.l,j.l,k.l,jj.l,p1.l,p2.l
 Protected fsize.l,vsize.l,neigh.l,visible.l
 Protected Dim v.POINT3F(4)
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 neigh=OffsetOf(FACE\neigh) ;64
 visible=OffsetOf(FACE\visible) ;76
 
 For i=0 To *o\nFaces-1
  If PeekB(*o\pFaces+(i*fsize)+visible) ;pFaces[i]\visible
   For j=0 To 3-1 ;Go Through Each Edge
    k=PeekL(*o\pFaces+(i*fsize)+neigh+(j*4)) ;pFaces[i]\neigh[j]
    ;If There Is No Neighbour, Or Its Neighbouring Face Is Not Visible, Then This Edge Casts A Shadow
    If k=0 Or PeekB(*o\pFaces+((k-1)*fsize)+visible)=0 ;pFaces[k-1]\visible
   
     ;Get The Points On The Edge
     p1=PeekL(*o\pFaces+(i*fsize)+(j*4)) ;pFaces[i]\vert[j]
     jj=(j+1) % 3
     p2=PeekL(*o\pFaces+(i*fsize)+(jj*4)) ;pFaces[i]\vert[jj]
     
     v(1)\x=PeekF(*o\pVerts+(p1*vsize)) ;pVerts[p1]\x
     v(1)\y=PeekF(*o\pVerts+(p1*vsize)+4) ;pVerts[p1]\y
     v(1)\z=PeekF(*o\pVerts+(p1*vsize)+8) ;pVerts[p1]\z
     
     v(2)\x=PeekF(*o\pVerts+(p2*vsize)) ;pVerts[p2]\x
     v(2)\y=PeekF(*o\pVerts+(p2*vsize)+4) ;pVerts[p2]\y
     v(2)\z=PeekF(*o\pVerts+(p2*vsize)+8) ;pVerts[p2]\z
     
     ;Calculate The Two Vertices In Distance (INFINITY=100)
     v(3)\x=(v(1)\x-lp(0))*100 ;pVerts[p1]\x
     v(3)\y=(v(1)\y-lp(1))*100 ;pVerts[p1]\y
     v(3)\z=(v(1)\z-lp(2))*100 ;pVerts[p1]\z
     
     v(4)\x=(v(2)\x-lp(0))*100 ;pVerts[p2]\x
     v(4)\y=(v(2)\y-lp(1))*100 ;pVerts[p2]\y
     v(4)\z=(v(2)\z-lp(2))*100 ;pVerts[p2]\z
     
     ;Draw The Quadrilateral (As A Triangle Strip)
     glBegin_(#GL_TRIANGLE_STRIP)
      glVertex3f_(v(1)\x,v(1)\y,v(1)\z)
      glVertex3f_(v(1)\x+v(3)\x,v(1)\y+v(3)\y,v(1)\z+v(3)\z)
      glVertex3f_(v(2)\x,v(2)\y,v(2)\z)
      glVertex3f_(v(2)\x+v(4)\x,v(2)\y+v(4)\y,v(2)\z+v(4)\z)
     glEnd_()
     
    EndIf
   Next
  EndIf
 Next
 
EndProcedure

Procedure castShadow(*o.SHADOWEDOBJECT, Array lp.f(1)) ;Render Object's Shadow

 Protected i.l,side.f
 Protected fsize.l,planeEq.l,visible.l
 Protected plEq.PLANE
 
 fsize=SizeOf(FACE) ;77
 planeEq=OffsetOf(FACE\planeEq) ;48
 visible=OffsetOf(FACE\visible) ;76
 
 ;Determine Which Faces Are Visible By The Light
 For i=0 To *o\nFaces-1
  plEq\a=PeekF(*o\pFaces+(i*fsize)+planeEq) ;pFaces[i]\planeEq\a
  plEq\b=PeekF(*o\pFaces+(i*fsize)+planeEq+4) ;pFaces[i]\planeEq\b
  plEq\c=PeekF(*o\pFaces+(i*fsize)+planeEq+8) ;pFaces[i]\planeEq\c
  plEq\d=PeekF(*o\pFaces+(i*fsize)+planeEq+12) ;pFaces[i]\planeEq\d
  side=plEq\a*lp(0) + plEq\b*lp(1) + plEq\c*lp(2) + plEq\d*lp(3)
  If side>0
   PokeB(*o\pFaces+(i*fsize)+visible,#True) ;pFaces[i]\visible
  Else
   PokeB(*o\pFaces+(i*fsize)+visible,#False) ;pFaces[i]\visible
  EndIf
 Next
 
 glDisable_(#GL_LIGHTING) ;Turn Off Lighting
 glDepthMask_(#GL_FALSE) ;Turn Off Writing To The Depth-Buffer
 glDepthFunc_(#GL_LEQUAL)
 
 glEnable_(#GL_STENCIL_TEST) ;Turn On Stencil Buffer Testing
 glColorMask_(0,0,0,0) ;Don't Draw Into The Colour Buffer
 glStencilFunc_(#GL_ALWAYS,1,$ffffffff)
 
 ;First Pass, Stencil Operation Increases Stencil Value
 glFrontFace_(#GL_CCW)
 glStencilOp_(#GL_KEEP,#GL_KEEP,#GL_INCR)
 doShadowPass(*o,lp())
 
 ;Second Pass, Stencil Operation Decreases Stencil Value
 glFrontFace_(#GL_CW)
 glStencilOp_(#GL_KEEP,#GL_KEEP,#GL_DECR)
 doShadowPass(*o,lp())
 
 glFrontFace_(#GL_CCW)
 glColorMask_(1,1,1,1) ;Enable Rendering To Colour Buffer For All Components
 
 ;Draw A Shadowing Rectangle Covering The Entire Screen
 glColor4f_(0.0,0.0,0.0,0.4)
 glEnable_(#GL_BLEND)
 glBlendFunc_(#GL_SRC_ALPHA,#GL_ONE_MINUS_SRC_ALPHA)
 glStencilFunc_(#GL_NOTEQUAL,0,$ffffffff)
 glStencilOp_(#GL_KEEP,#GL_KEEP,#GL_KEEP)
 glPushMatrix_()
 glLoadIdentity_()
 glBegin_(#GL_TRIANGLE_STRIP)
  glVertex3f_(-0.1, 0.1,-0.1)
  glVertex3f_(-0.1,-0.1,-0.1)
  glVertex3f_( 0.1, 0.1,-0.1)
  glVertex3f_( 0.1,-0.1,-0.1)
 glEnd_()
 glPopMatrix_()
 glDisable_(#GL_BLEND)
 
 glDepthFunc_(#GL_LEQUAL)
 glDepthMask_(#GL_TRUE)
 glEnable_(#GL_LIGHTING)
 glDisable_(#GL_STENCIL_TEST)
 glShadeModel_(#GL_SMOOTH)
 
EndProcedure
Last edited by hagibaba on Wed Feb 14, 2007 8:47 am, edited 3 times in total.
dige
Addict
Addict
Posts: 1254
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Post by dige »

Amazing! Good work, thank you!
benny
Enthusiast
Enthusiast
Posts: 465
Joined: Fri Apr 25, 2003 7:44 pm
Location: end of www
Contact:

Post by benny »

Awesome!!!
regards,
benny!
-
pe0ple ar3 str4nge!!!
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: Banu Octavian & NeHe's Shadow Tutorial (Lesson 27)

Post by mpz »

Hello,

next code actualised for x86/x64, PB 5.73.

Sorry, but you "must" get the original texture from the internet, i have not purebasic textures for that

P.S:I think the code can work with linux and mac Osx too.


Greetings Michael

C Code and texture
iamyaker.googlepages.com/27_Shadow.rar

Code: Select all

;Banu Octavian & NeHe's Shadow Casting Tutorial (Lesson 27)
;http://nehe.gamedev.net
;https://nehe.gamedev.net/tutorial/shadows/16010/
;Note: requires a vertex data text file in path "Data/Object2.txt"
;Alternative files to try "Object.txt", "Object1.txt", "SimpleObject.txt"
;Credits: Nico Gruener, Dreglor, traumatic, hagibaba
;Author: MPz
;Date: 1 Nov 2021
;Note: up-to-date with PB v5.73 (Windows)

;Start of Lesson 27

XIncludeFile "3dobject.pb" ;Include File For 3D Object Handling

Global DMsaved.DEVMODE ;Saves The Previous Screen Settings ( NEW )

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.i ;Quadratic For Drawing A Sphere

Global Dim SpherePos.f(3) ;Sphere Position
 SpherePos(0)=-4.0 : SpherePos(1)=-5.0 : SpherePos(2)=-6.0
 

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
 
 ResizeGadget(0, 0, 0, width, height)
 
 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.1,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 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 DrawScene(Gadget)
  
 Protected Dim Minv.f(16)
 Protected Dim wlp.f(4)
 Protected Dim lp.f(4)
 
 SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
 
 ;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
 
 SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
  
 ProcedureReturn #True ;Everything Went OK
  
EndProcedure

Procedure ProcessKeyboard() ;Process Keyboard Results
  

;Spin Object
 If KeyboardPushed(#PB_Key_Left) And yspeed>-2.5
  yspeed-0.1 ;'Arrow Left' Decrease yspeed
 EndIf
 If KeyboardPushed(#PB_Key_Right) And yspeed<2.5
  yspeed+0.1 ;'Arrow Right' Increase yspeed
 EndIf
 If KeyboardPushed(#PB_Key_Up) And xspeed>-2.5
  xspeed-0.1 ;'Arrow Up' Decrease xspeed
 EndIf
 If KeyboardPushed(#PB_Key_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 KeyboardPushed(#PB_Key_L)
  LightPos(0)+0.05 ;'L' Moves Light Right
 EndIf
 If KeyboardPushed(#PB_Key_J)
  LightPos(0)-0.05 ;'J' Moves Light Left
 EndIf
 If KeyboardPushed(#PB_Key_I)
  LightPos(1)+0.05 ;'I' Moves Light Up
 EndIf
 If KeyboardPushed(#PB_Key_K)
  LightPos(1)-0.05 ;'K' Moves Light Down
 EndIf
 If KeyboardPushed(#PB_Key_O)
  LightPos(2)+0.05 ;'O' Moves Light Toward Viewer
 EndIf
 If KeyboardPushed(#PB_Key_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 KeyboardPushed(#PB_Key_Pad6)
  ObjPos(0)+0.05 ;'Numpad6' Move Object Right
 EndIf
 If KeyboardPushed(#PB_Key_Pad4)
  ObjPos(0)-0.05 ;'Numpad4' Move Object Left
 EndIf
 If KeyboardPushed(#PB_Key_Pad8)
  ObjPos(1)+0.05 ;'Numpad8' Move Object Up
 EndIf
 If KeyboardPushed(#PB_Key_Pad5)
  ObjPos(1)-0.05 ;'Numpad5' Move Object Down
 EndIf
 If KeyboardPushed(#PB_Key_Pad9)
  ObjPos(2)+0.05 ;'Numpad9' Move Object Toward Viewer
 EndIf
 If KeyboardPushed(#PB_Key_Pad7)
  ObjPos(2)-0.05 ;'Numpad7' Move Object Away From Viewer
 EndIf
 
 ;Adjust Ball's Position (Q,W,E,A,S,D Keys)
 If KeyboardPushed(#PB_Key_D)
  SpherePos(0)+0.05 ;'D' Move Ball Right
 EndIf
 If KeyboardPushed(#PB_Key_A)
  SpherePos(0)-0.05 ;'A' Move Ball Left
 EndIf
 If KeyboardPushed(#PB_Key_W)
  SpherePos(1)+0.05 ;'W' Move Ball Up
 EndIf
 If KeyboardPushed(#PB_Key_S)
  SpherePos(1)-0.05 ;'S' Move Ball Down
 EndIf
 If KeyboardPushed(#PB_Key_E)
  SpherePos(2)+0.05 ;'E' Move Ball Toward Viewer
 EndIf
 If KeyboardPushed(#PB_Key_Q)
  SpherePos(2)-0.05 ;'Q' Move Ball Away From Viewer
 EndIf
 
EndProcedure

Procedure CreateGLWindow(title.s,WindowWidth.l,WindowHeight.l,bits.l=16,fullscreenflag.b=0,Vsync.b=0)
  
  If InitKeyboard() = 0 Or InitSprite() = 0 Or InitMouse() = 0
    MessageRequester("Error", "Can't initialize Keyboards or Mouse", 0)
    End
  EndIf

  If fullscreenflag
    hWnd = OpenWindow(0, 0, 0, WindowWidth, WindowHeight, title, #PB_Window_BorderLess|#PB_Window_Maximize )
    OpenWindowedScreen(WindowID(0), 0, 0,WindowWidth(0),WindowHeight(0)) 
  Else  
    hWnd = OpenWindow(0, 1, 1, WindowWidth, WindowHeight, title,#PB_Window_MinimizeGadget |  #PB_Window_MaximizeGadget | #PB_Window_SizeGadget ) 
    OpenWindowedScreen(WindowID(0), 1, 1, WindowWidth,WindowHeight) 
  EndIf
  
  If bits = 24
    OpenGlFlags + #PB_OpenGL_24BitDepthBuffer 
  EndIf
  
  If bits = 32
    OpenGlFlags + #PB_OpenGL_24BitDepthBuffer + #PB_OpenGL_8BitStencilBuffer
  EndIf
  
  If Vsync = 0
    OpenGlFlags + #PB_OpenGL_NoFlipSynchronization
  EndIf
  
  OpenGLGadget(0, 0, 0, WindowWidth(0),WindowHeight(0),OpenGlFlags)
  
  SetActiveGadget(0) 
  
  ReSizeGLScene(WindowWidth(0),WindowHeight(0))
  ;hDC = GetDC_(hWnd)
  
EndProcedure

CreateGLWindow("Banu Octavian & NeHe's Shadow Casting Tutorial (Lesson 27)",640,480,32,0) ; 24 Bit for Shadow 

InitGL() 

Repeat

  Repeat 
    Event = WindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        Quit = 1
      Case #PB_Event_SizeWindow  
        ReSizeGLScene(WindowWidth(0),WindowHeight(0)) ;LoWord=Width, HiWord=Height
    EndSelect
  
  Until Event = 0
  
  ExamineKeyboard()
  
  If KeyboardPushed(#PB_Key_Escape) ;  Esc key to exit
    Quit = 1
  EndIf 
  
  ProcessKeyboard() ;Processed Keyboard Presses 

  DrawScene(0)
  
  Delay(2)
Until Quit = 1


 

3dObjekt.pb

Code: Select all

;Include File For 3D Object Handling (Lesson 27)

;INFINITY For Calculating The Extension Vector For The Shadow Volume
;#INFINITY=100 ;Note: was used in doShadowPass()

Structure POINT3F ;Structure Describing An Object's Vertex
 x.f : y.f : z.f
EndStructure

Structure PLANE ;Structure Describing A Plane
 a.f : b.f : c.f : d.f ;Equation In The Format: ax + by + cz + d = 0
EndStructure

Structure FACE ;Structure Describing An Object's Face
 vert.l[3] ;Index Of Each Vertex That Makes Up The Triangle Of This Face
 normals.POINT3F[3] ;Normals To Each Vertex
 planeEq.PLANE ;Equation Of A Plane That Contains This Triangle
 neigh.l[3] ;Index Of Each Face That Neighbours This One
 visible.b ;Is The Face Visible By The Light?
EndStructure

Structure SHADOWEDOBJECT ;Shadowed Object Structure
 nVerts.l ;Number Of Vertices
 pVerts.i ;Pointer To Vertices, Dynamically Allocated
 nFaces.l ;Number Of Faces
 pFaces.i ;Pointer To Faces, Dynamically Allocated
EndStructure

Procedure.s readstr(f.i) ;Reads A String From File

 Protected string.s
 While Left(string,1)="/" Or Left(string,1)=""
  string=ReadString(f)
 Wend
 ProcedureReturn string
 
EndProcedure

Procedure readObject(filename.s,*o.SHADOWEDOBJECT) ;Load Object

 Protected file.i,i.l
 Protected fsize.l,vsize.l,normals.l
 Protected oneline.s,char.s,pos.l,count.l
 
 file=ReadFile(#PB_Any,filename)
 
 If file=0
  ProcedureReturn #False
 EndIf
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 normals=OffsetOf(FACE\normals) ;12
 
 ;Read Vertices
 *o\nVerts=Val(readstr(file))
 *o\pVerts=AllocateMemory((*o\nVerts+1)*vsize)
 For i=1 To *o\nVerts
  oneline=readstr(file)
 
  count=0 : char=""
  For pos=1 To Len(oneline)
   If Mid(oneline,pos,1)<>" " : char=char+Mid(oneline,pos,1) : EndIf
   If Len(char)>0 And (Mid(oneline,pos,1)=" " Or pos=Len(oneline))
    Select count
     Case 0 : PokeF(*o\pVerts+(i*vsize),ValF(char)) ;pVerts[i]\x
     Case 1 : PokeF(*o\pVerts+(i*vsize)+4,ValF(char)) ;pVerts[i]\y
     Case 2 : PokeF(*o\pVerts+(i*vsize)+8,ValF(char)) ;pVerts[i]\z
    EndSelect
    count=count+1 : char=""
   EndIf
  Next
 
 Next
 
 ;Read Faces
 *o\nFaces=Val(readstr(file))
 *o\pFaces=AllocateMemory(*o\nFaces*fsize)
 For i=0 To *o\nFaces-1
  oneline=readstr(file)
 
  count=0 : char=""
  For pos=1 To Len(oneline)
   If Mid(oneline,pos,1)<>" " : char=char+Mid(oneline,pos,1) : EndIf
   If Len(char)>0 And (Mid(oneline,pos,1)=" " Or pos=Len(oneline))
    Select count
     Case 0 : PokeL(*o\pFaces+(i*fsize),Val(char)) ;pFaces[i]\vert[0]
     Case 1 : PokeL(*o\pFaces+(i*fsize)+4,Val(char)) ;pFaces[i]\vert[1]
     Case 2 : PokeL(*o\pFaces+(i*fsize)+8,Val(char)) ;pFaces[i]\vert[2]
     
     Case 3 : PokeF(*o\pFaces+(i*fsize)+normals,ValF(char)) ;pFaces[i]\normals[0]\x
     Case 4 : PokeF(*o\pFaces+(i*fsize)+normals+4,ValF(char)) ;pFaces[i]\normals[0]\y
     Case 5 : PokeF(*o\pFaces+(i*fsize)+normals+8,ValF(char)) ;pFaces[i]\normals[0]\z
     Case 6 : PokeF(*o\pFaces+(i*fsize)+normals+12,ValF(char)) ;pFaces[i]\normals[1]\x
     Case 7 : PokeF(*o\pFaces+(i*fsize)+normals+16,ValF(char)) ;pFaces[i]\normals[1]\y
     Case 8 : PokeF(*o\pFaces+(i*fsize)+normals+20,ValF(char)) ;pFaces[i]\normals[1]\z
     Case 9 : PokeF(*o\pFaces+(i*fsize)+normals+24,ValF(char)) ;pFaces[i]\normals[2]\x
     Case 10 : PokeF(*o\pFaces+(i*fsize)+normals+28,ValF(char)) ;pFaces[i]\normals[2]\y
     Case 11 : PokeF(*o\pFaces+(i*fsize)+normals+32,ValF(char)) ;pFaces[i]\normals[2]\z
    EndSelect
    count=count+1 : char=""
   EndIf
  Next
 
 Next
 
 ProcedureReturn #True
 
EndProcedure

Procedure killObject(*o.SHADOWEDOBJECT) ;Free Object Data

 If *o\pFaces
  FreeMemory(*o\pFaces)
 EndIf
 *o\pFaces=#Null
 *o\nFaces=0
 
 If *o\pVerts
  FreeMemory(*o\pVerts)
 EndIf
 *o\pVerts=#Null
 *o\nVerts=0
 
EndProcedure

Procedure setConnectivity(*o.SHADOWEDOBJECT) ;Connectivity Procedure - Based On Gamasutra's Article

 Protected p1i.l,p2i.l,p1j.l,p2j.l
 Protected cP1i.l,cP2i.l,cP1j.l,cP2j.l
 Protected i.l,j.l,ki.l,kj.l
 Protected fsize.l,neigh.l
 
 fsize=SizeOf(FACE) ;77
 neigh=OffsetOf(FACE\neigh) ;64
 
 For i=0 To (*o\nFaces-1)-1
  For j=i+1 To *o\nFaces-1
   For ki=0 To 3-1
    If PeekL(*o\pFaces+(i*fsize)+neigh+(ki*4))=0 ;pFaces[i]\neigh[ki]
     For kj=0 To 3-1
      p1i=ki
      p1j=kj
      p2i=(ki+1) % 3
      p2j=(kj+1) % 3
     
      p1i=PeekL(*o\pFaces+(i*fsize)+(p1i*4)) ;pFaces[i]\vert[p1i]
      p2i=PeekL(*o\pFaces+(i*fsize)+(p2i*4)) ;pFaces[i]\vert[p2i]
      p1j=PeekL(*o\pFaces+(j*fsize)+(p1j*4)) ;pFaces[j]\vert[p1j]
      p2j=PeekL(*o\pFaces+(j*fsize)+(p2j*4)) ;pFaces[j]\vert[p2j]
     
      cP1i=((p1i+p2i)-Abs(p1i-p2i))/2
      cP2i=((p1i+p2i)+Abs(p1i-p2i))/2
      cP1j=((p1j+p2j)-Abs(p1j-p2j))/2
      cP2j=((p1j+p2j)+Abs(p1j-p2j))/2
     
      If cP1i=cP1j And cP2i=cP2j ;Check If They Are Neighbours - I.E. The Edges Are The Same
       PokeL(*o\pFaces+(i*fsize)+neigh+(ki*4),j+1) ;pFaces[i]\neigh[ki]
       PokeL(*o\pFaces+(j*fsize)+neigh+(kj*4),i+1) ;pFaces[j]\neigh[kj]
      EndIf
     Next
    EndIf
   Next
  Next
 Next
 
EndProcedure

Procedure drawObject(*o.SHADOWEDOBJECT) ;Draw An Object - Simply Draw Each Triangular Face

 Protected i.l,j.l,vi.l
 Protected fsize.l,vsize.l,normals.l
 Protected v.POINT3F
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 normals=OffsetOf(FACE\normals) ;12
 
 glBegin_(#GL_TRIANGLES)
 For i=0 To *o\nFaces-1
  For j=0 To 3-1
   v\x=PeekF(*o\pFaces+(i*fsize)+normals+(j*vsize)) ;pFaces[i]\normals[j]\x
   v\y=PeekF(*o\pFaces+(i*fsize)+normals+(j*vsize)+4) ;pFaces[i]\normals[j]\y
   v\z=PeekF(*o\pFaces+(i*fsize)+normals+(j*vsize)+8) ;pFaces[i]\normals[j]\z
   glNormal3f_(v\x,v\y,v\z)
   vi=PeekL(*o\pFaces+(i*fsize)+(j*4)) ;pFaces[i]\vert[j]
   v\x=PeekF(*o\pVerts+(vi*vsize)) ;pVerts[pFaces[i]\vert[j]]\x
   v\y=PeekF(*o\pVerts+(vi*vsize)+4) ;pVerts[pFaces[i]\vert[j]]\y
   v\z=PeekF(*o\pVerts+(vi*vsize)+8) ;pVerts[pFaces[i]\vert[j]]\z
   glVertex3f_(v\x,v\y,v\z)
  Next
 Next
 glEnd_()
 
EndProcedure

Procedure calculatePlane(*o.SHADOWEDOBJECT,fi.l) ;Function For Computing A Plane Equation Given 3 Points

 Protected Dim v.POINT3F(4)
 Protected i.l,vi.l
 Protected fsize.l,vsize.l,planeEq.l
 Protected plEq.PLANE
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 planeEq=OffsetOf(FACE\planeEq) ;48
 
 For i=0 To 3-1 ;Get Shortened Names For The Vertices Of The Face
  vi=PeekL(*o\pFaces+(fi*fsize)+(i*4)) ;pFaces[fi]\vert[i]
  v(i+1)\x=PeekF(*o\pVerts+(vi*vsize)) ;pVerts[pFaces[fi]\vert[i]]\x
  v(i+1)\y=PeekF(*o\pVerts+(vi*vsize)+4) ;pVerts[pFaces[fi]\vert[i]]\y
  v(i+1)\z=PeekF(*o\pVerts+(vi*vsize)+8) ;pVerts[pFaces[fi]\vert[i]]\z
 Next
 
 plEq\a= v(1)\y*(v(2)\z-v(3)\z) + v(2)\y*(v(3)\z-v(1)\z) + v(3)\y*(v(1)\z-v(2)\z)
 plEq\b= v(1)\z*(v(2)\x-v(3)\x) + v(2)\z*(v(3)\x-v(1)\x) + v(3)\z*(v(1)\x-v(2)\x)
 plEq\c= v(1)\x*(v(2)\y-v(3)\y) + v(2)\x*(v(3)\y-v(1)\y) + v(3)\x*(v(1)\y-v(2)\y)
 plEq\d=-( v(1)\x*(v(2)\y*v(3)\z - v(3)\y*v(2)\z) + v(2)\x*(v(3)\y*v(1)\z - v(1)\y*v(3)\z) + v(3)\x*(v(1)\y*v(2)\z - v(2)\y*v(1)\z) )
 PokeF(*o\pFaces+(fi*fsize)+planeEq,plEq\a) ;pFaces[fi]\planeEq\a
 PokeF(*o\pFaces+(fi*fsize)+planeEq+4,plEq\b) ;pFaces[fi]\planeEq\b
 PokeF(*o\pFaces+(fi*fsize)+planeEq+8,plEq\c) ;pFaces[fi]\planeEq\c
 PokeF(*o\pFaces+(fi*fsize)+planeEq+12,plEq\d) ;pFaces[fi]\planeEq\d
 
EndProcedure

Procedure doShadowPass(*o.SHADOWEDOBJECT, Array lp.f(1)) ;Draw Object's Shadow

 Protected i.l,j.l,k.l,jj.l,p1.l,p2.l
 Protected fsize.l,vsize.l,neigh.l,visible.l
 Protected Dim v.POINT3F(4)
 
 fsize=SizeOf(FACE) ;77
 vsize=SizeOf(POINT3F) ;12
 neigh=OffsetOf(FACE\neigh) ;64
 visible=OffsetOf(FACE\visible) ;76
 
 For i=0 To *o\nFaces-1
  If PeekB(*o\pFaces+(i*fsize)+visible) ;pFaces[i]\visible
   For j=0 To 3-1 ;Go Through Each Edge
    k=PeekL(*o\pFaces+(i*fsize)+neigh+(j*4)) ;pFaces[i]\neigh[j]
    ;If There Is No Neighbour, Or Its Neighbouring Face Is Not Visible, Then This Edge Casts A Shadow
    If k=0 Or PeekB(*o\pFaces+((k-1)*fsize)+visible)=0 ;pFaces[k-1]\visible
   
     ;Get The Points On The Edge
     p1=PeekL(*o\pFaces+(i*fsize)+(j*4)) ;pFaces[i]\vert[j]
     jj=(j+1) % 3
     p2=PeekL(*o\pFaces+(i*fsize)+(jj*4)) ;pFaces[i]\vert[jj]
     
     v(1)\x=PeekF(*o\pVerts+(p1*vsize)) ;pVerts[p1]\x
     v(1)\y=PeekF(*o\pVerts+(p1*vsize)+4) ;pVerts[p1]\y
     v(1)\z=PeekF(*o\pVerts+(p1*vsize)+8) ;pVerts[p1]\z
     
     v(2)\x=PeekF(*o\pVerts+(p2*vsize)) ;pVerts[p2]\x
     v(2)\y=PeekF(*o\pVerts+(p2*vsize)+4) ;pVerts[p2]\y
     v(2)\z=PeekF(*o\pVerts+(p2*vsize)+8) ;pVerts[p2]\z
     
     ;Calculate The Two Vertices In Distance (INFINITY=100)
     v(3)\x=(v(1)\x-lp(0))*100 ;pVerts[p1]\x
     v(3)\y=(v(1)\y-lp(1))*100 ;pVerts[p1]\y
     v(3)\z=(v(1)\z-lp(2))*100 ;pVerts[p1]\z
     
     v(4)\x=(v(2)\x-lp(0))*100 ;pVerts[p2]\x
     v(4)\y=(v(2)\y-lp(1))*100 ;pVerts[p2]\y
     v(4)\z=(v(2)\z-lp(2))*100 ;pVerts[p2]\z
     
     ;Draw The Quadrilateral (As A Triangle Strip)
     glBegin_(#GL_TRIANGLE_STRIP)
      glVertex3f_(v(1)\x,v(1)\y,v(1)\z)
      glVertex3f_(v(1)\x+v(3)\x,v(1)\y+v(3)\y,v(1)\z+v(3)\z)
      glVertex3f_(v(2)\x,v(2)\y,v(2)\z)
      glVertex3f_(v(2)\x+v(4)\x,v(2)\y+v(4)\y,v(2)\z+v(4)\z)
     glEnd_()
     
    EndIf
   Next
  EndIf
 Next
 
EndProcedure

Procedure castShadow(*o.SHADOWEDOBJECT, Array lp.f(1)) ;Render Object's Shadow

 Protected i.l,side.f
 Protected fsize.l,planeEq.l,visible.l
 Protected plEq.PLANE
 
 fsize=SizeOf(FACE) ;77
 planeEq=OffsetOf(FACE\planeEq) ;48
 visible=OffsetOf(FACE\visible) ;76
 
 ;Determine Which Faces Are Visible By The Light
 For i=0 To *o\nFaces-1
  plEq\a=PeekF(*o\pFaces+(i*fsize)+planeEq) ;pFaces[i]\planeEq\a
  plEq\b=PeekF(*o\pFaces+(i*fsize)+planeEq+4) ;pFaces[i]\planeEq\b
  plEq\c=PeekF(*o\pFaces+(i*fsize)+planeEq+8) ;pFaces[i]\planeEq\c
  plEq\d=PeekF(*o\pFaces+(i*fsize)+planeEq+12) ;pFaces[i]\planeEq\d
  side=plEq\a*lp(0) + plEq\b*lp(1) + plEq\c*lp(2) + plEq\d*lp(3)
  If side>0
   PokeB(*o\pFaces+(i*fsize)+visible,#True) ;pFaces[i]\visible
  Else
   PokeB(*o\pFaces+(i*fsize)+visible,#False) ;pFaces[i]\visible
  EndIf
 Next
 
 glDisable_(#GL_LIGHTING) ;Turn Off Lighting
 glDepthMask_(#GL_FALSE) ;Turn Off Writing To The Depth-Buffer
 glDepthFunc_(#GL_LEQUAL)
 
 glEnable_(#GL_STENCIL_TEST) ;Turn On Stencil Buffer Testing
 glColorMask_(0,0,0,0) ;Don't Draw Into The Colour Buffer
 glStencilFunc_(#GL_ALWAYS,1,$ffffffff)
 
 ;First Pass, Stencil Operation Increases Stencil Value
 glFrontFace_(#GL_CCW)
 glStencilOp_(#GL_KEEP,#GL_KEEP,#GL_INCR)
 doShadowPass(*o,lp())
 
 ;Second Pass, Stencil Operation Decreases Stencil Value
 glFrontFace_(#GL_CW)
 glStencilOp_(#GL_KEEP,#GL_KEEP,#GL_DECR)
 doShadowPass(*o,lp())
 
 glFrontFace_(#GL_CCW)
 glColorMask_(1,1,1,1) ;Enable Rendering To Colour Buffer For All Components
 
 ;Draw A Shadowing Rectangle Covering The Entire Screen
 glColor4f_(0.0,0.0,0.0,0.4)
 glEnable_(#GL_BLEND)
 glBlendFunc_(#GL_SRC_ALPHA,#GL_ONE_MINUS_SRC_ALPHA)
 glStencilFunc_(#GL_NOTEQUAL,0,$ffffffff)
 glStencilOp_(#GL_KEEP,#GL_KEEP,#GL_KEEP)
 glPushMatrix_()
 glLoadIdentity_()
 glBegin_(#GL_TRIANGLE_STRIP)
  glVertex3f_(-0.1, 0.1,-0.1)
  glVertex3f_(-0.1,-0.1,-0.1)
  glVertex3f_( 0.1, 0.1,-0.1)
  glVertex3f_( 0.1,-0.1,-0.1)
 glEnd_()
 glPopMatrix_()
 glDisable_(#GL_BLEND)
 
 glDepthFunc_(#GL_LEQUAL)
 glDepthMask_(#GL_TRUE)
 glEnable_(#GL_LIGHTING)
 glDisable_(#GL_STENCIL_TEST)
 glShadeModel_(#GL_SMOOTH)
 
EndProcedure
Working on - MP3D Library - PB 5.73 version ready for download
Post Reply