1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D is free software; you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation; either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <landscape/Landscape.h>
22 #include <landscape/LandscapePoints.h>
23 #include <landscapemap/LandscapeMaps.h>
24 #include <landscape/LandscapeSoundManager.h>
25 #include <landscape/LandscapeMusicManager.h>
26 #include <landscape/Smoke.h>
27 #include <landscape/Wall.h>
28 #include <landscape/ShadowMap.h>
29 #include <landscape/InfoMap.h>
30 #include <landscape/GraphicalLandscapeMap.h>
31 #include <landscapedef/LandscapeTex.h>
32 #include <landscapedef/LandscapeDefn.h>
33 #include <landscapedef/LandscapeDefinition.h>
34 #include <landscapedef/LandscapeDefinitions.h>
35 #include <lang/LangResource.h>
36 #include <sky/Sky.h>
37 #include <water/Water.h>
38 #include <land/VisibilityPatchGrid.h>
39 #include <movement/TargetMovement.h>
40 #include <image/ImageFactory.h>
41 #include <GLEXT/GLImageModifier.h>
42 #include <GLEXT/GLStateExtension.h>
43 #include <GLEXT/GLCameraFrustum.h>
44 #include <console/ConsoleRuleMethodIAdapter.h>
45 #include <GLSL/GLSLShaderSetup.h>
46 #include <common/OptionsTransient.h>
47 #include <common/Defines.h>
48 #include <graph/OptionsDisplay.h>
49 #include <graph/MainCamera.h>
50 #include <engine/Simulator.h>
51 #include <sound/Sound.h>
52 #include <client/ScorchedClient.h>
53 #include <dialogs/CameraDialog.h>
54 #include <engine/ActionController.h>
55 #include <tankgraph/RenderTargets.h>
56 #include <time.h>
57 
58 Landscape *Landscape::instance_ = 0;
59 
instance()60 Landscape *Landscape::instance()
61 {
62 	if (!instance_)
63 	{
64 		instance_ = new Landscape;
65 	}
66 	return instance_;
67 }
68 
Landscape()69 Landscape::Landscape() :
70 	resetLandscape_(false), resetLandscapeTimer_(0.0f),
71 	resetRoof_(false), resetRoofTimer_(0.0f),
72 	textureType_(eDefault),
73 	changeCount_(1),
74 	landShader_(0)
75 {
76 	water_ = new Water();
77 	points_ = new LandscapePoints();
78 	sky_ = new Sky();
79 	smoke_ = new Smoke();
80 	wall_ = new Wall();
81 
82 	new ConsoleRuleMethodIAdapter<Landscape>(
83 		this, &Landscape::savePlan, "SavePlan");
84 }
85 
~Landscape()86 Landscape::~Landscape()
87 {
88 }
89 
simulate(float frameTime)90 void Landscape::simulate(float frameTime)
91 {
92 	if (resetLandscape_)
93 	{
94 		resetLandscapeTimer_ -= frameTime;
95 		if (resetLandscapeTimer_ < 0.0f)
96 		{
97 			// Update the plan texture
98 			updatePlanATexture();
99 			updatePlanTexture();
100 
101 			// Update the landscape
102 			GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
103 				ScorchedClient::instance()->getLandscapeMaps().
104 					getGroundMaps().getHeightMap().getGraphicalMap();
105 			landscapeMap->updateWholeBuffer();
106 
107 			// Re-calculate the landsacpe on the wind indicator
108 			changeCount_++;
109 			resetLandscape_ = false;
110 		}
111 	}
112 	if (resetRoof_)
113 	{
114 		resetRoofTimer_ -= frameTime;
115 		if (resetRoofTimer_ < 0.0f)
116 		{
117 			if (ScorchedClient::instance()->getLandscapeMaps().getRoofMaps().getRoofOn())
118 			{
119 				// Update the landscape
120 				GraphicalLandscapeMap *roofMap = (GraphicalLandscapeMap *)
121 					ScorchedClient::instance()->getLandscapeMaps().
122 						getRoofMaps().getRoofMap().getGraphicalMap();
123 				roofMap->updateWholeBuffer();
124 
125 				// Re-calculate the landsacpe on the wind indicator
126 				changeCount_++;
127 			}
128 
129 			resetRoof_ = false;
130 		}
131 	}
132 
133 	float speedMult = ScorchedClient::instance()->
134 		getSimulator().getFast().asFloat();
135 	water_->simulate(frameTime * speedMult);
136 	sky_->simulate(frameTime * speedMult);
137 	wall_->simulate(frameTime * speedMult);
138 	LandscapeSoundManager::instance()->simulate(frameTime * speedMult);
139 }
140 
recalculateLandscape()141 void Landscape::recalculateLandscape()
142 {
143 	if (!resetLandscape_)
144 	{
145 		resetLandscape_ = true;
146 		float recalcTime = float(OptionsDisplay::instance()->getDeformRecalculationTime()) / 1000.0f;
147 		resetLandscapeTimer_ = recalcTime; // Recalculate the landscape in x seconds
148 	}
149 }
150 
recalculateRoof()151 void Landscape::recalculateRoof()
152 {
153 	if (!resetRoof_)
154 	{
155 		resetRoof_ = true;
156 		float recalcTime = float(OptionsDisplay::instance()->getDeformRecalculationTime()) / 1000.0f;
157 		resetRoofTimer_ = recalcTime; // Recalculate the water in x seconds
158 	}
159 }
160 
drawShadows()161 void Landscape::drawShadows()
162 {
163 	if (!GLStateExtension::hasHardwareShadows()) return;
164 
165 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SHADOWS_PRE");
166 
167 	// Turn off texturing
168 	GLState glstate(GLState::TEXTURE_OFF | GLState::DEPTH_ON);
169 
170 	float landWidth = ScorchedClient::instance()->getLandscapeMaps().
171 		getGroundMaps().getLandscapeWidth() / 2.0f;
172 	float landHeight = ScorchedClient::instance()->getLandscapeMaps().
173 		getGroundMaps().getLandscapeHeight() / 2.0f;
174 	float maxWidth = MAX(landWidth, landHeight);
175 
176 	// Get the sun's position and landscape dimensions
177 	Vector sunPosition = Landscape::instance()->getSky().getSun().getPosition();
178 	sunPosition *= 0.5f + (maxWidth - 128.0f) / 256.0f;
179 
180 	Vector relativePosition = sunPosition;
181 	relativePosition[0] -= landWidth;
182 	relativePosition[1] -= landHeight;
183 	float magnitude = relativePosition.Magnitude();
184 
185 	// Bind the frame buffer so we can render into it
186 	shadowFrameBuffer_.bind();
187 	glViewport(0, 0, shadowFrameBuffer_.getWidth(), shadowFrameBuffer_.getHeight());
188 
189 	// Setup the view from the sun
190 	glMatrixMode(GL_PROJECTION);
191 	glLoadIdentity();
192 	gluPerspective(60.0f, 1.0f, magnitude - (maxWidth * 1.5f), magnitude + (maxWidth * 1.5f));
193 	glMatrixMode(GL_MODELVIEW);
194 	glLoadIdentity();
195 	gluLookAt(
196 		sunPosition[0], sunPosition[1], sunPosition[2],
197 		landWidth, landHeight, 0.0f ,
198 		0.0f, 0.0f, 1.0f);
199 
200 	GLCameraFrustum::instance()->draw(0);
201 
202 	// Save the matrixs used for the sun
203 	glGetFloatv(GL_MODELVIEW_MATRIX, lightModelMatrix_);
204 	glGetFloatv(GL_PROJECTION_MATRIX, lightProjMatrix_);
205 
206 	// Clear and setup the offset
207     glClear(GL_DEPTH_BUFFER_BIT);
208 
209 	// Set poly offset so that the shadows dont get precision artifacts
210     glPolygonOffset(10.0f, 10.0f);
211     glEnable(GL_POLYGON_OFFSET_FILL);
212 	glCullFace(GL_FRONT);
213 
214 	//Disable color writes, and use flat shading for speed
215     glColorMask(0, 0, 0, 0);
216 
217 	// Draw items that cast shadows
218 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SHADOWS_PRE");
219 
220 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SHADOWS_DRAW_LAND");
221 	VisibilityPatchGrid::instance()->drawLand(0, true, true);
222 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SHADOWS_DRAW_LAND");
223 
224 	if (!OptionsDisplay::instance()->getNoGLObjectShadows())
225 	{
226 		RenderTargets::instance()->shadowDraw();
227 	}
228 
229 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SHADOWS_POST");
230 
231 	static bool createdMap = false;
232 	if (OptionsDisplay::instance()->getDrawGraphicalShadowMap())
233 	{
234 		if (!createdMap)
235 		{
236 			createdMap = true;
237 
238 			static float *depthResult =
239 				new float[shadowFrameBuffer_.getWidth() * shadowFrameBuffer_.getHeight()];
240 			static Image depthImage(
241 				shadowFrameBuffer_.getWidth(),
242 				shadowFrameBuffer_.getHeight());
243 
244 			glReadPixels(0, 0,
245 				shadowFrameBuffer_.getWidth(), shadowFrameBuffer_.getHeight(),
246 				GL_DEPTH_COMPONENT, GL_FLOAT, depthResult);
247 
248 			float min = 1.0, max = 0.0;
249 			float *src = depthResult;
250 			unsigned char *dest = depthImage.getBits();
251 			for (int i=0; i<shadowFrameBuffer_.getWidth() * shadowFrameBuffer_.getHeight(); i++, src++, dest+=3)
252 			{
253 				if (*src != 1.0f)
254 				{
255 					if (*src != 0.0f)
256 					{
257 						min = MIN(min, *src);
258 						max = MAX(max, *src);
259 					}
260 
261 					//*src = 0.0f; // Black and white
262 					dest[0] = (unsigned char) (*src * 255.0f);
263 					dest[1] = (unsigned char) (*src * 255.0f);
264 					dest[2] = (unsigned char) (*src * 255.0f);
265 				}
266 			}
267 
268 			colorDepthMap_.replace(depthImage);
269 		}
270 	}
271 	else
272 	{
273 		createdMap = false;
274 	}
275 
276 	//restore states
277     glColorMask(1, 1, 1, 1);
278 
279 	// Reset offset
280 	glDisable(GL_POLYGON_OFFSET_FILL);
281 	glCullFace(GL_BACK);
282 
283 	// Stop drawing to frame buffer
284 	shadowFrameBuffer_.unBind();
285 
286 	// Reset camera
287 	MainCamera::instance()->getCamera().draw();
288 	GLCameraFrustum::instance()->draw(0);
289 
290 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SHADOWS_POST");
291 }
292 
calculateVisibility()293 void Landscape::calculateVisibility()
294 {
295 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_LOD");
296 	VisibilityPatchGrid::instance()->calculateVisibility();
297 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_LOD");
298 }
299 
drawSetup()300 void Landscape::drawSetup()
301 {
302 	if (OptionsDisplay::instance()->getDrawLines()) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
303 
304 	// NOTE: The following code is drawn with fog on
305 	// Be carefull as this we "dull" bilboard textures
306 	if (!OptionsDisplay::instance()->getNoFog())
307 	{
308 		glEnable(GL_FOG); // NOTE: Fog on
309 	}
310 }
311 
drawTearDown()312 void Landscape::drawTearDown()
313 {
314 	glDisable(GL_FOG); // NOTE: Fog off
315 	if (OptionsDisplay::instance()->getDrawLines()) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
316 }
317 
drawLand()318 void Landscape::drawLand()
319 {
320 	drawSetup();
321 
322 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SKY");
323 	sky_->drawBackdrop(false);
324 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SKY");
325 
326 	if (OptionsDisplay::instance()->getDrawLandscape())
327 	{
328 		if (GLStateExtension::hasHardwareShadows() &&
329 			OptionsDisplay::instance()->getUseLandscapeTexture())
330 		{
331 			actualDrawLandShader();
332 		}
333 		else
334 		{
335 			actualDrawLandTextured();
336 		}
337 	}
338 
339 	if (OptionsDisplay::instance()->getDrawGraphicalShadowMap())
340 	{
341 		drawGraphicalTextureMap(colorDepthMap_);
342 	}
343 	if (OptionsDisplay::instance()->getDrawGraphicalReflectionMap())
344 	{
345 		drawGraphicalTextureMap(water_->getReflectionTexture());
346 	}
347 
348 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_POINTS");
349 	points_->draw();
350 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_POINTS");
351 
352 	if (OptionsDisplay::instance()->getDrawMovement())
353 	{
354 		ScorchedClient::instance()->getTargetMovement().draw();
355 	}
356 
357 	drawTearDown();
358 }
359 
drawWater()360 void Landscape::drawWater()
361 {
362 	if (!water_->getWaterOn()) return;
363 
364 	if (GLStateExtension::hasFBO() &&
365 		GLStateExtension::hasShaders() &&
366 		!OptionsDisplay::instance()->getNoWaterReflections() &&
367 		OptionsDisplay::instance()->getDrawWater() &&
368 		water_->getWaterOn())
369 	{
370 		water_->bindWaterReflection();
371 
372 		glClearColor(0, 1.0f/16.0f, 1.0f/8.0f, 0);
373 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
374 
375 		glPushMatrix();
376 
377 		glTranslatef(0.0f, 0.0f, water_->getWaterHeight() * 2.0f);
378 
379 		// flip geometry at z=0 plane
380 		glScalef(1.0f, 1.0f, -1.0f);
381 		glCullFace(GL_FRONT);
382 
383 		drawSetup();
384 		GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LAND_REFLECTIONS");
385 		sky_->drawBackdrop(true);
386 		sky_->drawLayers();
387 		actualDrawLandReflection();
388 		GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LAND_REFLECTIONS");
389 		if (!OptionsDisplay::instance()->getNoObjectReflections())
390 		{
391 			GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "TARGET_REFLECTIONS");
392 			RenderTargets::instance()->draw(true);
393 			GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "TARGET_REFLECTIONS");
394 		}
395 		if (!OptionsDisplay::instance()->getNoParticleReflections())
396 		{
397 			GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "PARTICLE_REFLECTIONS");
398 			ScorchedClient::instance()->getParticleEngine().draw(0);
399 			GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "PARTICLE_REFLECTIONS");
400 		}
401 		drawTearDown();
402 
403 		//water_->drawPoints(); // Bad reflections in large wind
404 
405 		glCullFace(GL_BACK);
406 		glPopMatrix();
407 
408 		water_->unBindWaterReflection();
409 	}
410 
411 	drawSetup();
412 
413 	water_->draw();
414 
415 	drawTearDown();
416 }
417 
drawObjects()418 void Landscape::drawObjects()
419 {
420 	drawSetup();
421 
422 	sky_->drawLayers();
423 	wall_->draw();
424 
425 	drawTearDown();
426 }
427 
getPlanTexSize()428 int Landscape::getPlanTexSize()
429 {
430 	switch (OptionsDisplay::instance()->getTexSize())
431 	{
432 	case 0:
433 		return 64;
434 		break;
435 	case 2:
436 		return 256;
437 		break;
438 	default:
439 		return 128;
440 		break;
441 	}
442 	return 128;
443 }
444 
getMapTexSize()445 int Landscape::getMapTexSize()
446 {
447 	switch (OptionsDisplay::instance()->getTexSize())
448 	{
449 	case 0:
450 		return 256;
451 		break;
452 	case 2:
453 		return 2048;
454 		break;
455 	default:
456 		return 1024;
457 		break;
458 	}
459 	return 1024;
460 }
461 
generate(ProgressCounter * counter)462 void Landscape::generate(ProgressCounter *counter)
463 {
464 	GraphicalLandscapeMap *landscapeMap = (GraphicalLandscapeMap *)
465 		ScorchedClient::instance()->getLandscapeMaps().
466 			getGroundMaps().getHeightMap().getGraphicalMap();
467 	landscapeMap->updateWholeBuffer();
468 
469 	if (ScorchedClient::instance()->getLandscapeMaps().getRoofMaps().getRoofOn())
470 	{
471 		GraphicalLandscapeMap *roofMap = (GraphicalLandscapeMap *)
472 			ScorchedClient::instance()->getLandscapeMaps().
473 				getRoofMaps().getRoofMap().getGraphicalMap();
474 		roofMap->updateWholeBuffer();
475 	}
476 
477 	textureType_ = eDefault;
478 	InfoMap::instance()->addAdapters();
479 
480 	// Choose the correct sizes for the current LOD
481 	int mapTexSize = getMapTexSize();
482 	int planTexSize = getPlanTexSize();
483 
484 	// Generate the texture used to map onto the landscape
485 	if (!mainMap_.getBits())
486 	{
487 		mainMap_ = Image(mapTexSize, mapTexSize);
488 		bitmapPlanAlpha_ = Image(planTexSize, planTexSize, true);
489 		bitmapPlan_ = Image(planTexSize, planTexSize);
490 		bitmapPlanAlphaAlpha_ = Image(planTexSize, planTexSize, 3, 0);
491 	}
492 
493 	if (GLStateExtension::hasHardwareShadows())
494 	{
495 		if (!shadowFrameBuffer_.bufferValid())
496 		{
497 			// Create the frame buffer
498 			if (!shadowFrameBuffer_.create(2048, 2048))
499 			{
500 				S3D::dialogExit("Scorched3D", "Failed to create shadow frame buffer");
501 			}
502 		}
503 	}
504 
505 	// Removed for now as plan is square
506 	// If (when) re-instated need to scale alpha map by playable arena, not full map size
507 	/*Image plana = ImageFactory::loadImage(S3D::getModFile("data/windows/planaa.bmp"));
508 	ImageModifier::scalePlanBitmap(bitmapPlanAlphaAlpha_, plana,
509 		ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth(),
510 	ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight());*/
511 
512 	// Load the texture bitmaps from resources
513 	LandscapeTex *tex =
514 			ScorchedClient::instance()->getLandscapeMaps().getDefinitions().getTex();
515 	if (tex->texture->getType() == LandscapeTexType::eTextureGenerate)
516 	{
517 		LandscapeTexTextureGenerate *generate =
518 			(LandscapeTexTextureGenerate *) tex->texture;
519 
520 		Image texture0 =
521 			ImageFactory::loadImage(S3D::eModLocation, generate->texture0.c_str());
522 		Image texture1 =
523 			ImageFactory::loadImage(S3D::eModLocation, generate->texture1.c_str());
524 		Image texture2 =
525 			ImageFactory::loadImage(S3D::eModLocation, generate->texture2.c_str());
526 		Image texture3 =
527 			ImageFactory::loadImage(S3D::eModLocation, generate->texture3.c_str());
528 		Image bitmapShore =
529 			ImageFactory::loadImage(S3D::eModLocation, generate->shore.c_str());
530 		Image bitmapRock =
531 			ImageFactory::loadImage(S3D::eModLocation, generate->rockside.c_str());
532 		Image bitmapRoof =
533 			ImageFactory::loadImage(S3D::eModLocation, generate->roof.c_str());
534 		Image *bitmaps[4];
535 		bitmaps[0] = &texture0;
536 		bitmaps[1] = &texture1;
537 		bitmaps[2] = &texture2;
538 		bitmaps[3] = &texture3;
539 
540 		// Generate the new landscape
541 		if (counter) counter->setNewOp(LANG_RESOURCE("LANDSCAPE_MAP", "Generate Landscape Map"));
542 		ImageModifier::addHeightToBitmap(
543 			ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeightMap(),
544 			mainMap_,
545 			bitmapRock, bitmapShore, bitmaps, 4, 1024, counter);
546 
547 		//mainMap_.writeToFile("i:\\plan.bmp");
548 
549 		// Set the general surround and roof texture
550 		groundTexture_.replace(texture0, false);
551 		roofTexture_.replace(bitmapRoof, true);
552 	}
553 	else if (tex->texture->getType() == LandscapeTexType::eTextureFile)
554 	{
555 		LandscapeTexTextureFile *generate =
556 			(LandscapeTexTextureFile *) tex->texture;
557 
558 		if (counter) counter->setNewOp(LANG_RESOURCE("LANDSCAPE_MAP", "Load Landscape Map"));
559 		Image texture =
560 			ImageFactory::loadImage(S3D::eModLocation, generate->texture.c_str());
561 		mainMap_ = texture.createResize(1024, 1024);
562 
563 		// Set the general surround and roof texture
564 		if (generate->surroundTexture.empty())
565 		{
566 			groundTexture_.replace(texture, false);
567 			roofTexture_.replace(texture, true);
568 		}
569 		else
570 		{
571 			Image surroundTexture =
572 				ImageFactory::loadImage(S3D::eModLocation, generate->surroundTexture.c_str());
573 			groundTexture_.replace(surroundTexture, false);
574 			roofTexture_.replace(surroundTexture, true);
575 		}
576 	}
577 	else
578 	{
579 		S3D::dialogExit("Landscape", S3D::formatStringBuffer(
580 			"Failed to find heightmap type %i",
581 			tex->texture->getType()));
582 	}
583 
584 	points_->generate();
585 
586 	// Add lighting to the landscape texture
587 	sky_->getSun().setPosition(tex->skysunxy, tex->skysunyz);
588 	if (!GLStateExtension::hasHardwareShadows())
589 	{
590 		Vector sunPos = sky_->getSun().getPosition();
591 		ImageModifier::addLightMapToBitmap(mainMap_,
592 			ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeightMap(),
593 			sunPos,  // Match with shadows
594 			tex->skyambience, tex->skydiffuse, counter);
595 	}
596 	else
597 	{
598 		GLSLShader::defines_list dl;
599 		if (getShadowFrameBuffer().bufferValid())
600 		{
601 			dl.push_back("USE_SHADOWS");
602 		}
603 
604 		// Load shader
605 		if (!landShader_)
606 		{
607 			landShader_ = new GLSLShaderSetup(
608 				S3D::getDataFile("data/shaders/land.vshader"),
609 				S3D::getDataFile("data/shaders/land.fshader"),
610 				dl);
611 		}
612 	}
613 
614 	// Add shadows to the mainmap
615 	std::list<PlacementShadowDefinition::Entry> &shadows =
616 		ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getShadows();
617 	std::list<PlacementShadowDefinition::Entry>::iterator itor;
618 	for (itor = shadows.begin();
619 		itor != shadows.end();
620 		++itor)
621 	{
622 		PlacementShadowDefinition::Entry &entry = (*itor);
623 
624 		entry.definition_->updateLandscapeTexture(
625 			!GLStateExtension::hasHardwareShadows() ||
626 			OptionsDisplay::instance()->getNoGLObjectShadows(),
627 			ScorchedClient::instance()->getContext(),
628 			entry.position_, entry.size_);
629 	}
630 
631 	// Create the main landscape texture
632 	DIALOG_ASSERT(texture_.replace(mainMap_, false));
633 
634     // Create the landscape texture used for the small plan window
635 	gluScaleImage(
636 		GL_RGB,
637 		mainMap_.getWidth(), mainMap_.getHeight(),
638 		GL_UNSIGNED_BYTE, mainMap_.getBits(),
639 		bitmapPlan_.getWidth(), bitmapPlan_.getHeight(),
640 		GL_UNSIGNED_BYTE, bitmapPlan_.getBits());
641 
642 	// Generate the scorch map for the landscape
643 	Image sprayMaskBitmap =
644 		ImageFactory::loadImage(
645 			S3D::eModLocation,
646 			"data/textures/smoke01.bmp",
647 			"data/textures/smoke01.bmp",
648 			false);
649 	scorchMap_ =
650 		ImageFactory::loadImage(
651 			S3D::eModLocation,
652 			tex->scorch);
653 	Image scorchMap = scorchMap_.createResize(
654 		sprayMaskBitmap.getWidth(), sprayMaskBitmap.getHeight());
655 	Image texture1New(sprayMaskBitmap.getWidth(), sprayMaskBitmap.getHeight(), true);
656 	ImageModifier::makeBitmapTransparent(texture1New, scorchMap, sprayMaskBitmap);
657 	landTex1_.replace(texture1New);
658 
659 	// Arena
660 	Image arenaBitmap = ImageModifier::makeArenaBitmap();
661 	DIALOG_ASSERT(arenaMainTexture_.replace(arenaBitmap));
662 	arenaMainTexture_.draw();
663 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
664 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
665     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
666     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
667 	Image arenaSurroundBitmap = ImageModifier::makeArenaSurroundBitmap();
668 	DIALOG_ASSERT(arenaSurroundTexture_.replace(arenaSurroundBitmap));
669 
670 	// Magma
671 	Image bitmapMagma =
672 		ImageFactory::loadImage(
673 			S3D::eModLocation,
674 			tex->magmasmall);
675 	DIALOG_ASSERT(magTexture_.replace(bitmapMagma));
676 
677 	// Detail
678 	Image bitmapDetail =
679 		ImageFactory::loadImage(
680 			S3D::eModLocation,
681 			tex->detail);
682 	DIALOG_ASSERT(detailTexture_.replace(bitmapDetail, true));
683 
684 	// Set the fog color
685 	GLfloat fogColorF[4];
686 	fogColorF[0] = tex->fog[0];
687 	fogColorF[1] = tex->fog[1];
688 	fogColorF[2] = tex->fog[2];
689 	fogColorF[3] = 1.0f;
690 	glFogfv(GL_FOG_COLOR, fogColorF);
691 	GLfloat fogDensity = tex->fogdensity;
692 	glFogf(GL_FOG_DENSITY, fogDensity);
693 
694 	// Load the sky
695 	sky_->generate();
696 
697 	// Load water
698 	water_->generate(counter);
699 
700 	// Create the plan textures (for the plan and wind dialogs)
701 	updatePlanTexture();
702 	updatePlanATexture();
703 
704 	// Add any ambientsounds
705 	LandscapeSoundManager::instance()->addSounds();
706 	LandscapeMusicManager::instance()->addMusics();
707 }
708 
updatePlanTexture()709 void Landscape::updatePlanTexture()
710 {
711 	if (water_->getWaterOn())
712 	{
713 		ImageModifier::addWaterToBitmap(
714 			ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeightMap(),
715 			bitmapPlan_, water_->getWaterBitmap(), water_->getWaterHeight());
716 	}
717 
718 	DIALOG_ASSERT(planTexture_.replace(bitmapPlan_, false));
719 }
720 
actualDrawLandTextured()721 void Landscape::actualDrawLandTextured()
722 {
723 	unsigned int state = 0;
724 	if (!OptionsDisplay::instance()->getUseLandscapeTexture()) state |= GLState::TEXTURE_OFF;
725 
726 	GLState glState(state);
727 
728 	bool showArenaArea = MainCamera::instance()->getShowArena();
729 
730 	bool useDetail =
731 		GLStateExtension::getTextureUnits() > 2 &&
732 		OptionsDisplay::instance()->getDetailTexture() &&
733 		GLStateExtension::hasEnvCombine();
734 
735 	if (OptionsDisplay::instance()->getUseLandscapeTexture())
736 	{
737 		if (GLStateExtension::hasMultiTex())
738 		{
739 			if (useDetail)
740 			{
741 				glActiveTextureARB(GL_TEXTURE2_ARB);
742 				glEnable(GL_TEXTURE_2D);
743 				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
744 				glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);
745 
746 				detailTexture_.draw(true);
747 			}
748 
749 			glActiveTextureARB(GL_TEXTURE1_ARB);
750 			glEnable(GL_TEXTURE_2D);
751 			if (showArenaArea)
752 			{
753 				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
754 				arenaMainTexture_.draw();
755 			}
756 			else getShadowMap().setTexture();
757 
758 			glActiveTextureARB(GL_TEXTURE0_ARB);
759 		}
760 
761 		texture_.draw(true);
762 	}
763 
764 	glColor3f(1.0f, 1.0f, 1.0f);
765 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_LAND");
766 	VisibilityPatchGrid::instance()->drawLand(0, false, false);
767 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_LAND");
768 
769 	if (OptionsDisplay::instance()->getDrawLandLOD())
770 	{
771 		VisibilityPatchGrid::instance()->drawLandLODLevels();
772 	}
773 
774 	if (OptionsDisplay::instance()->getUseLandscapeTexture())
775 	{
776 		if (GLStateExtension::hasMultiTex())
777 		{
778 			glActiveTextureARB(GL_TEXTURE1_ARB);
779 			if (showArenaArea) arenaSurroundTexture_.draw();
780 			else glEnable(GL_TEXTURE_2D);
781 
782 			glActiveTextureARB(GL_TEXTURE0_ARB);
783 		}
784 
785 		groundTexture_.draw(true);
786 	}
787 
788 	if (OptionsDisplay::instance()->getDrawSurround())
789 	{
790 		GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SURROUND");
791 		VisibilityPatchGrid::instance()->drawSurround();
792 		GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SURROUND");
793 	}
794 
795 	if (OptionsDisplay::instance()->getUseLandscapeTexture())
796 	{
797 		if (GLStateExtension::hasMultiTex())
798 		{
799 			if (useDetail)
800 			{
801 				glActiveTextureARB(GL_TEXTURE2_ARB);
802 				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
803 				glDisable(GL_TEXTURE_2D);
804 			}
805 
806 			glActiveTextureARB(GL_TEXTURE1_ARB);
807 			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
808 			glDisable(GL_TEXTURE_2D);
809 			glActiveTextureARB(GL_TEXTURE0_ARB);
810 		}
811 	}
812 }
813 
actualDrawLandReflection()814 void Landscape::actualDrawLandReflection()
815 {
816 	unsigned int state = GLState::BLEND_ON | GLState::LIGHTING_ON | GLState::LIGHT1_ON;
817 	if (!OptionsDisplay::instance()->getUseLandscapeTexture()) state |= GLState::TEXTURE_OFF;
818 	GLState glState(state);
819 
820 	Vector4 ambientColor(1.0f, 1.0f, 1.0f, 1.0f);
821 	Vector4 diffuseColor(0.0f, 0.0f, 0.0f, 1.0f);
822 	Vector4 specularColor(1.0f, 1.0f, 1.0f, 1.0f);
823 	Vector4 emissiveColor(0.0f, 0.0f, 0.0f, 1.0f);
824 	float shininess = 1.0f;
825 	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambientColor);
826 	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuseColor);
827 	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor);
828 	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissiveColor);
829 	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
830 
831 	Landscape::instance()->getSky().getSun().setLightPosition();
832 
833 	if (OptionsDisplay::instance()->getUseLandscapeTexture())
834 	{
835 		planAlphaTexture_.draw(true);
836 	}
837 
838 	glColor3f(1.0f, 1.0f, 1.0f);
839 	VisibilityPatchGrid::instance()->drawLand(2, false, false);
840 }
841 
createShadowMatrix()842 void Landscape::createShadowMatrix()
843 {
844 	if (!GLStateExtension::hasHardwareShadows()) return;
845 
846 	// Create texture matrix
847 	static const float mNormalizeMatrix[] =
848 	{
849 		0.5f, 0.0f, 0.0f, 0.0f,
850 		0.0f, 0.5f, 0.0f, 0.0f,
851 		0.0f, 0.0f, 0.5f, 0.0f,
852 		0.5f, 0.5f, 0.5f, 1.0f
853 	};
854 	static GLfloat modelMatrix[16], modelMatrixI[16];
855 	glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
856 
857 	// Copy and transpose
858 	modelMatrixI[ 0] = modelMatrix[ 0];
859 	modelMatrixI[ 4] = modelMatrix[ 1];
860 	modelMatrixI[ 8] = modelMatrix[ 2];
861 	modelMatrixI[ 1] = modelMatrix[ 4];
862 	modelMatrixI[ 5] = modelMatrix[ 5];
863 	modelMatrixI[ 9] = modelMatrix[ 6];
864 	modelMatrixI[ 2] = modelMatrix[ 8];
865 	modelMatrixI[ 6] = modelMatrix[ 9];
866 	modelMatrixI[10] = modelMatrix[10];
867 	modelMatrixI[ 3] = 0;
868 	modelMatrixI[ 7] = 0;
869 	modelMatrixI[11] = 0;
870 	modelMatrixI[15] = modelMatrix[15];
871 
872 	// Apply the inverse transformation
873 	modelMatrixI[12] = modelMatrixI[0] * -modelMatrix[12] + modelMatrixI[4] * -modelMatrix[13] + modelMatrixI[ 8] * -modelMatrix[14];
874 	modelMatrixI[13] = modelMatrixI[1] * -modelMatrix[12] + modelMatrixI[5] * -modelMatrix[13] + modelMatrixI[ 9] * -modelMatrix[14];
875 	modelMatrixI[14] = modelMatrixI[2] * -modelMatrix[12] + modelMatrixI[6] * -modelMatrix[13] + modelMatrixI[10] * -modelMatrix[14];
876 
877 	// Create and save texture matrix
878 	glMatrixMode(GL_TEXTURE);
879 	glLoadMatrixf(mNormalizeMatrix);
880 	glMultMatrixf(lightProjMatrix_);
881 	glMultMatrixf(lightModelMatrix_);
882 	glMultMatrixf(modelMatrixI);
883 	glGetFloatv(GL_TEXTURE_MATRIX, shadowTextureMatrix_);
884 	glMatrixMode(GL_MODELVIEW);
885 }
886 
actualDrawLandShader()887 void Landscape::actualDrawLandShader()
888 {
889 	GLState glState(GLState::TEXTURE_ON | GLState::DEPTH_ON);
890 
891 	getSky().getSun().setLightPosition(false);
892 
893 	landShader_->use();
894 	landShader_->set_gl_texture(texture_, "mainmap", 0);
895 	landShader_->set_gl_texture(detailTexture_, "detailmap", 1);
896 	landShader_->set_gl_texture(arenaMainTexture_, "arenamap", 3);
897 
898 	bool showArenaArea = MainCamera::instance()->getShowArena();
899 	landShader_->set_uniform("showarena", showArenaArea?1.0f:0.0f);
900 
901 	if (getShadowFrameBuffer().bufferValid())
902 	{
903 		glActiveTextureARB(GL_TEXTURE2_ARB);
904 		glEnable(GL_TEXTURE_2D);
905 		landShader_->set_gl_texture(shadowFrameBuffer_, "shadow", 2);
906 		glMatrixMode(GL_TEXTURE);
907 		createShadowMatrix();
908 		glMatrixMode(GL_MODELVIEW);
909 	}
910 
911 	glActiveTextureARB(GL_TEXTURE0_ARB);
912 	glColor3f(1.0f, 1.0f, 1.0f);
913 
914 	// Draw Land
915 	GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_LAND");
916 	VisibilityPatchGrid::instance()->drawLand(0, false, false);
917 	GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_LAND");
918 
919 	// Draw Surround
920 	if (OptionsDisplay::instance()->getDrawSurround())
921 	{
922 		GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SURROUND");
923 		if (OptionsDisplay::instance()->getDrawWater() &&
924 			Landscape::instance()->getWater().getTransparency() == 1.0f)
925 		{
926 			// Disable Tex
927 			glActiveTextureARB(GL_TEXTURE2_ARB);
928 			glMatrixMode(GL_TEXTURE);
929 			glLoadIdentity();
930 			glMatrixMode(GL_MODELVIEW);
931 			glActiveTextureARB(GL_TEXTURE0_ARB);
932 
933 			landShader_->use_fixed();
934 
935 			groundTexture_.draw(true);
936 		}
937 		else
938 		{
939 			landShader_->set_gl_texture(groundTexture_, "mainmap", 0);
940 			landShader_->set_gl_texture(arenaSurroundTexture_, "arenamap", 3);
941 		}
942 
943 		VisibilityPatchGrid::instance()->drawSurround();
944 		GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "LANDSCAPE_SURROUND");
945 	}
946 
947 	// Disable Tex
948 	glActiveTextureARB(GL_TEXTURE2_ARB);
949 	glMatrixMode(GL_TEXTURE);
950 	glLoadIdentity();
951 	glMatrixMode(GL_MODELVIEW);
952 	glActiveTextureARB(GL_TEXTURE0_ARB);
953 
954 	landShader_->use_fixed();
955 }
956 
drawGraphicalTextureMap(GLTexture & texture)957 void Landscape::drawGraphicalTextureMap(GLTexture &texture)
958 {
959 	GLState state(GLState::TEXTURE_ON);
960 
961 	glColor3f( 1.f, 1.f, 1.f );
962 	glMatrixMode(GL_PROJECTION);
963 	glPushMatrix();
964 	glLoadIdentity();
965 	gluOrtho2D(0, 800, 0, 600);
966 	glMatrixMode(GL_TEXTURE);
967 	glPushMatrix();
968 	glLoadIdentity();
969 	glMatrixMode(GL_MODELVIEW);
970 	glPushMatrix();
971 	glLoadIdentity();
972 	texture.draw(true);
973 	glBegin(GL_QUADS);
974 		glTexCoord2f(0.f,   0.f);
975 		glVertex2i  (0,   0);
976 		glTexCoord2f(1.f, 0.f);
977 		glVertex2i  (300, 0);
978 		glTexCoord2f(1.f, 1.f);
979 		glVertex2i  (300, 300);
980 		glTexCoord2f(0.f,   1.f);
981 		glVertex2i  (0,   300);
982 	glEnd();
983 	glMatrixMode(GL_PROJECTION);
984 	glPopMatrix();
985 	glMatrixMode( GL_TEXTURE );
986 	glPopMatrix();
987 	glMatrixMode( GL_MODELVIEW );
988 	glPopMatrix();
989 }
990 
updatePlanATexture()991 void Landscape::updatePlanATexture()
992 {
993 	ImageModifier::removeWaterFromBitmap(
994 		ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getHeightMap(),
995 		bitmapPlan_, bitmapPlanAlpha_, bitmapPlanAlphaAlpha_,
996 		(water_->getWaterOn()?water_->getWaterHeight():-50.0f));
997 	DIALOG_ASSERT(planAlphaTexture_.replace(bitmapPlanAlpha_, false));
998 	planAlphaTexture_.draw();
999 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
1000 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
1001 }
1002 
restoreLandscapeTexture()1003 void Landscape::restoreLandscapeTexture()
1004 {
1005 	if (textureType_ == eDefault) return;
1006 
1007 	DIALOG_ASSERT(texture_.replace(mainMap_, false));
1008 	textureType_ = eDefault;
1009 }
1010 
savePlan()1011 void Landscape::savePlan()
1012 {
1013 	static unsigned counter = 0;
1014 	time_t currentTime = time(0);
1015 	bitmapPlan_.writeToFile(
1016 		S3D::getHomeFile(
1017 			S3D::formatStringBuffer("PlanShot-%i-%i.bmp", currentTime, counter++)));
1018 }
1019 
CameraContext()1020 Landscape::CameraContext::CameraContext()
1021 {
1022 	shadowMap_ = new ShadowMap();
1023 }
1024 
getShadowMap()1025 ShadowMap &Landscape::getShadowMap()
1026 {
1027 	if (GLCamera::getCurrentCamera() ==
1028 		&MainCamera::instance()->getCamera())
1029 	{
1030 		return *cameraContexts_[0].shadowMap_;
1031 	}
1032 	else
1033 	{
1034 		return *cameraContexts_[1].shadowMap_;
1035 	}
1036 }
1037 
1038