示例#1
0
文件: ai.cpp 项目: mutnig/vdrift
///note that carposition must be in patch space
///returns distance from left side of the track
float GetHorizontalDistanceAlongPatch(const BEZIER & patch, MATHVECTOR <float, 3> carposition)
{
	MATHVECTOR <float, 3> leftside = (patch.GetPoint(0,0) + patch.GetPoint(3,0))*0.5;
	MATHVECTOR <float, 3> rightside = (patch.GetPoint(0,3) + patch.GetPoint(3,3))*0.5;
	MATHVECTOR <float, 3> patchwidthvector = rightside - leftside;
	return patchwidthvector.Normalize().dot(carposition-leftside);
}
示例#2
0
文件: ai.cpp 项目: Bengt/vdrift
double GetPatchRadius(const BEZIER & patch)
{
    if (patch.GetNextPatch() && patch.GetNextPatch()->GetNextPatch())
    {
        double track_radius = 0;

        /*MATHVECTOR <float, 3> d1 = -GetPatchDirection(patch);
        MATHVECTOR <float, 3> d2 = GetPatchDirection(*patch.GetNextPatch());*/
        MATHVECTOR <float, 3> d1 = -(patch.GetNextPatch()->GetRacingLine() - patch.GetRacingLine());
        MATHVECTOR <float, 3> d2 = patch.GetNextPatch()->GetNextPatch()->GetRacingLine() - patch.GetNextPatch()->GetRacingLine();
        d1[1] = 0;
        d2[1] = 0;
        float d1mag = d1.Magnitude();
        float d2mag = d2.Magnitude();
        float diff = d2mag - d1mag;
        double dd = ((d1mag < 0.0001) || (d2mag < 0.0001)) ? 0.0 : d1.Normalize().dot(d2.Normalize());
        float angle = acos((dd>=1.0L)?1.0L:(dd<=-1.0L)?-1.0L:dd);
        float d1d2mag = d1mag + d2mag;
        float alpha = (d1d2mag < 0.0001) ? 0.0f : (M_PI * diff + 2.0 * d1mag * angle) / d1d2mag / 2.0;
        if (fabs(alpha - M_PI/2.0) < 0.001) track_radius = 10000.0;
        else track_radius = d1mag / 2.0 / cos(alpha);

        return track_radius;
    }
    else //fall back
        return 0;
}
示例#3
0
文件: ai.cpp 项目: mutnig/vdrift
///trim the patch's width in-place
void TrimPatch(BEZIER & patch, float trimleft_front, float trimright_front, float trimleft_back, float trimright_back)
{
	MATHVECTOR <float, 3> frontvector = (patch.GetPoint(0,3) - patch.GetPoint(0,0));
	MATHVECTOR <float, 3> backvector = (patch.GetPoint(3,3) - patch.GetPoint(3,0));
	float frontwidth = frontvector.Magnitude();
	float backwidth = backvector.Magnitude();
	if (trimleft_front + trimright_front > frontwidth)
	{
		float scale = frontwidth/(trimleft_front + trimright_front);
		trimleft_front *= scale;
		trimright_front *= scale;
	}
	if (trimleft_back + trimright_back > backwidth)
	{
		float scale = backwidth/(trimleft_back + trimright_back);
		trimleft_back *= scale;
		trimright_back *= scale;
	}

	MATHVECTOR <float, 3> newfl = patch.GetPoint(0,0);
	MATHVECTOR <float, 3> newfr = patch.GetPoint(0,3);
	MATHVECTOR <float, 3> newbl = patch.GetPoint(3,0);
	MATHVECTOR <float, 3> newbr = patch.GetPoint(3,3);

	if (frontvector.Magnitude() > 0.001)
	{
		MATHVECTOR <float, 3> trimdirection_front = frontvector.Normalize();
		newfl = patch.GetPoint(0,0) + trimdirection_front*trimleft_front;
		newfr = patch.GetPoint(0,3) - trimdirection_front*trimright_front;
	}

	if (backvector.Magnitude() > 0.001)
	{
		MATHVECTOR <float, 3> trimdirection_back = backvector.Normalize();
		newbl = patch.GetPoint(3,0) + trimdirection_back*trimleft_back;
		newbr = patch.GetPoint(3,3) - trimdirection_back*trimright_back;
	}

	patch.SetFromCorners(newfl, newfr, newbl, newbr);
}
示例#4
0
文件: ai.cpp 项目: mutnig/vdrift
BEZIER AI::RevisePatch(const BEZIER * origpatch, bool use_racingline)
{
	BEZIER patch = *origpatch;

	//take into account the racing line
	//use_racingline = false;
	if (use_racingline && patch.GetNextPatch() && patch.HasRacingline())
	{
		float widthfront = std::min((patch.GetNextPatch()->GetRacingLine()-patch.GetPoint(0,0)).Magnitude(),
									 (patch.GetNextPatch()->GetRacingLine()-patch.GetPoint(0,3)).Magnitude());
		float widthback = std::min((patch.GetRacingLine()-patch.GetPoint(3,0)).Magnitude(),
									(patch.GetRacingLine()-patch.GetPoint(3,3)).Magnitude());
		float trimleft_front = (patch.GetNextPatch()->GetRacingLine() - patch.GetPoint(0,0)).Magnitude()-widthfront;
		float trimright_front = (patch.GetNextPatch()->GetRacingLine() - patch.GetPoint(0,3)).Magnitude()-widthfront;
		float trimleft_back = (patch.GetRacingLine() - patch.GetPoint(3,0)).Magnitude()-widthback;
		float trimright_back = (patch.GetRacingLine() - patch.GetPoint(3,3)).Magnitude()-widthback;
		TrimPatch(patch, trimleft_front, trimright_front, trimleft_back, trimright_back);
	}

	//check for revisions due to other cars
	/*const float trim_falloff_distance = 100.0; //trim fallof distance in meters per (meters per second)
	const MATHVECTOR <float, 3> throttle_axis(-1,0,0); //positive is in front of the car
	std::map <const CAR *, PATH_REVISION> & revmap = path_revisions;
	for (std::map <const CAR *, PATH_REVISION>::iterator i = revmap.begin(); i != revmap.end(); i++)
	{
		if (i->first != c->car)
		{
			//compute relative info
			MATHVECTOR <float, 3> myvel = c->car->GetVelocity();
			MATHVECTOR <float, 3> othervel = i->first->GetVelocity();
			(-c->car->GetOrientation()).RotateVector(myvel);
			(-i->first->GetOrientation()).RotateVector(othervel);
			float speed_diff = myvel.dot(throttle_axis) - othervel.dot(throttle_axis); //positive if other car is faster //actually positive if my car is faster, right?

			float cardist_back = patch.dist_from_start - i->second.car_pos_along_track; //positive if patch is ahead of car
			float patchlen = GetPatchDirection(patch).Magnitude();
			float cardist_front = (patch.dist_from_start+patchlen) - i->second.car_pos_along_track;

			const float minfalloff = 10;
			const float maxfalloff = 60;
			float cur_trim_falloff_distance_fwd = minfalloff;
			float cur_trim_falloff_distance_rear = minfalloff;
			float falloff = clamp(trim_falloff_distance*std::abs(speed_diff),minfalloff,maxfalloff);
			if (speed_diff > 0)
			{
				//cur_trim_falloff_distance_fwd = falloff;
			}
			else
				cur_trim_falloff_distance_rear = falloff;

			float scale_front = clamp(1.0f-cardist_front/cur_trim_falloff_distance_fwd, 0, 1);
			if (cardist_front < 0)
				scale_front = clamp(1.0f+cardist_front/cur_trim_falloff_distance_rear, 0, 1);
			float scale_back = clamp(1.0f-cardist_back/cur_trim_falloff_distance_fwd, 0, 1);
			if (cardist_back < 0)
				scale_back = clamp(1.0f+cardist_back/cur_trim_falloff_distance_rear, 0, 1);

			std::cout << speed_diff << ", " << cur_trim_falloff_distance_fwd << ", " << cur_trim_falloff_distance_rear << ", " << cardist_front << ", " << cardist_back << ", " << scale_front << ", " << scale_back << std::endl;

			float trimleft_front = i->second.trimleft_front*scale_front;
			float trimright_front = i->second.trimright_front*scale_front;
			float trimleft_back = i->second.trimleft_back*scale_back;
			float trimright_back = i->second.trimright_back*scale_back;

			TrimPatch(patch, trimleft_front, trimright_front, trimleft_back, trimright_back);
		}
	}*/

	return patch;
}
示例#5
0
文件: ai.cpp 项目: mutnig/vdrift
MATHVECTOR <float, 3> GetPatchWidthVector(const BEZIER & patch)
{
	return ((patch.GetPoint(0,0) + patch.GetPoint(3,0)) -
			(patch.GetPoint(0,3) + patch.GetPoint(3,3))) * 0.5;
}
示例#6
0
文件: ai.cpp 项目: mutnig/vdrift
MATHVECTOR <float, 3> GetPatchBackCenter(const BEZIER & patch)
{
	return (patch.GetPoint(3,0) + patch.GetPoint(3,3)) * 0.5;
}
示例#7
0
文件: ai.cpp 项目: mutnig/vdrift
MATHVECTOR <float, 3> GetPatchFrontCenter(const BEZIER & patch)
{
	return (patch.GetPoint(0,0) + patch.GetPoint(0,3)) * 0.5;
}
示例#8
0
void BEZIER::Attach(BEZIER & other, bool reverse)
{
	/*if (!reverse)
	{
		//move the other patch to the location of this patch and force its
		// intermediate points into a nice grid layout
		other.SetFromCorners(other.points[0][0], other.points[0][3], points[0][0], points[0][3]);
		
		for (int x = 0; x < 4; x++)
		{
			//slope points in the forward direction
			MATHVECTOR<float,3> slope = other.points[0][x] - points[3][x];
			if (slope.Magnitude() > 0.0001)
				slope = slope.Normalize();
			
			float otherlen = (other.points[0][x] - other.points[3][x]).Magnitude();
			float mylen = (points[0][x] - points[3][x]).Magnitude();
			
			float meanlen = (otherlen + mylen)/2.0;
			float leglen = meanlen / 3.0;
			
			if (slope.Magnitude() > 0.0001)
			{
				other.points[2][x] = other.points[3][x] + slope*leglen;
				points[1][x] = points[0][x] + slope*(-leglen);
			}
			else
			{
				other.points[2][x] = other.points[3][x];
				points[1][x] = points[0][x];
			}
		}
	}*/
	
	//CheckForProblems();
	
	//store the pointer to next patch
	next_patch = &other;

	//calculate the track radius at the connection of this patch and next patch
	MATHVECTOR<float,3> a = SurfCoord(0.5,0.0);
	MATHVECTOR<float,3> b = SurfCoord(0.5,1.0);
	MATHVECTOR<float,3> c = other.SurfCoord(0.5,1.0);
	
	if (reverse)
	{
		a = SurfCoord(0.5,1.0);
		b = SurfCoord(0.5,0.0);
		c = other.SurfCoord(0.5,0.0);
		
		//Reverse();
	}
	
	//racing_line = a;
	MATHVECTOR<float,3> d1 = a - b;
	MATHVECTOR<float,3> d2 = c - b;
	float diff = d2.Magnitude() - d1.Magnitude();
	double dd = ((d1.Magnitude() < 0.0001) || (d2.Magnitude() < 0.0001)) ? 0.0 : d1.Normalize().dot(d2.Normalize());
	float angle = acos((dd>=1.0L)?1.0L:(dd<=-1.0L)?-1.0L:dd);
	float d1d2mag = d1.Magnitude() + d2.Magnitude();
	float alpha = (d1d2mag < 0.0001) ? 0.0f : (M_PI * diff + 2.0 * d1.Magnitude() * angle) / d1d2mag / 2.0;
	if (fabs(alpha - M_PI/2.0) < 0.001) track_radius = 10000.0;
	else track_radius = d1.Magnitude() / 2.0 / cos(alpha);
	if (d1.Magnitude() < 0.0001)
		track_curvature = 0.0;
	else
		track_curvature = 2.0 * cos(alpha) / d1.Magnitude();

	//determine it's a left or right turn at the connection
	MATHVECTOR<float,3> d = d1.cross(d2);
	if (fabs(d[0]) < 0.1 && fabs(d[1]) < 0.1 && fabs(d[2]) < 0.1)
	{
		turn = 0; //straight ahead
	}
	else if (d[1] > 0.0) turn = -1; //left turn ahead
	else turn = 1; //right turn ahead

	//calculate distance from start of the road
	if (other.next_patch == NULL || reverse) other.dist_from_start = dist_from_start + d1.Magnitude();
	length = d1.Magnitude();
}
示例#9
0
void AutoTrace()
{
	if (activestrip != NULL)
	{
		BEZIER * lastbez = activestrip->GetLastPatch();
		if (lastbez != NULL && editordata.numbezinput == 4)
		{
			VERTEX tvec[4];
			/*VERTEX fl = lastbez->points[0][0];
			VERTEX fr = lastbez->points[0][3];
			VERTEX bl = lastbez->points[3][0];
			VERTEX br = lastbez->points[3][3];*/
			
			bool success(true);
			BEZIER patch;
			if (vertmode == TWOVERTS)
			{
				success = success && objects.AutoFindClosestVert(lastbez->points[0][0], lastbez->points[0][3], (lastbez->points[0][0]-lastbez->points[3][0]), tvec[0]);
				success = success && objects.AutoFindClosestVert(lastbez->points[0][3], lastbez->points[0][0], (lastbez->points[0][3]-lastbez->points[3][3]), tvec[1]);
				
				if (success)
				{
					patch.SetFromCorners(tvec[0], tvec[1], editordata.bezinput[0], editordata.bezinput[3]);
				}
			}
			else if (vertmode == THREEVERTS)
			{
				success = success && objects.AutoFindClosestVert(lastbez->points[0][0], lastbez->points[0][1], (lastbez->points[0][0]-lastbez->points[3][0]), tvec[0]);
				success = success && objects.AutoFindClosestVert(lastbez->points[0][1], lastbez->points[0][3], (lastbez->points[0][1]-lastbez->points[3][1]), tvec[1]);
				tvec[2] = tvec[1];
				success = success && objects.AutoFindClosestVert(lastbez->points[0][3], lastbez->points[0][1], (lastbez->points[0][3]-lastbez->points[3][3]), tvec[3]);
				
				if (success)
				{
					for (int i = 0; i < 4; i++)
						patch.points[3][i] = editordata.bezinput[i];
					for (int i = 0; i < 4; i++)
						patch.points[0][i] = tvec[i];
					patch.CalculateMiddleRows();
				}
			}
			else if (vertmode == FOURVERTS)
			{
				for (int i = 0; i < 4; i++)
				{
					int nextvert = i + 1;
					if (nextvert >= 4)
						nextvert = 2;
					success = success && objects.AutoFindClosestVert(lastbez->points[0][i], lastbez->points[0][nextvert], (lastbez->points[0][i]-lastbez->points[3][i]), tvec[i]);
				}
				
				if (success)
				{
					for (int i = 0; i < 4; i++)
						patch.points[3][i] = editordata.bezinput[i];
					for (int i = 0; i < 4; i++)
						patch.points[0][i] = tvec[i];
					patch.CalculateMiddleRows();
				}
			}
			else
				assert(0);
			
			if (success)
			{
				activestrip->Add(patch);
				
				editordata.numbezinput = 4;
				
				editordata.bezinput[0] = patch.points[0][0];
				editordata.bezinput[1] = patch.points[0][1];
				editordata.bezinput[2] = patch.points[0][2];
				editordata.bezinput[3] = patch.points[0][3];
				
				mq1.AddMessage("Auto-traced road");
			}
			else
			{
				mq1.AddMessage("Can't auto-trace road: found no candidate points");
			}
		}
		else
		{
			mq1.AddMessage("Can't auto-trace road: must start road first");
		}
	}
	else
	{
		mq1.AddMessage("Can't auto-trace road: no roads selected");
	}
}
示例#10
0
/* Here goes our drawing code */
int drawGLScene()
{
	#ifdef PERFORMANCE_PROFILE
	suseconds_t t1, t2;
	t1 = GetMicroSeconds();
	t1 = GetMicroSeconds();
	#endif
	
	//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "RenderReflectedScene() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	gluPerspective( 45.0f, (float)SCREEN_WIDTH/SCREEN_HEIGHT, 0.1f, settings.GetViewDistance() );
	glMatrixMode( GL_MODELVIEW );
	
	glSetup();
	
	glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); 
	//glClearColor( 255.0f, 0.0f, 0.0f, 0.0f ); 
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "glSetup() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	utility.Tex2D(3, false);
	utility.Tex2D(2, false);
	utility.Tex2D(1, false);
	utility.Tex2D(0, true);
	
	glStencilMask(~0);
	glClearStencil(0);
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);		// Clear Screen And Depth Buffer
	
	glDisable(GL_STENCIL_TEST);

	
	GLdouble temp_matrix[16];
	int i;
	
	

	cam.PutTransformInto(temp_matrix);
	glLoadMatrixd(temp_matrix);
	
	//reset sun position so it's in the correct frame
	float lp[4];
	lp[0] = LightPosition[0];
	lp[1] = LightPosition[1];
	lp[2] = LightPosition[2];
	lp[3] = 0;
	
	//lighting hardcoded to reasonable position
	lp[0] = 3;
	lp[1] = 3;
	lp[2] = 3;
	lp[3] = 0;
	glLightfv( GL_LIGHT1, GL_POSITION, lp );
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "Matrix setup and light setup ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	// model the highlighted vertex belongs to
	OBJECTMODEL * highlighted_model = NULL;
	//if (state.GetGameState() != STATE_INITIALMENU)
	{
		
//		bool normal = true;
		
		glClear (GL_DEPTH_BUFFER_BIT);
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "DrawSky() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
		
		glTranslatef(cam.GetPosition().x,cam.GetPosition().y,cam.GetPosition().z);
	
		/*GLdouble equation[4];
		VERTEX earthnormal = temp - cam.position;
		earthnormal.y += EARTH_RADIUS;
		earthnormal = earthnormal.normalize();
		equation[0] = earthnormal.x;
		equation[1] = -earthnormal.y;
		equation[2] = earthnormal.z;
		equation[3] = (waterheight);
		glClipPlane(GL_CLIP_PLANE1, equation);
		if (underwater)
			glEnable(GL_CLIP_PLANE1);
		else
			glDisable(GL_CLIP_PLANE1);
		*/
		
				
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "terrain.SetFrustum() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
		
		//glPolygonOffset(1.0,1.0);
		//glPolygonOffset(0.0,10.0);
		//glEnable(GL_POLYGON_OFFSET_FILL);
	
		/*if (normal)
		{
			//GLfloat LightAmbient2[]  = { 0.3f, 0.3f, 0.3f, 1.0f };
			//glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient2 );
			glDisable(GL_STENCIL_TEST);
			
			#ifdef PERFORMANCE_PROFILE
			t2 = GetMicroSeconds();
			cout << "terrain.Draw() ticks: " << t2-t1 << endl;
			t1 = GetMicroSeconds();
			#endif
			
			utility.SelectTU(3);
			glDisable(GL_TEXTURE_2D);
			utility.SelectTU(0);
			glEnable(GL_TEXTURE_2D);

			#ifdef PERFORMANCE_PROFILE
			t2 = GetMicroSeconds();
			cout << "trees.Draw() ticks: " << t2-t1 << endl;
			t1 = GetMicroSeconds();
			#endif
			objects.Draw();
			#ifdef PERFORMANCE_PROFILE
			t2 = GetMicroSeconds();
			cout << "objects.Draw() ticks: " << t2-t1 << endl;
			t1 = GetMicroSeconds();
			#endif
			
			//glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient );
		}
		
		glDisable(GL_POLYGON_OFFSET_FILL);*/
		
		//glClear (GL_DEPTH_BUFFER_BIT);
		
		//glDisable(GL_LIGHTING);
		objects.Draw();
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "normal draw done" << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
	
		/*
		//draw trees
		foliage.Draw(terrain, cam);
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "foliage.Draw() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
	
		//glDisable(GL_CLIP_PLANE1);
		ships.Draw(false);
	
		terrain.Draw(cam, 1.0f, false, false, true, false, timefactor, fps, day_time);
		//terrain.Draw(cam, 1.0f, false, false, true, false, timefactor, fps, day_time);
		
		//rain is drawn over everything else
		if (!underwater)
			backdrop.DrawRain(day_time);
	
		
		#ifdef PERFORMANCE_PROFILE
		t2 = GetMicroSeconds();
		cout << "DrawRain() ticks: " << t2-t1 << endl;
		t1 = GetMicroSeconds();
		#endif
		
		
		glDisable(GL_CLIP_PLANE1);
	*/	
	
		
		//glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		/*if (0)
		{	
			//experimental bezier stuff
			BEZIER patch;
			VERTEX fl, fr, bl, br;
			//fl.Set(20,40,0);
			fl.Set(5,10,0);
			fr = fl;
			bl = fl;
			br = fl;
			
			fr.x += 15;
			fr.y += 3;
			
			br.x += 12;
			br.z += 8;
			
			bl.z += 10;
			bl.y -= 2;
			
			patch.SetFromCorners(fl, fr, bl, br);
			
			BEZIER nextpatch;
			VERTEX offset;
			offset.x += -7;
			offset.z += -10;
			fl = fl + offset;
			fr = fr + offset;
			bl = bl + offset;
			br = br + offset;
			
			nextpatch.SetFromCorners(fl, fr, bl, br);
			
			//patch.Attach(nextpatch);
			
			BEZIER thirdpatch;
			offset.zero();
			offset.y += -3;
			offset.z += -10;
			fl = fl + offset;
			fr = fr + offset;
			bl = bl + offset;
			br = br + offset;
			
			thirdpatch.SetFromCorners(fl, fr, bl, br);
			
			//nextpatch.Attach(thirdpatch);
			
			TRACK track;
			ROADSTRIP * teststrip = track.AddNewRoad();
			teststrip->Add(patch);
			teststrip->Add(nextpatch);
			teststrip->Add(thirdpatch);
			
			//teststrip.DeleteLastPatch();
					
			track.VisualizeRoads(true, true);
			
			VERTEX down;
			down.y = -1;
			VERTEX colpoint;
			if (patch.Collide(cam.position.ScaleR(-1.0), down, colpoint))
			{
				//colpoint.DebugPrint();
			}
		}*/
		
		VERTEX camray;
		camray.z = -1;
		camray = cam.dir.ReturnConjugate().RotateVec(camray);
		/*camray.z = 1;
		camray = cam.dir.RotateVec(camray);*/
		VERTEX selvert;
		bool highlightedvert = false;
		if (objects.FindClosestVert(cam.position.ScaleR(-1.0), camray, selvert, highlighted_model))
		{
			/*cam.position.ScaleR(-1.0).DebugPrint();
			selvert.DebugPrint();
			cout << endl;*/
			
			//draw a highlighted vert
			
			highlightedvert = true;
			
			glPushAttrib(GL_ALL_ATTRIB_BITS);
			glDisable(GL_LIGHTING);
			glDisable(GL_TEXTURE_2D);
			glDisable(GL_DEPTH_TEST);
			//glEnable(GL_BLEND);
			//glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
			glPointSize(4.0);
			//glColor4f(1,1,0,0.75);
			glColor4f(1,1,0,1);
			glBegin(GL_POINTS);
			glVertex3fv(selvert.v3());
			glEnd();
			glDisable(GL_BLEND);
			glColor4f(1,1,1,1);
			glPopAttrib();
		}
		
		//left click
		if (highlightedvert && mouse.ButtonDown(1) && !editordata.mousebounce[1])
		{
			int oldnumbezinput = editordata.numbezinput;
			
			//left click on a highlighted vert
			if (vertmode == TWOVERTS)
			{
				if (editordata.numbezinput == 0)
					editordata.numbezinput = 3;
				else if (editordata.numbezinput <= 3)
					editordata.numbezinput = 4;
				else if (editordata.numbezinput <= 4)
					editordata.numbezinput = 7;
				else if (editordata.numbezinput <= 7)
					editordata.numbezinput = 8;
			}
			else
			{
				editordata.numbezinput++;
				if (vertmode == THREEVERTS && (editordata.numbezinput == 2 || editordata.numbezinput == 6))
					editordata.numbezinput++;
			}
			
			if (editordata.numbezinput >= 8)
			{
				//create bezier patch
				BEZIER patch;
				
				if (vertmode == TWOVERTS)
					patch.SetFromCorners(editordata.bezinput[4], selvert, editordata.bezinput[0], editordata.bezinput[3]);
				else
				{
					//copy the front and back selected rows to the patch, then tell it to do the math to find the other points
					// plus center and radius calculations
					
					editordata.bezinput[7] = selvert;
					
					for (int i = 0; i < 4; i++)
						patch.points[3][i] = editordata.bezinput[i];
					for (int i = 0; i < 4; i++)
						patch.points[0][i] = editordata.bezinput[i+4];
					
					/*if (vertmode == THREEVERTS)
					{
						//recalculate the middle two verts
						for (int i = 0; i < 4; i += 3)
						{
							if ((patch.points[i][1] - patch.points[i][2]).len() < 0.0001)
							{
								VERTEX leftslope = patch.points[i][1] - patch.points[i][0];
								VERTEX rightslope = patch.points[i][2] - patch.points[i][3];
								patch.points[i][1] = patch.points[i][0] + leftslope.ScaleR(0.5);
								patch.points[i][2] = patch.points[i][3] + rightslope.ScaleR(0.5);
							}
						}
					}*/
					
					patch.CalculateMiddleRows();
				}
				
				if (activestrip == NULL)
				{
					activestrip = track.AddNewRoad();
					mq1.AddMessage("New road created to hold new patch.");
				}
				
				activestrip->Add(patch);
				
				//editordata.numbezinput = 0;
				editordata.numbezinput = 4;
				
				editordata.bezinput[0] = patch.points[0][0];
				editordata.bezinput[1] = patch.points[0][1];
				editordata.bezinput[2] = patch.points[0][2];
				editordata.bezinput[3] = patch.points[0][3];
			}
			else
			{
				editordata.bezinput[oldnumbezinput] = selvert;
				if (vertmode == THREEVERTS && (oldnumbezinput == 1 || oldnumbezinput == 5))
					editordata.bezinput[oldnumbezinput+1] = selvert;
			}
		}
		
		editordata.mousebounce[1] = mouse.ButtonDown(1);
		
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		glDisable(GL_LIGHTING);
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_DEPTH_TEST);
		glPointSize(4.0);
		glColor4f(1,0,0,1);
		glBegin(GL_POINTS);
		for (i = 0; i < editordata.numbezinput; i++)
		{
			if (vertmode != TWOVERTS || i == 0 || i == 3 || i == 4 || i == 7)
			{
				glVertex3fv(editordata.bezinput[i].v3());
			}
		}
		glEnd();
		glColor4f(1,1,1,1);
		glPopAttrib();
		
		track.VisualizeRoads(true, false, activestrip);
		
		for (int l = 0; l < track.NumLapSeqs(); l++)
		{
			BEZIER * lapbez = track.GetLapSeq(l);
			if (lapbez != NULL)
			{
				VERTEX reddish;
				reddish.x = 0.5;
				reddish.y = 0.2;
				reddish.z = 0.2;
				lapbez->Visualize(true, false, reddish);
			}
		}
		
		
		//image in the framebuffer is now complete.
		
		
		/*//add a brightness/contrast adjustment
		glClear (GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glDisable(GL_FOG);
		glDisable(GL_LIGHTING);
		glTranslatef(0,0,-40.0f);
		glBlendFunc(GL_ONE, GL_SRC_ALPHA);
		
		float rd = (float) weathersystem.GetRainDrops();
		
		float rainscale = 0.7f;
		float clearscale = 1.1f;
		float rainbias = 0.035f;
		float clearbias = 0.0f;
		float rainmax = 50.0f;
		
		float rainfactor = (rd/rainmax);
		if (rainfactor > 1.0f)
			rainfactor = 1.0f;
	
		float scale = rainfactor*rainscale+(1.0f-rainfactor)*clearscale;
		float bias = rainfactor*rainbias+(1.0f-rainfactor)*clearbias;
	
	
		glColor4f(bias, bias, bias, scale);
		float x1, y1, x2, y2;
		x1 = -30;
		y1 = -30;
		x2 = 30;
		y2 = 30;
		
		if (scale > 1.0) 
		{
			float remainingScale;
			
			remainingScale = scale;
			glBlendFunc(GL_DST_COLOR, GL_ONE);
			if (remainingScale > 2.0) 
			{
				glColor4f(1, 1, 1, 1);
				while (remainingScale > 2.0) 
				{
					glRectf(x1,y1,x2,y2);
					remainingScale /= 2.0;
				}
			}
			glColor4f(remainingScale - 1,
				remainingScale - 1, remainingScale - 1, 1);
			glRectf(x1,y1,x2,y2);
			glBlendFunc(GL_ONE, GL_ONE);
			if (bias != 0)
			{
				if (bias > 0) 
				{
					glColor4f(bias, bias, bias, 0.0);
				} 
				else 
				{
					glColor4f(-bias, -bias, -bias, 0.0);
					//can't do bias < 0
				}
				glRectf(x1,y1,x2,y2);
			}
		}
		else 
		{
			if (bias > 0) 
			{
				glColor4f(bias, bias, bias, scale);
			}
			else 
			{
				glColor4f(-bias, -bias, -bias, scale);
				//can't do bias < 0
			}
			glBlendFunc(GL_ONE, GL_SRC_ALPHA);
			glRectf(x1,y1,x2,y2);
		}
		
		glPopAttrib();*/
	
		//timer.Draw();
	}
	
	float w, h;
	w = 0.02;
	h = w*(4/3.0);
	utility.Tex2D(0,true);
	utility.Draw2D(0.5-w, 0.5-h, 0.5+w, 0.5+h, editordata.cursortex);
	
	if (fps > 0.0f)
		mq1.Draw(timefactor, fps, font);
	
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "Brightness/contrast adjustment ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif

	
	
    Frames++;
	frameno++;
	if (frameno >= 30011)
		frameno -= 30011;
	lfps[lfpspos] = pfps;
	lfpspos++;
	if (lfpspos >= AVERAGEFRAMES)
	{
		lfpspos = lfpspos % AVERAGEFRAMES;
		lfpsfull = true;
	}
	
	float tfps = 0.0f;
	int tnum = 0;
	for (i = 0; i < AVERAGEFRAMES; i++)
	{
		if (!(!lfpsfull && i >= lfpspos))
		{
			tfps += lfps[i];
			tnum++;
		}
	}
	fps = std::min(1000.0f,tfps / (float) tnum);
	
	/*lfps += pfps;
    {
		//const int freq = (int) MIN_FPS;
		const int freq = 60;
		if (Frames >= freq)
		{
			fps = lfps / freq;
			Frames = 0;
			lfps = 0;
		}
	}*/
	
	char tempchar[1024];
	sprintf(tempchar, "Frames per second: %f\n", fps);
	
	//font.Print(0.5,0,tempchar,0,0,1,1,0);
	if (showfps)
		font.Print( 0.75, 0.0, tempchar, 1, 5, 1.0 );
	
	// print camera position
	VERTEX pos = cam.GetPosition();
	sprintf(tempchar, "Position: %0.2f, %0.2f, %0.2f\n", -pos.x, -pos.y, -pos.z);
	font.Print( 0.75, 0.025, tempchar, 1, 5, 1.0 );
	
	//VERTEX ang = cam.dir.GetEulerZYX();
	//sprintf(tempchar, "Angle: %0.2f, %0.2f, %0.2f\n", 180/M_PI*ang.x, -180/M_PI*ang.y, 180/M_PI*ang.z);
	//font.Print( 0.75, 0.05, tempchar, 1, 5, 1.0 );
	
	// print object name the highlighted vertex belongs to
	if (highlighted_model)
	{
		string modelname = highlighted_model->name;
		sprintf(tempchar, "Model: %s\n", modelname.c_str());
		font.Print( 0.75, 0.05, tempchar, 1, 5, 1.0 );
	}
	
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "font.Print() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	#endif
	
	
	//draw help screen(s)
	if (editordata.helppage > 2)
		editordata.helppage = 0;
	if (editordata.helppage == 1)
	{
		font.Print(0.1, 0.1, "VDrift Track Editor Keys (press H again for more help)\n"
	"Mouse left click\n"
	"Arrow keys\n"
	"Page Up\n"
	"A, F\n"
	"L\n"
	"K\n"
	"N\n"
	"R\n"
	"S\n"
	"I\n"
	"E\n"
	"- (minus)\n"
	"2, 3, 4\n"
	"BACKSPACE\n"
	"ESCAPE\n"
	, 1, 5, 1.0);
		font.Print(0.3, 0.1, "\n"
	"Select highligted vertex\n"
	"Move around\n"
	"Move forward very fast\n"
	"Automatically try to create the next bezier patch on this road (F: 25 at a time)\n"
	"Add the current camera position to the list of car start locations\n"
	"Remove the last start location from the list\n"
	"Create a new road (the new road is created once you add patches to it)\n"
	"Select the road under the cursor\n"
	"Save the track\n"
	"Print the object that owns the selected vertex to the console\n"
	"Mark a road segment as part of a lap sequence\n"
	"Clear all lap sequences\n"
	"Select vertices 2 at a time, 3 at a time, 4 at a time\n"
	"Delete the last bezier patch on this road\n"
	"Quit the editor\n"
	, 1, 5, 1.0);
	}
	if (editordata.helppage == 2)
		font.Print(0.1, 0.1, "VDrift Track Editor Textual Help\n"
	"The editor starts in vertex selection mode.  Vertices are highlighted yellow as the mouse pointer\n"
	"gets close to them.  Press the left mouse button to select the highlighted vertex.  It will turn\n"
	"red.  Select a vertex on the left side of the road, then a vertex on the right side of the road,\n"
	"with left and right determined by the direction you'd like to create the road in.  You can now select\n"
	"the next two vertices (left and then right), and a green box will be created to indicate a bezier\n"
	"patch has been created there.  Notice that the last two vertices you select are still colored red\n"
	"(selected).  You can now select the next two vertices (left and right), and continue to create bezier\n"
	"patches around the track.  Once you have created a bezier patch, you can alternatively press A to\n"
	"have the editor try to automatically select the next two vertices and auto-create the next patch.\n"
	"This works well in straight areas, not so well in curvy areas.  Press BACKSPACE at any time to delete\n"
	"the last patch that was created."
	, 1, 5, 1.0);


	/* Draw it to the screen */
    SDL_GL_SwapBuffers( );

    
		GLint t = SDL_GetTicks();
		//if (t - T0 >= 50) 
		{
			GLfloat seconds = (t - T0) / 1000.0;
			pfps = 1 / seconds;
			//printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
			T0 = t;
			//Frames = 0;
		}
		
	#ifdef PERFORMANCE_PROFILE
	t2 = GetMicroSeconds();
	cout << "SwapBuffers() ticks: " << t2-t1 << endl;
	t1 = GetMicroSeconds();
	cout << endl;
	#endif
		
    return( TRUE );
}
MATHVECTOR <float, 3> AI_Car_Experimental::GetPatchWidthVector(const BEZIER & patch)
{
	return ((patch.GetPoint(0,0) + patch.GetPoint(3,0)) -
			(patch.GetPoint(0,3) + patch.GetPoint(3,3))) * 0.5;
}
MATHVECTOR <float, 3> AI_Car_Experimental::GetPatchBackCenter(const BEZIER & patch)
{
	return (patch.GetPoint(3,0) + patch.GetPoint(3,3)) * 0.5;
}