Page 1 of 1

NeHe's Extensions, Scissoring & TGA Tutorial (Lesson 24)

Posted: Mon Jan 29, 2007 1:57 am
by hagibaba
Code updated for 5.20+

This shows how to read OpenGL extensions, use scissor testing and load TGA files as textures.
Press Arrows to scroll up and down.
You can get the "Font.tga" from the "lesson24.zip" here:
http://nehe.gamedev.net/data/lessons/vc/lesson24.zip

Last edited on 20 Feb 2007.

Code: Select all

;NeHe's Token, Extensions, Scissoring & TGA Loading Tutorial (Lesson 24)
;http://nehe.gamedev.net
;Credits: Nico Gruener, Dreglor, traumatic
;Author: hagibaba
;Date: 28 Jan 2007
;Note: up-to-date with PB v4.02 (Windows)
;Note: requires a targa in path "Data/Font.tga"

;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 "opengl32.lib"
  glClearDepth(depth.d) ;specifies the clear value for the depth buffer
  glOrtho(left.d,right.d,bottom.d,top.d,near.d,far.d) ;multiplies the current matrix by an orthographic matrix
  glTranslated(x.d,y.d,z.d) ;moves the current matrix to the point specified
EndImport

;Start of Lesson 24

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 scroll.l ;Used For Scrolling The Screen
Global maxtokens.l ;Keeps Track Of The Number Of Extensions Supported
Global swidth.l ;Scissor Width
Global sheight.l ;Scissor Height

Global base.l ;Base Display List For The Font

Structure TEXTUREIMAGE ;Create A Structure
  imageData.l ;Image Data (Up To 32 Bits)
  bpp.l ;Image Color Depth In Bits Per Pixel.
  width.l ;Image Width
  height.l ;Image Height
  texID.l ;Texture ID Used To Select A Texture
EndStructure

Global Dim textures.TEXTUREIMAGE(1) ;Storage For One Texture

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

