Is it just me or (display lists)

BlitzMax Forums/BlitzMax OpenGL Programming/Is it just me or (display lists)

Are display lists slower than just spitting out geometry?

Framework brl.GLGraphics
Import brl.bmploader
Import brl.max2d

Global ScreenWidth:Int=800
Global ScreenHeight:Int=600
Global ScreenDepth:Int=0

Global box:Int			' Storage For The Box Display List
Global top:Int			' Storage For The Top Display List

Global xrot:Float			' Rotates Cube On The X Axis
Global yrot:Float			' Rotates Cube On The Y Axis

Global ListDraw:Int=1
Global Keytrig:Int=0

Global boxcol:Float[]=[1.0,0.0,0.0,1.0,0.5,0.0,1.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0]
Global topcol:Float[]=[0.5,0.0,0.0,0.5,0.25,0.0,0.5,0.5,0.0,0.0,0.5,0.0,0.0,0.5,0.5]

Global Checkimage:Byte[128,128,3]
Global Texname:Int				' Storage for 1 texture

Global FPS_Array:Int[50]

GLGraphics(ScreenWidth,ScreenHeight,ScreenDepth,0,gl_BACKBUFFER | gl_DEPTHBUFFER) ' | gl_FULLSCREEN)
'(0)
InitGl()
' false
While Not KeyHit(KEY_ESCAPE)
	nehe12()
	glDisable(GL_TEXTURE_2D)	
	glDisable(GL_DEPTH_TEST)	
	glDisable(GL_LIGHT0)
	glDisable(GL_LIGHTING)
	glDisable(GL_COLOR_MATERIAL)
	glColor3f(1.0,1.0,1.0)
	'Framecounter--------------------------------------------
	NewFrameTime = MilliSecs()
	FPSTime = NewFrameTime - OldFrameTime 
	If FPSTime = 0 Then FPSTime = 1000 Else FPSTime = 1000/FPSTime
	OldFrameTime = MilliSecs()
	FPSTotal=0
	For A = 1 To 49
		FPS_Array[A-1] = FPS_Array[A]
		FPSTotal = FPSTotal + FPS_Array[A]
	Next
	FPS_Array[49] = FPSTime
	FPSTotal = FPSTotal + FPSTime
	NewFPSTime = FPSTotal / 50
	GLDrawText("FPS : "+NewFPSTime  +" List:"+ListDraw,ScreenWidth-(8*18),ScreenHeight-16-8)
	'--------------------------------------------------------
	GLDrawText("NeHe's Display List Tutorial (lesson 12)",10,24)
	glEnable(GL_TEXTURE_2D	)
	glEnable(GL_DEPTH_TEST)	
	glEnable(GL_LIGHT0)
	glEnable(GL_LIGHTING)
	glEnable(GL_COLOR_MATERIAL)

	Flip
Wend
End

Function InitGl()
	LoadGlTextures()														' Load The Texture(s)
	BuildLists()
	glEnable GL_TEXTURE_2D													' Enable Texture Mapping
	glClearColor(0.0, 0.0, 0.0, 0.5)										' This Will Clear The Background Color To Black
	glClearDepth 1.0														' Enables Clearing Of The Depth Buffer
	glDepthFunc GL_LESS													' The Type Of Depth Test To Do
	glEnable GL_DEPTH_TEST													' Enables Depth Testing
	glShadeModel(GL_SMOOTH)												' Enables Smooth Color Shading
	glEnable(GL_LIGHT0)													' Quick And Dirty Lighting (Assumes Light0 Is Set Up)
	glEnable(GL_LIGHTING)													' Enable Lighting
	glEnable(GL_COLOR_MATERIAL)											' Enable Material Coloring
	glViewport(0,0,ScreenWidth,ScreenHeight)								' Set viewport
	glMatrixMode(GL_PROJECTION)
	glLoadIdentity()														' Reset The Projection Matrix
	gluPerspective(45.0,Float(ScreenWidth)/Float(ScreenHeight),0.5,100.0)		' Calculate The Aspect Ratio Of The Window
	glMatrixMode(GL_MODELVIEW)
End Function

