Piotr Cieslak & NeHe's Morphing Tutorial (Lesson 25)

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:

Piotr Cieslak & NeHe's Morphing Tutorial (Lesson 25)

Post by hagibaba »

Code updated for 5.20+

This shows how to load objects from a file and morph from one object to another.
Press 1-4 keys to morph object, Arrows and Pageup/Pagedown to rotate, A/D, W/S and Q/Z keys to move.
You can get the "Sphere.txt", "Torus.txt", "Tube.txt" from the "lesson25.zip" here:
http://nehe.gamedev.net/data/lessons/vc/lesson25.zip

Last edited on 20 Feb 2007.

Code: Select all

;Piotr Cieslak & NeHe's Morphing Points Tutorial (Lesson 25)
;http://nehe.gamedev.net
;Credits: Nico Gruener, Dreglor, traumatic
;Author: hagibaba
;Date: 9 Feb 2007
;Note: up-to-date with PB v4.02 (Windows)
;Note: requires vertex data text files in paths "Data/Sphere.txt",
;"Data/Torus.txt", "Data/Tube.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
EndImport

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

;Start of Lesson 25

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 xrot.f,yrot.f,zrot.f ;X, Y & Z Rotation
Global xspeed.f,yspeed.f,zspeed.f ;X, Y & Z Spin Speed
Global cx.f,cy.f,cz.f=-15 ;X, Y & Z Position

Global key.l=1 ;Used To Make Sure Same Morph Key Is Not Pressed
Global stepcount.l=0,steps.l=200 ;Step Counter And Maximum Number Of Steps
Global morph.b=#False ;Default morph To False (Not Morphing)

Structure VERTEX ;Structure For 3D Points
  x.f : y.f : z.f ;X, Y & Z Points
EndStructure

Structure OBJECT ;Structure For An Object
  verts.l ;Number Of Vertices For The Object
  points.l ;Address Of Vertice Data (x,y & z)
EndStructure

Global maxver.l ;Will Eventually Hold The Maximum Number Of Vertices
Global morph1.OBJECT,morph2.OBJECT,morph3.OBJECT,morph4.OBJECT ;Our 4 Morphable Objects
Global helper.OBJECT ;Helper Object
Global *sour.OBJECT,*dest.OBJECT ;Source Object, Destination Object

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

Procedure objallocate(*k.OBJECT,n.l) ;Allocate Memory For Each Object And Defines points
  
  *k\points=AllocateMemory(SizeOf(VERTEX)*n) ;Sets points Equal To VERTEX * Number Of Vertices (3 Points For Each Vertice)
  
EndProcedure

Procedure objfree(*k.OBJECT) ;Frees The Object (Releasing The Memory)
  
  FreeMemory(*k\points) ;Frees Points
  
EndProcedure

Procedure.s readstr(f.l) ;Reads A String From File (f)
  
  Protected string.s
  While Left(string,1)="/" Or Left(string,1)="" ;Until End Of Line Is Reached
    string=ReadString(f) ;Gets A String From f (File)
  Wend
  ProcedureReturn string ;return the line
  
EndProcedure

