NeHe's Blitter & Raw Image Loading Tutorial (Lesson 29)

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 Blitter & Raw Image Loading Tutorial (Lesson 29)

Post by hagibaba »

Code updated for 5.20+

This shows how to blit textures and load RAW image files. It also has a few fixes to CreateGLWindow() and WinMain().
You can get the "Monitor.raw" and "GL.raw" from the "lesson29.zip" here:
http://nehe.gamedev.net/data/lessons/vc/lesson29.zip

Last edited on 20 Feb 2007.

Code: Select all

;Andreas Löffler, Rob Fletcher & NeHe's Blitter & Raw Image Loading Tutorial (Lesson 29)
;http://nehe.gamedev.net
;Credits: Nico Gruener, Dreglor, traumatic
;Author: hagibaba
;Date: 17 Jan 2007
;Note: up-to-date with PB v4.02 (Windows)
;Note: requires RAW files in paths "Data/Monitor.raw", "Data/GL.raw"

;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
#ENUM_CURRENT_SETTINGS=-1
#CDS_TEST=2
#CDS_FULLSCREEN=4
#CDS_RESET=$40000000
#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 29

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 DMsaved.DEVMODE ;Saves The Previous Screen Settings

Global xrot.f ;X Rotation
Global yrot.f ;Y Rotation
Global zrot.f ;Z Rotation

Global Dim texture.l(1) ;Storage For 1 Texture

Structure TEXTURE_IMAGE
 width.l ;Width Of Image In Pixels
 height.l ;Height Of Image In Pixels
 format.l ;Number Of Bytes Per Pixel
 Data.l ;Texture Data
EndStructure

Global t1.TEXTURE_IMAGE ;Pointer To The Texture Image Data Type
Global t2.TEXTURE_IMAGE ;Pointer To The Texture Image Data Type

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