Function LoadGlTextures()
	Local PointeurImg:Byte Ptr
	Local TexWidth
	Local TexHeight
	tex01:TPixmap=LoadPixmap("data\cube.bmp")
	TexWidth=tex01.Width
	TexHeight=tex01.Height
	PointeurImg=PixmapPixelPtr(tex01,0,0)
	pp=0
	For y=TexHeight-1 To 0 Step -1
		For x=0 To TexWidth-1
			Checkimage[y,x,0]=PointeurImg[pp]
			Checkimage[y,x,1]=PointeurImg[pp+1]
			Checkimage[y,x,2]=PointeurImg[pp+2]
			pp=pp+3
		Next
	Next
	' Create Texture
	glGenTextures 1, Varptr Texname
	glBindTexture GL_TEXTURE_2D,Texname
	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
	glTexImage2D GL_TEXTURE_2D, 0, 3, TexWidth, TexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, Checkimage
End Function

Function nehe12()
	Local yloop:Int
	Local xloop:Int
	
	If KeyDown(KEY_LEFT) Then yrot:-0.2
	If KeyDown(KEY_RIGHT) Then yrot:+0.2
	If KeyDown(KEY_UP) Then xrot:-0.2
	If KeyDown(KEY_DOWN) Then xrot:+0.2
	If KeyDown(KEY_1) And Keytrig = 0 Then ListDraw=1-ListDraw;Keytrig=1
	If KeyDown(KEY_1)=0 And Keytrig = 1 Then Keytrig = 0
	
	glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT		' Clear The Screen And The Depth Buffer
	glBindTexture(GL_TEXTURE_2D, Texname)
	For yloop=1 To 100
		For xloop=0 To yloop-1
			glLoadIdentity()								' Reset The View
			glTranslatef(1.4+(Float(xloop)*2.8)-(Float(yloop)*1.4),((6.0-Float(yloop))*2.4)-7.0,-20.0)
			glRotatef(45.0-(2.0*Float(yloop))+xrot,1.0,0.0,0.0)
			glRotatef(45.0+yrot,0.0,1.0,0.0)
				If ListDraw Then
					glColor3fv(Varptr boxcol[yloop-1])										'(boxcol[yloop-1])
					glCallList(box)
					glColor3fv(Varptr topcol[yloop-1])
					glCallList(top)				
				Else
					glColor3fv(Varptr boxcol[yloop-1])
					ManualDraw()
				EndIf

		Next
	Next
End Function

Function ManualDraw()
		glBegin(GL_QUADS)
			' Bottom 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)
			' Front Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0)
			glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0)
			' Back Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(0.0, 0.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()
		glBegin(GL_QUADS)
			' Top Face
			glNormal3f( 0.0, 1.0, 0.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);
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);
		glEnd()

End Function

' Build Cube Display Lists
Function BuildLists()
	box=glGenLists(2)													' Generate 2 Different Lists
	glNewList(box,GL_COMPILE)											' Start With The Box List
		glBegin(GL_QUADS)
			' Bottom 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)
			' Front Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0)
			glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0)
			' Back Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(0.0, 0.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()
	glEndList()
	top=box+1														' Storage For "Top" Is "Box" Plus One
	glNewList(top,GL_COMPILE)											' Now The "Top" Display List
		glBegin(GL_QUADS)
			' Top Face
			glNormal3f( 0.0, 1.0, 0.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);
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);
		glEnd()
	glEndList()
End Function



The above code would suggest so.... Strange, they say display lists are faster.

wont run with out that image, contains more than 1 frame??

nope, just one frame

http://www.mattsbigbrownbox.com/code_issues/cube.bmp

Kit key 1 to toggle between the Display lists and the "intermediate mode" drawing..

You should note that display lists are slower

No commercial game that I've ever worked on has used display lists. Just stick with vertex buffers/triangle lists and you'll be fine.

So stay away from intermediate mode and go with vertex buffers?

It really depends what you're using them for.

The example you've got there isn't suited for display list processing - display lists are more geared up for high poly geometry.

Try this code & see if you notice the difference.

Strict

Framework BRL.GLGraphics
Import Pub.OpenGL
Import pub.glew

SetGraphicsDriver GLGraphicsDriver()

Global ScreenWidth:Int=800
Global ScreenHeight:Int=600
Global ScreenDepth:Int=32

Global fullscreen:Int=0
If fullscreen=1
	ScreenWidth=1280
	ScreenHeight=1024
	ScreenDepth=32
