NeHe 11 Waving flag with metaballs

BlitzMax Forums/BlitzMax OpenGL Programming/NeHe 11 Waving flag with metaballs

Doesnt require any media.

Ive been working on converting the NeHe tutorials to BMAX. Previously Ive been playing with simple 2d metaballs. Here they are combined :)

The flag is just a bunch of quads.
The 2d drawing area is a 2d array, pixels are set individually.
The "2d surface" is put on the flag pixel-by-pixel, quad-by-quad with glColor3f.

----
How do I change from windowed to fullscreen while running? Guess I could look at the NeHe tutorials for this.

SuperStrict
Framework BRL.GLGraphics
Import Pub.GLEW
Import BRL.BMPLoader
Import BRL.PNGLoader
Import BRL.Random

Const filtering_near:Int = 0
Const filtering_linear:Int = 1
Const filtering_mipmapped:Int = 2
Const format_bmp:Int = 0
Const format_png:Int = 1

Global resX:Int = 640, resY:Int = 480
AppTitle = "NEHE 11 Flag effect + metaballs. Press SPACE to change colors"

SetGraphicsDriver GLGraphicsDriver()		
	Local neheTut:nehe = New nehe
	Local mbs:TMetaballSystem = TMetaballSystem.Create( neheTut )

	While Not KeyHit(key_escape) 
		mbs.updateMeta()
		neheTut.glDraw()
			
		If MouseDown(1) Then neheTut.xrot:+3
		If KeyHit(KEY_SPACE) Then mbs.rgbColors = Not mbs.rgbColors
		
		Flip
		Delay 16
	Wend
	EndGraphics()
End