Procedure AllocateTextureBuffer(*ti.TEXTURE_IMAGE,w.l,h.l,f.l) ;Allocate Memory For An Image

 Protected c.l=#Null ;Pointer To Block Memory For Image
 
 If *ti<>#Null
  *ti\width=w ;Set Width
  *ti\height=h ;Set Height
  *ti\format=f ;Set Format
  c=AllocateMemory(w*h*f)
  If c<>#Null
   *ti\Data=c ;Set Data
  Else
   MessageBox_(#Null,"Could Not Allocate Memory For A Texture Buffer","BUFFER ERROR",#MB_OK | #MB_ICONINFORMATION)
   ProcedureReturn #Null
  EndIf
 Else
  MessageBox_(#Null,"Invalid Image Structure","IMAGE STRUCTURE ERROR",#MB_OK | #MB_ICONINFORMATION)
  ProcedureReturn #Null
 EndIf
 
EndProcedure

Procedure DeallocateTexture(*t.TEXTURE_IMAGE) ;Free Up The Image Data

 If *t
  If *t\Data
   FreeMemory(*t\Data)
  EndIf
  ;FreeMemory(*t) ;Note: this doesn't apply for a structure
 EndIf
 
EndProcedure

;Read A .RAW File In To The Allocated Image Buffer Using Data In The Image Structure Header.
;Flip The Image Top To Bottom. Returns 0 For Failure Of Read, Or Number Of Bytes Read.

Procedure.l ReadTextureData(filename.s,*buffer.TEXTURE_IMAGE)

 Protected f.l,i.l,j.l,k.l
 Protected done.l=0,stride.l,p.l=#Null
 
 stride=*buffer\width**buffer\format ;Size Of A Row (Width * Bytes Per Pixel)
 
 f=ReadFile(#PB_Any,filename) ;Open "filename" For Reading Bytes
 
 If f<>#Null ;If File Exists
  For i=*buffer\height-1 To 0 Step -1 ;Loop Through Height (Bottoms Up - Flip Image)
   p=*buffer\Data+(i*stride)
   For j=0 To *buffer\width-1 ;Loop Through Width
    For k=0 To (*buffer\format-1)-1
     PokeB(p,ReadByte(f)) ;Read Value From File And Store In Memory
     p+1 : done+1 ;Next Byte
    Next
    PokeB(p,255) : p+1 ;Store 255 In Alpha Channel And Increase Pointer
   Next
  Next
  CloseFile(f) ;Close The File
 Else ;Otherwise
  MessageBox_(#Null,"Unable To Open Image File","IMAGE ERROR",#MB_OK | #MB_ICONINFORMATION)
 EndIf
 
 ProcedureReturn done ;Returns Number Of Bytes Read In
 
EndProcedure

Procedure BuildTexture(*tex.TEXTURE_IMAGE)

 glGenTextures_(1,@texture(0))
 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)
 gluBuild2DMipmaps_(#GL_TEXTURE_2D,#GL_RGB,*tex\width,*tex\height,#GL_RGBA,#GL_UNSIGNED_BYTE,*tex\Data)
 
EndProcedure

Procedure Blit(*src.TEXTURE_IMAGE,*dst.TEXTURE_IMAGE,src_xstart.l,src_ystart.l,src_width.l,src_height.l,dst_xstart.l,dst_ystart.l,blend.l,alpha.l)

 Protected i.l,j.l,k.l,v.l
 Protected s.l,d.l ;Source & Destination
 
 ;Clamp Alpha If Value Is Out Of Range
 If alpha>255 : alpha=255 : EndIf
 If alpha<0 : alpha=0 : EndIf
 
 ;Check For Incorrect Blend Flag Values
 If blend<0 : blend=0 : EndIf
 If blend>1 : blend=1 : EndIf
 
 d=*dst\Data+(dst_ystart**dst\width**dst\format) ;Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
 s=*src\Data+(src_ystart**src\width**src\format) ;Start Row - src (Row * Width In Pixels * Bytes Per Pixel)
 
 For i=0 To src_height-1 ;Height Loop
  s=s+(src_xstart**src\format) ;Move Through Src Data By Bytes Per Pixel
  d=d+(dst_xstart**dst\format) ;Move Through Dst Data By Bytes Per Pixel
  For j=0 To src_width-1 ;Width Loop
   For k=0 To *src\format-1 ;"n" Bytes At A Time
    If blend ;If Blending Is On
     v=((PeekB(s) & 255)*alpha)+((PeekB(d) & 255)*(255-alpha)) ;Src Data*alpha + Dst Data*(255-alpha)
     PokeB(d,v >> 8) ;Keep in 0-255 Range With >> 8
    Else
     PokeB(d,PeekB(s)) ;No Blending Just Do A Straight Copy
    EndIf
    d+1 : s+1 ;Next Byte
   Next
  Next
  d=d+(*dst\width-(src_width+dst_xstart))**dst\format ;Add End Of Row
  s=s+(*src\width-(src_width+src_xstart))**src\format ;Add End Of Row
 Next
 
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

 AllocateTextureBuffer(t1,256,256,4) ;Get An Image Structure
 If ReadTextureData("Data/Monitor.raw",t1)=0 ;Fill The Image Structure With Data
  MessageBox_(#Null,"Could Not Read 'Monitor.raw' Image Data","TEXTURE ERROR",#MB_OK | #MB_ICONINFORMATION)
  ProcedureReturn #False ;Nothing Read?
 EndIf
 
 AllocateTextureBuffer(t2,256,256,4) ;Second Image Structure
 If ReadTextureData("Data/GL.raw",t2)=0 ;Fill The Image Structure With Data
  MessageBox_(#Null,"Could Not Read 'GL.raw' Image Data","TEXTURE ERROR",#MB_OK | #MB_ICONINFORMATION)
  ProcedureReturn #False ;Nothing Read?
 EndIf
 
 ;Image To Blend In, Original Image, Src Start X & Y, Src Width & Height, Dst Start X & Y, Blend Flag, Alpha Value
 Blit(t2,t1,127,127,128,128,64,64,1,127) ;Call The Blitter Routine
 
 BuildTexture(t1) ;Load The Texture Map Into Texture Memory
 
 DeallocateTexture(t1) ;Clean Up Image Memory Because Texture Is
 DeallocateTexture(t2) ;In GL Texture Memory Now
 
 glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
 
 glShadeModel_(#GL_SMOOTH) ;Enables Smooth Color Shading
 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
 glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
 glDepthFunc_(#GL_LESS) ;The Type Of Depth Test To Do
 
 ProcedureReturn #True
 
EndProcedure

Procedure 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_(0.0,0.0,-5.0)
 
 glRotatef_(xrot,1.0,0.0,0.0)
 glRotatef_(yrot,0.0,1.0,0.0)
 glRotatef_(zrot,0.0,0.0,1.0)
 
 glBindTexture_(#GL_TEXTURE_2D,texture(0))
 
 glBegin_(#GL_QUADS)
  ;Front Face
  glNormal3f_( 0.0, 0.0, 1.0)
  glTexCoord2f_(1.0, 1.0) : glVertex3f_( 1.0, 1.0, 1.0)
  glTexCoord2f_(0.0, 1.0) : glVertex3f_(-1.0, 1.0, 1.0)
  glTexCoord2f_(0.0, 0.0) : glVertex3f_(-1.0,-1.0, 1.0)
  glTexCoord2f_(1.0, 0.0) : glVertex3f_( 1.0,-1.0, 1.0)
  ;Back Face
  glNormal3f_( 0.0, 0.0,-1.0)
  glTexCoord2f_(1.0, 1.0) : glVertex3f_(-1.0, 1.0,-1.0)
  glTexCoord2f_(0.0, 1.0) : glVertex3f_( 1.0, 1.0,-1.0)
  glTexCoord2f_(0.0, 0.0) : glVertex3f_( 1.0,-1.0,-1.0)
  glTexCoord2f_(1.0, 0.0) : glVertex3f_(-1.0,-1.0,-1.0)
  ;Top Face
  glNormal3f_( 0.0, 1.0, 0.0)
  glTexCoord2f_(1.0, 1.0) : glVertex3f_( 1.0, 1.0,-1.0)
  glTexCoord2f_(0.0, 1.0) : glVertex3f_(-1.0, 1.0,-1.0)
  glTexCoord2f_(0.0, 0.0) : glVertex3f_(-1.0, 1.0, 1.0)
  glTexCoord2f_(1.0, 0.0) : glVertex3f_( 1.0, 1.0, 1.0)
  ;Bottom Face
  glNormal3f_( 0.0,-1.0, 0.0)
  glTexCoord2f_(0.0, 0.0) : glVertex3f_( 1.0,-1.0, 1.0)
  glTexCoord2f_(1.0, 0.0) : glVertex3f_(-1.0,-1.0, 1.0)
  glTexCoord2f_(1.0, 1.0) : glVertex3f_(-1.0,-1.0,-1.0)
  glTexCoord2f_(0.0, 1.0) : glVertex3f_( 1.0,-1.0,-1.0)
  ;Right Face
  glNormal3f_( 1.0, 0.0, 0.0)
  glTexCoord2f_(1.0, 0.0) : glVertex3f_( 1.0,-1.0,-1.0)
  glTexCoord2f_(1.0, 1.0) : glVertex3f_( 1.0, 1.0,-1.0)
  glTexCoord2f_(0.0, 1.0) : glVertex3f_( 1.0, 1.0, 1.0)
  glTexCoord2f_(0.0, 0.0) : glVertex3f_( 1.0,-1.0, 1.0)
  ;Left Face
  glNormal3f_(-1.0, 0.0, 0.0)
  glTexCoord2f_(0.0, 0.0) : glVertex3f_(-1.0,-1.0,-1.0)
  glTexCoord2f_(1.0, 0.0) : glVertex3f_(-1.0,-1.0, 1.0)
  glTexCoord2f_(1.0, 1.0) : glVertex3f_(-1.0, 1.0, 1.0)
  glTexCoord2f_(0.0, 1.0) : glVertex3f_(-1.0, 1.0,-1.0)
 glEnd_()
 
 xrot+0.3
 yrot+0.2
 zrot+0.4
 
EndProcedure

Procedure KillGLWindow() ;Properly Kill The Window

 If fullscreen ;Are We In Fullscreen Mode?
  If ChangeDisplaySettings_(#Null,#CDS_TEST)=0 ;If The Shortcut Doesn't Work
   ChangeDisplaySettings_(#Null,#CDS_RESET) ;Do It Anyway (To Get The Values Out Of The Registry)
   ChangeDisplaySettings_(DMsaved,#CDS_RESET) ;Change It To The Saved Settings
  Else
   ChangeDisplaySettings_(#Null,#CDS_RESET) ;If It Works, Go Right Ahead
  EndIf
  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 wpos.POINT ;Window position
 
 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 
 
 EnumDisplaySettings_(#Null,#ENUM_CURRENT_SETTINGS,DMsaved) ;Save The Current Display State
 
 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 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 ;Are We Still In Fullscreen Mode?
  dwExStyle=#WS_EX_APPWINDOW ;Window Extended Style
  dwStyle=#WS_POPUP | #WS_CLIPSIBLINGS | #WS_CLIPCHILDREN ;Windows Style
  ShowCursor_(#False) ;Hide Mouse Pointer
 Else
  dwExStyle=#WS_EX_APPWINDOW | #WS_EX_WINDOWEDGE ;Window Extended Style
  dwStyle=#WS_OVERLAPPEDWINDOW | #WS_CLIPSIBLINGS | #WS_CLIPCHILDREN ;Windows Style
 EndIf
 
 If fullscreen=0 ;if not fullscreen mode calculate screen centered window
  wpos\x=(GetSystemMetrics_(#SM_CXSCREEN)/2)-(width/2)
  wpos\y=(GetSystemMetrics_(#SM_CYSCREEN)/2)-(height/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,wpos\x,wpos\y,width,height,#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_DRAW_TO_WINDOW | #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER ;Format Must Support Window, OpenGL, Double Buffering
 pfd\iPixelType=#PFD_TYPE_RGBA ;Request An RGBA Format
 pfd\cColorBits=bits ;Select Our Color Depth
 pfd\cRedBits=0 ;Color Bits Ignored
 pfd\cRedShift=0
 pfd\cGreenBits=0
 pfd\cGreenShift=0
 pfd\cBlueBits=0
 pfd\cBlueShift=0
 pfd\cAlphaBits=0 ;No Alpha Buffer
 pfd\cAlphaShift=0 ;Shift Bit Ignored
 pfd\cAccumBits=0 ;No Accumulation Buffer
 pfd\cAccumRedBits=0 ;Accumulation Bits Ignored
 pfd\cAccumGreenBits=0
 pfd\cAccumBlueBits=0
 pfd\cAccumAlphaBits=0
 pfd\cDepthBits=16 ;16Bit Z-Buffer (Depth Buffer)
 pfd\cStencilBits=1 ;Use Stencil Buffer ( * Important * )
 pfd\cAuxBuffers=0 ;No Auxiliary Buffer
 pfd\iLayerType=#PFD_MAIN_PLANE ;Main Drawing Layer
 pfd\bReserved=0 ;Reserved
 pfd\dwLayerMask=0 ;Layer Masks Ignored
 pfd\dwVisibleMask=0
 pfd\dwDamageMask=0
 
 hDC=GetDC_(hWnd)
 If hDC=0 ;Did We Get A Device Context?
  KillGLWindow() ;Reset The Display
  MessageBox_(#Null,"Can't Create A GL Device Context.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
  ProcedureReturn #False
 EndIf
 
 PixelFormat=ChoosePixelFormat_(hDC,pfd)
 If PixelFormat=0 ;Did Windows Find A Matching Pixel Format?
  KillGLWindow() ;Reset The Display
  MessageBox_(#Null,"Can't Find A Suitable PixelFormat.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
  ProcedureReturn #False
 EndIf
 
 If SetPixelFormat_(hDC,PixelFormat,pfd)=0 ;Are We Able To Set The Pixel Format?
  KillGLWindow() ;Reset The Display
  MessageBox_(#Null,"Can't Set The PixelFormat.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
  ProcedureReturn #False
 EndIf
 
 hRC=wglCreateContext_(hDC)
 If hRC=0 ;Are We Able To Get A Rendering Context?
  KillGLWindow() ;Reset The Display
  MessageBox_(#Null,"Can't Create A GL Rendering Context.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
  ProcedureReturn #False
 EndIf
 
 If wglMakeCurrent_(hDC,hRC)=0 ;Try To Activate The Rendering Context
  KillGLWindow() ;Reset The Display
  MessageBox_(#Null,"Can't Activate The GL Rendering Context.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
  ProcedureReturn #False
 EndIf
 
 ShowWindow_(hWnd,#SW_SHOW) ;Show The Window
 SetForegroundWindow_(hWnd) ;Slightly Higher Priority
 SetFocus_(hWnd) ;Sets Keyboard Focus To The Window
 ReSizeGLScene(width,height) ;Set Up Our Perspective GL Screen
 
 If InitGL()=0 ;Initialize Our Newly Created GL Window
  KillGLWindow() ;Reset The Display
  MessageBox_(#Null,"Initialization Failed.","ERROR",#MB_OK | #MB_ICONEXCLAMATION)
  ProcedureReturn #False
 EndIf
 
 ProcedureReturn #True ;Success
 
EndProcedure

Procedure.l WndProc(hWnd.l,uMsg.l,wParam.l,lParam.l)

 Select uMsg ;Check For Windows Messages
 
  Case #WM_ACTIVATE ;Watch For Window Activate Message
   If HiWord(wParam)=0 ;Check Minimization State
    active=#True ;Program Is Active
   Else
    active=#False ;Program Is No Longer Active
   EndIf
   ProcedureReturn 0 ;Return To The Message Loop
   
  Case #WM_SYSCOMMAND ;Intercept System Commands
   Select wParam ;Check System Calls
    Case #SC_SCREENSAVE ;Screensaver Trying To Start?
     ProcedureReturn 0 ;Prevent From Happening
    Case #SC_MONITORPOWER ;Monitor Trying To Enter Powersave?
     ProcedureReturn 0 ;Prevent From Happening
   EndSelect
   
  Case #WM_CLOSE ;Did We Receive A Close Message?
   PostQuitMessage_(0) ;Send A Quit Message
   ProcedureReturn 0 ;Jump Back
   
  Case #WM_KEYDOWN ;Is A Key Being Held Down?
   keys(wParam)=#True ;If So, Mark It As TRUE
   ProcedureReturn 0 ;Jump Back
   
  Case #WM_KEYUP ;Has A Key Been Released?
   keys(wParam)=#False ;If So, Mark It As FALSE
   ProcedureReturn 0 ;Jump Back
   
  Case #WM_SIZE ;Resize The OpenGL Window
   ReSizeGLScene(LoWord(lParam),HiWord(lParam)) ;LoWord=Width, HiWord=Height
   ProcedureReturn 0 ;Jump Back
   
 EndSelect
 
 ;Pass All Unhandled Messages To DefWindowProc
 ProcedureReturn DefWindowProc_(hWnd,uMsg,wParam,lParam)
 
EndProcedure

Procedure.l WinMain() ;Main Program

 Protected msg.MSG ;Windows Message Structure
 Protected done.b=#False ;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("Andreas Löffler, Rob Fletcher & NeHe's Blitter & Raw Image 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
   
  EndIf
 
  If active=0 ;Program Inactive?
   WaitMessage_() ;Wait For A Message / Do Nothing ( NEW ... Thanks Jim Strong )
  EndIf
 
  If keys(#VK_ESCAPE) ;Was Escape Pressed?
   done=#True ;ESC Signalled A Quit
  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("Andreas Löffler, Rob Fletcher & NeHe's Blitter & Raw Image Loading Tutorial",640,480,16,fullscreen)=0
    ProcedureReturn 0 ;Quit If Window Was Not Created
   EndIf
  EndIf
   
  DrawGLScene() ;Draw The Scene
  SwapBuffers_(hDC) ;Swap Buffers (Double Buffering)
  Delay(5)
 
 Wend
 
 ;Shutdown
 KillGLWindow() ;Kill The Window
 End ;Exit The Program
 
EndProcedure

WinMain() ;run the main program
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: NeHe's Blitter & Raw Image Loading Tutorial (Lesson 29)

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/29_Blit.rar

Code: Select all

;Andreas Löffler, Rob Fletcher & NeHe's Blitter & Raw Image Loading Tutorial (Lesson 29)
;http://nehe.gamedev.net and http://www.tiptup.com
;https://nehe.gamedev.net/tutorial/bezier_patches__fullscreen_fix/18003/
;Note: requires RAW files in paths "Data/Monitor.raw", "Data/GL.raw"
;Credits: Nico Gruener, Dreglor, traumatic, hagibaba
;Author: MPz
;Date: 2 Nov 2021
;Note: up-to-date with PB v5.73 (Windows)

UsePNGImageDecoder() 

;Start of Lesson 29

Global DMsaved.DEVMODE ;Saves The Previous Screen Settings

Global xrot.f ;X Rotation
Global yrot.f ;Y Rotation
Global zrot.f ;Z Rotation

Global Dim texture.i(1) ;Storage For 1 Texture

Structure TEXTURE_IMAGE
 width.l ;Width Of Image In Pixels
 height.l ;Height Of Image In Pixels
 format.l ;Number Of Bytes Per Pixel
 Data.i ;Texture Data
EndStructure

Global t1.TEXTURE_IMAGE ;Pointer To The Texture Image Data Type
Global t2.TEXTURE_IMAGE ;Pointer To The Texture Image Data Type

Procedure AllocateTextureBuffer(*ti.TEXTURE_IMAGE,w.l,h.l,f.l) ;Allocate Memory For An Image

 Protected c.i=#Null ;Pointer To Block Memory For Image
 
 If *ti<>#Null
  *ti\width=w ;Set Width
  *ti\height=h ;Set Height
  *ti\format=f ;Set Format
  c=AllocateMemory(w*h*f)
  If c<>#Null
   *ti\Data=c ;Set Data
  Else
   MessageBox_(#Null,"Could Not Allocate Memory For A Texture Buffer","BUFFER ERROR",#MB_OK | #MB_ICONINFORMATION)
   ProcedureReturn #Null
  EndIf
 Else
  MessageBox_(#Null,"Invalid Image Structure","IMAGE STRUCTURE ERROR",#MB_OK | #MB_ICONINFORMATION)
  ProcedureReturn #Null
 EndIf
 
EndProcedure

Procedure DeallocateTexture(*t.TEXTURE_IMAGE) ;Free Up The Image Data

 If *t
  If *t\Data
   FreeMemory(*t\Data)
  EndIf
  ;FreeMemory(*t) ;Note: this doesn't apply for a structure
 EndIf
 
EndProcedure

;Read A .RAW File In To The Allocated Image Buffer Using Data In The Image Structure Header.
;Flip The Image Top To Bottom. Returns 0 For Failure Of Read, Or Number Of Bytes Read.

Procedure ReadTextureData(filename.s,*buffer.TEXTURE_IMAGE)

 Protected f.i,i.i,j.i,k.i
 Protected done.l=0,stride.i,p.i=#Null
 
 stride=*buffer\width**buffer\format ;Size Of A Row (Width * Bytes Per Pixel)
 
 f=ReadFile(#PB_Any,filename) ;Open "filename" For Reading Bytes
 
 If f<>#Null ;If File Exists
  For i=*buffer\height-1 To 0 Step -1 ;Loop Through Height (Bottoms Up - Flip Image)
   p=*buffer\Data+(i*stride)
   For j=0 To *buffer\width-1 ;Loop Through Width
    For k=0 To (*buffer\format-1)-1
     PokeB(p,ReadByte(f)) ;Read Value From File And Store In Memory
     p+1 : done+1 ;Next Byte
    Next
    PokeB(p,255) : p+1 ;Store 255 In Alpha Channel And Increase Pointer
   Next
  Next
  CloseFile(f) ;Close The File
 Else ;Otherwise
  MessageBox_(#Null,"Unable To Open Image File","IMAGE ERROR",#MB_OK | #MB_ICONINFORMATION)
 EndIf
 
 ProcedureReturn done ;Returns Number Of Bytes Read In
 
EndProcedure

Procedure BuildTexture(*tex.TEXTURE_IMAGE)

 glGenTextures_(1,@texture(0))
 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)
 gluBuild2DMipmaps_(#GL_TEXTURE_2D,#GL_RGB,*tex\width,*tex\height,#GL_RGBA,#GL_UNSIGNED_BYTE,*tex\Data)
 
EndProcedure

Procedure Blit(*src.TEXTURE_IMAGE,*dst.TEXTURE_IMAGE,src_xstart.l,src_ystart.l,src_width.l,src_height.l,dst_xstart.l,dst_ystart.l,blend.l,alpha.l)

 Protected i.l,j.l,k.l,v.l
 Protected s.i,d.i ;Source & Destination
 
 ;Clamp Alpha If Value Is Out Of Range
 If alpha>255 : alpha=255 : EndIf
 If alpha<0 : alpha=0 : EndIf
 
 ;Check For Incorrect Blend Flag Values
 If blend<0 : blend=0 : EndIf
 If blend>1 : blend=1 : EndIf
 
 d=*dst\Data+(dst_ystart**dst\width**dst\format) ;Start Row - dst (Row * Width In Pixels * Bytes Per Pixel)
 s=*src\Data+(src_ystart**src\width**src\format) ;Start Row - src (Row * Width In Pixels * Bytes Per Pixel)
 
 For i=0 To src_height-1 ;Height Loop
  s=s+(src_xstart**src\format) ;Move Through Src Data By Bytes Per Pixel
  d=d+(dst_xstart**dst\format) ;Move Through Dst Data By Bytes Per Pixel
  For j=0 To src_width-1 ;Width Loop
   For k=0 To *src\format-1 ;"n" Bytes At A Time
    If blend ;If Blending Is On
     v=((PeekB(s) & 255)*alpha)+((PeekB(d) & 255)*(255-alpha)) ;Src Data*alpha + Dst Data*(255-alpha)
     PokeB(d,v >> 8) ;Keep in 0-255 Range With >> 8
    Else
     PokeB(d,PeekB(s)) ;No Blending Just Do A Straight Copy
    EndIf
    d+1 : s+1 ;Next Byte
   Next
  Next
  d=d+(*dst\width-(src_width+dst_xstart))**dst\format ;Add End Of Row
  s=s+(*src\width-(src_width+src_xstart))**src\format ;Add End Of Row
 Next
 
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

 AllocateTextureBuffer(t1,256,256,4) ;Get An Image Structure
 If ReadTextureData("Data/Monitor.raw",t1)=0 ;Fill The Image Structure With Data
  MessageBox_(#Null,"Could Not Read 'Monitor.raw' Image Data","TEXTURE ERROR",#MB_OK | #MB_ICONINFORMATION)
  ProcedureReturn #False ;Nothing Read?
 EndIf
 
 AllocateTextureBuffer(t2,256,256,4) ;Second Image Structure
 If ReadTextureData("Data/GL.raw",t2)=0 ;Fill The Image Structure With Data
  MessageBox_(#Null,"Could Not Read 'GL.raw' Image Data","TEXTURE ERROR",#MB_OK | #MB_ICONINFORMATION)
  ProcedureReturn #False ;Nothing Read?
 EndIf
 
 ;Image To Blend In, Original Image, Src Start X & Y, Src Width & Height, Dst Start X & Y, Blend Flag, Alpha Value
 Blit(t2,t1,127,127,128,128,64,64,1,127) ;Call The Blitter Routine
 
 BuildTexture(t1) ;Load The Texture Map Into Texture Memory
 
 DeallocateTexture(t1) ;Clean Up Image Memory Because Texture Is
 DeallocateTexture(t2) ;In GL Texture Memory Now
 
 glEnable_(#GL_TEXTURE_2D) ;Enable Texture Mapping
 
 glShadeModel_(#GL_SMOOTH) ;Enables Smooth Color Shading
 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
 glEnable_(#GL_DEPTH_TEST) ;Enables Depth Testing
 glDepthFunc_(#GL_LESS) ;The Type Of Depth Test To Do
 
 ProcedureReturn #True

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_(0.0,0.0,-5.0)
 
  glRotatef_(xrot,1.0,0.0,0.0)
  glRotatef_(yrot,0.0,1.0,0.0)
  glRotatef_(zrot,0.0,0.0,1.0)
 
  glBindTexture_(#GL_TEXTURE_2D,texture(0))
 
  glBegin_(#GL_QUADS)
   ;Front Face
   glNormal3f_( 0.0, 0.0, 1.0)
   glTexCoord2f_(1.0, 1.0) : glVertex3f_( 1.0, 1.0, 1.0)
   glTexCoord2f_(0.0, 1.0) : glVertex3f_(-1.0, 1.0, 1.0)
   glTexCoord2f_(0.0, 0.0) : glVertex3f_(-1.0,-1.0, 1.0)
   glTexCoord2f_(1.0, 0.0) : glVertex3f_( 1.0,-1.0, 1.0)
   ;Back Face
   glNormal3f_( 0.0, 0.0,-1.0)
   glTexCoord2f_(1.0, 1.0) : glVertex3f_(-1.0, 1.0,-1.0)
   glTexCoord2f_(0.0, 1.0) : glVertex3f_( 1.0, 1.0,-1.0)
   glTexCoord2f_(0.0, 0.0) : glVertex3f_( 1.0,-1.0,-1.0)
   glTexCoord2f_(1.0, 0.0) : glVertex3f_(-1.0,-1.0,-1.0)
   ;Top Face
   glNormal3f_( 0.0, 1.0, 0.0)
   glTexCoord2f_(1.0, 1.0) : glVertex3f_( 1.0, 1.0,-1.0)
   glTexCoord2f_(0.0, 1.0) : glVertex3f_(-1.0, 1.0,-1.0)
   glTexCoord2f_(0.0, 0.0) : glVertex3f_(-1.0, 1.0, 1.0)
   glTexCoord2f_(1.0, 0.0) : glVertex3f_( 1.0, 1.0, 1.0)
   ;Bottom Face
   glNormal3f_( 0.0,-1.0, 0.0)
   glTexCoord2f_(0.0, 0.0) : glVertex3f_( 1.0,-1.0, 1.0)
   glTexCoord2f_(1.0, 0.0) : glVertex3f_(-1.0,-1.0, 1.0)
   glTexCoord2f_(1.0, 1.0) : glVertex3f_(-1.0,-1.0,-1.0)
   glTexCoord2f_(0.0, 1.0) : glVertex3f_( 1.0,-1.0,-1.0)
   ;Right Face
   glNormal3f_( 1.0, 0.0, 0.0)
   glTexCoord2f_(1.0, 0.0) : glVertex3f_( 1.0,-1.0,-1.0)
   glTexCoord2f_(1.0, 1.0) : glVertex3f_( 1.0, 1.0,-1.0)
   glTexCoord2f_(0.0, 1.0) : glVertex3f_( 1.0, 1.0, 1.0)
   glTexCoord2f_(0.0, 0.0) : glVertex3f_( 1.0,-1.0, 1.0)
   ;Left Face
   glNormal3f_(-1.0, 0.0, 0.0)
   glTexCoord2f_(0.0, 0.0) : glVertex3f_(-1.0,-1.0,-1.0)
   glTexCoord2f_(1.0, 0.0) : glVertex3f_(-1.0,-1.0, 1.0)
   glTexCoord2f_(1.0, 1.0) : glVertex3f_(-1.0, 1.0, 1.0)
   glTexCoord2f_(0.0, 1.0) : glVertex3f_(-1.0, 1.0,-1.0)
  glEnd_()
 
  xrot+0.3
  yrot+0.2
  zrot+0.4
  
  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 bits = 32
    OpenGlFlags + #PB_OpenGL_24BitDepthBuffer + #PB_OpenGL_8BitStencilBuffer
  EndIf
  
  If Vsync = 0
    OpenGlFlags + #PB_OpenGL_NoFlipSynchronization
  EndIf
  
  OpenGLGadget(0, 0, 0, WindowWidth(0),WindowHeight(0),OpenGlFlags)
  
  SetActiveGadget(0) 
  
  ReSizeGLScene(WindowWidth(0),WindowHeight(0))
  ;hDC = GetDC_(hWnd)
  
EndProcedure

CreateGLWindow("Andreas Löffler, Rob Fletcher & NeHe's Blitter & Raw Image Loading Tutorial (Lesson 29)",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) ;  Esc key to exit
    Quit = 1
  EndIf      

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


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