Else
	ScreenWidth=800
	ScreenHeight=600
	ScreenDepth=0
EndIf

Global box:Int			' Storage For The Box Display List
Global top:Int			' Storage For The Top Display List

Global ListDraw:Int=1
Global Keytrig:Int=0

Global xrot:Float			' Rotates Cube On The X Axis
Global yrot:Float			' Rotates Cube On The Y Axis

Global boxcol:Float[]=[1.0,0.0,0.0,1.0,0.5,0.0,1.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0]
Global ambient:Float[]=[0.3,0.3,0.3,0.0]
Global Checkimage:Byte[64,64,3]


Global framecounter_counter, framecounter_time, framecounter_framerate
Global tex01:TPixmap, pp
Global x:Float, y:Float, z:Float, l:Float, w:Float, h:Float
glEnable(GL_ARB_MULTISAMPLE)
GLGraphics(ScreenWidth,ScreenHeight,ScreenDepth,0,GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER)' | BGL_FULLSCREEN)
'glSetSwapInterval(0)
glEnable(GL_CULL_FACE)
InitGl()
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glHint (GL_FOG_HINT, GL_FASTEST)	

'HideMouse
While Not KeyHit(KEY_ESCAPE)
	nehe12()
	glDisable(GL_TEXTURE_2D)	
	glDisable(GL_DEPTH_TEST)	
	glDisable(GL_LIGHT0)
	glDisable(GL_LIGHTING)
	glDisable(GL_COLOR_MATERIAL)
	glColor3f(1.0,0.8,0.7)
	'Framecounter--------------------------------------------
	Framecounter_counter=Framecounter_counter+1
	If Framecounter_time=0 Then Framecounter_time=MilliSecs()
	If Framecounter_time+1001 <MilliSecs() Then
		Framecounter_framerate=Framecounter_counter
		Framecounter_counter=0
		Framecounter_time=MilliSecs()
	EndIf
	GLDrawText("FPS : "+Framecounter_framerate,0,0)
	If listdraw=1
		GLDrawText("Display List",0,20)
	Else
		GLDrawText("'On the fly'",0,20)
	EndIf
	'--------------------------------------------------------
	glEnable(GL_TEXTURE_2D	)
	glEnable(GL_DEPTH_TEST)	
	glEnable(GL_LIGHT0)
	glEnable(GL_LIGHTING)
	glEnable(GL_COLOR_MATERIAL)
	Flip(-1)
Wend
End

Function InitGl()
	BuildLists()
	glEnable GL_TEXTURE_2D													' Enable Texture Mapping
	glClearColor(0.1, 0.4, 0.45, 0)										' This Will Clear The Background Color To Black
	glClearDepth 1.0														' Enables Clearing Of The Depth Buffer
	glDepthFunc GL_LESS ' GOOD													' The Type Of Depth Test To Do
	glEnable GL_DEPTH_TEST													' Enables Depth Testing
	glShadeModel(GL_SMOOTH)												' Enables Smooth Color Shading
	glEnable(GL_LIGHT0)
	glEnable(GL_LIGHTING)													' Enable Lighting
	ambient:Float=[0.51,0.51,0.51,1.0]
	glLightfv(GL_LIGHT0, GL_AMBIENT, ambient)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, ambient )
	ambient:Float=[0.21,0.91,0.91,1.0]
    glLightfv(GL_LIGHT0, GL_SPECULAR, ambient)
	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 5.0);
	glEnable(GL_COLOR_MATERIAL)												' Enable Material Coloring
	glViewport(0,0,ScreenWidth,ScreenHeight)								' Set viewport
	glMatrixMode(GL_PROJECTION)
	glLoadIdentity()														' Reset The Projection Matrix
	gluPerspective(45.0,Float(ScreenWidth)/Float(ScreenHeight),1.5,150.0)	' Calculate The Aspect Ratio Of The Window
	glMatrixMode(GL_MODELVIEW)
End Function