Procedure objload(name.s,*k.OBJECT) ;Loads Object From File (name)
  
  Protected ver.l ;Will Hold Vertice Count
  Protected filein.l ;Filename To Open
  Protected oneline.s ;Holds One Line Of Text (255 Chars Max)
  Protected i.l,char.s,pos.l,count.l
  
  filein=ReadFile(#PB_Any,name) ;Opens The File For Reading Text In Translated Mode
  
  oneline=readstr(filein) ;Jumps To Code That Reads One Line Of Text From The File
  
  For pos=1 To Len(oneline) ;parse the line, instead of sscanf()
    If Asc(Mid(oneline,pos,1))>48 And Asc(Mid(oneline,pos,1))<58 ;numeric char
      char=Mid(oneline,pos,Len(oneline)-pos+1)
      ver=Val(char) ;Number Is Stored In ver
      Break ;exit loop
    EndIf
  Next
  
  *k\verts=ver ;Sets Objects verts Variable To Equal The Value Of ver
  objallocate(*k,ver) ;Jumps To Code That Allocates Ram To Hold The Object
  
  For i=0 To ver-1 ;Loops Through The Vertices
    oneline=readstr(filein) ;Reads In The Next Line Of Text
    
    count=0 : char="" ;reset for each line
    For pos=1 To Len(oneline) ;parse the line, instead of sscanf()
      If Mid(oneline,pos,1)<>" " ;if not space
        char=char+Mid(oneline,pos,1) ;add char
      EndIf
      If Len(char)>0 And (Mid(oneline,pos,1)=" " Or pos=Len(oneline)) ;if char and space or end-of-line
        Select count ;Store Values Into Respective Vertices
          Case 0 : PokeF(*k\points+(i*SizeOf(VERTEX)),ValF(char)) ;Sets Objects (k) points x Value
          Case 1 : PokeF(*k\points+(i*SizeOf(VERTEX))+4,ValF(char)) ;Sets Objects (k) points y Value
          Case 2 : PokeF(*k\points+(i*SizeOf(VERTEX))+8,ValF(char)) ;Sets Objects (k) points z Value
        EndSelect
        count=count+1 ;next VERTEX member
        char="" ;reset for next
      EndIf
    Next
    
  Next
  
  CloseFile(filein) ;Close The File
  
  If ver>maxver ;If ver Is Greater Than maxver Set maxver Equal To ver
    maxver=ver ;Keeps Track Of Highest Number Of Vertices Used In Any Of The Objects
  EndIf
  
EndProcedure

Procedure.l calculate(i.l) ;Calculates Movement Of Points During Morphing
  
  ;This Makes Points Move At A Speed So They All Get To Their Destination At The Same Time
  Static a.VERTEX ;Static Vertex Called a
  a\x=(PeekF(*sour\points+(i*SizeOf(VERTEX)))-PeekF(*dest\points+(i*SizeOf(VERTEX))))/steps ;a\x Value Equals Source x - Destination x Divided By Steps
  a\y=(PeekF(*sour\points+(i*SizeOf(VERTEX))+4)-PeekF(*dest\points+(i*SizeOf(VERTEX))+4))/steps ;a\y Value Equals Source y - Destination y Divided By Steps
  a\z=(PeekF(*sour\points+(i*SizeOf(VERTEX))+8)-PeekF(*dest\points+(i*SizeOf(VERTEX))+8))/steps ;a\z Value Equals Source z - Destination z Divided By Steps
  ProcedureReturn a ;Return Pointer To The Results
  
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
  
  Protected i.l
  
  glBlendFunc_(#GL_SRC_ALPHA,#GL_ONE) ;Set The Blending Function For Translucency
  glClearColor_(0.0,0.0,0.0,0.0) ;This Will Clear The Background Color To Black
  glClearDepth(1.0) ;Enables Clearing Of The Depth Buffer
  glDepthFunc_(#GL_LESS) ;The Type Of Depth Test To Do
  glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
  glShadeModel_(#GL_SMOOTH) ;Enables Smooth Color Shading
  glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
  
  maxver=0 ;Sets Max Vertices To 0 By Default
  objload("Data/Sphere.txt",morph1) ;Load The First Object Into morph1 From File Sphere.txt
  objload("Data/Torus.txt",morph2) ;Load The Second Object Into morph2 From File Torus.txt
  objload("Data/Tube.txt",morph3) ;Load The Third Object Into morph3 From File Tube.txt
  
  objallocate(morph4,486) ;Manually Reserver Ram For A 4th 486 Vertice Object (morph4)
  For i=0 To 486-1 ;Loop Through All 486 Vertices
    PokeF(morph4\points+(i*SizeOf(VERTEX)),(Random(14000)/1000)-7) ;morph4 x Point Becomes A Random Float Value From -7 to 7
    PokeF(morph4\points+(i*SizeOf(VERTEX))+4,(Random(14000)/1000)-7) ;morph4 y Point Becomes A Random Float Value From -7 to 7
    PokeF(morph4\points+(i*SizeOf(VERTEX))+8,(Random(14000)/1000)-7) ;morph4 z Point Becomes A Random Float Value From -7 to 7
  Next
  
  objload("Data/Sphere.txt",helper) ;Load Sphere.txt Object Into Helper (Used As Starting Point)
  *sour=morph1 ;Source & Destination Are Set To Equal First Object (morph1)
  *dest=morph1
  
  ProcedureReturn #True ;Initialization Went OK
  
EndProcedure

Procedure.l DrawGLScene() ;Here's Where We Do All The Drawing
  
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear The Screen And The Depth Buffer
  glLoadIdentity_() ;Reset The View
  glTranslatef_(cx,cy,cz) ;Translate The The Current Position To Start Drawing
  glRotatef_(xrot,1.0,0.0,0.0) ;Rotate On The X Axis By xrot
  glRotatef_(yrot,0.0,1.0,0.0) ;Rotate On The Y Axis By yrot
  glRotatef_(zrot,0.0,0.0,1.0) ;Rotate On The Z Axis By zrot
  
  xrot+xspeed : yrot+yspeed : zrot+zspeed ;Increase xrot,yrot & zrot by xspeed, yspeed & zspeed
  
  Protected tx.f,ty.f,tz.f ;Temp X, Y & Z Variables
  Protected *q.VERTEX ;Holds Returned Calculated Values For One Vertex
  Protected i.l,t.VERTEX
  
  glBegin_(#GL_POINTS) ;Begin Drawing Points
  For i=0 To morph1\verts-1 ;Loop Through All The Verts Of morph1 (All Objects Have The Same Amount Of Verts For Simplicity, Could Use maxver Also)
    If morph ;If morph Is True Calculate Movement Otherwise Movement=0
      *q=calculate(i) ;*q points to a.VERTEX
    Else
      *q=t.VERTEX ;*q points to t.VERTEX, t fields are always zero
    EndIf
    tx=PeekF(helper\points+(i*SizeOf(VERTEX)))-*q\x
    ty=PeekF(helper\points+(i*SizeOf(VERTEX))+4)-*q\y
    tz=PeekF(helper\points+(i*SizeOf(VERTEX))+8)-*q\z
    PokeF(helper\points+(i*SizeOf(VERTEX)),tx) ;Subtract q\x Units From helper\points x (Move On X Axis)
    PokeF(helper\points+(i*SizeOf(VERTEX))+4,ty) ;Subtract q\y Units From helper\points y (Move On Y Axis)
    PokeF(helper\points+(i*SizeOf(VERTEX))+8,tz) ;Subtract q\z Units From helper\points z (Move On Z Axis)
    tx=PeekF(helper\points+(i*SizeOf(VERTEX))) ;Make Temp X Variable Equal To Helper's X Variable
    ty=PeekF(helper\points+(i*SizeOf(VERTEX))+4) ;Make Temp Y Variable Equal To Helper's Y Variable
    tz=PeekF(helper\points+(i*SizeOf(VERTEX))+8) ;Make Temp Z Variable Equal To Helper's Z Variable
    
    glColor3f_(0.0,1.0,1.0) ;Set Color To A Bright Shade Of Off Blue
    glVertex3f_(tx,ty,tz) ;Draw A Point At The Current Temp Values (Vertex)
    glColor3f_(0.0,0.5,1.0) ;Darken Color A Bit
    tx-2**q\x : ty-2**q\y : tz-2**q\z ;Calculate Two Positions Ahead
    glVertex3f_(tx,ty,tz) ;Draw A Second Point At The Newly Calculate Position
    glColor3f_(0.0,0.0,1.0) ;Set Color To A Very Dark Blue
    tx-2**q\x : ty-2**q\y : tz-2**q\z ;Calculate Two More Positions Ahead
    glVertex3f_(tx,ty,tz) ;Draw A Third Point At The Second New Position
  Next ;This Creates A Ghostly Tail As Points Move
  glEnd_() ;Done Drawing Points
  
  ;If We're Morphing And We Haven't Gone Through All 200 Steps Increase Our Step Counter
  ;Otherwise Set Morphing To False, Make Source=Destination And Set The Step Counter Back To Zero.
  If morph And stepcount<=steps
    stepcount+1
  Else
    morph=#False : *sour=*dest : stepcount=0
  EndIf
  
  ProcedureReturn #True ;Keep Going
  
EndProcedure

Procedure KillGLWindow() ;Properly Kill The Window
  
  objfree(morph1) ;Jump To Code To Release morph1 Allocated Ram
  objfree(morph2) ;Jump To Code To Release morph2 Allocated Ram
  objfree(morph3) ;Jump To Code To Release morph3 Allocated Ram
  objfree(morph4) ;Jump To Code To Release morph4 Allocated Ram
  objfree(helper) ;Jump To Code To Release helper Allocated Ram
  
  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("Piotr Cieslak & NeHe's Morphing Points 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(5)
        SwapBuffers_(hDC) ;Swap Buffers (Double Buffering)
        
        If keys(#VK_PRIOR) And zspeed<0.5 ;Is Page Up Being Pressed?
          zspeed+0.01 ;Increase zspeed
        EndIf
        If keys(#VK_NEXT) And zspeed>-0.5 ;Is Page Down Being Pressed?
          zspeed-0.01 ;Decrease zspeed
        EndIf
        If keys(#VK_DOWN) And xspeed<0.5 ;Is Page Up Being Pressed?
          xspeed+0.01 ;Increase xspeed
        EndIf
        If keys(#VK_UP) And xspeed>-0.5 ;Is Page Up Being Pressed?
          xspeed-0.01 ;Decrease xspeed
        EndIf
        If keys(#VK_RIGHT) And yspeed<0.5 ;Is Page Up Being Pressed?
          yspeed+0.01 ;Increase yspeed
        EndIf
        If keys(#VK_LEFT) And yspeed>-0.5 ;Is Page Up Being Pressed?
          yspeed-0.01 ;Decrease yspeed
        EndIf
        
        If keys(#VK_Q) ;Is Q Key Being Pressed?
          cz-0.01 ;Move Object Away From Viewer
        EndIf
        If keys(#VK_Z) ;Is Z Key Being Pressed?
          cz+0.01 ;Move Object Towards Viewer
        EndIf
        If keys(#VK_W) ;Is W Key Being Pressed?
          cy+0.01 ;Move Object Up
        EndIf
        If keys(#VK_S) ;Is S Key Being Pressed?
          cy-0.01 ;Move Object Down
        EndIf
        If keys(#VK_D) ;Is D Key Being Pressed?
          cx+0.01 ;Move Object Right
        EndIf
        If keys(#VK_A) ;Is A Key Being Pressed?
          cx-0.01 ;Move Object Left
        EndIf
        
        If keys(#VK_1) And key<>1 And morph=0 ;Is 1 Pressed, key Not Equal To 1 And Morph False?
          key=1 ;Sets key To 1 (To Prevent Pressing 1 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph1 ;Destination Object To Morph To Becomes morph1
        EndIf
        If keys(#VK_2) And key<>2 And morph=0 ;Is 2 Pressed, key Not Equal To 2 And Morph False?
          key=2 ;Sets key To 2 (To Prevent Pressing 2 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph2 ;Destination Object To Morph To Becomes morph2
        EndIf
        If keys(#VK_3) And key<>3 And morph=0 ;Is 3 Pressed, key Not Equal To 3 And Morph False?
          key=3 ;Sets key To 3 (To Prevent Pressing 3 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph3 ;Destination Object To Morph To Becomes morph3
        EndIf
        If keys(#VK_4) And key<>4 And morph=0 ;Is 4 Pressed, key Not Equal To 4 And Morph False?
          key=4 ;Sets key To 4 (To Prevent Pressing 4 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph4 ;Destination Object To Morph To Becomes morph4
        EndIf
        
      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("Piotr Cieslak & NeHe's Morphing Points 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
mpz
Enthusiast
Enthusiast
Posts: 497
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: Piotr Cieslak & NeHe's Morphing Tutorial (Lesson 25)

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/25_Morph.rar

Code: Select all

;Piotr Cieslak & NeHe's Morphing Points Tutorial (Lesson 25)
;http://nehe.gamedev.net
;https://nehe.gamedev.net/tutorial/morphing__loading_objects_from_a_file/16003/
;Credits: Nico Gruener, Dreglor, traumatic, hagibaba
;Author: MPz
;Date: 29 Oct 2021
;Note: up-to-date with PB v5.73 (Windows)
;Note: requires vertex data text files in paths "Data/Sphere.txt",
;"Data/Torus.txt", "Data/Tube.txt"

Global xrot.f,yrot.f,zrot.f ;X, Y & Z Rotation
Global xspeed.f,yspeed.f,zspeed.f ;X, Y & Z Spin Speed
Global cx.f,cy.f,cz.f=-15 ;X, Y & Z Position

Global key.l=1 ;Used To Make Sure Same Morph Key Is Not Pressed
Global stepcount.l=0,steps.l=200 ;Step Counter And Maximum Number Of Steps
Global morph.b=#False ;Default morph To False (Not Morphing)

Structure VERTEX ;Structure For 3D Points
  x.f : y.f : z.f ;X, Y & Z Points
EndStructure

Structure OBJECT ;Structure For An Object
  verts.l ;Number Of Vertices For The Object
  points.i ;Address Of Vertice Data (x,y & z)
EndStructure

Global maxver.l ;Will Eventually Hold The Maximum Number Of Vertices
Global morph1.OBJECT,morph2.OBJECT,morph3.OBJECT,morph4.OBJECT ;Our 4 Morphable Objects
Global helper.OBJECT ;Helper Object
Global *sour.OBJECT,*dest.OBJECT ;Source Object, Destination Object

Procedure objallocate(*k.OBJECT,n.l) ;Allocate Memory For Each Object And Defines points
  
  *k\points=AllocateMemory(SizeOf(VERTEX)*n) ;Sets points Equal To VERTEX * Number Of Vertices (3 Points For Each Vertice)
  
EndProcedure

Procedure objfree(*k.OBJECT) ;Frees The Object (Releasing The Memory)
  
  FreeMemory(*k\points) ;Frees Points
  
EndProcedure

Procedure.s readstr(f.i) ;Reads A String From File (f)
  
  Protected string.s
  While Left(string,1)="/" Or Left(string,1)="" ;Until End Of Line Is Reached
    string=ReadString(f) ;Gets A String From f (File)
  Wend
  ProcedureReturn string ;return the line
  
EndProcedure

Procedure objload(name.s,*k.OBJECT) ;Loads Object From File (name)
  
  Protected ver.l ;Will Hold Vertice Count
  Protected filein.i ;Filename To Open
  Protected oneline.s ;Holds One Line Of Text (255 Chars Max)
  Protected i.l,char.s,pos.l,count.l
  
  filein=ReadFile(#PB_Any,name) ;Opens The File For Reading Text In Translated Mode
  
  oneline=readstr(filein) ;Jumps To Code That Reads One Line Of Text From The File
  
  For pos=1 To Len(oneline) ;parse the line, instead of sscanf()
    If Asc(Mid(oneline,pos,1))>48 And Asc(Mid(oneline,pos,1))<58 ;numeric char
      char=Mid(oneline,pos,Len(oneline)-pos+1)
      ver=Val(char) ;Number Is Stored In ver
      Break ;exit loop
    EndIf
  Next
  
  *k\verts=ver ;Sets Objects verts Variable To Equal The Value Of ver
  objallocate(*k,ver) ;Jumps To Code That Allocates Ram To Hold The Object
  
  For i=0 To ver-1 ;Loops Through The Vertices
    oneline=readstr(filein) ;Reads In The Next Line Of Text
    
    count=0 : char="" ;reset for each line
    For pos=1 To Len(oneline) ;parse the line, instead of sscanf()
      If Mid(oneline,pos,1)<>" " ;if not space
        char=char+Mid(oneline,pos,1) ;add char
      EndIf
      If Len(char)>0 And (Mid(oneline,pos,1)=" " Or pos=Len(oneline)) ;if char and space or end-of-line
        Select count ;Store Values Into Respective Vertices
          Case 0 : PokeF(*k\points+(i*SizeOf(VERTEX)),ValF(char)) ;Sets Objects (k) points x Value
          Case 1 : PokeF(*k\points+(i*SizeOf(VERTEX))+4,ValF(char)) ;Sets Objects (k) points y Value
          Case 2 : PokeF(*k\points+(i*SizeOf(VERTEX))+8,ValF(char)) ;Sets Objects (k) points z Value
        EndSelect
        count=count+1 ;next VERTEX member
        char="" ;reset for next
      EndIf
    Next
    
  Next
  
  CloseFile(filein) ;Close The File
  
  If ver>maxver ;If ver Is Greater Than maxver Set maxver Equal To ver
    maxver=ver ;Keeps Track Of Highest Number Of Vertices Used In Any Of The Objects
  EndIf
  
EndProcedure

Procedure calculate(i.l) ;Calculates Movement Of Points During Morphing
  
  ;This Makes Points Move At A Speed So They All Get To Their Destination At The Same Time
  Static a.VERTEX ;Static Vertex Called a
  a\x=(PeekF(*sour\points+(i*SizeOf(VERTEX)))-PeekF(*dest\points+(i*SizeOf(VERTEX))))/steps ;a\x Value Equals Source x - Destination x Divided By Steps
  a\y=(PeekF(*sour\points+(i*SizeOf(VERTEX))+4)-PeekF(*dest\points+(i*SizeOf(VERTEX))+4))/steps ;a\y Value Equals Source y - Destination y Divided By Steps
  a\z=(PeekF(*sour\points+(i*SizeOf(VERTEX))+8)-PeekF(*dest\points+(i*SizeOf(VERTEX))+8))/steps ;a\z Value Equals Source z - Destination z Divided By Steps
  ProcedureReturn a ;Return Pointer To The Results
  
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

Protected i.l
  
  glBlendFunc_(#GL_SRC_ALPHA,#GL_ONE) ;Set The Blending Function For Translucency
  glClearColor_(0.0,0.0,0.0,0.0) ;This Will Clear The Background Color To Black
  glClearDepth_(1.0) ;Enables Clearing Of The Depth Buffer
  glDepthFunc_(#GL_LESS) ;The Type Of Depth Test To Do
  glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
  glShadeModel_(#GL_SMOOTH) ;Enables Smooth Color Shading
  glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
  
  maxver=0 ;Sets Max Vertices To 0 By Default
  objload("Data/Sphere.txt",morph1) ;Load The First Object Into morph1 From File Sphere.txt
  objload("Data/Torus.txt",morph2) ;Load The Second Object Into morph2 From File Torus.txt
  objload("Data/Tube.txt",morph3) ;Load The Third Object Into morph3 From File Tube.txt
  
  objallocate(morph4,486) ;Manually Reserver Ram For A 4th 486 Vertice Object (morph4)
  For i=0 To 486-1 ;Loop Through All 486 Vertices
    PokeF(morph4\points+(i*SizeOf(VERTEX)),(Random(14000)/1000)-7) ;morph4 x Point Becomes A Random Float Value From -7 to 7
    PokeF(morph4\points+(i*SizeOf(VERTEX))+4,(Random(14000)/1000)-7) ;morph4 y Point Becomes A Random Float Value From -7 to 7
    PokeF(morph4\points+(i*SizeOf(VERTEX))+8,(Random(14000)/1000)-7) ;morph4 z Point Becomes A Random Float Value From -7 to 7
  Next
  
  objload("Data/Sphere.txt",helper) ;Load Sphere.txt Object Into Helper (Used As Starting Point)
  *sour=morph1 ;Source & Destination Are Set To Equal First Object (morph1)
  *dest=morph1
  
  ProcedureReturn #True ;Initialization Went OK
 
EndProcedure


Procedure DrawScene(Gadget)
  
  SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear The Screen And The Depth Buffer
  glLoadIdentity_() ;Reset The View
  glTranslatef_(cx,cy,cz) ;Translate The The Current Position To Start Drawing
  glRotatef_(xrot,1.0,0.0,0.0) ;Rotate On The X Axis By xrot
  glRotatef_(yrot,0.0,1.0,0.0) ;Rotate On The Y Axis By yrot
  glRotatef_(zrot,0.0,0.0,1.0) ;Rotate On The Z Axis By zrot
  
  xrot+xspeed : yrot+yspeed : zrot+zspeed ;Increase xrot,yrot & zrot by xspeed, yspeed & zspeed
  
  Protected tx.f,ty.f,tz.f ;Temp X, Y & Z Variables
  Protected *q.VERTEX ;Holds Returned Calculated Values For One Vertex
  Protected i.l,t.VERTEX
  
  glBegin_(#GL_POINTS) ;Begin Drawing Points
  For i=0 To morph1\verts-1 ;Loop Through All The Verts Of morph1 (All Objects Have The Same Amount Of Verts For Simplicity, Could Use maxver Also)
    If morph ;If morph Is True Calculate Movement Otherwise Movement=0
      *q=calculate(i) ;*q points to a.VERTEX
    Else
      *q=t.VERTEX ;*q points to t.VERTEX, t fields are always zero
    EndIf
    tx=PeekF(helper\points+(i*SizeOf(VERTEX)))-*q\x
    ty=PeekF(helper\points+(i*SizeOf(VERTEX))+4)-*q\y
    tz=PeekF(helper\points+(i*SizeOf(VERTEX))+8)-*q\z
    PokeF(helper\points+(i*SizeOf(VERTEX)),tx) ;Subtract q\x Units From helper\points x (Move On X Axis)
    PokeF(helper\points+(i*SizeOf(VERTEX))+4,ty) ;Subtract q\y Units From helper\points y (Move On Y Axis)
    PokeF(helper\points+(i*SizeOf(VERTEX))+8,tz) ;Subtract q\z Units From helper\points z (Move On Z Axis)
    tx=PeekF(helper\points+(i*SizeOf(VERTEX))) ;Make Temp X Variable Equal To Helper's X Variable
    ty=PeekF(helper\points+(i*SizeOf(VERTEX))+4) ;Make Temp Y Variable Equal To Helper's Y Variable
    tz=PeekF(helper\points+(i*SizeOf(VERTEX))+8) ;Make Temp Z Variable Equal To Helper's Z Variable
    
    glColor3f_(0.0,1.0,1.0) ;Set Color To A Bright Shade Of Off Blue
    glVertex3f_(tx,ty,tz) ;Draw A Point At The Current Temp Values (Vertex)
    glColor3f_(0.0,0.5,1.0) ;Darken Color A Bit
    tx-2**q\x : ty-2**q\y : tz-2**q\z ;Calculate Two Positions Ahead
    glVertex3f_(tx,ty,tz) ;Draw A Second Point At The Newly Calculate Position
    glColor3f_(0.0,0.0,1.0) ;Set Color To A Very Dark Blue
    tx-2**q\x : ty-2**q\y : tz-2**q\z ;Calculate Two More Positions Ahead
    glVertex3f_(tx,ty,tz) ;Draw A Third Point At The Second New Position
  Next ;This Creates A Ghostly Tail As Points Move
  glEnd_() ;Done Drawing Points
  
  ;If We're Morphing And We Haven't Gone Through All 200 Steps Increase Our Step Counter
  ;Otherwise Set Morphing To False, Make Source=Destination And Set The Step Counter Back To Zero.
  If morph And stepcount<=steps
    stepcount+1
  Else
    morph=#False : *sour=*dest : stepcount=0
  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("Piotr Cieslak & NeHe's Morphing Points Tutorial (Lesson 25), push key 1-4",640,480,16,0)

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)    ; // push ESC key
     Quit = 1                               ; // This is the end
  EndIf
  
  
   If KeyboardPushed(#PB_Key_PageUp) And zspeed<0.5 ;Is Page Up Being Pressed?
          zspeed+0.01 ;Increase zspeed
        EndIf
        If KeyboardPushed(#PB_Key_PageDown) And zspeed>-0.5 ;Is Page Down Being Pressed?
          zspeed-0.01 ;Decrease zspeed
        EndIf
        If KeyboardPushed(#PB_Key_Down) And xspeed<0.5 ;Is Page Up Being Pressed?
          xspeed+0.01 ;Increase xspeed
        EndIf
        If KeyboardPushed(#PB_Key_Up) And xspeed>-0.5 ;Is Page Up Being Pressed?
          xspeed-0.01 ;Decrease xspeed
        EndIf
        If KeyboardPushed(#PB_Key_Right) And yspeed<0.5 ;Is Page Up Being Pressed?
          yspeed+0.01 ;Increase yspeed
        EndIf
        If KeyboardPushed(#PB_Key_Left) And yspeed>-0.5 ;Is Page Up Being Pressed?
          yspeed-0.01 ;Decrease yspeed
        EndIf
        
        If KeyboardPushed(#PB_Key_Q) ;Is Q Key Being Pressed?
          cz-0.01 ;Move Object Away From Viewer
        EndIf
        If KeyboardPushed(#PB_Key_Z) ;Is Z Key Being Pressed?
          cz+0.01 ;Move Object Towards Viewer
        EndIf
        If KeyboardPushed(#PB_Key_W) ;Is W Key Being Pressed?
          cy+0.01 ;Move Object Up
        EndIf
        If KeyboardPushed(#PB_Key_S) ;Is S Key Being Pressed?
          cy-0.01 ;Move Object Down
        EndIf
        If KeyboardPushed(#PB_Key_D) ;Is D Key Being Pressed?
          cx+0.01 ;Move Object Right
        EndIf
        If KeyboardPushed(#PB_Key_A) ;Is A Key Being Pressed?
          cx-0.01 ;Move Object Left
        EndIf
        
        If KeyboardPushed(#PB_Key_1) And key<>1 And morph=0 ;Is 1 Pressed, key Not Equal To 1 And Morph False?
          key=1 ;Sets key To 1 (To Prevent Pressing 1 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph1 ;Destination Object To Morph To Becomes morph1
        EndIf
        If KeyboardPushed(#PB_Key_2) And key<>2 And morph=0 ;Is 2 Pressed, key Not Equal To 2 And Morph False?
          key=2 ;Sets key To 2 (To Prevent Pressing 2 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph2 ;Destination Object To Morph To Becomes morph2
        EndIf
        If KeyboardPushed(#PB_Key_3) And key<>3 And morph=0 ;Is 3 Pressed, key Not Equal To 3 And Morph False?
          key=3 ;Sets key To 3 (To Prevent Pressing 3 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph3 ;Destination Object To Morph To Becomes morph3
        EndIf
        If KeyboardPushed(#PB_Key_4) And key<>4 And morph=0 ;Is 4 Pressed, key Not Equal To 4 And Morph False?
          key=4 ;Sets key To 4 (To Prevent Pressing 4 2x In A Row)
          morph=#True ;Set morph To True (Starts Morphing Process)
          *dest=morph4 ;Destination Object To Morph To Becomes morph4
        EndIf


        

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

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