NeHe's Particle Tutorial (Lesson 19)

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:

NeHe's Particle Tutorial (Lesson 19)

Post by hagibaba »

Code updated for 5.20+

This shows how to set up a user-controlled particle emitter.
Press the Spacebar to cycle colors, Return to toggle rainbow mode, Tab for an explosion burst.
PageUp/PageDown to zoom, NumPad +/- for release rate, Arrows for speed, NumPad Arrows for gravity.
You can get the "Particle.bmp" from the "lesson19.zip" here:
http://nehe.gamedev.net/data/lessons/vc/lesson19.zip

Last edited on 20 Feb 2007.

Code: Select all

;NeHe's Particle Tutorial (Lesson 19)
;http://nehe.gamedev.net
;Credits: Nico Gruener, Dreglor, traumatic
;Author: hagibaba
;Date: 14 Jan 2007
;Note: up-to-date with PB v4.02 (Windows)
;Note: requires a bitmap in path "Data/Particle.bmp"

;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

Structure AUX_RGBImageRec ;glaux.h structure
  sizeX.l : sizeY.l
  Data.l
EndStructure

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

;glaux.lib symbols
!public ___ftoll
!___ftoll dw 0
!public __imp__wsprintfA
!__imp__wsprintfA dw 0

Import "glaux.lib"
  CompilerIf #PB_Compiler_Unicode
    auxDIBImageLoad.l(filename.s) As "_auxDIBImageLoadW@4" ;loads a 24-bit Windows DIB
  CompilerElse
    auxDIBImageLoad.l(filename.s) As "_auxDIBImageLoadA@4" ;loads a 24-bit Windows DIB
  CompilerEndIf
EndImport

Import "glu32.lib"
  gluPerspective(fovy.d,aspect.d,zNear.d,zFar.d) ;sets up a perspective projection matrix
EndImport

Import "opengl32.lib"
  glClearDepth(depth.d) ;specifies the clear value for the depth buffer
EndImport

;Start of Lesson 19

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

#MAX_PARTICLES=1000 ;Number Of Particles To Create

Global rainbow.b=#True ;Rainbow Mode?
Global sp.b ;Spacebar Pressed?
Global rp.b ;Enter Key Pressed?
Global tp.b ;Tab Pressed? Note: added code for cleaner particle burst

Global slowdown.f=2.0 ;Slow Down Particles
Global xspeed.f ;Base X Speed (To Allow Keyboard Direction Of Tail)
Global yspeed.f ;Base Y Speed (To Allow Keyboard Direction Of Tail)
Global zoom.f=-40.0 ;Used To Zoom Out

Global loop.l ;Misc Loop Variable
Global col.l ;Current Color Selection
Global delay.l ;Rainbow Effect Delay
Global Dim texture.l(1) ;Storage For Our Particle Texture

Structure PARTICLES ;Create A Structure For Particles
  active.b ;Active (Yes/No)
  life.f ;Particle Life
  fade.f ;Fade Speed
  r.f : g.f : b.f ;Red, Green, Blue Values
  x.f : y.f : z.f ;X, Y, Z Position
  xi.f : yi.f : zi.f ;X, Y, Z Direction (or increment)
  xg.f : yg.f : zg.f ;X, Y, Z Gravity
EndStructure