Function nehe12()
	Local yloop:Int
	Local xloop:Int

	If KeyDown(KEY_LEFT) Then yrot:-0.5
	If KeyDown(KEY_RIGHT) Then yrot:+0.5
	If KeyDown(KEY_UP) Then xrot:-0.5
	If KeyDown(KEY_DOWN) Then xrot:+0.5
	If KeyDown(KEY_1) And Keytrig = 0 Then ListDraw=1-ListDraw;Keytrig=1
	If KeyDown(KEY_1)=0 And Keytrig = 1 Then Keytrig = 0

	glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT		' Clear The Screen And The Depth Buffer
	glPolygonMode(GL_FRONT,GL_FILL)
	glLoadIdentity()								' Reset The View
	glTranslatef(0,-4,-60.0)
	glRotatef(45.0-(2.0*Float(yloop))+xrot,1.0,0.0,0.0)
	glRotatef(45.0+yrot,0.0,1.0,0.0)
	If listdraw=1
		glCallList(box)
	Else
		glBegin(GL_QUADS)
		' build test scene
		For x=-20 To 20 Step 2
			For y=-20 To 20 Step 2
				For z=-10 To 10 Step 2
					addcubetodisplaylist(x,y,z,1,1,1)
				Next		
			Next
		Next
		glEnd()
	EndIf

End Function

' Build Cube Display Lists
Function BuildLists()
	box=glGenLists(1)
	glNewList(box,GL_COMPILE)
	glBegin(GL_QUADS)
		For x=-20 To 20 Step 2
			For y=-20 To 20 Step 2
				For z=-10 To 10 Step 2
					addcubetodisplaylist(x,y,z,1,1,1)
				Next		
			Next
		Next
	glEnd()
	glEndList()
End Function

Function addcubetodisplaylist(x:Float,y:Float,z:Float,l:Float,w:Float,h:Float)
' by dimensions
			' Top Face
			glNormal3f( 0.0, 1.0, 0.0);
			glTexCoord2f(0.0, w); glVertex3f(x,   z+h, y)
			glTexCoord2f(0.0, 0.0); glVertex3f(x,   z+h, y+w)
			glTexCoord2f(l, 0.0); glVertex3f(x+l, z+h, y+w)
			glTexCoord2f(l, w); glVertex3f(x+l, z+h, y)
			' Bottom Face
			glNormal3f( 0.0,-1.0, 0.0)
			glTexCoord2f(l, w); glVertex3f(x,   z, y)
			glTexCoord2f(0.0, w); glVertex3f(x+l, z, y)
			glTexCoord2f(0.0, 0.0); glVertex3f(x+l, z, y+w)
			glTexCoord2f(l, 0.0); glVertex3f(x,   z, y+w)
			' Front Face
			glNormal3f( 0.0, 0.0, 1.0)
			glTexCoord2f(0.0, 0.0); glVertex3f(x,   z,   y+w)
			glTexCoord2f(l, 0.0); glVertex3f(x+l, z,   y+w)
			glTexCoord2f(l, h); glVertex3f(x+l, z+h, y+w)
			glTexCoord2f(0.0, h); glVertex3f(x,   z+h, y+w)
			' Back Face
			glNormal3f( 0.0, 0.0,-1.0)
			glTexCoord2f(l, 0.0); glVertex3f(x, z, y)
			glTexCoord2f(l, h); glVertex3f(x,  z+h, y)
			glTexCoord2f(0.0, h); glVertex3f(x+l,  z+h, y)
			glTexCoord2f(0.0, 0.0); glVertex3f(x+l,z, y)
			' Right face
			glNormal3f( 1.0, 0.0, 0.0)
			glTexCoord2f(w, 0.0); glVertex3f(x+l,z, y)
			glTexCoord2f(w, h); glVertex3f( x+l,  z+h, y)
			glTexCoord2f(0.0, h); glVertex3f( x+l,  z+h, y+w)
			glTexCoord2f(0.0, 0.0); glVertex3f( x+l,z, y+w)
			' Left Face
			glNormal3f(-1.0, 0.0, 0.0)
			glTexCoord2f(0.0, 0.0); glVertex3f(x, z, y)
			glTexCoord2f(w, 0.0); glVertex3f(x, z, y+w)
			glTexCoord2f(w, h); glVertex3f(x,  z+h, y+w)
			glTexCoord2f(0.0, h); glVertex3f(x,  z+h, y)
End Function


PJames: Flip 0 shows the correct FPS

Dark Half, try this. Set the path to your texture.

Your demo used the wrong consts for backbuffer & depthbuffer, in max it's GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER

VBOs offer a slight increase over arrays (at least on my card they do, I'm wondering if vertex arrays are just plain fast on this card?), but probably aren't as flexible. They're best used for large maps (static geometry!)

Arrays are much faster than lists though!

Also look into glDrawElements(), with that command you can draw indexed geometry.


Global ScreenWidth:Int=800
Global ScreenHeight:Int=600
Global ScreenDepth:Int=0

Global box:Int			' Storage For The Box Display List
Global top:Int			' Storage For The Top Display List

Global xrot:Float			' Rotates Cube On The X Axis
Global yrot:Float			' Rotates Cube On The Y Axis

Global ListDraw:Int=0

Global boxcol:Float[]=[1.0,0.0,0.0,1.0,0.5,0.0,1.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0]
Global topcol:Float[]=[0.5,0.0,0.0,0.5,0.25,0.0,0.5,0.5,0.0,0.0,0.5,0.0,0.0,0.5,0.5]

Global Checkimage:Byte[128,128,3]

Global Texname:Int


Global cubeVertArray:Float[] = cubeArray()
Global cubeUVArray:Float[] = uvArray()
Global cubeNormalsArray:Float[] = normalArray()


Global vertVBO:Int = 0
Global texcoordsVBO:Int = 0
Global normalsVBO:Int = 0

GLGraphics(ScreenWidth,ScreenHeight,0,0)',gl_BACKBUFFER | gl_DEPTHBUFFER) ' | gl_FULLSCREEN)

GlewInit()
InitGl()

Local fps:Int = 0
Local counter:Int = 0
Local time:Int = MilliSecs()
While Not KeyHit(KEY_ESCAPE)
	nehe12()
	glDisable(GL_TEXTURE_2D)	
	
	glDisable(GL_LIGHTING)
	glColor3f(1.0,1.0,1.0)


	If MilliSecs() - time > 1000
		fps = counter
		counter=0
		time=MilliSecs()
	End If
	
	Local dMode$
	Select ListDraw
		Case 0
			dMode="glBegin()/glEnd()"
		Case 1
			dMode="Lists"
		Case 2
			dMode="Arrays"
		Case 3
			dMode="VBOs"
	End Select
	
	GLDrawText("FPS : "+fps,0,0)
	GLDrawText("Mode: "+dMode+ " (SPACE To change): ",0,20)
	'--------------------------------------------------------

	glEnable(GL_TEXTURE_2D	)
	glEnable(GL_LIGHTING)
	'glEnable(GL_COLOR_MATERIAL)

	Flip False
	
	counter:+1
Wend
End

Function InitGl()
	LoadGlTextures()														' Load The Texture(s)
	BuildLists()
	initvbo()
	glEnable GL_TEXTURE_2D													' Enable Texture Mapping
	glClearColor(0.0, 0.0, 0.0, 0.5)										' This Will Clear The Background Color To Black
	glClearDepth 1.0														' Enables Clearing Of The Depth Buffer
	glDepthFunc GL_LESS													' The Type Of Depth Test To Do
	glEnable GL_DEPTH_TEST													' Enables Depth Testing
	glShadeModel(GL_SMOOTH)												' Enables Smooth Color Shading
	glEnable(GL_LIGHT0)													' Quick And Dirty Lighting (Assumes Light0 Is Set Up)
	glEnable(GL_LIGHTING)													' Enable Lighting
	glEnable(GL_COLOR_MATERIAL)											' Enable Material Coloring
	glViewport(0,0,ScreenWidth,ScreenHeight)								' Set viewport
	glMatrixMode(GL_PROJECTION)
	glLoadIdentity()														' Reset The Projection Matrix
	gluPerspective(45.0,Float(ScreenWidth)/Float(ScreenHeight),0.5,100.0)		' Calculate The Aspect Ratio Of The Window
	glMatrixMode(GL_MODELVIEW)
End Function

Function LoadGlTextures()
	Local PointeurImg:Byte Ptr
	Local TexWidth
	Local TexHeight
	tex01:TPixmap=LoadPixmap("cube.bmp")
	TexWidth=tex01.Width
	TexHeight=tex01.Height
	PointeurImg=PixmapPixelPtr(tex01,0,0)
	pp=0
	For y=TexHeight-1 To 0 Step -1
		For x=0 To TexWidth-1
			Checkimage[y,x,0]=PointeurImg[pp]
			Checkimage[y,x,1]=PointeurImg[pp+1]
			Checkimage[y,x,2]=PointeurImg[pp+2]
			pp=pp+3
		Next
	Next
	' Create Texture
	glGenTextures 1, Varptr Texname
	glBindTexture GL_TEXTURE_2D,Texname
	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
	glTexImage2D GL_TEXTURE_2D, 0, 3, TexWidth, TexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, Checkimage