Procedure.b LoadTGA(*texture.TEXTUREIMAGE,filename.s) ;Loads A TGA File Into Memory
  
  Protected Dim TGAheader.b(12) ;Uncompressed TGA Header
  TGAheader(2)=2 ;ie. {0,0,2,0,0,0,0,0,0,0,0,0}
  Protected Dim TGAcompare.b(12) ;Used To Compare TGA Header
  Protected Dim header.b(6) ;First 6 Useful Bytes From The Header
  Protected bytesPerPixel.l ;Holds Number Of Bytes Per Pixel Used In The TGA File
  Protected imageSize.l ;Used To Store The Image Size When Setting Aside Ram
  Protected temp.l ;Temporary Variable
  Protected type.l=#GL_RGBA ;Set The Default GL Mode To RBGA (32 BPP)
  Protected file.l ;file handle
  Protected i.l ;loop variable
  
  file=ReadFile(#PB_Any,filename) ;Open The TGA File
  
  If file=0 ;Does File Even Exist?
    ProcedureReturn #False ;Return False
  EndIf
  If ReadData(file,TGAcompare(),12)<>12 ;Are There 12 Bytes To Read?
    CloseFile(file) ;Close The File
    ProcedureReturn #False ;Return False
  EndIf
  For i=0 To 12-1 ;Does The Header Match What We Want?
    If TGAheader(i)<>TGAcompare(i)
      CloseFile(file) ;Close The File
      ProcedureReturn #False ;Return False
    EndIf
  Next
  If ReadData(file,header(),6)<>6 ;If So Read Next 6 Header Bytes
    CloseFile(file) ;Close The File
    ProcedureReturn #False ;Return False
  EndIf
  
  *texture\width=((header(1) & 255)*256)+(header(0) & 255) ;Determine The TGA Width (highbyte*256+lowbyte)
  *texture\height=((header(3) & 255)*256)+(header(2) & 255) ;Determine The TGA Height (highbyte*256+lowbyte)
  
  ;Is The Width Or Height Less Than Or Equal To Zero Or Is The TGA Not 24 Or 32 Bit?
  If *texture\width<=0 Or *texture\height<=0 Or (header(4)<>24 And header(4)<>32)
    CloseFile(file) ;If Anything Failed, Close The File
    ProcedureReturn #False ;Return False
  EndIf
  
  *texture\bpp=header(4) ;Grab The TGA's Bits Per Pixel (24 or 32)
  bytesPerPixel=*texture\bpp/8 ;Divide By 8 To Get The Bytes Per Pixel
  imageSize=*texture\width**texture\height*bytesPerPixel ;Calculate The Memory Required For The TGA Data
  
  *texture\imageData=AllocateMemory(imageSize) ;Reserve Memory To Hold The TGA Data
  
  ;Does The Storage Memory Exist? and Does The Image Size Match The Memory Reserved?
  If *texture\imageData=0 Or ReadData(file,*texture\imageData,imageSize)<>imageSize
    If *texture\imageData<>0 ;Was Image Data Loaded
      FreeMemory(*texture\imageData) ;If So, Release The Image Data
    EndIf
    CloseFile(file) ;Close The File
    ProcedureReturn #False ;Return False
  EndIf
  
  For i=0 To (imageSize/bytesPerPixel)-1 ;Loop Through The Image Data
    ;Swaps The 1st And 3rd Bytes ('R'ed And 'B'lue)
    temp=PeekB(*texture\imageData+(i*bytesPerPixel)) ;Temporarily Store The Value At Image Data 'i'
    PokeB(*texture\imageData+(i*bytesPerPixel),PeekB(*texture\imageData+(i*bytesPerPixel)+2)) ;Set The 1st Byte To The Value Of The 3rd Byte
    PokeB(*texture\imageData+(i*bytesPerPixel)+2,temp) ;Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
  Next
  
  CloseFile(file) ;Close The File
  
  ;Build A Texture From The Data
  glGenTextures_(1,@*texture\texID) ;Generate OpenGL texture IDs
  
  glBindTexture_(#GL_TEXTURE_2D,*texture\texID) ;Bind Our Texture
  glTexParameterf_(#GL_TEXTURE_2D,#GL_TEXTURE_MIN_FILTER,#GL_LINEAR) ;Linear Filtered
  glTexParameterf_(#GL_TEXTURE_2D,#GL_TEXTURE_MAG_FILTER,#GL_LINEAR) ;Linear Filtered
  
  If *texture\bpp=24 ;Was The TGA 24 Bits
    type=#GL_RGB ;If So Set The 'type' To GL_RGB
  EndIf
  
  glTexImage2D_(#GL_TEXTURE_2D,0,type,*texture\width,*texture\height,0,type,#GL_UNSIGNED_BYTE,*texture\imageData)
  
  If *texture\imageData
    FreeMemory(*texture\imageData)
  EndIf
  
  ProcedureReturn #True ;Texture Building Went Ok, Return True
  
EndProcedure

Procedure BuildFont() ;Build Our Font Display List
  
  Protected loop1.l,cx.f,cy.f,modx.l
  
  base=glGenLists_(256) ;Creating 256 Display Lists
  glBindTexture_(#GL_TEXTURE_2D,textures(0)\texID) ;Select Our Font Texture
  
  For loop1=0 To 256-1 ;Loop Through All 256 Lists
    modx=loop1 % 16 ;Note: can't use % with floats
    cx=modx/16.0 ;X Position Of Current Character
    cy=Int(loop1/16)/16.0 ;Y Position Of Current Character
    
    glNewList_(base+loop1,#GL_COMPILE) ;Start Building A List
    glBegin_(#GL_QUADS) ;Use A Quad For Each Character
    glTexCoord2f_(cx,1.0-cy-0.0625) ;Texture Coord (Bottom Left)
    glVertex2i_(0,16) ;Vertex Coord (Bottom Left)
    glTexCoord2f_(cx+0.0625,1.0-cy-0.0625) ;Texture Coord (Bottom Right)
    glVertex2i_(16,16) ;Vertex Coord (Bottom Right)
    glTexCoord2f_(cx+0.0625,1.0-cy-0.001) ;Texture Coord (Top Right)
    glVertex2i_(16,0) ;Vertex Coord (Top Right)
    glTexCoord2f_(cx,1.0-cy-0.001) ;Texture Coord (Top Left)
    glVertex2i_(0,0) ;Vertex Coord (Top Left)
    glEnd_() ;Done Building Our Quad (Character)
    glTranslated(14,0,0) ;Move To The Right Of The Character
    glEndList_() ;Done Building The Display List
  Next ;Loop Until All 256 Are Built
  
EndProcedure

Procedure KillFont() ;Delete The Font From Memory
  
  glDeleteLists_(base,256) ;Delete All 256 Display Lists
  
EndProcedure

Procedure glPrint(x.l,y.l,set.l,text.s) ;Where The Printing Happens
  
  If text="" ;If There's No Text
    ProcedureReturn 0 ;Do Nothing
  EndIf
  
  If set : set=1 : EndIf ;Is set True? If So, Select Set 1 (Italic)
  
  glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
  glLoadIdentity_() ;Reset The Modelview Matrix
  glTranslated(x,y,0) ;Position The Text (0,0 - Top Left)
  glListBase_(base-32+(128*set)) ;Choose The Font Set (0 or 1)
  
  glScalef_(1.0,2.0,1.0) ;Make The Text 2X Taller
  
  glCallLists_(Len(text),#GL_UNSIGNED_BYTE,text) ;Write The Text To The Screen
  glDisable_(#GL_TEXTURE_2D) ;Disable Texture Mapping
  
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
  
  swidth=width ;Set Scissor Width To Window Width
  sheight=height ;Set Scissor Height To Window Height
  
  glViewport_(0,0,width,height) ;Reset The Current Viewport
  
  glMatrixMode_(#GL_PROJECTION) ;Select The Projection Matrix
  glLoadIdentity_() ;Reset The Projection Matrix
  
  glOrtho(0.0,640,480,0.0,-1.0,1.0) ;Create Ortho 640x480 View (0,0 At Top Left)
  
  glMatrixMode_(#GL_MODELVIEW) ;Select The Modelview Matrix
  glLoadIdentity_() ;Reset The Modelview Matrix
  
EndProcedure

Procedure.l InitGL() ;All Setup For OpenGL Goes Here
  
  If LoadTGA(textures(0),"Data/Font.tga")=0 ;Load The Font Texture
    ProcedureReturn #False ;If Loading Failed, Return False
  EndIf
  
  BuildFont() ;Build The Font
  
  glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
  glClearColor_(0.0,0.0,0.0,0.5) ;Black Background
  glClearDepth(1.0) ;Depth Buffer Setup
  glBindTexture_(#GL_TEXTURE_2D,textures(0)\texID) ;Select Our Font Texture
  
  ProcedureReturn #True ;Initialization Went OK
  
EndProcedure

Procedure.l DrawGLScene() ;Here's Where We Do All The Drawing
  
  Protected token.s ;Storage For Our Token
  Protected cnt.l=0 ;Local Counter Variable
  Protected text.s ;Storage For Our Extension String
  Protected start.l,len.l ;token variables
  
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear Screen And Depth Buffer
  
  glColor3f_(1.0,0.5,0.5) ;Set Color To Bright Red
  glPrint(20,16,1,"Renderer") ;Display Renderer
  glPrint(50,48,1,"Vendor") ;Display Vendor Name
  glPrint(36,80,1,"Version") ;Display Version
  
  glColor3f_(1.0,0.7,0.4) ;Set Color To Orange
  glPrint(170,16,1,PeekS(glGetString_(#GL_RENDERER))) ;Display Renderer
  glPrint(170,48,1,PeekS(glGetString_(#GL_VENDOR))) ;Display Vendor Name
  glPrint(170,80,1,PeekS(glGetString_(#GL_VERSION))) ;Display Version
  
  glColor3f_(0.5,0.5,1.0) ;Set Color To Bright Blue
  glPrint(192,432,1,"NeHe Productions") ;Write NeHe Productions At The Bottom Of The Screen
  
  glLoadIdentity_() ;Reset The ModelView Matrix
  glColor3f_(1.0,1.0,1.0) ;Set The Color To White
  glBegin_(#GL_LINE_STRIP) ;Start Drawing Line Strips (Something New)
  glVertex2i_(639,417) ;Top Right Of Bottom Box
  glVertex2i_(  1,417) ;Top Left Of Bottom Box
  glVertex2i_(  1,480) ;Lower Left Of Bottom Box
  glVertex2i_(639,480) ;Lower Right Of Bottom Box
  glVertex2i_(639,128) ;Up To Bottom Right Of Top Box
  glEnd_() ;Done First Line Strip
  glBegin_(#GL_LINE_STRIP) ;Start Drawing Another Line Strip
  glVertex2i_(  1,128) ;Bottom Left Of Top Box
  glVertex2i_(639,128) ;Bottom Right Of Top Box       
  glVertex2i_(639,  1) ;Top Right Of Top Box
  glVertex2i_(  1,  1) ;Top Left Of Top Box
  glVertex2i_(  1,417) ;Down To Top Left Of Bottom Box
  glEnd_() ;Done Second Line Strip
  
  glScissor_(1,Int(0.135416*sheight),swidth-2,Int(0.597916*sheight)) ;Define Scissor Region
  glEnable_(#GL_SCISSOR_TEST) ;Enable Scissor Testing
  
  text=PeekS(glGetString_(#GL_EXTENSIONS)) ;Grab The Extension List, Store In Text
  
  start=1 ;Parse 'text' For Words, Seperated By " " (spaces)
  len=FindString(text," ",start)
  token=Mid(text,start,len-start)
  While token<>"" ;While The Token Isn't NULL
    cnt+1 ;Increase The Counter
    If cnt>maxtokens ;Is 'maxtokens' Less Than 'cnt'
      maxtokens=cnt ;If So, Set 'maxtokens' Equal To 'cnt'
    EndIf
    
    glColor3f_(0.5,1.0,0.5) ;Set Color To Bright Green
    glPrint(2,96+(cnt*32)-scroll,0,Str(cnt)) ;Print Current Extension Number
    glColor3f_(1.0,1.0,0.5) ;Set Color To Yellow
    glPrint(50,96+(cnt*32)-scroll,0,token) ;Print The Current Token (Parsed Extension Name)
    
    start=len+1 ;Search For The Next Token
    len=FindString(text," ",start)
    token=Mid(text,start,len-start)
  Wend
  
  glDisable_(#GL_SCISSOR_TEST) ;Disable Scissor Testing
  
  glFlush_() ;Flush The Rendering Pipeline
  
  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
  
  KillFont() ;Kill The Font
  
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 Token, Extensions, Scissoring & TGA Loading 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
        
        SwapBuffers_(hDC) ;Swap Buffers (Double Buffering)
        
        If keys(#VK_UP) And scroll>0 ;Is Up Arrow Being Pressed?
          scroll-2 ;If So, Decrease 'scroll' Moving Screen Down
        EndIf
        
        If keys(#VK_DOWN) And scroll<32*(maxtokens-9) ;Is Down Arrow Being Pressed?
          scroll+2 ;If So, Increase 'scroll' Moving Screen Up
        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("NeHe's Token, Extensions, Scissoring & TGA Loading 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

Posted: Fri Feb 09, 2007 12:08 pm
by THCM
Hi, this lesson doesn't work. I only get square boxes instead of regulat font output. The original lesson works fine here. Any Clue?

Posted: Sat Feb 10, 2007 4:19 am
by hagibaba
Strange, it works for me. Sounds like a problem in loading the tga.

Try changing in LoadTGA() the glTexImage2D_() 3rd param to "type". I changed that to use "bytesPerPixel".

Code: Select all

 glTexImage2D_(#GL_TEXTURE_2D,0,type,*texture\width,*texture\height,0,type,#GL_UNSIGNED_BYTE,*texture\imageData)
If that doesn't work try debugging the TEXTUREIMAGE fields to see if they are right.
If they are all ok then I'm out of ideas.

Re: NeHe's Extensions, Scissoring & TGA Tutorial (Lesson 24)

Posted: Fri Oct 29, 2021 10:10 pm
by mpz
Hello,

next code actualised for x86/x64, PB 5.73, Windows only.

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

P.S: It is possible to fix this with opengl commands. Please write it here if you are interested

Greetings Michael

C Code and texture
iamyaker.googlepages.com/24_TGA_Extension.rar

Code: Select all

;NeHe's Token, Extensions, Scissoring & TGA Loading Tutorial (Lesson 24)
;http://nehe.gamedev.net
;https://nehe.gamedev.net/tutorial/tokens_extensions_scissor_testing_and_tga_loading/19002/
;Credits: Nico Gruener, Dreglor, traumatic, hagibaba
;Author: MPz
;Date: 29 Oct 2021
;Note: up-to-date with PB v5.73 (Windows)

Global hDC.i ;Private GDI Device Context

Global scroll.l ;Used For Scrolling The Screen
Global maxtokens.l ;Keeps Track Of The Number Of Extensions Supported
Global swidth.l ;Scissor Width
Global sheight.l ;Scissor Height

Global base.l ;Base Display List For The Font

Structure TEXTUREIMAGE ;Create A Structure
  imageData.i ;Image Data (Up To 32 Bits)
  bpp.l ;Image Color Depth In Bits Per Pixel.
  width.l ;Image Width
  height.l ;Image Height
  texID.i ;Texture ID Used To Select A Texture
EndStructure

Global Dim textures.TEXTUREIMAGE(1) ;Storage For One Texture

Procedure.b LoadTGA(*texture.TEXTUREIMAGE,filename.s) ;Loads A TGA File Into Memory
  
  Protected Dim TGAheader.b(12) ;Uncompressed TGA Header
  TGAheader(2)=2 ;ie. {0,0,2,0,0,0,0,0,0,0,0,0}
  Protected Dim TGAcompare.b(12) ;Used To Compare TGA Header
  Protected Dim header.b(6) ;First 6 Useful Bytes From The Header
  Protected bytesPerPixel.l ;Holds Number Of Bytes Per Pixel Used In The TGA File
  Protected imageSize.l ;Used To Store The Image Size When Setting Aside Ram
  Protected temp.i ;Temporary Variable
  Protected type.l=#GL_RGBA ;Set The Default GL Mode To RBGA (32 BPP)
  Protected file.i ;file handle
  Protected i.l ;loop variable
  
  file=ReadFile(#PB_Any,filename) ;Open The TGA File
  
  If file=0 ;Does File Even Exist?
    ProcedureReturn #False ;Return False
  EndIf
  If ReadData(file,TGAcompare(),12)<>12 ;Are There 12 Bytes To Read?
    CloseFile(file) ;Close The File
    ProcedureReturn #False ;Return False
  EndIf
  For i=0 To 12-1 ;Does The Header Match What We Want?
    If TGAheader(i)<>TGAcompare(i)
      CloseFile(file) ;Close The File
      ProcedureReturn #False ;Return False
    EndIf
  Next
  If ReadData(file,header(),6)<>6 ;If So Read Next 6 Header Bytes
    CloseFile(file) ;Close The File
    ProcedureReturn #False ;Return False
  EndIf
  
  *texture\width=((header(1) & 255)*256)+(header(0) & 255) ;Determine The TGA Width (highbyte*256+lowbyte)
  *texture\height=((header(3) & 255)*256)+(header(2) & 255) ;Determine The TGA Height (highbyte*256+lowbyte)
  
  ;Is The Width Or Height Less Than Or Equal To Zero Or Is The TGA Not 24 Or 32 Bit?
  If *texture\width<=0 Or *texture\height<=0 Or (header(4)<>24 And header(4)<>32)
    CloseFile(file) ;If Anything Failed, Close The File
    ProcedureReturn #False ;Return False
  EndIf
  
  *texture\bpp=header(4) ;Grab The TGA's Bits Per Pixel (24 or 32)
  bytesPerPixel=*texture\bpp/8 ;Divide By 8 To Get The Bytes Per Pixel
  imageSize=*texture\width**texture\height*bytesPerPixel ;Calculate The Memory Required For The TGA Data
  
  *texture\imageData=AllocateMemory(imageSize) ;Reserve Memory To Hold The TGA Data
  
  ;Does The Storage Memory Exist? and Does The Image Size Match The Memory Reserved?
  If *texture\imageData=0 Or ReadData(file,*texture\imageData,imageSize)<>imageSize
    If *texture\imageData<>0 ;Was Image Data Loaded
      FreeMemory(*texture\imageData) ;If So, Release The Image Data
    EndIf
    CloseFile(file) ;Close The File
    ProcedureReturn #False ;Return False
  EndIf
  
  For i=0 To (imageSize/bytesPerPixel)-1 ;Loop Through The Image Data
    ;Swaps The 1st And 3rd Bytes ('R'ed And 'B'lue)
    temp=PeekB(*texture\imageData+(i*bytesPerPixel)) ;Temporarily Store The Value At Image Data 'i'
    PokeB(*texture\imageData+(i*bytesPerPixel),PeekB(*texture\imageData+(i*bytesPerPixel)+2)) ;Set The 1st Byte To The Value Of The 3rd Byte
    PokeB(*texture\imageData+(i*bytesPerPixel)+2,temp) ;Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
  Next
  
  CloseFile(file) ;Close The File
  
  ;Build A Texture From The Data
  glGenTextures_(1,@*texture\texID) ;Generate OpenGL texture IDs
  
  glBindTexture_(#GL_TEXTURE_2D,*texture\texID) ;Bind Our Texture
  glTexParameterf_(#GL_TEXTURE_2D,#GL_TEXTURE_MIN_FILTER,#GL_LINEAR) ;Linear Filtered
  glTexParameterf_(#GL_TEXTURE_2D,#GL_TEXTURE_MAG_FILTER,#GL_LINEAR) ;Linear Filtered
  
  If *texture\bpp=24 ;Was The TGA 24 Bits
    type=#GL_RGB ;If So Set The 'type' To GL_RGB
  EndIf
  
  glTexImage2D_(#GL_TEXTURE_2D,0,type,*texture\width,*texture\height,0,type,#GL_UNSIGNED_BYTE,*texture\imageData)
  
  If *texture\imageData
    FreeMemory(*texture\imageData)
  EndIf
  
  ProcedureReturn #True ;Texture Building Went Ok, Return True
  
EndProcedure

Procedure BuildFont() ;Build Our Font Display List
  
  Protected loop1.l,cx.f,cy.f,modx.l
  
  base=glGenLists_(256) ;Creating 256 Display Lists
  glBindTexture_(#GL_TEXTURE_2D,textures(0)\texID) ;Select Our Font Texture
  
  For loop1=0 To 256-1 ;Loop Through All 256 Lists
    modx=loop1 % 16 ;Note: can't use % with floats
    cx=modx/16.0 ;X Position Of Current Character
    cy=Int(loop1/16)/16.0 ;Y Position Of Current Character
    
    glNewList_(base+loop1,#GL_COMPILE) ;Start Building A List
    glBegin_(#GL_QUADS) ;Use A Quad For Each Character
    glTexCoord2f_(cx,1.0-cy-0.0625) ;Texture Coord (Bottom Left)
    glVertex2i_(0,16) ;Vertex Coord (Bottom Left)
    glTexCoord2f_(cx+0.0625,1.0-cy-0.0625) ;Texture Coord (Bottom Right)
    glVertex2i_(16,16) ;Vertex Coord (Bottom Right)
    glTexCoord2f_(cx+0.0625,1.0-cy-0.001) ;Texture Coord (Top Right)
    glVertex2i_(16,0) ;Vertex Coord (Top Right)
    glTexCoord2f_(cx,1.0-cy-0.001) ;Texture Coord (Top Left)
    glVertex2i_(0,0) ;Vertex Coord (Top Left)
    glEnd_() ;Done Building Our Quad (Character)
    glTranslated_(14,0,0) ;Move To The Right Of The Character
    glEndList_() ;Done Building The Display List
  Next ;Loop Until All 256 Are Built
  
EndProcedure

Procedure KillFont() ;Delete The Font From Memory
  
  glDeleteLists_(base,256) ;Delete All 256 Display Lists
  
EndProcedure

Procedure glPrint(x.l,y.l,set.l,text.s) ;Where The Printing Happens
  
  If text="" ;If There's No Text
    ProcedureReturn 0 ;Do Nothing
  EndIf
  
  If set : set=1 : EndIf ;Is set True? If So, Select Set 1 (Italic)
  
  glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
  glLoadIdentity_() ;Reset The Modelview Matrix
  glTranslated_(x,y,0) ;Position The Text (0,0 - Top Left)
  glListBase_(base-32+(128*set)) ;Choose The Font Set (0 or 1)
  
  glScalef_(1.0,2.0,1.0) ;Make The Text 2X Taller
  *pointer = Ascii(text)
  glCallLists_(Len(text),#GL_UNSIGNED_BYTE,*pointer) ;Write The Text To The Screen
  FreeMemory (*pointer)
  
  glDisable_(#GL_TEXTURE_2D) ;Disable Texture Mapping
  
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)
  
  swidth=width ;Set Scissor Width To Window Width
  sheight=height ;Set Scissor Height To Window Height
  
  glViewport_(0,0,width,height) ;Reset The Current Viewport
  
  glMatrixMode_(#GL_PROJECTION) ;Select The Projection Matrix
  glLoadIdentity_() ;Reset The Projection Matrix
  
  glOrtho_(0.0,640,480,0.0,-1.0,1.0) ;Create Ortho 640x480 View (0,0 At Top Left)
  
  glMatrixMode_(#GL_MODELVIEW) ;Select The Modelview Matrix
  glLoadIdentity_() ;Reset The Modelview Matrix
 
 
EndProcedure

Procedure.l InitGL() ;All Setup For OpenGL Goes Here

  If LoadTGA(textures(0),"Data/Font.tga")=0 ;Load The Font Texture
    ProcedureReturn #False ;If Loading Failed, Return False
  EndIf
  
  BuildFont() ;Build The Font
  
  glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
  glClearColor_(0.0,0.0,0.0,0.5) ;Black Background
  glClearDepth_(1.0) ;Depth Buffer Setup
  glBindTexture_(#GL_TEXTURE_2D,textures(0)\texID) ;Select Our Font Texture
  
  ProcedureReturn #True ;Initialization Went OK
 
EndProcedure

Procedure DrawScene(Gadget)
   SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
Protected token.s ;Storage For Our Token
  Protected cnt.l=0 ;Local Counter Variable
  Protected text.s ;Storage For Our Extension String
  Protected start.l,len.l ;token variables
  
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT) ;Clear Screen And Depth Buffer
  
  glColor3f_(1.0,0.5,0.5) ;Set Color To Bright Red
  glPrint(20,16,1,"Renderer") ;Display Renderer
  glPrint(50,48,1,"Vendor") ;Display Vendor Name
  glPrint(36,80,1,"Version") ;Display Version
  
  glColor3f_(1.0,0.7,0.4) ;Set Color To Orange
  glPrint(170,16,1,PeekS(glGetString_(#GL_RENDERER),-1,#PB_Ascii)) ;Display Renderer
  glPrint(170,48,1,PeekS(glGetString_(#GL_VENDOR),-1,#PB_Ascii)) ;Display Vendor Name
  glPrint(170,80,1,PeekS(glGetString_(#GL_VERSION),-1,#PB_Ascii)) ;Display Version
  
  glColor3f_(0.5,0.5,1.0) ;Set Color To Bright Blue
  glPrint(192,432,1,"NeHe Productions") ;Write NeHe Productions At The Bottom Of The Screen
  
  glLoadIdentity_() ;Reset The ModelView Matrix
  glColor3f_(1.0,1.0,1.0) ;Set The Color To White
  glBegin_(#GL_LINE_STRIP) ;Start Drawing Line Strips (Something New)
  glVertex2i_(639,417) ;Top Right Of Bottom Box
  glVertex2i_(  1,417) ;Top Left Of Bottom Box
  glVertex2i_(  1,480) ;Lower Left Of Bottom Box
  glVertex2i_(639,480) ;Lower Right Of Bottom Box
  glVertex2i_(639,128) ;Up To Bottom Right Of Top Box
  glEnd_() ;Done First Line Strip
  glBegin_(#GL_LINE_STRIP) ;Start Drawing Another Line Strip
  glVertex2i_(  1,128) ;Bottom Left Of Top Box
  glVertex2i_(639,128) ;Bottom Right Of Top Box       
  glVertex2i_(639,  1) ;Top Right Of Top Box
  glVertex2i_(  1,  1) ;Top Left Of Top Box
  glVertex2i_(  1,417) ;Down To Top Left Of Bottom Box
  glEnd_() ;Done Second Line Strip
  
  glScissor_(1,Int(0.135416*sheight),swidth-2,Int(0.597916*sheight)) ;Define Scissor Region
  glEnable_(#GL_SCISSOR_TEST) ;Enable Scissor Testing
  
  text=PeekS(glGetString_(#GL_EXTENSIONS),-1,#PB_Ascii) ;Grab The Extension List, Store In Text

  start=1 ;Parse 'text' For Words, Seperated By " " (spaces)
  len=FindString(text," ",start)
  token=Mid(text,start,len-start)
  While token<>"" ;While The Token Isn't NULL
    cnt+1 ;Increase The Counter
    If cnt>maxtokens ;Is 'maxtokens' Less Than 'cnt'
      maxtokens=cnt ;If So, Set 'maxtokens' Equal To 'cnt'
    EndIf
    glColor3f_(0.5,1.0,0.5) ;Set Color To Bright Green
    glPrint(2,96+(cnt*32)-scroll,0,Str(cnt)) ;Print Current Extension Number
    glColor3f_(1.0,1.0,0.5) ;Set Color To Yellow
    glPrint(50,96+(cnt*32)-scroll,0,token) ;Print The Current Token (Parsed Extension Name)
    start=len+1 ;Search For The Next Token
    len=FindString(text," ",start)
    token=Mid(text,start,len-start)
  Wend
  
  glDisable_(#GL_SCISSOR_TEST) ;Disable Scissor Testing
  
  glFlush_() ;Flush The Rendering Pipeline
  
  SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
  
  ProcedureReturn #True ;Everything Went OK
 

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 Token, Extensions, Scissoring & TGA Loading Tutorial (Lesson 24)",640,480,16)

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_Up) And scroll>0 ;Is Up Arrow Being Pressed? 
    scroll-2                   ;If So, Decrease 'scroll' Moving Screen Down
  EndIf

  If KeyboardPushed(#PB_Key_Down) And scroll<32*(maxtokens-9) ;Is Down Arrow Being Pressed?
     scroll+2 ;If So, Increase 'scroll' Moving Screen Up
  EndIf
        
  DrawScene(0)
  Delay(10)
Until Quit = 1