Type NEHE		
	Field fullscreen:Int = 0
	Field flagsize:Int = 100
	Field xrot:Float = 0.0
	Field yrot:Float = 0.0
	Field zrot:Float = 0.0
	Field texture:Int[1]
	Field points:Float[flagsize,flagsize,3]
	Field wiggle_count:Int = 0	
	Field colorArrayRed:Float[flagsize,flagsize]
	Field colorArrayGreen:Float[flagsize,flagsize]
	Field colorArrayBlue:Float[flagsize,flagsize]
	
	Method New()
		Self.CreateGLWindow(False)
		If Not Self.InitGLContext()
			Notify "InitGLContext returned :("
			End
		EndIf
		Self.OnSizeChange()
	End Method
	
	Method LoadGLTextures:Int()
		Local img:TPixmap = LoadPixmap("tim.bmp")
		If img = Null Return False
		glGenTextures(1, texture); ' generate texture name for 1 tex
		setupTexture(0, img, filtering_near, format_bmp)
		img = Null
		Return True
	End Method
	
	Method InitGLContext:Int()
		'If Not LoadGLTextures() Then Return False
		
		glEnable(GL_TEXTURE_2D)
		glShadeModel(GL_SMOOTH);
		glClearColor (0.0, 0.0, 0.0, 0.5);
		glClearDepth(1.0); 'depth buffer setup
		glDepthFunc(GL_LEQUAL)
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 'nice perspective calculations		
		glPolygonMode( GL_BACK, GL_FILL );	'Back Face Is Filled In
		glPolygonMode( GL_FRONT, GL_LINE ); 'Front Face Is Drawn With Lines
			
		Local x:Int
		For x = 0 Until flagsize
			Local y:Int
			For y = 0 Until flagsize
				points[x,y,0] =Float( (x/5.0)-4.5) 
				points[x,y,1] =Float( (y/5.0)-4.5) 
				'points[x,y,2] =Float(Sin((((x/5.0)*40.0)/360.0)*3.141592654*2.0));
				'blitzmax uses degrees, not radians:
				points[x,y,2] =Float(Sin((((x/5.0)*40.0))*2.0));
			Next
		Next
		Return True
	End Method
	
	Method glDraw()
		Local x:Int 'loop variables
		Local y:Int
		Local float_x:Float 'used to break flag into tiny quads
		Local float_y:Float
		Local float_xb:Float
		Local float_yb:Float
		
		glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity()
		
		glTranslatef(-7.0, -7.0, -35.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]) ' defines the texture
		
		glBegin(GL_QUADS)
		For x=0 Until flagsize-1
			For y=0 Until flagsize-1
				float_x = Float(x)/flagsize;		'Create A Floating Point X Value
				float_y = Float(y)/flagsize;		'Create A Floating Point Y Value
				float_xb = Float(x+1)/flagsize;		'Create A Floating Point Y Value+0.0227f
				float_yb = Float(y+1)/flagsize;		'Create A Floating Point Y Value+0.0227f
				'glTexCoord2f( float_x, float_y);	' First Texture Coordinate (Bottom Left)
				
				glColor3f( colorArrayRed[x,y],colorArrayGreen[x,y],colorArrayBlue[x,y])
				
				glVertex3f( points[x,y,0], points[x,y,1], points[x,y,2] );
				'glTexCoord2f( float_x, float_yb );	' Second Texture Coordinate (Top Left)
				glVertex3f( points[x,y+1,0], points[x,y+1,1], points[x,y+1,2] );
				'glTexCoord2f( float_xb, float_yb );	' Third Texture Coordinate (Top Right)
				glVertex3f( points[x+1,y+1,0], points[x+1,y+1,1], points[x+1,y+1,2] );
				'glTexCoord2f( float_xb, float_y );	' Fourth Texture Coordinate (Bottom Right)
				glVertex3f( points[x+1,y,0], points[x+1,y,1], points[x+1,y,2] )
			Next
		Next
		glEnd()
				
		If wiggle_count = 2
			For y=0 Until flagsize-1
				Local hold:Float = points[0,y,2]
				For x=0 Until flagsize-1
					points[x,y,2] = points[x+1, y, 2]
				Next
				points[flagsize-1,y,2] = hold 'lsat value becomes the far left stored val
			Next
			wiggle_count = 0 'set counter back to zero
		EndIf
		
		wiggle_count:+1
	End Method
	
	Method OnSizeChange()
		glMatrixMode(GL_PROJECTION)
		glLoadIdentity()
		gluPerspective(45.0, Double(resX)/ Double(resY), 0.1, 100.0)
		glMatrixMode(GL_MODELVIEW)
		glLoadIdentity()
	End Method
	
	'textureNumber in texture name array
	'image, png or bmp
	'filteringMethod (near, linear, mipmapped
	'imageFormat, png or bmp
	Method setupTexture(textureNumber:Int, image:TPixmap, filteringMethod:Int, imageFormat:Int )				
		'glBindTexture(GL_TEXTURE_2D, texture[textureNumber]); 'bind named texture to texture target
		'actually generate texture
		If imageFormat = format_bmp
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, image.pixels)
		Else If imageFormat = format_png
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, image.pixels)
		EndIf
		'filter texture	
		If filteringMethod = filtering_near
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
		    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		Else If filteringMethod = filtering_linear
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) 
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
		Else If filteringMethod = filtering_mipmapped
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
			If imageFormat = format_bmp
				gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, image.width, image.height, GL_BGR_EXT, GL_UNSIGNED_BYTE, image.pixels)
			Else If imageFormat = format_png
				gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, image.width, image.height, GL_RGB, GL_UNSIGNED_BYTE, image.pixels)
			EndIf
		EndIf
	End Method	
	
	Function CreateGLWindow(fullscreen:Int)
		If fullscreen
			'not done
		EndIf
		GLGraphics( resX, resY, 0, 0 )
	End Function
	
	Method SetArrayColor(x:Int ,y:Int , r:Float, g:Float, b:Float)
		If x > flagsize-1 Or y > flagsize-1 Then Return
		If x < 0 Or y < 0 Then Return
		colorArrayRed[x,y] = r
		colorArrayGreen[x,y] = g
		colorArrayBlue[x,y] = b
	End Method
End Type