End Function

Function nehe12()
	Local yloop
	Local xloop
	
	'If KeyDown(KEY_LEFT) Then yrot:-0.2
	'If KeyDown(KEY_RIGHT) Then yrot:+0.2
	'If KeyDown(KEY_UP) Then xrot:-0.2
	'If KeyDown(KEY_DOWN) Then xrot:+0.2
	If KeyHit(KEY_SPACE)
		ListDraw:+1
		If ListDraw = 4 Then ListDraw = 0
	End If
	
	yrot:+.08
	xrot:+.05
	
	glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT		' Clear The Screen And The Depth Buffer
	glClientActiveTextureARB(GL_TEXTURE0_ARB)
	glBindTexture(GL_TEXTURE_2D, Texname)

	If ListDraw=2 Or ListDraw=3
		glEnableClientState(GL_VERTEX_ARRAY)
		glEnableClientState(GL_TEXTURE_COORD_ARRAY)
		glEnableClientState(GL_NORMAL_ARRAY)
		
		If listDraw=2
			'Set texture unit 0 as the active unit
			glBindBufferARB( GL_ARRAY_BUFFER_ARB, Null )

			'Pass pointers to the vertex, normal & texture coordinate arrays
			glVertexPointer(3, GL_FLOAT, 0, cubeVertArray)
			glTexCoordPointer(2, GL_FLOAT, 0, cubeUVArray)
			glNormalPointer(GL_FLOAT, 0, cubeNormalsArray)
		End If
		
		If listDraw=3
			'set pointers to the VBOs instead of pointers
			glBindBufferARB( GL_ARRAY_BUFFER_ARB, vertVBO )
			glVertexPointer( 3, GL_FLOAT, 0, Null)
					
			glBindBufferARB( GL_ARRAY_BUFFER_ARB, texcoordsVBO )
			glTexCoordPointer( 2, GL_FLOAT, 0, Null)
					
			glBindBufferARB( GL_ARRAY_BUFFER_ARB, normalsVBO )
			glNormalPointer(GL_FLOAT, 0, Null)
		End If
	End If

	
	For yloop=0 To 50
		glColor3fv(Varptr boxcol[yloop-1])
		For xloop=0 To yloop-1
			glLoadIdentity()								' Reset The View
			glTranslatef(1.4+(Float(xloop)*2.8)-(Float(yloop)*1.4),10+((6.0-Float(yloop))*2.4)-7.0,-50.0)
			glRotatef(45.0-(2.0*Float(yloop))+xrot,1.0,0.0,0.0)
			glRotatef(45.0+yrot,0.0,1.0,0.0)
			
			Select ListDraw
				Case 0
					glCallList(box)
					glCallList(top)				
				Case 1
					ManualDraw()
				Case 2
					glDrawArrays(GL_QUADS,0,cubeVertArray.length/3)
				Case 3
					glDrawArrays(GL_QUADS,0,cubeVertArray.length/3)
			End Select

		Next
	Next
	If ListDraw=2 Or ListDraw=3
		glDisableClientState(GL_VERTEX_ARRAY)
		glDisableClientState(GL_TEXTURE_COORD_ARRAY)
		glDisableClientState(GL_NORMAL_ARRAY)
	End If
End Function

Function ManualDraw()
		glBegin(GL_QUADS)
			' Bottom 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)
			' Front Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0)
			glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0)
			' Back Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(0.0, 0.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()
		glBegin(GL_QUADS)
			' Top Face
			glNormal3f( 0.0, 1.0, 0.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);
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);
		glEnd()

End Function

