www.pudn.com > CSharp_OpenGL_Material.rar > View.cs, change:2009-06-17,size:19557b


 
// CSharp_OpenGL_Material 
 
// [ IceSharK - PP.Poet ] 
 
// 2004.10.6 
 
using System; 
using System.Drawing; 
using System.Windows.Forms; 
 
using CsGL.OpenGL; // 引用 CsGL.OpenGL 名字空间 
 
namespace CSharp_OpenGL_Material 
{ 
	internal class View : OpenGLControl // 创建一个View类,继承自CsGL.OpenGL.OpenGLControl 
	{	 
		private float[] Teapot_Ambient_And_Diffuse = { 1.0f , 0.0f , 0.0f , 1.0f }; // 定义 茶壶的环境反射和漫反射颜色 
		private float[] Teapot_Specular = { 1.0f , 1.0f , 1.0f , 1.0f }; // 定义 茶壶的镜面反射颜色 
		private float Teapot_Shininess = 55.0f; // 定义 茶壶的镜面反射指数 即 材质亮度 
 
		private float Angle; // 旋转角度 
		private float Step = 1.0f; // 控制旋转角速度 
 
		GLUquadric pillarCylinder; 
		GLUquadric ballQuadric; 
 
		uint[] displayList; 
		Sphere[] ballList; 
		uint[] theTexture; 
 
		static double[] camera = {0.0, 60.0, 70.0, 0.0, 0.0, 0.0}; 
		float[] light0Pos = {0.0f, 205.0f, 0.0f, 1.0f}; 
		float[] light0Dir = {0.0f, -1.0f, 0.0f}; 
		float[] light1Pos = {100.0f, 205.0f, 100.0f, 1.0f}; 
 
		//static int mainWindow; 
 
		double tableWidth;  
		double	tableLength;  
		double	pocketRadius;  
		double	theta;  
		double	power;  
		double	elevationAngle;  
		double	zoom;  
		double pressedTheta;  
		double	pressedZoom;  
		double	pressedElevation;  
		double	maxX;  
		double	minX;  
		double	maxZ;  
		double	minZ; 
 
		public View() 
		{ 
			ballList = new Sphere[16]; 
			tableWidth = 50.0; 
			tableLength = 100.0; 
			pocketRadius = 1.5; 
			theta = Math.PI + Math.PI/2.0; 
			power = 0.0; 
			elevationAngle = 15.0*Math.PI/180.0; 
			zoom = 65.0; 
			pressedTheta = 0.0; 
			pressedZoom = zoom; 
			pressedElevation = 0.0; 
			maxX = tableWidth/(2.0) - 2; 
			minX = tableWidth/(-2.0) + 2; 
			maxZ = tableLength/(2.0) - 2; 
			minZ = tableLength/(-2.0) + 2; 
			displayList = new uint[5]; 
			ballQuadric = GLU.gluNewQuadric(); 
			pillarCylinder = GLU.gluNewQuadric(); 
 
			theTexture = new uint[35]; 
		} 
 
		protected override void InitGLContext()   
		{ 
			/*GL.glMaterialfv( GL.GL_FRONT , GL.GL_AMBIENT_AND_DIFFUSE , Teapot_Ambient_And_Diffuse ); // 设置 茶壶的环境反射和漫反射颜色 
			GL.glMaterialfv( GL.GL_FRONT , GL.GL_SPECULAR , Teapot_Specular ); // 设置 茶壶的镜面反射颜色 
			GL.glMaterialf( GL.GL_FRONT , GL.GL_SHININESS , Teapot_Shininess ); // 设置 茶壶的镜面反射指数 
 
			GL.glEnable( GL.GL_LIGHTING ); // 启用 光照 
			GL.glEnable( GL.GL_LIGHT0 ); // 启用 0号光源 
 
			GL.glEnable( GL.GL_DEPTH_TEST ); // 启用 深度检测 
			*/

			// Global parameters / settings
			float[] lmodel_ambient = { 0.5f, 0.5f, 0.5f, 1.0f };
			GL.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
			GL.glLightModeli(GL.GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
			float[] ambient = { 0.8f, 0.8f, 0.8f, 1.0f };
			float[] specular = { 1.0f, 1.0f, 1.0f, 1.0f};

			// Table spotlight (0)
			GL.glLightfv(GL.GL_LIGHT0,GL.GL_SPECULAR,specular);
			GL.glLightfv(GL.GL_LIGHT0,GL.GL_POSITION,light0Pos);
			GL.glLightf(GL.GL_LIGHT0,GL.GL_SPOT_CUTOFF,45.0f);
			GL.glLightf(GL.GL_LIGHT0,GL.GL_SPOT_EXPONENT,100.0f);

			// Global Ambient light (1)
			GL.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, ambient);
			GL.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, ambient);
			GL.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, light1Pos);

