NeHe's Texturemapped Outline Font Tutorial (Lesson 15)

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 Texturemapped Outline Font Tutorial (Lesson 15)

Post by hagibaba »

Code updated for 5.20+

This shows how to print texturemapped outline fonts. Press the L key for lighting.
The BuildFont3D procedure is the same as in lesson 14. Here it is used to print the "Wingdings" symbol font.
You can get the "Lights.bmp" from the "lesson15.zip" here:
nehe.gamedev.net/data/lessons/vc/lesson15.zip

Last edited on 20 Feb 2007.

Code: Select all

;NeHe's Texturemapped Outline Font Tutorial (Lesson 15)
;http://nehe.gamedev.net
;Credits: Nico Gruener, Dreglor, traumatic
;Author: hagibaba
;Date: 10 Jan 2007
;Note: up-to-date with PB v4.02 (Windows)
;Note: requires a bitmap in path "Data/Lights.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
#ANTIALIASED_QUALITY=4 ;for CreateFont_()
#WGL_FONT_POLYGONS=1 ;for wglUseFontOutlines_()
#DM_BITSPERPEL=$40000
#DM_PELSWIDTH=$80000
#DM_PELSHEIGHT=$100000

;winuser.h constants
#CDS_FULLSCREEN=4
#DISP_CHANGE_SUCCESSFUL=0
#SC_MONITORPOWER=$F170

Structure POINTFLOAT ;wingdi.h structure
 x.f : y.f
EndStructure

Structure GLYPHMETRICSFLOAT ;wingdi.h structure
 gmfBlackBoxX.f
 gmfBlackBoxY.f
 gmfptGlyphOrigin.POINTFLOAT
 gmfCellIncX.f
 gmfCellIncY.f
EndStructure

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 15

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 Dim texture.l(1) ;One Texture Map
Global base.l ;Base Display List For The Font Set
Global rot.f ;Used To Rotate The Text

Global Dim gmf.GLYPHMETRICSFLOAT(256) ;Buffer For Font Storage

Global light.b=#True ;Lighting ON/OFF
Global lp.b ;L Pressed? Note: added L key code to toggle lighting

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