' Build Cube Display Lists
Function BuildLists()
	box=glGenLists(2)													' Generate 2 Different Lists
	glNewList(box,GL_COMPILE)											' Start With The Box List
		glBegin(GL_QUADS)
			' Bottom 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)
			' Front Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0)
			glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0)
			' Back Face
			glNormal3f( 0.0, 0.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)
			glTexCoord2f(0.0, 0.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()
	glEndList()
	top=box+1														' Storage For "Top" Is "Box" Plus One
	glNewList(top,GL_COMPILE)											' Now The "Top" Display List
		glBegin(GL_QUADS)
			' Top Face
			glNormal3f( 0.0, 1.0, 0.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);
			glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0);
		glEnd()
	glEndList()
End Function




Function cubeArray:Float[]()
	Return [-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0,-1.0,-1.0, 1.0, ..
          -1.0,-1.0, 1.0, 1.0,-1.0, 1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0, ..
          -1.0,-1.0,-1.0,-1.0, 1.0,-1.0, 1.0, 1.0,-1.0, 1.0,-1.0,-1.0, ..
           1.0,-1.0,-1.0, 1.0, 1.0,-1.0, 1.0, 1.0, 1.0, 1.0,-1.0, 1.0, ..
          -1.0,-1.0,-1.0,-1.0,-1.0, 1.0,-1.0, 1.0, 1.0,-1.0, 1.0,-1.0, ..
          -1.0, 1.0,-1.0,-1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,-1.0]
End Function

Function uvArray:Float[]()
	Return [1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, ..
          0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, ..
          1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, ..
          1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, ..
          0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, ..
          0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0]
End Function

Function normalArray:Float[]()
	Return [0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, ..
	        0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, ..
	        0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, ..
	        1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, ..
	       -1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0, ..
	        0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]
End Function



Function InitVBO()
	'Generate And Bind The Vertex Buffer
	glGenBuffersARB(1, Varptr(vertVBO)) 'Get A Valid Name
	glBindBufferARB( GL_ARRAY_BUFFER_ARB, vertVBO ) 'Bind The Buffer
	glBufferDataARB( GL_ARRAY_BUFFER_ARB, SizeOf(cubeVertArray), cubeVertArray, GL_STATIC_DRAW_ARB )

	glGenBuffersARB( 1, Varptr(texcoordsVBO) )
	glBindBufferARB( GL_ARRAY_BUFFER_ARB, texcoordsVBO )
	glBufferDataARB( GL_ARRAY_BUFFER_ARB, SizeOf(cubeUVArray), cubeUVArray, GL_STATIC_DRAW_ARB )
	
	glGenBuffersARB(1, Varptr(normalsVBO))
	glBindBufferARB( GL_ARRAY_BUFFER_ARB, normalsVBO )
	glBufferDataARB( GL_ARRAY_BUFFER_ARB, SizeOf(cubeNormalsArray), cubeNormalsArray, GL_STATIC_DRAW_ARB )
End Function


alright, thanks tom, I have been looking for VBO and VA code for a few days now :-)

Thanks a TON!

Don't use display lists. They are complicated, and a waste of time.

Use vertex arrays. For rendering batches of identical geometry, use vertex buffer objects, when available. Compiled vertex arrays may increase speed for unique geometry.

Note that VBO's do absolutely nothing for geometry you only render once. You are supposed to set the VBO, then render all instances of that mesh.

So to sum up:

Unique geometry
-compiled vertex array

Instanced geometry (static meshes)
-vertex buffer object

Fall back on regular vertex arrays when either of those options are unavailable. Use regular vertex arrays on any geometry that has moving vertices, like characters.

Ok a couple of points...

1] display lists are not complex + represent a decent way
to compile common state changes together. They also
improve performance when rendering static meshes,
compared with straight array based immediate mode
rendering - on some systems anyway.

2] VBO's are great, but only really in cases such as those
described by halo and for very large vertex collections.
And though i havent tried it yet - i imagine they are
perfect for shader based skeleton animation.

basically do everything halo said - but consider supporting
display lists...on my system, packing vertex arrays into
displays lists improves performance by a huge amount..
jst keep in mind that the compiled list data is static, if
you need to edit anything..you will have to rebuild the
entire list..

You might want to test which version of windows is
being used - though VBO's are a better choice for large
collections of static verts - older operating systems, or
those with iffy drivers may not support them. I know that
win98 ATI drivers are mangled, vbos only partially work.
Display Lists provide a semi decent fallback..sorta..

glLockArrays() - noel found this, its a 1.1 extension or
something - i didnt know about it..but supposedly, this will
essentially act like a compiled array...handy to know.