Type TMetaballSystem
	Field neheGraphics:NEHE
	Field xscreen:Int
	Field yscreen:Int
	Field squareDistance:Int = True 'if true then dist=(x*x) else dist=sqr(x*x) 
		
	Field meta1x:Int = 0 'mouse position updated in main loop
	Field meta1y:Int = 0
	Field meta2x:Float 
	Field meta2y:Float
	Field meta3x:Float 
	Field meta3y:Float 
	
	Field potential1:Float =  0.00005
	Field potential2:Float =  0.00005
	Field potential3:Float =  0.00005
	
	Field rgbColors:Int = True
	
	Function Create:TMetaballSystem( neheGraphics:NEHE )
		Local tmp:TMetaballSystem = New TMetaballSystem
		tmp.neheGraphics=neheGraphics
		tmp.xscreen = neheGraphics.flagsize
		tmp.yscreen = neheGraphics.flagsize
		tmp.meta2x = neheGraphics.flagsize/2
		tmp.meta2y = neheGraphics.flagsize/2
		tmp.meta3x = neheGraphics.flagsize/2
		tmp.meta3y = neheGraphics.flagsize/3
		Return tmp
	End Function

	Method UpdateMeta()	
		Local x:Int
		Local y:Int
		Local meta1x:Int = MouseX() Mod xscreen
		Local meta1y:Int = yscreen -MouseY() Mod yscreen
		
		Local pixelX:Int
		Local pixelY:Int
		Local threshold:Float
			
		'for hver pixel  skjermen
		' igjennom alle andre og beregn kraften fra dem
		For pixelX=0 Until xscreen+1
			For pixelY=0 Until yscreen+1
				Local dist1:Float
				Local dist2:Float
				Local dist3:Float
				
				If(squareDistance)
					dist1 =(pixelX-meta1x)*(pixelX-meta1x) + (pixelY-meta1y)*(pixelY-meta1y)
					dist2 =(pixelX-meta2x)*(pixelX-meta2x) + (pixelY-meta2y)*(pixelY-meta2y) 	
					dist3 =(pixelX-meta3x)*(pixelX-meta3x) + (pixelY-meta3y)*(pixelY-meta3y)
				Else 'real distance
					dist1 = Sqr(  (pixelX - meta1x)*(pixelX - meta1x) + (pixelY - meta1y)*(pixelY - meta1y)  )
					dist2 = Sqr(  (pixelX - meta2x)*(pixelX - meta2x) + (pixelY - meta2y)*(pixelY - meta2y)  )
					dist3 = Sqr(  (pixelX - meta3x)*(pixelX - meta3x) + (pixelY - meta3y)*(pixelY - meta3y)  )
				EndIf
				
				If(squareDistance)
					threshold = 0.0000000003
				Else 'real distance
					threshold = 0.0000003
				EndIf
				
				Local force1:Float = 1/(dist1*dist1)
				Local force2:Float = 1/(dist2*dist2)
				Local force3:Float = 1/(dist3*dist3)			
				Local sumOfForces:Float = force1*potential1 + force2*potential2 + force3*potential3
				
				If(sumOfForces > threshold)
					If rgbColors
						neheGraphics.SetArrayColor(pixelX, pixelY, Float(dist1)/1000,Float(dist2)/1000, Float(dist3)/1000)
					Else
						neheGraphics.SetArrayColor(pixelX, pixelY, 0,1,0)
					EndIf
				Else 'If(sumOfForces < threshold*potential1) 'potential 1 is expected to be negative
					neheGraphics.SetArrayColor(pixelX, pixelY, .05,.05,.05)
				EndIf
			Next
		Next

		' plot a pixel at metaballs center		
		neheGraphics.SetArrayColor meta1x, meta1y, 1,1,1
		neheGraphics.SetArrayColor meta2x, meta2y, 1,1,1
		neheGraphics.SetArrayColor meta3x, meta3y, 1,1,1
		
		meta2x :+0.5
		If(meta2x > xscreen) Then meta2x = 0
		meta3x :-0.5
		If(meta3x < 0) Then meta3x = xscreen
	End Method
End Type


Are you aware of this ?