Procedure BuildFont(name.s,bold.l,italic.b,symbol.l,depth.f,blocky.f) ;Build Our Outline Font

 Protected font.l ;Windows Font ID
 Protected oldfont.l ;Used For Good House Keeping
 
 If bold : bold=#FW_BOLD : Else : bold=#FW_NORMAL : EndIf ;font weight
 If symbol : symbol=#SYMBOL_CHARSET : Else : symbol=#ANSI_CHARSET : EndIf ;character set
 If blocky : blocky=0.1 : Else : blocky=0.0 : EndIf ;blocky font shape
 
 base=glGenLists_(256) ;Storage For 256 Characters
 
 ;CreateFont_(Height, Width, Angle Of Escapement, Orientation Angle, Weight, Italic, Underline, Strikeout, Character Set, Output Precision, Clipping Precision, Output Quality, Family And Pitch, Name)
 font=CreateFont_(0,0,0,0,bold,italic,#False,#False,symbol,#OUT_TT_PRECIS,#CLIP_DEFAULT_PRECIS,#ANTIALIASED_QUALITY,#FF_DONTCARE | #DEFAULT_PITCH,name)
 
 oldfont=SelectObject_(hDC,font) ;Selects The Font We Created
 
 ;wglUseFontOutlines_(DC, Starting Character, Number Of Display Lists, Starting Display List, Deviation From True Outlines, Font Thickness, Use Polygons, Buffer To Receive Data)
 wglUseFontOutlines_(hDC,0,255,base,blocky,depth,#WGL_FONT_POLYGONS,gmf(0))
 
 SelectObject_(hDC,oldfont) ;reselect the old font again
 DeleteObject_(font) ;Delete The Font
 
EndProcedure

Procedure KillFont() ;Delete The Font List

 glDeleteLists_(base,256) ;Delete All 256 Characters
 
EndProcedure

Procedure glPrint(text.s) ;Custom GL "Print" Routine

 If text="" ;If There's No Text
  ProcedureReturn #False ;Do Nothing
 EndIf
 
 glPushAttrib_(#GL_LIST_BIT) ;Pushes The Display List Bits
  glListBase_(base) ;Sets The Base Character to 0
  glCallLists_(Len(text),#GL_UNSIGNED_BYTE,text) ;Draws The Display List Text
 glPopAttrib_() ;Pops The Display List Bits
 
EndProcedure

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 Texture
 
 ;Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
 *TextureImage(0)=LoadBMP("Data/Lights.bmp")
 If *TextureImage(0)
  Status=#True ;Set The Status To TRUE
 
  glGenTextures_(1,@texture(0)) ;Create The 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_MIPMAP_NEAREST)
  gluBuild2DMipmaps_(#GL_TEXTURE_2D,3,*TextureImage(0)\sizeX,*TextureImage(0)\sizeY,#GL_RGB,#GL_UNSIGNED_BYTE,*TextureImage(0)\Data)
 
  ;Note: GL_OBJECT_LINEAR did not work on my PC, GL_EYE_LINEAR/GL_SPHERE_MAP did
  glTexGeni_(#GL_S,#GL_TEXTURE_GEN_MODE,#GL_EYE_LINEAR) ;X Texturing Contour Anchored To The Object
  glTexGeni_(#GL_T,#GL_TEXTURE_GEN_MODE,#GL_EYE_LINEAR) ;Y Texturing Contour Anchored To The Object
  glEnable_(#GL_TEXTURE_GEN_S) ;Auto Texture Generation
  glEnable_(#GL_TEXTURE_GEN_T) ;Auto Texture Generation
 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
 
 ;BuildFont(name,bold,italic,symbol,depth,blocky)
 BuildFont("Wingdings",1,0,1,0.2,1) ;Build The Outline Font
 
 glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
 glClearColor_(0.0,0.0,0.0,0.5) ;Black Background
 glClearDepth(1.0) ;Depth Buffer Setup
 glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
 glDepthFunc_(#GL_LEQUAL) ;The Type Of Depth Testing To Do
 glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
 
 glEnable_(#GL_LIGHT0) ;Quick And Dirty Lighting (Assumes Light0 Is Set Up)
 glEnable_(#GL_LIGHTING) ;Enable Lighting
 glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
 
 glBindTexture_(#GL_TEXTURE_2D,texture(0)) ;Select The Texture
 
 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 Screen And Depth Buffer
 glLoadIdentity_() ;Reset The View
 
 glTranslatef_(1.1*Cos(rot/16.0),0.8*Sin(rot/20.0),-3.0)
 
 glRotatef_(rot,1.0,0.0,0.0) ;Rotate On The X Axis
 glRotatef_(rot*1.2,0.0,1.0,0.0) ;Rotate On The Y Axis
 glRotatef_(rot*1.4,0.0,0.0,1.0) ;Rotate On The Z Axis
 
 glTranslatef_(-0.35,-0.35,0.1) ;Center On X, Y, Z Axis
 
 glPrint("N") ;Draw A Skull And Crossbones Symbol
 
 rot+0.05 ;Increase The Rotation Variable
 
 ProcedureReturn #True ;Keep Going
 
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() ;Destroy The Outline 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 Texturemapped Outline Font 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_L) And lp=0 ;L Key Being Pressed Not Held?
     lp=#True ;lp Becomes TRUE
     light=~light & 1 ;Toggle Light TRUE/FALSE
     If light=0 ;If Not Light
      glDisable_(#GL_LIGHTING) ;Disable Lighting
     Else ;Otherwise
      glEnable_(#GL_LIGHTING) ;Enable Lighting
     EndIf
    EndIf
    If keys(#VK_L)=0 ;Has L Key Been Released?
     lp=#False ;If So, lp Becomes FALSE
    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 Texturemapped Outline Font 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:15 pm, edited 10 times in total.
dige
Addict
Addict
Posts: 1247
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Post by dige »

Thanks a lot! Can't await the next lesson :D
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: NeHe's Texturemapped Outline Font Tutorial (Lesson 15)

Post by mpz »

Hello,

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


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

Greetings Michael

Code: Select all

;NeHe's Texturemapped Outline Font Tutorial (Lesson 15)
;http://nehe.gamedev.net 
;https://nehe.gamedev.net/tutorial/texture_mapped_outline_fonts/18001/
;Credits: Nico Gruener, Dreglor, traumatic, hagibaba
;Author: MPz
;Date: 04 Oct 2021
;Note: up-to-date with PB v5.73 (Windows)

Global hDC.i ;Private GDI Device Context

Global base.l ;Base Display List For The Font Set
Global rot.f ;Used To Rotate The Text

#WGL_FONT_POLYGONS=1 ;for wglUseFontOutlines_()

Structure POINTFLOAT ;wingdi.h structure
  x.f : y.f
EndStructure

Structure GLYPHMETRICSFLOAT ;wingdi.h structure
  gmfBlackBoxX.f
  gmfBlackBoxY.f
  gmfptGlyphOrigin.POINTFLOAT
  gmfCellIncX.f
  gmfCellIncY.f
EndStructure

Global Dim gmf.GLYPHMETRICSFLOAT(256) ;Storage For Information About Our Outline Font Characters

Global Dim texture.l(1) ;One Texture Map
Global base.l ;Base Display List For The Font Set
Global rot.f ;Used To Rotate The Text

Global Dim gmf.GLYPHMETRICSFLOAT(256) ;Buffer For Font Storage

Global light.b=#True ;Lighting ON/OFF
Global lp.b ;L Pressed? Note: added L key code to toggle lighting

Procedure BuildFont(name.s,bold.l,italic.b,symbol.l,depth.f,blocky.f) ;Build Our Outline Font
  
  Protected font.l ;Windows Font ID
  Protected oldfont.l ;Used For Good House Keeping
  
  If bold : bold=#FW_BOLD : Else : bold=#FW_NORMAL : EndIf ;font weight
  If symbol : symbol=#SYMBOL_CHARSET : Else : symbol=#ANSI_CHARSET : EndIf ;character set
  If blocky : blocky=0.1 : Else : blocky=0.0 : EndIf ;blocky font shape
  
  base=glGenLists_(256) ;Storage For 256 Characters
  
  ;CreateFont_(Height, Width, Angle Of Escapement, Orientation Angle, Weight, Italic, Underline, Strikeout, Character Set, Output Precision, Clipping Precision, Output Quality, Family And Pitch, Name)
  font=CreateFont_(0,0,0,0,bold,italic,#False,#False,symbol,#OUT_TT_PRECIS,#CLIP_DEFAULT_PRECIS,#ANTIALIASED_QUALITY,#FF_DONTCARE | #DEFAULT_PITCH,name)
  
  oldfont=SelectObject_(hDC,font) ;Selects The Font We Created
  
  ;wglUseFontOutlines_(DC, Starting Character, Number Of Display Lists, Starting Display List, Deviation From True Outlines, Font Thickness, Use Polygons, Buffer To Receive Data)
  wglUseFontOutlines_(hDC,0,255,base,blocky,depth,#WGL_FONT_POLYGONS,gmf(0))
  
  SelectObject_(hDC,oldfont) ;reselect the old font again
  DeleteObject_(font) ;Delete The Font
  
EndProcedure

Procedure KillFont() ;Delete The Font List
  
  glDeleteLists_(base,256) ;Delete All 256 Characters
  
EndProcedure

Procedure glPrint(text.s) ;Custom GL "Print" Routine
  
  If text="" ;If There's No Text
    ProcedureReturn #False ;Do Nothing
  EndIf
  
  Protected length.f ;Used To Find The Length Of The Text
  Protected LOOP.l ;Loop Variable
  
  For LOOP=0 To Len(text)-1 ;Loop To Find Text Length
    length=length+gmf(Asc(Mid(text,LOOP+1,1)))\gmfCellIncX ;Increase Length By Each Characters Width
  Next
  
  glTranslatef_(-length/2,0.0,0.0) ;Center Our Text On The Screen
  
  glPushAttrib_(#GL_LIST_BIT) ;Pushes The Display List Bits
  glListBase_(base)           ;Sets The Base Character to 0
  
  *pointer = Ascii(text)
  ;glCallLists_(Len(text),#GL_UNSIGNED_BYTE,text) ;Draws The Display List Text
  glCallLists_(Len(text),#GL_UNSIGNED_BYTE,*pointer) ;Draws The Display List Text
  FreeMemory(*pointer)
  
  glPopAttrib_() ;Pops The Display List Bits
  
EndProcedure

Procedure LoadGLTextures(Names.s) ;Load Bitmaps And Convert To Textures

  LoadImage(0, Names) ; Load texture with name
  *pointer = EncodeImage(0, #PB_ImagePlugin_BMP,0,24 );  
  FreeImage(0)
  	
  glGenTextures_(1,@texture(0)) ;Create The 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_MIPMAP_NEAREST)
  gluBuild2DMipmaps_(#GL_TEXTURE_2D, 3,PeekL(*pointer+18), PeekL(*pointer+22), #GL_BGR_EXT, #GL_UNSIGNED_BYTE, *pointer+54); // ( NEW )
  
  ;Note: GL_OBJECT_LINEAR did not work on my PC, GL_EYE_LINEAR/GL_SPHERE_MAP did
  glTexGeni_(#GL_S,#GL_TEXTURE_GEN_MODE,#GL_EYE_LINEAR) ;X Texturing Contour Anchored To The Object
  glTexGeni_(#GL_T,#GL_TEXTURE_GEN_MODE,#GL_EYE_LINEAR) ;Y Texturing Contour Anchored To The Object
  glEnable_(#GL_TEXTURE_GEN_S) ;Auto Texture Generation
  glEnable_(#GL_TEXTURE_GEN_T) ;Auto Texture Generation
  
  FreeMemory(*pointer)
  
EndProcedure

Procedure ReSizeGLScene(width.l,height.l) ;Resize And Initialize The GL Window

 If height=0 : height=1 : EndIf ;Prevent A Divide By Zero Error
 
 ResizeGadget(0, 0, 0, width, height)
 
 glViewport_(0,0,width,height) ;Reset The Current Viewport
 
 glMatrixMode_(#GL_PROJECTION) ;Select The Projection Matrix
 glLoadIdentity_() ;Reset The Projection Matrix
 
 gluPerspective_(45.0,Abs(width/height),0.1,100.0) ;Calculate The Aspect Ratio Of The Window
 
 glMatrixMode_(#GL_MODELVIEW) ;Select The Modelview Matrix
 glLoadIdentity_() ;Reset The Modelview Matrix
 
EndProcedure

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

 ;BuildFont(name,bold,italic,symbol,depth,blocky)
 BuildFont("Wingdings",1,0,1,0.2,1) ;Build The Outline Font
 
 glShadeModel_(#GL_SMOOTH) ;Enable Smooth Shading
 glClearColor_(0.0,0.0,0.0,0.5) ;Black Background
 glClearDepth_(1.0) ;Depth Buffer Setup
 glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
 glDepthFunc_(#GL_LEQUAL) ;The Type Of Depth Testing To Do
 glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ;Really Nice Perspective Calculations
 
 glEnable_(#GL_LIGHT0) ;Quick And Dirty Lighting (Assumes Light0 Is Set Up)
 glEnable_(#GL_LIGHTING) ;Enable Lighting
 glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
 
 glBindTexture_(#GL_TEXTURE_2D,texture(0)) ;Select The Texture
 
 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 Screen And Depth Buffer
 glLoadIdentity_() ;Reset The View
 
 glTranslatef_(1.1*Cos(rot/16.0),0.8*Sin(rot/20.0),-3.0)
 
 glRotatef_(rot,1.0,0.0,0.0) ;Rotate On The X Axis
 glRotatef_(rot*1.2,0.0,1.0,0.0) ;Rotate On The Y Axis
 glRotatef_(rot*1.4,0.0,0.0,1.0) ;Rotate On The Z Axis
 
 glTranslatef_(-0.35,-0.35,0.1) ;Center On X, Y, Z Axis
 
 glPrint("NM") ;Draw A Skull And Crossbones Symbol
 
 rot+0.05 ;Increase The Rotation Variable  
 
 SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
 
EndProcedure

Procedure HandleError (Result, Text$)
  If Result = 0
    MessageRequester("Error", Text$, 0)
    End
  EndIf
EndProcedure

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

  If fullscreenflag
    hWnd = OpenWindow(0, 0, 0, WindowWidth, WindowHeight, title, #PB_Window_BorderLess|#PB_Window_Maximize )
    OpenWindowedScreen(WindowID(0), 0, 0,WindowWidth(0),WindowHeight(0)) 
  Else  
    hWnd = OpenWindow(0, 1, 1, WindowWidth, WindowHeight, title,#PB_Window_MinimizeGadget |  #PB_Window_MaximizeGadget | #PB_Window_SizeGadget ) 
    OpenWindowedScreen(WindowID(0), 1, 1, WindowWidth,WindowHeight) 
  EndIf
  
  If bits = 24
    OpenGlFlags + #PB_OpenGL_24BitDepthBuffer
  EndIf
  
  If 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 Texturemapped Outline Font Tutorial (Lesson 15)",640,480,16,0)

InitGL()

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

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_L) And lp=0 ;L Key Being Pressed Not Held?
     lp=#True ;lp Becomes TRUE
     light=~light & 1 ;Toggle Light TRUE/FALSE
     If light=0 ;If Not Light
        glDisable_(#GL_LIGHTING) ;Disable Lighting
     Else ;Otherwise
        glEnable_(#GL_LIGHTING) ;Enable Lighting
     EndIf
  EndIf
  If Not KeyboardPushed(#PB_Key_L) ;Has L Key Been Released?
     lp=#False ;If So, lp Becomes FALSE
  EndIf
  
  DrawScene(0)
  Delay(1)
Until Quit = 1

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