Global Dim particle.PARTICLES(#MAX_PARTICLES) ;Particle Array (Room For Particle Info)

Global Dim colors.f(12,3) ;Rainbow Of Colors
colors( 0,0)=1.0  : colors( 0,1)=0.5  : colors( 0,2)=0.5 ;red
colors( 1,0)=1.0  : colors( 1,1)=0.75 : colors( 1,2)=0.5
colors( 2,0)=1.0  : colors( 2,1)=1.0  : colors( 2,2)=0.5 ;yellow
colors( 3,0)=0.75 : colors( 3,1)=1.0  : colors( 3,2)=0.5
colors( 4,0)=0.5  : colors( 4,1)=1.0  : colors( 4,2)=0.5 ;green
colors( 5,0)=0.5  : colors( 5,1)=1.0  : colors( 5,2)=0.75
colors( 6,0)=0.5  : colors( 6,1)=1.0  : colors( 6,2)=1.0 ;cyan
colors( 7,0)=0.5  : colors( 7,1)=0.75 : colors( 7,2)=1.0
colors( 8,0)=0.5  : colors( 8,1)=0.5  : colors( 8,2)=1.0 ;blue
colors( 9,0)=0.75 : colors( 9,1)=0.5  : colors( 9,2)=1.0
colors(10,0)=1.0  : colors(10,1)=0.5  : colors(10,2)=1.0 ;purple
colors(11,0)=1.0  : colors(11,1)=0.5  : colors(11,2)=0.75

Declare.l WndProc(hWnd.l,uMsg.l,wParam.l,lParam.l) ;Declaration For WndProc

Procedure.l LoadBMP(Filename.s) ;Loads A Bitmap Image
  
  Protected File.l=#Null ;File Handle
  
  If Filename="" ;Make Sure A Filename Was Given
    ProcedureReturn #Null ;If Not Return NULL
  EndIf
  
  File=ReadFile(#PB_Any,Filename) ;Check To See If The File Exists
  
  If File ;Does The File Exist?
    CloseFile(File) ;Close The Handle
    ProcedureReturn auxDIBImageLoad(Filename) ;Load The Bitmap And Return A Pointer
  EndIf
  
  ProcedureReturn #Null ;If Load Failed Return NULL
  
EndProcedure

Procedure.l LoadGLTextures() ;Load Bitmaps And Convert To Textures
  
  Protected Status.l=#False ;Status Indicator
  Protected Dim *TextureImage.AUX_RGBImageRec(1) ;Create Storage Space For The Textures
  
  *TextureImage(0)=LoadBMP("Data/Particle.bmp")
  If *TextureImage(0) ;Load Particle Texture
    Status=#True ;Set The Status To TRUE
    
    glGenTextures_(1,@texture(0)) ;Create One Texture
    
    glBindTexture_(#GL_TEXTURE_2D,texture(0))
    glTexParameteri_(#GL_TEXTURE_2D,#GL_TEXTURE_MAG_FILTER,#GL_LINEAR)
    glTexParameteri_(#GL_TEXTURE_2D,#GL_TEXTURE_MIN_FILTER,#GL_LINEAR)
    glTexImage2D_(#GL_TEXTURE_2D,0,3,*TextureImage(0)\sizeX,*TextureImage(0)\sizeY,0,#GL_RGB,#GL_UNSIGNED_BYTE,*TextureImage(0)\Data)
  EndIf
  
  If *TextureImage(0) ;If Texture Exists
    If *TextureImage(0)\Data ;If Texture Image Exists
      ;FreeMemory(*TextureImage(0)\Data) ;Free The Texture Image Memory
    EndIf
    ;FreeMemory(*TextureImage(0)) ;Free The Image Structure
  EndIf
  
  ProcedureReturn Status ;Return The Status
  
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.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 InitGL() ;All Setup For OpenGL Goes Here
  
  If LoadGLTextures()=0 ;Jump To Texture Loading Routine
    ProcedureReturn #False ;If Texture Didn't Load Return FALSE
  EndIf
  
  glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
  glClearColor_(0.0,0.0,0.0,0.0) ;Black Background
  glClearDepth(1.0) ;Depth Buffer Setup
  glDisable_(#GL_DEPTH_TEST) ;Disable Depth Testing
  glEnable_(#GL_BLEND) ;Enable Blending
  glBlendFunc_(#GL_SRC_ALPHA,#GL_ONE) ;Type Of Blending To Perform
  glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
  glHint_(#GL_POINT_SMOOTH_HINT,#GL_NICEST) ;Really Nice Point Smoothing
  glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
  
  glBindTexture_(#GL_TEXTURE_2D,texture(0)) ;Select Our Texture
  
  For loop=0 To #MAX_PARTICLES-1 ;Initializes All The Particles
    particle(loop)\active=#True ;Make All The Particles Active
    particle(loop)\life=1.0 ;Give All The Particles Full Life
    particle(loop)\fade=Random(100)/1000.0+0.003 ;Random Fade Speed
    particle(loop)\r=colors((loop*12)/#MAX_PARTICLES,0) ;Select Red Rainbow Color
    particle(loop)\g=colors((loop*12)/#MAX_PARTICLES,1) ;Select Green Rainbow Color
    particle(loop)\b=colors((loop*12)/#MAX_PARTICLES,2) ;Select Blue Rainbow Color
    particle(loop)\xi=(Random(50)-25.0)*10.0 ;Random Speed On X Axis
    particle(loop)\yi=(Random(50)-25.0)*10.0 ;Random Speed On Y Axis
    particle(loop)\zi=(Random(50)-25.0)*10.0 ;Random Speed On Z Axis
    particle(loop)\xg=0.0 ;Set Horizontal Pull To Zero
    particle(loop)\yg=-0.8 ;Set Vertical Pull Downward
    particle(loop)\zg=0.0 ;Set Pull On Z Axis To Zero
  Next
  
  ProcedureReturn #True ;Initialization Went OK
  
EndProcedure

Procedure.l DrawGLScene() ;Here's Where We Do All The Drawing
  
  Protected x.f,y.f,z.f ;particle positions
  
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear Screen And Depth Buffer
  glLoadIdentity_() ;Reset The Modelview Matrix
  
  For loop=0 To #MAX_PARTICLES-1 ;Loop Through All The Particles
    If particle(loop)\active ;If The Particle Is Active
      
      x=particle(loop)\x ;Grab Our Particle X Position
      y=particle(loop)\y ;Grab Our Particle Y Position
      z=particle(loop)\z+zoom ;Particle Z Pos + Zoom
      
      ;Draw The Particle Using Our RGB Values, Fade The Particle Based On It's Life
      glColor4f_(particle(loop)\r,particle(loop)\g,particle(loop)\b,particle(loop)\life)
      
      glBegin_(#GL_TRIANGLE_STRIP) ;Build Quad From A Triangle Strip
      glTexCoord2f_(1.0,1.0) : glVertex3f_(x+0.5,y+0.5,z) ;Top Right (v0)
      glTexCoord2f_(0.0,1.0) : glVertex3f_(x-0.5,y+0.5,z) ;Top Left (v1)
      glTexCoord2f_(1.0,0.0) : glVertex3f_(x+0.5,y-0.5,z) ;Bottom Right (v2)
      glTexCoord2f_(0.0,0.0) : glVertex3f_(x-0.5,y-0.5,z) ;Bottom Left (v3)
      glEnd_() ;Done Building Triangle Strip
      
      particle(loop)\x+particle(loop)\xi/(slowdown*1000) ;Move On The X Axis By X Speed
      particle(loop)\y+particle(loop)\yi/(slowdown*1000) ;Move On The Y Axis By Y Speed
      particle(loop)\z+particle(loop)\zi/(slowdown*1000) ;Move On The Z Axis By Z Speed
      
      particle(loop)\xi+particle(loop)\xg ;Take Pull On X Axis Into Account
      particle(loop)\yi+particle(loop)\yg ;Take Pull On Y Axis Into Account
      particle(loop)\zi+particle(loop)\zg ;Take Pull On Z Axis Into Account
      
      particle(loop)\life-particle(loop)\fade ;Reduce Particles Life By 'Fade'
      
      If particle(loop)\life<0.0 ;If Particle Is Burned Out
        particle(loop)\life=1.0 ;Give It New Life
        particle(loop)\fade=Random(100)/1000.0+0.003 ;Random Fade Value
        particle(loop)\x=0.0 ;Center On X Axis
        particle(loop)\y=0.0 ;Center On Y Axis
        particle(loop)\z=0.0 ;Center On Z Axis
        particle(loop)\xi=xspeed+(Random(60)-30.0) ;X Axis Speed And Direction
        particle(loop)\yi=yspeed+(Random(60)-30.0) ;Y Axis Speed And Direction
        particle(loop)\zi=(Random(60)-30.0) ;Z Axis Speed And Direction
        particle(loop)\r=colors(col,0) ;Select Red From Color Table
        particle(loop)\g=colors(col,1) ;Select Green From Color Table
        particle(loop)\b=colors(col,2) ;Select Blue From Color Table
      EndIf
      
      If keys(#VK_NUMPAD8) And particle(loop)\yg<1.5 ;NumPad 8 And Y Gravity Less Than 1.5
        particle(loop)\yg+0.01 ;Increase Pull Upwards
      EndIf
      If keys(#VK_NUMPAD2) And particle(loop)\yg>-1.5 ;NumPad 2 And Y Gravity Greater Than -1.5
        particle(loop)\yg-0.01 ;Increase Pull Downwards
      EndIf
      If keys(#VK_NUMPAD6) And particle(loop)\xg<1.5 ;NumPad 6 And X Gravity Less Than 1.5
        particle(loop)\xg+0.01 ;Increase Pull Right
      EndIf
      If keys(#VK_NUMPAD4) And particle(loop)\xg>-1.5 ;NumPad 4 And X Gravity Greater Than -1.5
        particle(loop)\xg-0.01 ;Increase Pull Left
      EndIf
      
    EndIf
  Next
  
  If keys(#VK_TAB) And tp=0 ;Tab Key Causes A Burst
    tp=#True ;Set Flag
    For loop=0 To #MAX_PARTICLES-1 ;Loop Through All The Particles
      particle(loop)\life=1.0 ;Give It New Life
      particle(loop)\x=0.0 ;Center On X Axis
      particle(loop)\y=0.0 ;Center On Y Axis
      particle(loop)\z=0.0 ;Center On Z Axis
      particle(loop)\xi=(Random(50)-25.0)*10.0 ;Random Speed On X Axis
      particle(loop)\yi=(Random(50)-25.0)*10.0 ;Random Speed On Y Axis
      particle(loop)\zi=(Random(50)-25.0)*10.0 ;Random Speed On Z Axis
    Next
  EndIf
  If keys(#VK_TAB)=0 ;If Tab Is Released
    tp=#False ;Clear Flag
  EndIf
  
  ProcedureReturn #True ;Everything Went OK
  
EndProcedure

Procedure KillGLWindow() ;Properly Kill The Window
  
  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=0 ;No Stencil Buffer
  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("NeHe's Particle Tutorial",640,480,16,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(1)
        SwapBuffers_(hDC) ;Swap Buffers (Double Buffering)
        
        If keys(#VK_ADD) And slowdown>1.0 ;NumPad + Pressed
          slowdown-0.01 ;Speed Up Particles
        EndIf
        If keys(#VK_SUBTRACT) And slowdown<4.0 ;NumPad - Pressed
          slowdown+0.01 ;Slow Down Particles
        EndIf
        
        If keys(#VK_PRIOR) ;Page Up Pressed
          zoom+0.1 ;Zoom In
        EndIf
        If keys(#VK_NEXT) ;Page Down Pressed
          zoom-0.1 ;Zoom Out
        EndIf
        
        If keys(#VK_RETURN) And rp=0 ;Return Key Pressed
          rp=#True ;Set Flag Telling Us It's Pressed
          rainbow=~rainbow & 1 ;Toggle Rainbow Mode On / Off
        EndIf
        If keys(#VK_RETURN)=0 ;If Return Is Released
          rp=#False ;Clear Flag
        EndIf
        
        If (keys(#VK_SPACE) And sp=0) Or (rainbow And delay>25) ;Space Or Rainbow Mode
          If keys(#VK_SPACE) ;If Spacebar Is Pressed
            sp=#True ;Set Flag Telling Us Space Is Pressed
            rainbow=#False ;Disable Rainbow Mode
          EndIf
          delay=0 ;Reset The Rainbow Color Cycling Delay
          col+1 ;Change The Particle Color
          If col>11 : col=0 : EndIf ;If Color Is Too High Reset It
        EndIf
        If keys(#VK_SPACE)=0 ;If Spacebar Is Released Clear Flag
          sp=#False
        EndIf
        
        If keys(#VK_UP) And yspeed<200 ;Up Arrow And Y Speed Less Than 200
          yspeed+1.0 ;Increase Upward Speed
        EndIf
        If keys(#VK_DOWN) And yspeed>-200 ;Down Arrow And Y Speed Greater Than -200
          yspeed-1.0 ;Increase Downward Speed
        EndIf
        If keys(#VK_RIGHT) And xspeed<200 ;Right Arrow And X Speed Less Than 200
          xspeed+1.0 ;Increase Speed To The Right
        EndIf
        If keys(#VK_LEFT) And xspeed>-200 ;Left Arrow And X Speed Greater Than -200
          xspeed-1.0 ;Increase Speed To The Left
        EndIf
        
        delay+1 ;Increase Rainbow Mode Color Cycling Delay Counter
        
      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("NeHe's Particle Tutorial",640,480,16,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:17 pm, edited 9 times in total.
THCM
Enthusiast
Enthusiast
Posts: 276
Joined: Fri Apr 25, 2003 5:06 pm
Location: Gummersbach - Germany
Contact:

Post by THCM »

Good work... keep it coming!
The Human Code Machine / Masters' Design Group
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: NeHe's Particle Tutorial (Lesson 19)

Post by mpz »

Hello,

next code actualised for x86/x64, PB 5.73.

you can choose a purebasic texture or get the original from the internet

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


Greetings Michael

C Code and texture
iamyaker.googlepages.com/19_Particles.rar

Code: Select all

;NeHe's Particle Tutorial (Lesson 19)
;http://nehe.gamedev.net 
;https://nehe.gamedev.net/tutorial/particle_engine_using_triangle_strips/21001/
;Credits: Nico Gruener, Dreglor, traumatic, hagibaba
;Author: MPz
;Date: 05 Oct 2021
;Note: up-to-date with PB v5.73 (Windows)


UsePNGImageDecoder() 

#MAX_PARTICLES=1000 ;Number Of Particles To Create

Global rainbow.b=#True ;Rainbow Mode?
Global sp.b ;Spacebar Pressed?
Global rp.b ;Enter Key Pressed?
Global tp.b ;Tab Pressed? Note: added code for cleaner particle burst

Global slowdown.f=2.0 ;Slow Down Particles
Global xspeed.f ;Base X Speed (To Allow Keyboard Direction Of Tail)
Global yspeed.f ;Base Y Speed (To Allow Keyboard Direction Of Tail)
Global zoom.f=-40.0 ;Used To Zoom Out

Global LOOP.l ;Misc Loop Variable
Global col.l ;Current Color Selection
Global delay.l ;Rainbow Effect Delay
Global Dim texture.l(1) ;Storage For Our Particle Texture

Structure PARTICLES ;Create A Structure For Particles
  active.b ;Active (Yes/No)
  life.f ;Particle Life
  fade.f ;Fade Speed
  r.f : g.f : b.f ;Red, Green, Blue Values
  x.f : y.f : z.f ;X, Y, Z Position
  xi.f : yi.f : zi.f ;X, Y, Z Direction (or increment)
  xg.f : yg.f : zg.f ;X, Y, Z Gravity
EndStructure

Global Dim particle.PARTICLES(#MAX_PARTICLES) ;Particle Array (Room For Particle Info)

Global Dim colors.f(12,3) ;Rainbow Of Colors
colors( 0,0)=1.0  : colors( 0,1)=0.5  : colors( 0,2)=0.5 ;red
colors( 1,0)=1.0  : colors( 1,1)=0.75 : colors( 1,2)=0.5
colors( 2,0)=1.0  : colors( 2,1)=1.0  : colors( 2,2)=0.5 ;yellow
colors( 3,0)=0.75 : colors( 3,1)=1.0  : colors( 3,2)=0.5
colors( 4,0)=0.5  : colors( 4,1)=1.0  : colors( 4,2)=0.5 ;green
colors( 5,0)=0.5  : colors( 5,1)=1.0  : colors( 5,2)=0.75
colors( 6,0)=0.5  : colors( 6,1)=1.0  : colors( 6,2)=1.0 ;cyan
colors( 7,0)=0.5  : colors( 7,1)=0.75 : colors( 7,2)=1.0
colors( 8,0)=0.5  : colors( 8,1)=0.5  : colors( 8,2)=1.0 ;blue
colors( 9,0)=0.75 : colors( 9,1)=0.5  : colors( 9,2)=1.0
colors(10,0)=1.0  : colors(10,1)=0.5  : colors(10,2)=1.0 ;purple
colors(11,0)=1.0  : colors(11,1)=0.5  : colors(11,2)=0.75

Procedure LoadGLTextures(Names.s)
  
  Define.i img = LoadImage(0, Names)
  
  If img
    
    *pointer = EncodeImage(0, #PB_ImagePlugin_BMP,0,24);  
    FreeImage(0)
  	
    glGenTextures_(1, @Texture(0));                  // Create Three Textures

    ;// Create Linear Filtered Texture
    glBindTexture_(#GL_TEXTURE_2D, Texture(0));
    glTexParameteri_(#GL_TEXTURE_2D,#GL_TEXTURE_MAG_FILTER,#GL_LINEAR);
    glTexParameteri_(#GL_TEXTURE_2D,#GL_TEXTURE_MIN_FILTER,#GL_LINEAR);
    glTexImage2D_(#GL_TEXTURE_2D, 0, 3, PeekL(*pointer+18),PeekL(*pointer+22), 0, #GL_BGR_EXT, #GL_UNSIGNED_BYTE,  *pointer+54);
    
    FreeMemory(*pointer)
    
   Else
     MessageRequester("Error", "Konnte Textur "+names+" nicht laden", 0)
   EndIf

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 InitGL() ;All Setup For OpenGL Goes Here

  glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
  glClearColor_(0.0,0.0,0.0,0.0) ;Black Background
  glClearDepth_(1.0) ;Depth Buffer Setup
  glDisable_(#GL_DEPTH_TEST) ;Disable Depth Testing
  glEnable_(#GL_BLEND) ;Enable Blending
  glBlendFunc_(#GL_SRC_ALPHA,#GL_ONE) ;Type Of Blending To Perform
  glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
  glHint_(#GL_POINT_SMOOTH_HINT,#GL_NICEST) ;Really Nice Point Smoothing
  glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
  
  glBindTexture_(#GL_TEXTURE_2D,texture(0)) ;Select Our Texture
  
  For LOOP=0 To #MAX_PARTICLES-1 ;Initializes All The Particles
    particle(LOOP)\active=#True ;Make All The Particles Active
    particle(LOOP)\life=1.0 ;Give All The Particles Full Life
    particle(LOOP)\fade=Random(100)/1000.0+0.003 ;Random Fade Speed
    particle(LOOP)\r=colors((LOOP*12)/#MAX_PARTICLES,0) ;Select Red Rainbow Color
    particle(LOOP)\g=colors((LOOP*12)/#MAX_PARTICLES,1) ;Select Green Rainbow Color
    particle(LOOP)\b=colors((LOOP*12)/#MAX_PARTICLES,2) ;Select Blue Rainbow Color
    particle(LOOP)\xi=(Random(50)-25.0)*10.0 ;Random Speed On X Axis
    particle(LOOP)\yi=(Random(50)-25.0)*10.0 ;Random Speed On Y Axis
    particle(LOOP)\zi=(Random(50)-25.0)*10.0 ;Random Speed On Z Axis
    particle(LOOP)\xg=0.0 ;Set Horizontal Pull To Zero
    particle(LOOP)\yg=-0.8 ;Set Vertical Pull Downward
    particle(LOOP)\zg=0.0 ;Set Pull On Z Axis To Zero
  Next
 
 ProcedureReturn #True ;Initialization Went OK
 
EndProcedure


Procedure DrawScene(Gadget)
  
 SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
  
 Protected x.f,y.f,z.f ;particle positions
  
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear Screen And Depth Buffer
  glLoadIdentity_() ;Reset The Modelview Matrix
  
  For LOOP=0 To #MAX_PARTICLES-1 ;Loop Through All The Particles
    If particle(LOOP)\active ;If The Particle Is Active
      
      x=particle(LOOP)\x ;Grab Our Particle X Position
      y=particle(LOOP)\y ;Grab Our Particle Y Position
      z=particle(LOOP)\z+zoom ;Particle Z Pos + Zoom
      
      ;Draw The Particle Using Our RGB Values, Fade The Particle Based On It's Life
      glColor4f_(particle(LOOP)\r,particle(LOOP)\g,particle(LOOP)\b,particle(LOOP)\life)
      
      glBegin_(#GL_TRIANGLE_STRIP) ;Build Quad From A Triangle Strip
      glTexCoord2f_(1.0,1.0) : glVertex3f_(x+0.5,y+0.5,z) ;Top Right (v0)
      glTexCoord2f_(0.0,1.0) : glVertex3f_(x-0.5,y+0.5,z) ;Top Left (v1)
      glTexCoord2f_(1.0,0.0) : glVertex3f_(x+0.5,y-0.5,z) ;Bottom Right (v2)
      glTexCoord2f_(0.0,0.0) : glVertex3f_(x-0.5,y-0.5,z) ;Bottom Left (v3)
      glEnd_() ;Done Building Triangle Strip
      
      particle(LOOP)\x+particle(LOOP)\xi/(slowdown*1000) ;Move On The X Axis By X Speed
      particle(LOOP)\y+particle(LOOP)\yi/(slowdown*1000) ;Move On The Y Axis By Y Speed
      particle(LOOP)\z+particle(LOOP)\zi/(slowdown*1000) ;Move On The Z Axis By Z Speed
      
      particle(LOOP)\xi+particle(LOOP)\xg ;Take Pull On X Axis Into Account
      particle(LOOP)\yi+particle(LOOP)\yg ;Take Pull On Y Axis Into Account
      particle(LOOP)\zi+particle(LOOP)\zg ;Take Pull On Z Axis Into Account
      
      particle(LOOP)\life-particle(LOOP)\fade ;Reduce Particles Life By 'Fade'
      
      If particle(LOOP)\life<0.0 ;If Particle Is Burned Out
        particle(LOOP)\life=1.0 ;Give It New Life
        particle(LOOP)\fade=Random(100)/1000.0+0.003 ;Random Fade Value
        particle(LOOP)\x=0.0 ;Center On X Axis
        particle(LOOP)\y=0.0 ;Center On Y Axis
        particle(LOOP)\z=0.0 ;Center On Z Axis
        particle(LOOP)\xi=xspeed+(Random(60)-30.0) ;X Axis Speed And Direction
        particle(LOOP)\yi=yspeed+(Random(60)-30.0) ;Y Axis Speed And Direction
        particle(LOOP)\zi=(Random(60)-30.0) ;Z Axis Speed And Direction
        particle(LOOP)\r=colors(col,0) ;Select Red From Color Table
        particle(LOOP)\g=colors(col,1) ;Select Green From Color Table
        particle(LOOP)\b=colors(col,2) ;Select Blue From Color Table
      EndIf
      
      If KeyboardPushed(#PB_Key_Pad8) And particle(LOOP)\yg<1.5 ;NumPad 8 And Y Gravity Less Than 1.5
        particle(LOOP)\yg+0.01 ;Increase Pull Upwards
      EndIf
      If KeyboardPushed(#PB_Key_Pad2) And particle(LOOP)\yg>-1.5 ;NumPad 2 And Y Gravity Greater Than -1.5
        particle(LOOP)\yg-0.01 ;Increase Pull Downwards
      EndIf
      If KeyboardPushed(#PB_Key_Pad6) And particle(LOOP)\xg<1.5 ;NumPad 6 And X Gravity Less Than 1.5
        particle(LOOP)\xg+0.01 ;Increase Pull Right
      EndIf
      If KeyboardPushed(#PB_Key_Pad4) And particle(LOOP)\xg>-1.5 ;NumPad 4 And X Gravity Greater Than -1.5
        particle(LOOP)\xg-0.01 ;Increase Pull Left
      EndIf
      
    EndIf
  Next
  
  If KeyboardPushed(#PB_Key_Tab) And tp=0 ;Tab Key Causes A Burst
    tp=#True ;Set Flag
    For LOOP=0 To #MAX_PARTICLES-1 ;Loop Through All The Particles
      particle(LOOP)\life=1.0 ;Give It New Life
      particle(LOOP)\x=0.0 ;Center On X Axis
      particle(LOOP)\y=0.0 ;Center On Y Axis
      particle(LOOP)\z=0.0 ;Center On Z Axis
      particle(LOOP)\xi=(Random(50)-25.0)*10.0 ;Random Speed On X Axis
      particle(LOOP)\yi=(Random(50)-25.0)*10.0 ;Random Speed On Y Axis
      particle(LOOP)\zi=(Random(50)-25.0)*10.0 ;Random Speed On Z Axis
    Next
  EndIf
  If Not KeyboardPushed(#PB_Key_Tab) ;If Tab Is Released
    tp=#False ;Clear Flag
  EndIf
  
 SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
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 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("NeHe's Particle Tutorial (Lesson 19)",640,480,16,0)

InitGL()

LoadGLTextures(#PB_Compiler_Home + "examples/3d/Data/Textures/flare.png")
;LoadGLTextures("Data/Particle.bmp"); -> Original from http://nehe.gamedev.net


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)    ; // push ESC key
    Quit = 1                               ; // This is the end
  EndIf
  
  If KeyboardPushed(#PB_Key_Add) And slowdown>1.0 ;NumPad + Pressed
     slowdown-0.01 ;Speed Up Particles
  EndIf
  
  If KeyboardPushed(#PB_Key_Subtract) And slowdown<4.0 ;NumPad - Pressed
     slowdown+0.01 ;Slow Down Particles
  EndIf
        
  If KeyboardPushed(#PB_Key_PageUp) ;Page Up Pressed
     zoom+0.1 ;Zoom In
  EndIf
  
  If KeyboardPushed(#PB_Key_PageDown) ;Page Down Pressed
     zoom-0.1 ;Zoom Out
  EndIf
        
  If KeyboardPushed(#PB_Key_Return) And rp=0 ;Return Key Pressed
     rp=#True ;Set Flag Telling Us It's Pressed
     rainbow=~rainbow & 1 ;Toggle Rainbow Mode On / Off
  EndIf
  
  If Not KeyboardPushed(#PB_Key_Return)=0 ;If Return Is Released
     rp=#False ;Clear Flag
  EndIf
        
  If (KeyboardPushed(#PB_Key_Space) And sp=0) Or (rainbow And delay>25) ;Space Or Rainbow Mode
     If KeyboardPushed(#PB_Key_Space) ;If Spacebar Is Pressed
        sp=#True ;Set Flag Telling Us Space Is Pressed
        rainbow=#False ;Disable Rainbow Mode
      EndIf
      
     delay=0 ;Reset The Rainbow Color Cycling Delay
     col+1 ;Change The Particle Color
     If col>11 : col=0 : EndIf ;If Color Is Too High Reset It
  EndIf
  
  If Not KeyboardPushed(#PB_Key_Space) ;If Spacebar Is Released Clear Flag
     sp=#False
  EndIf
        
  If KeyboardPushed(#PB_Key_Up) And yspeed<200 ;Up Arrow And Y Speed Less Than 200
     yspeed+1.0 ;Increase Upward Speed
  EndIf
  
  If KeyboardPushed(#PB_Key_Down) And yspeed>-200 ;Down Arrow And Y Speed Greater Than -200
     yspeed-1.0 ;Increase Downward Speed
  EndIf
  
  If KeyboardPushed(#PB_Key_Right) And xspeed<200 ;Right Arrow And X Speed Less Than 200
     xspeed+1.0 ;Increase Speed To The Right
  EndIf
  
  If KeyboardPushed(#PB_Key_Left) And xspeed>-200 ;Left Arrow And X Speed Greater Than -200
     xspeed-1.0 ;Increase Speed To The Left
  EndIf
        
  delay+1 ;Increase Rainbow Mode Color Cycling Delay Counter
  
  DrawScene(0)
  Delay(1)
Until Quit = 1

Working on - MP3D Library - PB 5.73 version ready for download
Post Reply