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