示例#1
0
void	Display()
// Display function.
{
	// Turn on z-buffering.
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);

	// Set up the view matrix.
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	matrix	ViewMatrix;
	ViewMatrix.View(ViewerDir, ViewerUp, ViewerLoc);
	OGLViewMatrix(ViewMatrix);

	// Transform the frustum planes from view coords into world coords.
	int	i;
	for (i = 0; i < 6; i++) {
		// Rotate the plane from view coords into world coords.  I'm pretty sure this is not a slick
		// way to do this :)
		PlaneInfo&	tp = TransformedFrustumPlane[i];
		PlaneInfo&	p = FrustumPlane[i];
		ViewMatrix.ApplyInverseRotation(&tp.Normal, p.Normal);
		vector	v;
		ViewMatrix.ApplyInverse(&v, p.Normal * p.D);
		tp.D = v * tp.Normal;
	}
	
	// Clear buffers.
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Draw the quadtree.
	if (root) {
		root->Update(RootCornerData, (const float*) ViewerLoc, Detail);
		TriangleCounter += root->Render(RootCornerData, Textured);
	}

	// Show frame.
	glutSwapBuffers();
}
示例#2
0
void	Update()
// Runs one iteration of the game loop.
{
	CurrentTicks = Timer::GetTicks() - StartTicks;
	int	DeltaTicks = CurrentTicks - LastTicks;

	// Force DeltaTicks to a fixed value if we're making a movie.
	if (Config::GetValue("RecordMoviePath") /*&& Config::GetBool("RecordMoviePause") == false*/ ) {
		DeltaTicks = 33;
		if (MovieFrameNumber % 3 == 0) DeltaTicks++;	// Exactly 30 frames/sec.

		// Monkey with the time base so that CurrentTicks
		// increments at 30 frames/sec in sync with DeltaTicks.
		// This is so code which samples CurrentTicks will behave
		// properly during movie recording.
		CurrentTicks = LastTicks + DeltaTicks;
//		StartTicks = (Timer::GetTicks() - CurrentTicks);
	}
	
	if (MovieMode == true) {
		LastTicks = CurrentTicks;

		if (DeltaTicks > 200) DeltaTicks = 200;
		
		//
		// Movie mode.
		//
		// Don't do world update and rendering.  Just show the movie, until
		// it's done, or until the user escapes past the movie.

		// Check for user escape.
		int	UpdateCount = 0;	// For protection against update functions taking longer than the sampling period.
		UpdateState	u;
		while (UpdatesPending() && UpdateCount++ < 30) {
			GetNextUpdateState(&u);
		}
		if (Input::CheckForEventDown(Input::BUTTON0) ||
		    Input::CheckForEventDown(Input::ENTER) ||
		    Input::CheckForEventDown(Input::ESCAPE) ||
		    Input::CheckForEventDown(Input::BUTTON2) ||
		    Config::GetBoolValue("SkipIntro"))
		{
			// Cut the movie short.
			MovieDuration = 0;
		}
		Input::EndFrameNotify();
		
		// Show a new frame.
		glViewport(0, 0, Render::GetWindowWidth(), Render::GetWindowHeight());
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		if (MoviePlayer) MoviePlayer->play(DeltaTicks);

		if (Config::GetValue("RecordMoviePath")) SaveMovieFrame();
		
		Render::ShowFrame();

		MovieDuration -= DeltaTicks;

		if (MovieDuration <= 0) {
			// Done with the movie, now exit movie mode.
			MovieDuration = 0;

			if (MoviePlayer) {
				MoviePlayer->unRef();
				MoviePlayer = NULL;
			}

			MovieMode = false;
		}

		// Sleep a little.
		int	SleepTime = 13 - DeltaTicks;
		if (SleepTime > 0) {
			Timer::Sleep(SleepTime);
		}
		
		return;
	}

	//
	// Update the game logic & physics.
	//

	UpdateState	u;
	
	if (Config::GetValue("RecordMoviePath") != NULL) {
		// Special case -- simulate a fixed update rate.

		// Consume input.
		do {
			GetNextUpdateState(&u);
		} while (UpdatesPending());

		u.DeltaTicks = DeltaTicks;	// Force frame time.
		u.Ticks = CurrentTicks;
		DoUpdates(u);
			
	} else {
		// Normal case -- consume input info and update in real-time.
		int	UpdateCount = 0;	// For protection against update functions taking longer than the sampling period.
		while (UpdatesPending() && UpdateCount++ < 30) {
			GetNextUpdateState(&u);
			DoUpdates(u);
		}
		if (!Config::GetBoolValue("LimitUpdateRate")) {
			UpdateCount++;
			GetNextUpdateState(&u);
			
			//xxxxxx
			Config::SetBoolValue("LastUpdateBeforeRender", true);
			//xxxxx
			
			DoUpdates(u);
		} else {
			if (UpdateCount) {
				Config::SetBoolValue("LastUpdateBeforeRender", true);
			}
		}
		
		if (UpdateCount == 0) {
			return;
		}
	}
	
	LastTicks = CurrentTicks;

	// Don't try to render if we've entered movie mode during the updates.
	if (MovieMode) return;

	// Don't render if we're about to quit.
	if (Main::GetQuit()) return;
	
	// Render visuals.

	int number_of_players = MultiPlayer::NumberOfLocalPlayers();
	
	int window_corner_x[4];
	int window_corner_y[4];
	int window_size_x[4];
	int window_size_y[4];
	
	SetWindowCoordinates(number_of_players, window_corner_x, window_corner_y, window_size_x, window_size_y);

	// For each player, draw graphics
	for (int player_index = 0; player_index < number_of_players; player_index++){

	  MultiPlayer::SetCurrentPlayerIndex(player_index);
	  
	  ViewState	s;


	  // Increment the frame number.
	  //if (player_index == 0)
	  FrameNumber++;
	  s.FrameNumber = FrameNumber;
	  
	  // Set the time value.
	  s.Ticks = u.Ticks;
	
	float	ViewAngle = Config::GetFloatValue("ViewAngle") * (PI / 180);

	// Get viewer orientation.
	vec3	ViewerDir = XAxis;
	vec3	ViewerUp = YAxis;
	vec3	ViewerLoc = ZeroVector;
	if (Viewer) {
		ViewerDir = Viewer->GetDirection();
		ViewerUp = Viewer->GetUp();
		ViewerLoc = Viewer->GetLocation();

		if (ViewerDir.checknan() || ViewerUp.checknan()) {
			// Trouble.  Fall back to a default orientation.
			ViewerDir = XAxis;
			ViewerUp = YAxis;
		}
		if (ViewerLoc.checknan()) {
			// Trouble.  Fall back to a default location.
			ViewerLoc = ZeroVector;
		}
	}

	// Establish transformation from world coordinates to view coordinates.
	s.CameraMatrix.View(ViewerDir, ViewerUp, ViewerLoc);

	s.ViewMatrix = s.CameraMatrix;
	s.Viewpoint = ViewerLoc;
	s.MinZ = 1;
	s.MaxZ = Z_MAX;
	s.OneOverMaxZMinusMinZ = 1.0f / (s.MaxZ - s.MinZ);

	// Set the clipping planes.
//	s.ClipPlaneCount = 0;

	// Near.
	s.ClipPlane[0].Normal = ZAxis;
	s.ClipPlane[0].D = s.MinZ;
//	s.ClipPlaneCount++;

	// Left.
	s.ClipPlane[1].Normal = vec3(-cosf(ViewAngle/2), 0, sinf(ViewAngle/2));
	s.ClipPlane[1].D = 0;
//	s.ClipPlaneCount++;
	
	// Right.
	s.ClipPlane[2].Normal = vec3(cosf(ViewAngle/2), 0, sinf(ViewAngle/2));
	s.ClipPlane[2].D = 0;
//	s.ClipPlaneCount++;

//	float	AspectRatio = float(Render::GetWindowHeight()) / float(Render::GetWindowWidth() * 2.0); // Bjorn
//	float	VerticalAngle2 = atanf(tanf(ViewAngle/2) * AspectRatio);
	float	AspectRatio = float(window_size_y[player_index]) / float(window_size_x[player_index]); // Bjorn
	float	VerticalAngle2 = atanf(tanf(ViewAngle/2) * AspectRatio);

	// Top.
	s.ClipPlane[3].Normal = vec3(0, -cosf(VerticalAngle2), sinf(VerticalAngle2));
	s.ClipPlane[3].D = 0;
//	s.ClipPlaneCount++;
	
	// Bottom.
	s.ClipPlane[4].Normal = vec3(0, cosf(VerticalAngle2), sinf(VerticalAngle2));
	s.ClipPlane[4].D = 0;
//	s.ClipPlaneCount++;
	
	// Far.
	s.ClipPlane[5].Normal = -ZAxis;
	s.ClipPlane[5].D = -s.MaxZ;
//	s.ClipPlaneCount++;

	// Set the projection factors so the view volume fills the screen.
	s.XProjectionFactor = (Render::GetWindowWidth() - 0.6f) / 2 / tanf(ViewAngle/2);
	s.YProjectionFactor = s.XProjectionFactor;

	// Set the x/y offsets so that 0,0 appears in the middle of the screen.
	s.XOffset = (Render::GetWindowWidth() + 1) * 0.5f;
	s.YOffset = (Render::GetWindowHeight() + 1) * 0.5f;

	// Only clear the screen the first time each frame
	if (player_index == 0){
	  Render::BeginFrame();
	  Render::ClearFrame();
	}

	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);
	

	// Set the viewport (split the screen)
	glViewport(window_corner_x[player_index], 
		   window_corner_y[player_index], 
		   window_size_x[player_index], 
		   window_size_y[player_index]);
	
	// Set up OpenGL matrices.
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	float	w = 2 * s.MinZ * tanf(ViewAngle/2);
	float	h = w * AspectRatio;
	OGLFrustum(w, h, s.MinZ, s.MaxZ);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	OGLViewMatrix(ViewerDir, ViewerUp, ViewerLoc);

	// Update the terrain.
	TerrainMesh::Update(s);

	// Set up fog parameters.
	if (Config::GetBoolValue("Fog")) {
		glEnable(GL_FOG);
		glFogi(GL_FOG_MODE, GL_LINEAR /* GL_EXP */);
		glFogf(GL_FOG_START, 0);
		glFogf(GL_FOG_END, Weather::GetFadeDistance());	// For GL_LINEAR mode.
//		glFogf(GL_FOG_DENSITY, 4.852 / Weather::GetFadeDistance());		// For GL_EXP mode; meaningless for GL_LINEAR mode.
		glHint(GL_FOG_HINT, GL_NICEST);
		glFogfv(GL_FOG_COLOR, Weather::GetFadeColor());
	}

	// Determine far clipping plane, and decide whether or not to do two passes.
	float	MaxZ = fmin(Z_MAX, Weather::GetFadeDistance());
	bool	TwoPass = true;	// Should set to false if we have a 24- or 32-bit z-buffer...
	if (MaxZ < TWO_PASS_CUTOFF) TwoPass = false;
	if (TwoPass && Config::GetBoolValue("ZSinglePass")) TwoPass = false;	// Manual override, force single pass.
	
	float	MidZ = MaxZ;

	if (TwoPass) {
		//
		// Draw the distant part of the world.
		//

		// Pick a z value to separate the near and far passes, in order to optimize z-buffer usage.
		MidZ = sqrtf(Z_MIN * Z_MAX);

		s.MaxZ = MaxZ;
		s.MinZ = MidZ * 0.9f;
		s.OneOverMaxZMinusMinZ = 1.0f / (s.MaxZ - s.MinZ);
		// Near.
		s.ClipPlane[0].Normal = ZAxis;
		s.ClipPlane[0].D = s.MinZ;
		
		// Far.
		s.ClipPlane[5].Normal = -ZAxis;
		s.ClipPlane[5].D = -s.MaxZ;
		
		// Set up OpenGL matrices.
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		w = 2 * s.MinZ * tanf(ViewAngle/2);
		h = w * AspectRatio;
		OGLFrustum(w, h, s.MinZ, s.MaxZ);
		
		glMatrixMode(GL_MODELVIEW);
//		glLoadIdentity();
//		OGLViewMatrix(Viewer->GetDirection(), Viewer->GetUp(), Viewer->GetLocation());
		
		// Bjorn : moved this for sky to work when having two players
		// Draw a backdrop.
		glDisable(GL_FOG);
		Weather::RenderBackdrop(s);
		
		TerrainMesh::Render(s);
		
		Model::Render(s);
	}

	//
	// Draw closer part of terrain.
	//
	
	Render::ClearZBuffer();

	s.MaxZ = MidZ;
	s.MinZ = Z_MIN;
	s.OneOverMaxZMinusMinZ = 1.0f / (s.MaxZ - s.MinZ);
	// Near.
	s.ClipPlane[0].Normal = ZAxis;
	s.ClipPlane[0].D = s.MinZ;

	// Far.
	s.ClipPlane[5].Normal = -ZAxis;
	s.ClipPlane[5].D = -s.MaxZ;
	
	// Set up OpenGL matrices.
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	w = 2 * s.MinZ * tanf(ViewAngle/2);
	h = w * AspectRatio;
	OGLFrustum(w, h, s.MinZ, s.MaxZ);
	
	glMatrixMode(GL_MODELVIEW);
//	glLoadIdentity();
//	OGLViewMatrix(Viewer->GetDirection(), Viewer->GetUp(), Viewer->GetLocation());
	
	TerrainMesh::Render(s);

	// Draw the objects.
	Model::Render(s);

	//
	// Overlay effects.
	//
	
	// Turn off the fog for overlay stuff.
	glDisable(GL_FOG);
	
	if (Config::GetBoolValue("BoarderShadow")) {
		// Draw boarder shadow.
		Boarder::RenderShadow(s);
	}
	
	// Draw a trail in the snow.
//	Trail::Render(s);

	// Draw ballistic particles.
	Particle::Render(s);

	// Draw weather overlays (falling snow, etc).
	if (player_index == 0)
	  Weather::RenderOverlay(s, true);
	else
	  Weather::RenderOverlay(s, false);
	
	// End of 3D drawing.
	Render::EndFrame();

	// Draw any UI stuff.
	UI::Render(s, player_index);

	// Music captions.
	Music::Render(s);
	
	// Console.
	Console::Render(s);

	// Remember the frame time, for computing frame rate stats.
	FrameTimeQueue[NextFTSample].Timestamp = CurrentTicks;
	FrameTimeQueue[NextFTSample].FrameTime = DeltaTicks;
	NextFTSample += 1;
	if (NextFTSample >= FT_SAMPLES) NextFTSample = 0;
	
	// Show the frame rate.
	if (Config::GetBoolValue("ShowFrameRate")) {
		// Compute min, max, average frame times over the past one second.
		int	min = 1000, max = 1, sum = 0, SampleCount = 0;
		int	i;
		for (i = 0; i < FT_SAMPLES; i++) {
			FrameTimeSample&	s = FrameTimeQueue[i];
			if (CurrentTicks - s.Timestamp < 1000) {
				// Sample is within the last second.
				if (s.FrameTime < min) min = s.FrameTime;
				if (s.FrameTime > max) max = s.FrameTime;
				sum += s.FrameTime;
				SampleCount++;
			}
		}

		// Compute corresponding frame rates.
		float	MinFR, MaxFR, AvgFR;
		MinFR = 1000.0f / max;
		MaxFR = 1000.0f / min;
		if (SampleCount) {
			AvgFR = (SampleCount * 1000.0f) / sum;
		}
		
		// Show the stats.
		char	buf[80];
		strcpy(buf, "fps: ");
		Text::FormatNumber(buf + strlen(buf), 1000.0f / DeltaTicks, 2, 1);	// last
		strcat(buf, "/");
		Text::FormatNumber(buf + strlen(buf), MinFR, 2, 1);	// min
		strcat(buf, "/");
		Text::FormatNumber(buf + strlen(buf), MaxFR, 2, 1);	// max
		strcat(buf, "/");
		Text::FormatNumber(buf + strlen(buf), AvgFR, 2, 1);	// avg
		
		Text::DrawString(5, 12, Text::FIXEDSYS, Text::ALIGN_LEFT, buf);

		// Show a scrolling bar graph of frame rate.
		GUIBegin();//xxxx
		for (i = 0; i < FT_SAMPLES; i++) {
			FrameTimeSample&	s = FrameTimeQueue[(NextFTSample + i) % FT_SAMPLES];
			float	height = 0;
			if (s.FrameTime) height = (1000.0f / s.FrameTime) / 240.0f;
			glColor3f(1, 0.25f, 0.25f);
			glBegin(GL_QUADS);
			glVertex2f((i-320)/320.0f, 180/240.0f + 0);
			glVertex2f((i-320+1)/320.0f, 180/240.0f + 0);
			glVertex2f((i-320+1)/320.0f, 180/240.0f + height);
			glVertex2f((i-320)/320.0f, 180/240.0f + height);
			glEnd();
		}
		GUIEnd();//xxxx
		
	}

	// Show some other miscellaneous info, if desired.
	if (Config::GetBoolValue("ShowRenderStats")) {
		char	buf[1000];
		sprintf(buf, "Model:\n texels: %dK\n tris: %d\n"
			"Terrain:\n tris: %d\n active nodes: %d\n total nodes: %d\n nudge: %g\n"
			" cache:\n  texels: %dK\n  active nodes = %d\n  nodes built = %d\n  thrash ct = %d"
			,
			Model::GetTexelCount() / 1024,
			Model::GetRenderedTriangleCount(),
			TerrainMesh::GetRenderedTriangleCount(),
			TerrainMesh::GetNodesActiveCount(),
			TerrainMesh::GetNodesTotalCount(),
			TerrainMesh::GetDetailNudge(),
			Surface::GetTexelCount() / 1024,
			Surface::GetActiveNodeCount(),
			Surface::GetNodesBuilt(),
			Surface::GetThrashCount()
		       );
		Text::DrawMultiLineString(5, 24, Text::FIXEDSYS, Text::ALIGN_LEFT, 640, buf);
	}

	// Show viewer location.
	if (Config::GetBoolValue("ShowViewerLocation") && Viewer) {
		char	buf[80];
		Text::FontID	f = Text::FIXEDSYS;

		vec3	v = ViewerLoc;
		
		int	y = 400;
		int	dy = Text::GetFontHeight(f);
		Text::FormatNumber(buf, v.X() + 32768, 4, 1);
		Text::DrawString(20, y, f, Text::ALIGN_LEFT, buf, 0xFF000000);
		y += dy;
		Text::FormatNumber(buf, v.Y(), 4, 1);
		Text::DrawString(20, y, f, Text::ALIGN_LEFT, buf, 0xFF000000);
		y += dy;
		Text::FormatNumber(buf, v.Z() + 32768, 4, 1);
		Text::DrawString(20, y, f, Text::ALIGN_LEFT, buf, 0xFF000000);
		y += dy;
	}
		
	
//	// Log user speed xxxxxx
//	{
//		char	buf[80];
//		float	speed = 0;
//		MDynamic*	d = Game::GetUser();
//		if (d) speed = d->GetVelocity().magnitude();
//		Text::FormatNumber(buf, speed * 2.2369, 3, 1);
//		Text::DrawString(40, 400, Text::DEFAULT, Text::ALIGN_LEFT, buf);
//	}
//	// xxxxxxxx

	Overlay::Render();
	
	if (Config::GetValue("RecordMoviePath")) SaveMovieFrame();

	const char*	fn = Config::GetValue("SaveFramePPM");
	if (fn) {
		Render::WriteScreenshotFilePPM(fn);
		Config::SetValue("SaveFramePPM", NULL);
	}
	
	} // end of two player display
	
	Render::ShowFrame();

	//xxxxxxx
	Config::SetBoolValue("F4Pressed", false);
}