1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "FeatureDrawer.h"
4
5 #include "Game/Camera.h"
6 #include "Game/GlobalUnsynced.h"
7 #include "Map/MapInfo.h"
8 #include "Map/ReadMap.h"
9 #include "Map/BaseGroundDrawer.h"
10 #include "Rendering/GlobalRendering.h"
11 #include "Rendering/Env/IGroundDecalDrawer.h"
12 #include "Rendering/FarTextureHandler.h"
13 #include "Rendering/Env/ISky.h"
14 #include "Rendering/Env/ITreeDrawer.h"
15 #include "Rendering/Env/IWater.h"
16 #include "Rendering/GL/glExtra.h"
17 #include "Rendering/GL/myGL.h"
18 #include "Rendering/GL/VertexArray.h"
19 #include "Rendering/ShadowHandler.h"
20 #include "Rendering/Shaders/Shader.h"
21 #include "Rendering/Textures/S3OTextureHandler.h"
22 #include "Rendering/Textures/3DOTextureHandler.h"
23 #include "Rendering/UnitDrawer.h"
24 #include "Rendering/Models/WorldObjectModelRenderer.h"
25 #include "Sim/Features/Feature.h"
26 #include "Sim/Features/FeatureHandler.h"
27 #include "Sim/Misc/GlobalSynced.h"
28 #include "System/Config/ConfigHandler.h"
29 #include "System/EventHandler.h"
30 #include "System/myMath.h"
31 #include "System/Util.h"
32
33 #define DRAW_QUAD_SIZE 32
34
35 CONFIG(bool, ShowRezBars).defaultValue(true);
36
37 CONFIG(float, FeatureDrawDistance)
38 .defaultValue(6000.0f)
39 .minimumValue(0.0f)
40 .description("Maximum distance at which features will be drawn.");
41
42 CONFIG(float, FeatureFadeDistance)
43 .defaultValue(4500.0f)
44 .minimumValue(0.0f)
45 .description("Distance at which features will begin to fade from view.");
46
47 CFeatureDrawer* featureDrawer = NULL;
48
49 /******************************************************************************/
50
51 CR_BIND(CFeatureDrawer, )
52 CR_BIND(CFeatureDrawer::DrawQuad, )
53
54 CR_REG_METADATA(CFeatureDrawer, (
55 CR_POSTLOAD(PostLoad)
56 ))
57
58 /******************************************************************************/
59
60
61
CFeatureDrawer()62 CFeatureDrawer::CFeatureDrawer(): CEventClient("[CFeatureDrawer]", 313373, false)
63 {
64 eventHandler.AddClient(this);
65
66 drawQuadsX = gs->mapx/DRAW_QUAD_SIZE;
67 drawQuadsY = gs->mapy/DRAW_QUAD_SIZE;
68 drawQuads.resize(drawQuadsX * drawQuadsY);
69 featureDrawDistance = configHandler->GetFloat("FeatureDrawDistance");
70 featureFadeDistance = std::min(configHandler->GetFloat("FeatureFadeDistance"), featureDrawDistance);
71 opaqueModelRenderers.resize(MODELTYPE_OTHER, NULL);
72 cloakedModelRenderers.resize(MODELTYPE_OTHER, NULL);
73
74 for (int modelType = MODELTYPE_3DO; modelType < MODELTYPE_OTHER; modelType++) {
75 opaqueModelRenderers[modelType] = IWorldObjectModelRenderer::GetInstance(modelType);
76 cloakedModelRenderers[modelType] = IWorldObjectModelRenderer::GetInstance(modelType);
77 }
78 }
79
80
~CFeatureDrawer()81 CFeatureDrawer::~CFeatureDrawer()
82 {
83 eventHandler.RemoveClient(this);
84
85 for (int modelType = MODELTYPE_3DO; modelType < MODELTYPE_OTHER; modelType++) {
86 delete opaqueModelRenderers[modelType];
87 delete cloakedModelRenderers[modelType];
88 }
89
90 opaqueModelRenderers.clear();
91 cloakedModelRenderers.clear();
92 }
93
94
95
RenderFeatureCreated(const CFeature * feature)96 void CFeatureDrawer::RenderFeatureCreated(const CFeature* feature)
97 {
98 CFeature* f = const_cast<CFeature*>(feature);
99 texturehandlerS3O->UpdateDraw();
100
101 if (feature->def->drawType == DRAWTYPE_MODEL) {
102 f->drawQuad = -1;
103 UpdateDrawQuad(f);
104
105 unsortedFeatures.insert(f);
106 }
107 }
108
RenderFeatureDestroyed(const CFeature * feature)109 void CFeatureDrawer::RenderFeatureDestroyed(const CFeature* feature)
110 {
111 CFeature* f = const_cast<CFeature*>(feature);
112
113 if (f->def->drawType == DRAWTYPE_MODEL) {
114 unsortedFeatures.erase(f);
115 }
116
117 if (f->drawQuad >= 0) {
118 DrawQuad* dq = &drawQuads[f->drawQuad];
119 dq->features.erase(f);
120 }
121
122 if (f->model) {
123 opaqueModelRenderers[MDL_TYPE(f)]->DelFeature(f);
124 cloakedModelRenderers[MDL_TYPE(f)]->DelFeature(f);
125 }
126
127 if (feature->objectDef->decalDef.useGroundDecal)
128 groundDecals->RemoveSolidObject(f, NULL);
129 }
130
131
RenderFeatureMoved(const CFeature * feature,const float3 & oldpos,const float3 & newpos)132 void CFeatureDrawer::RenderFeatureMoved(const CFeature* feature, const float3& oldpos, const float3& newpos)
133 {
134 CFeature* f = const_cast<CFeature*>(feature);
135
136 UpdateDrawQuad(f);
137 }
138
UpdateDrawQuad(CFeature * feature)139 void CFeatureDrawer::UpdateDrawQuad(CFeature* feature)
140 {
141 const int oldDrawQuad = feature->drawQuad;
142 if (oldDrawQuad >= -1) {
143 int newDrawQuadX = feature->pos.x / DRAW_QUAD_SIZE / SQUARE_SIZE;
144 int newDrawQuadY = feature->pos.z / DRAW_QUAD_SIZE / SQUARE_SIZE;
145 newDrawQuadX = Clamp(newDrawQuadX, 0, drawQuadsX - 1);
146 newDrawQuadY = Clamp(newDrawQuadY, 0, drawQuadsY - 1);
147 const int newDrawQuad = newDrawQuadY * drawQuadsX + newDrawQuadX;
148
149 if (oldDrawQuad != newDrawQuad) {
150 //TODO check if out of map features get drawn, when the camera is outside of the map
151 // (q: does DrawGround render the border quads in such cases?)
152 assert(oldDrawQuad < drawQuadsX * drawQuadsY);
153 assert(newDrawQuad < drawQuadsX * drawQuadsY);
154
155 if (oldDrawQuad >= 0)
156 drawQuads[oldDrawQuad].features.erase(feature);
157 drawQuads[newDrawQuad].features.insert(feature);
158 feature->drawQuad = newDrawQuad;
159 }
160 }
161 }
162
163
Update()164 void CFeatureDrawer::Update()
165 {
166 eventHandler.UpdateDrawFeatures();
167
168 {
169 for (std::set<CFeature*>::iterator fsi = unsortedFeatures.begin(); fsi != unsortedFeatures.end(); ++fsi) {
170 UpdateDrawPos(*fsi);
171 }
172 }
173 }
174
175
UpdateDrawPos(CFeature * f)176 inline void CFeatureDrawer::UpdateDrawPos(CFeature* f)
177 {
178 const float time = globalRendering->timeOffset;
179
180 f->drawPos = f->pos + (f->speed * time);
181 f->drawMidPos = f->midPos + (f->speed * time);
182 }
183
184
Draw()185 void CFeatureDrawer::Draw()
186 {
187 ISky::SetupFog();
188
189 CBaseGroundDrawer* gd = readMap->GetGroundDrawer();
190
191 if (gd->DrawExtraTex()) {
192 glActiveTextureARB(GL_TEXTURE2_ARB);
193 glEnable(GL_TEXTURE_2D);
194 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_SIGNED_ARB);
195 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
196
197 glMultiTexCoord4f(GL_TEXTURE2_ARB, 1.0f,1.0f,1.0f,1.0f); // workaround a nvidia bug with TexGen
198 SetTexGen(1.0f / (gs->pwr2mapx * SQUARE_SIZE), 1.0f / (gs->pwr2mapy * SQUARE_SIZE), 0.0f, 0.0f);
199
200 glBindTexture(GL_TEXTURE_2D, gd->GetActiveInfoTexture());
201 glActiveTextureARB(GL_TEXTURE0_ARB);
202 }
203
204 unitDrawer->SetupForUnitDrawing(false);
205 GetVisibleFeatures(0, true);
206
207 for (int modelType = MODELTYPE_3DO; modelType < MODELTYPE_OTHER; modelType++) {
208 opaqueModelRenderers[modelType]->PushRenderState();
209 DrawOpaqueFeatures(modelType);
210 opaqueModelRenderers[modelType]->PopRenderState();
211 }
212
213 unitDrawer->CleanUpUnitDrawing(false);
214
215 farTextureHandler->Draw();
216
217 if (gd->DrawExtraTex()) {
218 glActiveTextureARB(GL_TEXTURE2_ARB);
219 glDisable(GL_TEXTURE_2D);
220 glDisable(GL_TEXTURE_GEN_S);
221 glDisable(GL_TEXTURE_GEN_T);
222 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
223 glActiveTextureARB(GL_TEXTURE0_ARB);
224 }
225
226 glDisable(GL_TEXTURE_2D);
227 glDisable(GL_FOG);
228 }
229
DrawOpaqueFeatures(int modelType)230 void CFeatureDrawer::DrawOpaqueFeatures(int modelType)
231 {
232 FeatureRenderBin& featureBin = opaqueModelRenderers[modelType]->GetFeatureBinMutable();
233
234 FeatureRenderBin::iterator featureBinIt;
235 FeatureSet::iterator featureSetIt;
236
237 for (featureBinIt = featureBin.begin(); featureBinIt != featureBin.end(); ++featureBinIt) {
238 if (modelType != MODELTYPE_3DO) {
239 texturehandlerS3O->SetS3oTexture(featureBinIt->first);
240 }
241
242 FeatureSet& featureSet = featureBinIt->second;
243
244 for (featureSetIt = featureSet.begin(); featureSetIt != featureSet.end(); ) {
245 if (!DrawFeatureNow(featureSetIt->first)) {
246 featureSetIt = set_erase(featureSet, featureSetIt);
247 } else {
248 ++featureSetIt;
249 }
250 }
251 }
252 }
253
DrawFeatureNow(const CFeature * feature,float alpha)254 bool CFeatureDrawer::DrawFeatureNow(const CFeature* feature, float alpha)
255 {
256 if (feature->IsInVoid()) { return false; }
257 if (!camera->InView(feature->drawMidPos, feature->drawRadius)) { return false; }
258 if (!feature->IsInLosForAllyTeam(gu->myAllyTeam) && !gu->spectatingFullView) { return false; }
259
260 const float sqDist = (feature->pos - camera->GetPos()).SqLength();
261 const float farLength = feature->sqRadius * unitDrawer->unitDrawDistSqr;
262 const float sqFadeDistEnd = featureDrawDistance * featureDrawDistance;
263
264 if (sqDist >= std::min(farLength, sqFadeDistEnd)) return false;
265
266 glPushMatrix();
267 glMultMatrixf(feature->GetTransformMatrixRef());
268
269 unitDrawer->SetTeamColour(feature->team, alpha);
270
271 if (!(feature->luaDraw && eventHandler.DrawFeature(feature))) {
272 feature->model->DrawStatic();
273 }
274
275 glPopMatrix();
276
277 return true;
278 }
279
280
281
282
283
284
DrawFadeFeatures(bool noAdvShading)285 void CFeatureDrawer::DrawFadeFeatures(bool noAdvShading)
286 {
287 const bool oldAdvShading = unitDrawer->UseAdvShading();
288
289 {
290 unitDrawer->SetUseAdvShading(unitDrawer->UseAdvShading() && !noAdvShading);
291
292 if (unitDrawer->UseAdvShading()) {
293 unitDrawer->SetupForUnitDrawing(false);
294 } else {
295 unitDrawer->SetupForGhostDrawing();
296 }
297
298 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
299 glDepthMask(GL_TRUE);
300 glEnable(GL_ALPHA_TEST);
301 glAlphaFunc(GL_GREATER, 0.5f);
302
303 ISky::SetupFog();
304
305 {
306 for (int modelType = MODELTYPE_3DO; modelType < MODELTYPE_OTHER; modelType++) {
307 cloakedModelRenderers[modelType]->PushRenderState();
308 DrawFadeFeaturesHelper(modelType);
309 cloakedModelRenderers[modelType]->PopRenderState();
310 }
311 }
312
313 glDisable(GL_FOG);
314
315 glPopAttrib();
316
317 if (unitDrawer->UseAdvShading()) {
318 unitDrawer->CleanUpUnitDrawing(false);
319 } else {
320 unitDrawer->CleanUpGhostDrawing();
321 }
322
323 unitDrawer->SetUseAdvShading(oldAdvShading);
324 }
325 }
326
DrawFadeFeaturesHelper(int modelType)327 void CFeatureDrawer::DrawFadeFeaturesHelper(int modelType) {
328 {
329 FeatureRenderBin& featureBin = cloakedModelRenderers[modelType]->GetFeatureBinMutable();
330
331 for (FeatureRenderBinIt it = featureBin.begin(); it != featureBin.end(); ++it) {
332 if (modelType != MODELTYPE_3DO) {
333 texturehandlerS3O->SetS3oTexture(it->first);
334 }
335
336 DrawFadeFeaturesSet(it->second, modelType);
337 }
338 }
339 }
340
DrawFadeFeaturesSet(FeatureSet & fadeFeatures,int modelType)341 void CFeatureDrawer::DrawFadeFeaturesSet(FeatureSet& fadeFeatures, int modelType)
342 {
343 for (FeatureSet::iterator fi = fadeFeatures.begin(); fi != fadeFeatures.end(); ) {
344 const float cols[] = {1.0f, 1.0f, 1.0f, fi->second};
345
346 if (modelType != MODELTYPE_3DO) {
347 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, cols);
348 }
349
350 // hack, sorting objects by distance would look better
351 glAlphaFunc(GL_GREATER, fi->second / 2.0f);
352 glColor4fv(cols);
353
354 if (!DrawFeatureNow(fi->first, fi->second)) {
355 fi = set_erase(fadeFeatures, fi);
356 } else {
357 ++fi;
358 }
359 }
360 }
361
362
363
364
DrawShadowPass()365 void CFeatureDrawer::DrawShadowPass()
366 {
367 glPolygonOffset(1.0f, 1.0f);
368 glEnable(GL_POLYGON_OFFSET_FILL);
369
370 Shader::IProgramObject* po =
371 shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_MODEL);
372
373 po->Enable();
374
375 {
376 // note: for the shadow-pass, we want to make sure
377 // out-of-view features casting frustum-intersecting
378 // shadows are still rendered, but this is expensive
379 // and does not make much difference
380 //
381 // GetVisibleFeatures(1, false);
382
383 // need the alpha-mask for transparent features
384 glEnable(GL_TEXTURE_2D);
385 glPushAttrib(GL_COLOR_BUFFER_BIT);
386 glEnable(GL_ALPHA_TEST);
387 glAlphaFunc(GL_GREATER, 0.5f);
388
389 // needed for 3do models (else they will use any currently bound texture)
390 // note: texture0 is by default a 1x1 texture with rgba(0,0,0,255)
391 // (we are just interested in the 255 alpha here)
392 glBindTexture(GL_TEXTURE_2D, 0);
393
394 // 3DO's have clockwise-wound faces and
395 // (usually) holes, so disable backface
396 // culling for them
397 glDisable(GL_CULL_FACE);
398 DrawOpaqueFeatures(MODELTYPE_3DO);
399 glEnable(GL_CULL_FACE);
400
401 for (int modelType = MODELTYPE_S3O; modelType < MODELTYPE_OTHER; modelType++) {
402 DrawOpaqueFeatures(modelType);
403 }
404
405 glPopAttrib();
406 glDisable(GL_TEXTURE_2D);
407 }
408
409 po->Disable();
410
411 glDisable(GL_POLYGON_OFFSET_FILL);
412 }
413
414
415
416 class CFeatureQuadDrawer : public CReadMap::IQuadDrawer {
417 public:
418 int drawQuadsX;
419 bool drawReflection, drawRefraction;
420 float sqFadeDistBegin;
421 float sqFadeDistEnd;
422 bool farFeatures;
423
424 std::vector<CFeatureDrawer::DrawQuad>* drawQuads;
425
DrawQuad(int x,int y)426 void DrawQuad(int x, int y)
427 {
428 std::vector<IWorldObjectModelRenderer*>& opaqueModelRenderers = featureDrawer->opaqueModelRenderers;
429 std::vector<IWorldObjectModelRenderer*>& cloakedModelRenderers = featureDrawer->cloakedModelRenderers;
430
431 const CFeatureDrawer::DrawQuad* dq = &(*drawQuads)[y * drawQuadsX + x];
432
433 for (std::set<CFeature*>::const_iterator fi = dq->features.begin(); fi != dq->features.end(); ++fi) {
434 CFeature* f = (*fi);
435
436 if (f->IsInVoid())
437 continue;
438
439 assert(f->def->drawType == DRAWTYPE_MODEL);
440
441 if (gu->spectatingFullView || f->IsInLosForAllyTeam(gu->myAllyTeam)) {
442 if (drawReflection) {
443 float3 zeroPos;
444
445 if (f->midPos.y < 0.0f) {
446 zeroPos = f->midPos;
447 } else {
448 const float dif = f->midPos.y - camera->GetPos().y;
449 zeroPos =
450 camera->GetPos() * (f->midPos.y / dif) +
451 f->midPos * (-camera->GetPos().y / dif);
452 }
453 if (CGround::GetApproximateHeight(zeroPos.x, zeroPos.z, false) > f->drawRadius) {
454 continue;
455 }
456 }
457 if (drawRefraction) {
458 if (f->pos.y > 0.0f)
459 continue;
460 }
461
462 const float sqDist = (f->pos - camera->GetPos()).SqLength();
463 const float farLength = f->sqRadius * unitDrawer->unitDrawDistSqr;
464
465 if (sqDist < farLength) {
466 float sqFadeDistE;
467 float sqFadeDistB;
468
469 if (farLength < sqFadeDistEnd) {
470 sqFadeDistE = farLength;
471 sqFadeDistB = farLength * sqFadeDistBegin / sqFadeDistEnd;
472 } else {
473 sqFadeDistE = sqFadeDistEnd;
474 sqFadeDistB = sqFadeDistBegin;
475 }
476
477 if (sqDist < sqFadeDistB) {
478 cloakedModelRenderers[MDL_TYPE(f)]->DelFeature(f);
479 if (camera->InView(f->drawMidPos, f->drawRadius))
480 opaqueModelRenderers[MDL_TYPE(f)]->AddFeature(f);
481 } else if (sqDist < sqFadeDistE) {
482 const float falpha = 1.0f - (sqDist - sqFadeDistB) / (sqFadeDistE - sqFadeDistB);
483 opaqueModelRenderers[MDL_TYPE(f)]->DelFeature(f);
484 if (camera->InView(f->drawMidPos, f->drawRadius))
485 cloakedModelRenderers[MDL_TYPE(f)]->AddFeature(f, falpha);
486 }
487 } else {
488 if (farFeatures) {
489 farTextureHandler->Queue(f);
490 }
491 }
492 }
493 }
494 }
495 };
496
497
498
GetVisibleFeatures(int extraSize,bool drawFar)499 void CFeatureDrawer::GetVisibleFeatures(int extraSize, bool drawFar)
500 {
501 CFeatureQuadDrawer drawer;
502 drawer.drawQuads = &drawQuads;
503 drawer.drawQuadsX = drawQuadsX;
504 drawer.drawReflection = water->DrawReflectionPass();
505 drawer.drawRefraction = water->DrawRefractionPass();
506 drawer.sqFadeDistEnd = featureDrawDistance * featureDrawDistance;
507 drawer.sqFadeDistBegin = featureFadeDistance * featureFadeDistance;
508 drawer.farFeatures = drawFar;
509
510 readMap->GridVisibility(camera, DRAW_QUAD_SIZE, featureDrawDistance, &drawer, extraSize);
511 }
512
SwapFeatures()513 void CFeatureDrawer::SwapFeatures() {
514 for(int i = 0; i < MODELTYPE_OTHER; ++i) {
515 opaqueModelRenderers[i]->SwapFeatures();
516 cloakedModelRenderers[i]->SwapFeatures();
517 }
518 }
519
PostLoad()520 void CFeatureDrawer::PostLoad()
521 {
522 drawQuadsX = gs->mapx/DRAW_QUAD_SIZE;
523 drawQuadsY = gs->mapy/DRAW_QUAD_SIZE;
524 drawQuads.clear();
525 drawQuads.resize(drawQuadsX * drawQuadsY);
526
527 const CFeatureSet& fs = featureHandler->GetActiveFeatures();
528 for (CFeatureSet::const_iterator it = fs.begin(); it != fs.end(); ++it)
529 if ((*it)->drawQuad >= 0)
530 drawQuads[(*it)->drawQuad].features.insert(*it);
531 }
532