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