			// Material settings
			float[] mat_diffuse = { 0.5f, 0.5f, 0.5f, 1.0f };
			float[] mat_specular = { 1.0f, 1.0f, 1.0f, 1.0f };
			float[] mat_shininess = { 80.0f };
			GL.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE);
			GL.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat_diffuse);
			GL.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR,mat_specular);
			GL.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess);

			// Enable lighting
			GL.glEnable(GL.GL_LIGHTING);
			GL.glEnable(GL.GL_LIGHT0);
			GL.glEnable(GL.GL_LIGHT1);

			GL.glShadeModel(GL.GL_SMOOTH);
			GL.glClearStencil(0);
			GL.glClearDepth(1.0f);
			GL.glEnable(GL.GL_DEPTH_TEST);
			GL.glDepthFunc(GL.GL_LEQUAL);
			GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
			GL.glEnable(GL.GL_TEXTURE_2D);

			// Instantiates the quadric object used to render the pillars and table sides (etc.).
			pillarCylinder=GL.gluNewQuadric();
			GL.gluQuadricNormals(pillarCylinder, GL.GLU_FLAT);
			GL.gluQuadricOrientation(pillarCylinder, GL.GLU_OUTSIDE);
			GL.gluQuadricTexture(pillarCylinder, 1);

			// Instantiates the quadric object used to render the billiard balls.
			ballQuadric=GL.gluNewQuadric();
			GL.gluQuadricNormals(ballQuadric, GL.GLU_SMOOTH);
			GL.gluQuadricOrientation(ballQuadric, GL.GLU_OUTSIDE);
			GL.gluQuadricTexture(ballQuadric, 1); 
		} 
		 
		protected override void OnSizeChanged( System.EventArgs e) 
		{ 
			base.OnSizeChanged( e ); 
			 
			Size _Size = Size; 
			//if (Size.Height == 0)  
			//	Size.Height = 1; 
			GL.glViewport(0, 0, Size.Width, Size.Height); 
			GL.glMatrixMode(GL.GL_PROJECTION);	// 选择 GL_PROJECTION 矩阵 
			GL.glLoadIdentity();				// 重置投影矩阵 
			GL.gluPerspective( 45.0f , (double)_Size.Width / (double)_Size.Height , 0.1f , 5000.0f ); // 设置透视图 
			GL.glMatrixMode(GL.GL_MODELVIEW);	// 选择模型观察( GL_MODELVIEW )矩阵 
			GL.glLoadIdentity();				// 重置当前的模型观察矩阵	 
		} 
 
		public override void glDraw() 
		{	 
			GL.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT ); // 清除 颜色缓存和深度缓存 
 
			GL.glLoadIdentity(); // 重置 当前的模型观察矩阵 
			//GL.glTranslatef( 0.0f , 0.0f , -4.0f ); // 调整 视图	 
			 
			//GL.glRotatef( 31.0f , 1.0f , 0.0f , 0.0f ); // 设置 视图角度 
 
			Angle += Step; 
			GL.glRotatef( Angle , 0.0f , 1.0f , 0.0f ); // 控制 旋转 
			
			GL.gluLookAt(0,60,-120,0,0,0, 0.0, 1.0, 0.0);
			 
			//RenderTableLeg(); 
			RenderTable(); 
 
			GL.glTranslatef(0.0f,-24.9f,-0.0f); 
			InitPhysics(); 
			RenderBall(); 
 
			//GL.gluLookAt(camera[0],camera[1],camera[2],camera[3],camera[4],camera[5], 0.0, 1.0, 0.0); 
			//GL.gluSphere(ballQuadric, 0.2, 32, 32); 
 
						 
			GL.glFlush(); // 强制绘制完成 
		} 
 
		public void RenderTable() 
		{ 
			//GL.glNewList(displayList[1], GL.GL_COMPILE); 
			GL.glColor3d(1.0,1.0,1.0);

			// Table carpeted area
			GL.glPushMatrix();
			//glBindTexture(GL_TEXTURE_2D, surfaceTexture);
			for (double k=(tableWidth/(-2.0)); k  (tableWidth/(2.0)); k += (tableWidth/10.0))  
			{
				for (double r=(tableLength/(-2.0)); r  (tableLength/(2.0)); r += (tableLength/15.0))  
				{

					GL.glBegin(GL.GL_QUADS);
					GL.glNormal3d(0.0, 1.0, 0.0);
					GL.glTexCoord2d(0.0, 1.0);
					GL.glVertex3d(k, -1.5, r+tableLength/15.0);
					GL.glTexCoord2d(1.0, 1.0);
					GL.glVertex3d(k+tableWidth/10.0, -1.5, r+tableLength/15.0);
					GL.glTexCoord2d(1.0, 0.0);
					GL.glVertex3d(k+tableWidth/10.0, -1.5, r);
					GL.glTexCoord2d(0.0, 0.0);
					GL.glVertex3d(k, -1.5, r);
					GL.glEnd();

				}
			}

			GL.glPopMatrix();

			// Anti-aliased game-lines on carpeted area
			GL.glPushMatrix();
			GL.glDisable(GL.GL_TEXTURE_2D);
			GL.glDisable(GL.GL_LIGHTING);
			GL.glEnable(GL.GL_BLEND);
			GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
			GL.glEnable(GL.GL_LINE_SMOOTH);
			GL.glColor4d(0.5, 0.5, 0.5, 0.4);
			GL.glLineWidth(2.5f);

			// Horisontal line
			GL.glTranslated(0.0, -1.45, 0.0);
			GL.glBegin(GL.GL_LINES);
			GL.glVertex3d(minX - pocketRadius, 0.0, minZ - minZ/3);
			GL.glVertex3d(maxX + pocketRadius, 0.0, minZ - minZ/3);
			GL.glEnd();

			// Half-circle
			GL.glTranslated(0.0, 0.0, minZ - minZ/3);
			GL.glRotated(90.0, 0.0, 1.0, 0.0);
			GL.glBegin(GL.GL_LINES);
			for (double i = 0.0; i  Math.PI-(Math.PI/12.0); i+=Math.PI/12.0)  
			{
				GL.glVertex3d((maxZ/6.0)*Math.Sin(i), 0.0, (maxZ/6.0)*Math.Cos(i));
				GL.glVertex3d((maxZ/6.0)*Math.Sin(i+Math.PI/12.0), 0.0, (maxZ/6.0)*Math.Cos(i+Math.PI/12.0));
			}
			GL.glEnd();
			GL.glLineWidth(1.0f);

			// Start-point on line
			GL.glRotated(90.0, 1.0, 0.0, 0.0);
			GL.gluDisk(pillarCylinder, 0, 0.3, 9, 1);

			GL.glDisable(GL.GL_LINE_SMOOTH);
			GL.glDisable(GL.GL_BLEND);
			GL.glEnable(GL.GL_LIGHTING);
			GL.glEnable(GL.GL_TEXTURE_2D);
			GL.glPopMatrix();

			// Table sides
			int divCount = -5, angleDirection = 1;
			double offA = 2.4, offB = 3.0, offTemp = 0.0, sideAngle = 270.0;

			for(int f=1; f >= -1; f--)  
			{
				for (double r=-1.0; r = 1.0; r+=2.0)  
				{

					GL.glPushMatrix();
					GL.glTranslated(tableWidth/(r*2.0) + (Math.Abs(divCount)/divCount)*offA, 0.0, f*tableWidth + r*offB);
					GL.glRotated(sideAngle, 0.0, 1.0, 0.0);
					// Wooden side
					GL.glPushMatrix();
					GL.glTranslated(0, -0.3, 0);
					GL.glScaled(1.0, 1.0, 2.0);
					GL.glRotated(270.0, 0.0, 1.0, 0.0);
					GL.glRotated(45.0, 0.0, 0.0, 1.0);
					//GL.glBindTexture(GL_TEXTURE_2D, theTexture[WOOD]);
					GL.gluCylinder(pillarCylinder, 1.7, 1.7, tableWidth - 6, 4, 4);
					GL.glPopMatrix();

					// Green carpeted side
					GL.glPushMatrix();
					GL.glTranslated(-1.0*tableWidth + 6, 0.0, -2.35);
					GL.glRotated(180.0, 0.0, 0.0, 1.0);
					GL.glRotated(270.0, 0.0, 1.0, 0.0);
					GL.glScaled(0.5, 1.0, 1.0);

					//glBindTexture(GL_TEXTURE_2D, theTexture[GREEN_CARPET]);
					GL.gluCylinder(pillarCylinder, 1.7, 1.7, tableWidth - 6, 3, 3);
					GL.glPopMatrix();
					GL.glPopMatrix();

					divCount += 2;
					if ((f == 0) && (r == -1.0))  
					{
						offA = 2.4; offB = 3.0; offTemp = 0.0;
						sideAngle = 90.0;
						angleDirection = 1;
					}  
					else  
					{
						offTemp = offA; offA = offB; offB = offTemp;
						sideAngle = sideAngle + angleDirection*90.0;
						angleDirection *= -1;
					}
				}
			}

			// Pockets
			double direction = -1.0, angle = 360.0, sweep = Math.PI + Math.PI/2.0;
			bool sidePocket = false;

			for (int g=-1; g = 1; g+=2)  
			{
				for (int d=1; d >= -1; d-=1)  
				{
					GL.glPushMatrix();
					GL.glTranslated(g*tableWidth/(2.0), 0.0, d*tableWidth);
					GL.glRotated(angle,0.0,1.0,0.0);
					RenderPocket(sweep);
					GL.glPopMatrix();

					if (d == 1)  
					{
						sweep = Math.PI;
						if (g == -1)  
						{
							angle = angle + direction*90;
							sidePocket = true;
						}
					}  
					else  
					{
						if (sidePocket == false) angle = angle + direction*90; else sidePocket = false;
						sweep = Math.PI + Math.PI/2.0;
					}
				}
				direction = -1*direction;
				angle = 90;
			}

			// Base
			//glBindTexture(GL_TEXTURE_2D, theTexture[WOOD]);
			GL.glPushMatrix();
			GL.glTranslated(0.0, -1.4, 0.0);
			GL.glScaled(1.5, 1.0, 2.9);
			GL.glRotated(45.0, 0.0, 1.0, 0.0);
			GL.glRotated(90.0, 1.0, 0.0, 0.0);
			GL.gluCylinder(pillarCylinder, tableWidth/2, tableWidth/2 - 2, 5, 4, 2);
			GL.glPopMatrix();

			// Legs
			//glBindTexture(GL_TEXTURE_2D, theTexture[DARK_WOOD]);
			for (int g=-1; g = 1; g+=2)  
			{
				for (int d=-1; d = 1; d+=2)  
				{
					GL.glPushMatrix();
					GL.glTranslated(tableWidth/(g*2.0) + g*(-5.0), -20.0, tableLength/(d*2.0) + d*(-5.0));
					//GL.glCallList(displayList[4]);
					RenderTableLeg();
					GL.glPopMatrix();
				}
			} 
			//GL.glEndList(); 
		} 
 
		public void RenderTableLeg() 
		{ 
			//GL.glNewList(displayList[4], GL.GL_COMPILE);

			//GL.glBindTexture(GL.GL_TEXTURE_2D, theTexture[DARK_WOOD]);

			GL.glPushMatrix();

			for (double k=0; k  3.0*Math.PI; k+=1.4)  
			{
				for (double g=0; g  Math.PI*2.0; g+=0.5)  
				{
					double[] point1 = {3.0*Math.Sin((k+1.4)/3.0)*Math.Cos(g), k*2, 3.0*Math.Sin((k+1.4)/3.0)*Math.Sin(g)};
					double[] point2 = {3.0*Math.Sin((k+1.4)/3.0)*Math.Cos(g+0.5), k*2, 3.0*Math.Sin((k+1.4)/3.0)*Math.Sin(g+0.5)};
					double[] point3 = {3.0*Math.Sin(k/3.0)*Math.Cos(g+0.5), k*2 - 2.8, 3.0*Math.Sin(k/3.0)*Math.Sin(g+0.5)};
					double[] point4 = {3.0*Math.Sin(k/3.0)*Math.Cos(g), k*2 - 2.8, 3.0*Math.Sin(k/3.0)*Math.Sin(g)};
					RenderQuad(point1, point2, point3, point4, 1.0, 1.0, 1.0);
				}
			}

			GL.glRotatef(90.0f, 1.0f, 0.0f ,0.0f);
			GL.glutSolidTorus(1.0, 1.8, 5, 8);
			GL.gluCylinder(pillarCylinder, 1.0, 3.0, 4.0, 8, 2);

			GL.glPopMatrix();

			//GL.glEndList(); 
		} 
 
		public void RenderPocket(double sweep) 
		{ 
			GL.glPushMatrix();
			GL.glTranslated(0.0, -1.55, 0.0);
			RenderCurve(5.5, 2.55, sweep, 16, 1,  theTexture[24]);
			//RenderCurve(3.0, 2.55, sweep, 16, -1, theTexture[35]);
			RenderCap(0.0001, 5.5, 6.3, 6.3, 16, theTexture[8]);
			GL.glPopMatrix();
			GL.glPushMatrix();
			GL.glTranslated(0.0, 1.0, 0.0);
			RenderCap(3.0, 5.5, sweep, sweep, 16, theTexture[20]);
			GL.glPopMatrix();
			GL.glPushMatrix();
			GL.glTranslated(0.0, -1.4, 0.0);
			if (sweep  Math.PI+0.001) 
				RenderCap(0.0001, 3.0, Math.PI, Math.PI, 16, theTexture[8]);
			else 
				RenderCap(0.0001, 3.0, 6.3, 6.3, 16, theTexture[8]);
			GL.glPopMatrix(); 
		} 
 
		public void RenderQuad(double[] point1, double[] point2, double[] point3, double[] point4, double orientation, double texXTile, double texYTile) 
		{ 
			GL.glBegin(GL.GL_QUADS);
			Vector theNormal = new Vector();
			theNormal = GetNormal(point1, point3, point4);
			theNormal = theNormal.KaliNilai(orientation);
			GL.glNormal3d(theNormal.GetX(), theNormal.GetY(), theNormal.GetZ());
			GL.glTexCoord2d(0.0, texYTile);
			GL.glVertex3dv(point1);
			GL.glNormal3d(theNormal.GetX(), theNormal.GetY(), theNormal.GetZ());
			GL.glTexCoord2d(texXTile, texYTile);
			GL.glVertex3dv(point2);
			GL.glNormal3d(theNormal.GetX(), theNormal.GetY(), theNormal.GetZ());
			GL.glTexCoord2d(texXTile, 0.0);
			GL.glVertex3dv(point3);
			GL.glNormal3d(theNormal.GetX(), theNormal.GetY(), theNormal.GetZ());
			GL.glTexCoord2d(0.0, 0.0);
			GL.glVertex3dv(point4);
			GL.glEnd(); 
		} 
 
		public Vector GetNormal(double[] point1, double[] point3, double[] point4) 
		{ 
			Vector theNormal = new Vector();
			theNormal.SetX((point1[1] - point4[1])*(point3[2] - point4[2]) - (point3[1] - point4[1])*(point1[2] - point4[2]));
			theNormal.SetY((point3[0] - point4[0])*(point1[2] - point4[2]) - (point1[0] - point4[0])*(point3[2] - point4[2]));
			theNormal.SetZ((point1[0] - point4[0])*(point3[1] - point4[1]) - (point3[0] - point4[0])*(point1[1] - point4[1]));
			return theNormal; 
		} 
 
		public void RenderCurve(double radius, double height, double sweep, uint segments, double orientation, uint aTexture) 
		{ 
			GL.glPushMatrix();
			//glBindTexture(GL_TEXTURE_2D, aTexture);

			for (double t=0.0; t = sweep-(sweep/segments); t += sweep/segments)  
			{
				//double x = 0.0, y = 0.0, z = 0.0;
				double[] point1 = new double[3]{radius*Math.Cos(t), height, radius*Math.Sin(t)};
				double[] point2 = new double[3]{radius*Math.Cos(t+sweep/segments), height, radius*Math.Sin(t+sweep/segments)};
				double[] point3 = new double[3]{radius*Math.Cos(t+sweep/segments), 0.0, radius*Math.Sin(t+sweep/segments)};
				double[] point4 = new double[3]{radius*Math.Cos(t), 0.0, radius*Math.Sin(t)};
				RenderQuad(point1, point2, point3, point4, orientation, 1.0, 1.0);
			}

			GL.glPopMatrix(); 
		} 
 
		public void RenderCap(double inner_radius, double outer_radius, double inner_sweep, double outer_sweep, uint segments, uint myTexture) 
		{ 
			GL.glPushMatrix();

			double ciX = 0.0, coX = 0.0, ciZ = 0.0, coZ = 0.0;
			double angle = -1.0*outer_sweep/segments;

			//glBindTexture(GL_TEXTURE_2D, myTexture);

			for (int k=0; k  segments; k++)  
			{

				ciX = inner_radius*Math.Cos(angle + inner_sweep/segments);
				ciZ = inner_radius*Math.Sin(angle + inner_sweep/segments);
				coX = outer_radius*Math.Cos(angle + outer_sweep/segments);
				coZ = outer_radius*Math.Sin(angle + outer_sweep/segments);
				angle += inner_sweep/segments;

				GL.glBegin(GL.GL_QUADS);
				GL.glNormal3d(0.0,1.0,0.0);
				GL.glTexCoord2d(coX/(2.0*outer_radius), coZ/(2.0*outer_radius));
				GL.glVertex3d(coX, 0.0, coZ);
				GL.glNormal3d(0.0,1.0,0.0);
				GL.glTexCoord2d(outer_radius*Math.Cos(angle + outer_sweep/segments)/(2.0*outer_radius), outer_radius*Math.Sin(angle + outer_sweep/segments)/(2.0*outer_radius));
				GL.glVertex3d(outer_radius*Math.Cos(angle + outer_sweep/segments), 0.0, outer_radius*Math.Sin(angle + outer_sweep/segments));
				GL.glNormal3d(0.0,1.0,0.0);
				GL.glTexCoord2d(inner_radius*Math.Cos(angle + inner_sweep/segments)/(2.0*inner_radius), inner_radius*Math.Sin(angle + inner_sweep/segments)/(2.0*inner_radius));
				GL.glVertex3d(inner_radius*Math.Cos(angle + inner_sweep/segments), 0.0, inner_radius*Math.Sin(angle + inner_sweep/segments));
				GL.glNormal3d(0.0,1.0,0.0);
				GL.glTexCoord2d(ciX/(2.0*inner_radius), ciZ/(2.0*inner_radius));
				GL.glVertex3d(ciX, 0.0, ciZ);
				GL.glEnd();
			}

			GL.glPopMatrix(); 
		} 
 
		public void RenderBall() 
		{ 
			double[] m;
			m = new double[16];
			for (int i=0; i  15; i++) 
				m[i] = 0.0;
			m[0] = m[5] = m[10] = 1.0;
			m[7] = (-1.0)/(light0Pos[1] + 2.0);

			for (int p=0; p  16; p++)  
			{
				GL.glPushMatrix();
				GL.glTranslated(ballList[p].position.GetX(),ballList[p].position.GetY(),ballList[p].position.GetZ());

				// Determine shadows.
				GL.glPushMatrix();
				GL.glTranslated(light0Pos[0], light0Pos[1]+0.65, light0Pos[2]);
				GL.glMultMatrixd(m);
				GL.glTranslated(-1.0*light0Pos[0], -1.0*light0Pos[1], -1.0*light0Pos[2]);
				GL.glColor3d(0.0,0.0,0.0);
				//glBindTexture(GL_TEXTURE_2D, theTexture[BLACK]);
				GL.gluSphere(ballQuadric, ballList[p].radius, 32, 12);
				GL.glPopMatrix();

				Vector tempSpeed = new Vector();
				tempSpeed= tempSpeed.Sama(ballList[p].speed);
				tempSpeed.Normalize();
				Vector speedNormal = new Vector();
				speedNormal.SetX(tempSpeed.GetZ());
				speedNormal.SetY(0.0);
				speedNormal.SetZ((-1.0)*tempSpeed.GetX());

				if (ballList[p].rotation > 360.0) 
					ballList[p].rotation =  ballList[p].rotation - 360.0;

				ballList[p].rotation += ballList[p].speedSize/ballList[p].radius*(180.0/Math.PI);

				//GL.glBindTexture(GL_TEXTURE_2D, theTexture[p]);
				GL.glRotated(ballList[p].rotation, speedNormal.GetX(), speedNormal.GetY(), speedNormal.GetZ());

				GL.gluSphere(ballQuadric, ballList[p].radius, 32, 32);
				GL.glPopMatrix();
			} 
		} 
 
		public void InitPhysics() 
		{ 
			// Setup balls' positions on table
			ballList[0] = new Sphere(0.0, 24.9 , minZ - minZ/3);

			// Closely packed triangle (may cause some problems for collision detection/response)
			ballList[15] = new Sphere(7.0, 24.9 , 27.0);
			ballList[1] = new Sphere(3.5, 24.9 , 27.0);
			ballList[14] = new Sphere(0.0, 24.9 , 27.0);
			ballList[13] = new Sphere(-3.5, 24.9 , 27.0);
			ballList[2] = new Sphere(-7.0, 24.9 , 27.0);

			ballList[3] = new Sphere(5.25, 24.9 , 23.5);
			ballList[12] = new Sphere(1.75, 24.9 , 23.5);
			ballList[4] = new Sphere(-1.75, 24.9 , 23.5);
			ballList[11] = new Sphere(-5.25, 24.9 , 23.5);

			ballList[10] = new Sphere(3.5, 24.9 , 20.0);
			ballList[8] = new Sphere(0.0, 24.9 , 20.0);
			ballList[5] = new Sphere(-3.5, 24.9 , 20.0);

			ballList[6] = new Sphere(1.75, 24.9 , 16.5);
			ballList[7] = new Sphere(-1.75, 24.9 , 16.5);

			ballList[9] = new Sphere(0.0, 24.9 , 13.0);

			// Initialize physics properties for balls
			for (int r=0; r  16; r++)  
			{
				ballList[r].SetDefault();
			} 
		} 
 
		public void updateCamera()  
		{
			camera[0] = zoom*(Math.Cos(theta)) + camera[3];
			camera[1] = zoom*Math.Sin(elevationAngle) + camera[4];
			camera[2] = zoom*(Math.Sin(theta)) + camera[5];
			if (camera[1]  29) camera[1] = 29;
			if (camera[1] > 90) camera[1] = 90;
			//GL.glutPostRedisplay();
		}

		// Updates the camera look-at position
		public void updateTarget()  
		{
			camera[3] = ballList[0].position.GetX();
			camera[4] = ballList[0].position.GetY();
			camera[5] = ballList[0].position.GetZ();
			//glutPostRedisplay();
		} 
	} 
}