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 <tankgraph/TargetRendererImpl.h>
22 #include <tankgraph/TargetParticleRenderer.h>
23 #include <target/TargetShield.h>
24 #include <target/TargetState.h>
25 #include <target/TargetLife.h>
26 #include <client/ScorchedClient.h>
27 #include <graph/ParticleEngine.h>
28 #include <graph/ParticleTypes.h>
29 #include <graph/OptionsDisplay.h>
30 #include <common/Defines.h>
31 #include <sky/Hemisphere.h>
32 #include <weapons/ShieldRound.h>
33 #include <weapons/ShieldSquare.h>
34 #include <weapons/Accessory.h>
35 #include <actions/TargetFalling.h>
36 #include <GLEXT/GLState.h>
37 #include <GLEXT/GLTexture.h>
38 #include <image/ImageFactory.h>
39 #include <GLEXT/GLViewPort.h>
40 #include <GLEXT/GLCameraFrustum.h>
41 #include <GLEXT/GLCamera.h>
42 #include <land/VisibilityPatchGrid.h>
43 
44 TargetRendererImpl::HighlightType TargetRendererImpl::highlightType_ =
45 	TargetRendererImpl::eNoHighlight;
46 
TargetRendererImpl(Target * target)47 TargetRendererImpl::TargetRendererImpl(Target *target) :
48 	target_(target),
49 	particleMade_(false), tree_(false), matrixCached_(false),
50 	posX_(0.0f), posY_(0.0f), posZ_(0.0f),
51 	currentVisibilityPatch_(0), patchEpoc_(-1)
52 {
53 
54 }
55 
~TargetRendererImpl()56 TargetRendererImpl::~TargetRendererImpl()
57 {
58 	setMovedPatch(0);
59 }
60 
moved()61 void TargetRendererImpl::moved()
62 {
63 	if (VisibilityPatchGrid::instance()->getEpocNumber() == 0) return;
64 
65 	TargetVisibilityPatch *newPatch = 0;
66 	if (target_->getVisible())
67 	{
68 		FixedVector &position = target_->getLife().getTargetPosition();
69 		newPatch = VisibilityPatchGrid::instance()->getTargetVisibilityPatch(
70 			position[0].asInt(), position[1].asInt());
71 	}
72 	setMovedPatch(newPatch);
73 	matrixCached_ = false;
74 }
75 
setMovedPatch(TargetVisibilityPatch * newPatch)76 void TargetRendererImpl::setMovedPatch(TargetVisibilityPatch *newPatch)
77 {
78 	float boundingSize = target_->getLife().getFloatBoundingSize();
79 	if (boundingSize > 32.0f) // Landscape square size
80 	{
81 		if (newPatch) TargetVisibilityPatch::addLargeTarget(target_);
82 		else TargetVisibilityPatch::removeLargeTarget(target_);
83 
84 		return;
85 	}
86 
87 	if (patchEpoc_ != VisibilityPatchGrid::instance()->getEpocNumber())
88 	{
89 		currentVisibilityPatch_ = 0;
90 		patchEpoc_ = VisibilityPatchGrid::instance()->getEpocNumber();
91 	}
92 	if (newPatch != currentVisibilityPatch_)
93 	{
94 		if (currentVisibilityPatch_)
95 		{
96 			if (!tree_)
97 			{
98 				currentVisibilityPatch_->removeTarget(target_);
99 				if (!target_->getTargetName().empty())
100 					currentVisibilityPatch_->removeTooltip(target_);
101 			}
102 			else
103 			{
104 				currentVisibilityPatch_->removeTree(target_);
105 			}
106 		}
107 		if (newPatch)
108 		{
109 			if (!tree_)
110 			{
111 				newPatch->addTarget(target_);
112 				if (!target_->getTargetName().empty())
113 					newPatch->addTooltip(target_);
114 			}
115 			else
116 			{
117 				newPatch->addTree(target_);
118 			}
119 		}
120 		currentVisibilityPatch_ = newPatch;
121 	}
122 }
123 
getVisible()124 bool TargetRendererImpl::getVisible()
125 {
126 	if (!currentVisibilityPatch_ || !currentVisibilityPatch_->getVisible()) return false;
127 	if (!target_->getVisible()) return false;
128 
129 	return true;
130 }
131 
drawShield(float shieldHit,float totalTime)132 void TargetRendererImpl::drawShield(float shieldHit, float totalTime)
133 {
134 	// Create the shield textures
135 	static GLTextureReference shieldtexture(ImageID(
136 		S3D::eModLocation,
137 		"data/textures/shield.bmp",
138 		"data/textures/shielda.bmp",
139 		false));
140 	static GLTextureReference texture(ImageID(
141 		S3D::eModLocation,
142 		"data/textures/bordershield/grid2.bmp",
143 		"data/textures/bordershield/grid2.bmp",
144 		false));
145 	static GLTextureReference texture2(ImageID(
146 		S3D::eModLocation,
147 		"data/textures/bordershield/grid22.bmp",
148 		"data/textures/bordershield/grid22.bmp",
149 		false));
150 	static GLTextureReference magtexture(ImageID(
151 		S3D::eModLocation,
152 		"data/textures/shield2.bmp",
153 		"data/textures/shield2.bmp",
154 		false));
155 	static GLUquadric *obj = 0;
156 	if (!obj)
157 	{
158 		obj = gluNewQuadric();
159 		gluQuadricTexture(obj, GL_TRUE);
160 	}
161 
162 	// Create the shield objects
163 	static unsigned int squareListNo = 0;
164 	static unsigned int smallListNo = 0;
165 	static unsigned int smallHalfListNo = 0;
166 	static unsigned int spiralListNo = 0;
167 	GLTexture magTexture;
168 	if (!smallListNo)
169 	{
170 		glNewList(smallListNo = glGenLists(1), GL_COMPILE);
171 			gluSphere(obj, 1.0f, 8, 8);
172 		glEndList();
173 		glNewList(squareListNo = glGenLists(1), GL_COMPILE);
174 			glBegin(GL_QUADS);		// Draw The Cube Using quads
175 				glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f,-1.0f);	// Top Right Of The Quad (Top)
176 				glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f,-1.0f);	// Top Left Of The Quad (Top)
177 				glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);	// Bottom Left Of The Quad (Top)
178 				glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);	// Bottom Right Of The Quad (Top)
179 
180 				glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f);	// Top Right Of The Quad (Bottom)
181 				glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);	// Top Left Of The Quad (Bottom)
182 				glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f);	// Bottom Left Of The Quad (Bottom)
183 				glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,-1.0f,-1.0f);	// Bottom Right Of The Quad (Bottom)
184 
185 				glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);	// Top Right Of The Quad (Front)
186 				glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);	// Top Left Of The Quad (Front)
187 				glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f);	// Bottom Left Of The Quad (Front)
188 				glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,-1.0f, 1.0f);	// Bottom Right Of The Quad (Front)
189 
190 				glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f);	// Top Right Of The Quad (Back)
191 				glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f,-1.0f);	// Top Left Of The Quad (Back)
192 				glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);	// Bottom Left Of The Quad (Back)
193 				glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f,-1.0f);	// Bottom Right Of The Quad (Back)
194 
195 				glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);	// Top Right Of The Quad (Left)
196 				glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f,-1.0f);	// Top Left Of The Quad (Left)
197 				glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,-1.0f,-1.0f);	// Bottom Left Of The Quad (Left)
198 				glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f);	// Bottom Right Of The Quad (Left)
199 
200 				glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f,-1.0f);	// Top Right Of The Quad (Right)
201 				glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);	// Top Left Of The Quad (Right)
202 				glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,-1.0f, 1.0f);	// Bottom Left Of The Quad (Right)
203 				glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,-1.0f,-1.0f);	// Bottom Right Of The Quad (Right)
204 			glEnd();
205 		glEndList();
206 		glNewList(smallHalfListNo = glGenLists(1), GL_COMPILE);
207 			Hemisphere::draw(1.0f, 1.0f, 10, 10, 6, 0, 10, 10, true);
208 			Hemisphere::draw(1.0f, 1.0f, 10, 10, 6, 0, 10, 10, false);
209 		glEndList();
210 		glNewList(spiralListNo = glGenLists(1), GL_COMPILE);
211 			float height = 0.0f;
212 			float width = 0.0f;
213 			float totalA = 5.0f * PI;
214 			float aInc = PI / 6.0f;
215 			glBegin(GL_QUAD_STRIP);
216 			for (float a=0.0f; a<totalA; a+=aInc)
217 			{
218 				height += 0.05f;
219 				width += 0.05f;
220 				float x = getFastSin(a) * width;
221 				float y = getFastCos(a) * width;
222 				float z = height;
223 				glTexCoord2f(a / totalA, 0.0f);
224 				glVertex3f(x, y, z);
225 				glTexCoord2f(a / totalA, 1.0f);
226 				glVertex3f(x, y, z - 0.4f);
227 			}
228 			glEnd();
229 
230 			height = 0.0f;
231 			width = 0.0f;
232 			glBegin(GL_QUAD_STRIP);
233 			for (float a=0.0f; a<5.0f * PI; a+=PI/6.0f)
234 			{
235 				height += 0.05f;
236 				width += 0.05f;
237 				float x = getFastSin(a) * width;
238 				float y = getFastCos(a) * width;
239 				float z = height;
240 				glTexCoord2f(a / totalA, 0.0f);
241 				glVertex3f(x, y, z - 0.4f);
242 				glTexCoord2f(a / totalA, 1.0f);
243 				glVertex3f(x, y, z);
244 			}
245 			glEnd();
246 		glEndList();
247 	}
248 
249 	// Draw the actual shield
250 	Accessory *accessory = target_->getShield().getGraphicalCurrentShield();
251 	if (!accessory) return;
252 	Shield *shield = (Shield *) accessory->getAction();
253 
254 	GLState state(GLState::BLEND_ON | GLState::TEXTURE_ON);
255 	Vector &position = target_->getLife().getFloatPosition();
256 	Vector &color = shield->getColor();
257 
258 	if (shield->getRound())
259 	{
260 		ShieldRound *round = (ShieldRound *) shield;
261 		if (shield->getShieldType() == Shield::ShieldTypeRoundMag)
262 		{
263 			magtexture.draw();
264 
265 			glDepthMask(GL_FALSE);
266 			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
267 			glColor4f(color[0], color[1], color[2], 0.4f);
268 			glPushMatrix();
269 				glTranslatef(position[0], position[1], position[2] + 1.0f);
270 				float scale = round->getActualRadius().asFloat() / 3.0f;
271 				glScalef(scale, scale, scale);
272 
273 				glRotatef(totalTime * 800.0f, 0.0f, 0.0f, 1.0f);
274 				glCallList(spiralListNo);
275 				glRotatef(120.0f, 0.0f, 0.0f, 1.0f);
276 				glCallList(spiralListNo);
277 				glRotatef(120.0f, 0.0f, 0.0f, 1.0f);
278 				glCallList(spiralListNo);
279 			glPopMatrix();
280 			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
281 			glDepthMask(GL_TRUE);
282 		}
283 		else if (round->getHalfShield())
284 		{
285 			texture.draw();
286 			glPushMatrix();
287 				glColor4f(color[0], color[1], color[2], 0.5f + shieldHit);
288 				glTranslatef(position[0], position[1], position[2]);
289 				glScalef(
290 					round->getActualRadius().asFloat(),
291 					round->getActualRadius().asFloat(),
292 					round->getActualRadius().asFloat());
293 				glCallList(smallHalfListNo);
294 			glPopMatrix();
295 		}
296 		else
297 		{
298 			texture.draw();
299 			glPushMatrix();
300 				glColor4f(color[0], color[1], color[2], 0.5f + shieldHit);
301 				glTranslatef(position[0], position[1], position[2]);
302 				glScalef(
303 					round->getActualRadius().asFloat(),
304 					round->getActualRadius().asFloat(),
305 					round->getActualRadius().asFloat());
306 				glCallList(smallListNo);
307 			glPopMatrix();
308 
309 			if (round->getGlow())
310 			{
311 				shieldtexture.draw();
312 				GLCameraFrustum::instance()->drawBilboard(
313 					position,
314 					color,
315 					1.0f - shieldHit,
316 					round->getActualRadius().asFloat() * 0.95f,
317 					round->getActualRadius().asFloat() * 0.95f,
318 					true, // Additive
319 					0); // texcoord
320 			}
321 		}
322 	}
323 	else
324 	{
325 		ShieldSquare *square = (ShieldSquare *) shield;
326 
327 		texture.draw();
328 		glPushMatrix();
329 			glColor4f(color[0], color[1], color[2], 0.5f + shieldHit);
330 			glTranslatef(position[0], position[1], position[2]);
331 			glScalef(
332 				square->getSize()[0].asFloat(),
333 				square->getSize()[1].asFloat(),
334 				square->getSize()[2].asFloat());
335 			glCallList(squareListNo);
336 		glPopMatrix();
337 	}
338 }
339 
drawParachute()340 void TargetRendererImpl::drawParachute()
341 {
342 	static GLuint listNo = 0;
343 	if (!listNo)
344 	{
345 		float a;
346 		glNewList(listNo = glGenLists(1), GL_COMPILE);
347 			glColor3f(1.0f, 1.0f, 1.0f);
348 			glBegin(GL_LINES);
349 				for (a=0.0f; a< 3.14f*2.0f; a+=3.14f / 4.0f)
350 				{
351 					glVertex3f(0.0f, 0.0f, 0.0f);
352 					glVertex3f(sinf(a) * 2.0f, cosf(a) * 2.0f, 2.0f);
353 				}
354 			glEnd();
355 			glBegin(GL_TRIANGLE_FAN);
356 				glVertex3f(0.0f, 0.0f, 3.0f);
357 
358 				glColor3f(0.5f, 0.5f, 0.5f);
359 				for (a=3.14f*2.0f; a> 0.0f; a-=3.14f / 4.0f)
360 				{
361 					glVertex3f(sinf(a) * 2.0f, cosf(a) * 2.0f, 2.0f);
362 				}
363 			glEnd();
364 		glEndList();
365 	}
366 
367 	// Check this tank is falling
368 	if (!target_->getTargetState().getFalling()) return;
369 
370 	// Check this tank has parachutes
371 	if (!target_->getTargetState().getFalling()->getParachute())
372 	{
373 		return;
374 	}
375 
376 	Vector &position = target_->getLife().getFloatPosition();
377 	GLState state(GLState::TEXTURE_OFF);
378 	glPushMatrix();
379 		glTranslatef(position[0], position[1], position[2]);
380 		glCallList(listNo);
381 	glPopMatrix();
382 }
383 
createParticle()384 void TargetRendererImpl::createParticle()
385 {
386 	// Check if we have made the particle
387 	// We may not have if there were not enough to create the
388 	// tank in the first place
389 	if (particleMade_) return;
390 
391 	// If this is a target we only need the particle
392 	// if we have a shield or if we are falling
393 	if (target_->getType() != Target::TypeTank)
394 	{
395 		if (!target_->getShield().getGraphicalCurrentShield() &&
396 			(tree_ || !target_->getTargetState().getFalling()))
397 		{
398 			return;
399 		}
400 	}
401 
402 	// Else we need the particle
403 	{
404 
405 		// Pretent the tank is actually a particle, this is so
406 		// it gets rendered during the particle renderering phase
407 		// and using the correct z ordering
408 		Particle *particle =
409 			ScorchedClient::instance()->getParticleEngine().
410 				getNextAliveParticle(ParticleTarget);
411 		if (particle)
412 		{
413 			particle->setParticle(
414 				1000.0f,  1.0f, 1.0f, //float life, float mass, float friction,
415 				Vector::getNullVector(), Vector::getNullVector(), //Vector &velocity, Vector &gravity,
416 				Vector::getNullVector(), Vector::getNullVector(), //Vector &color, Vector &colorCounter,
417 				Vector::getNullVector(), Vector::getNullVector(), //Vector &size, Vector &sizeCounter,
418 				1.0f, 0.0f, // float alpha, float alphaCounter,
419 				false, //bool additiveTexture,
420 				false); //bool windAffect);
421 
422 			particleMade_ = true;
423 			particle->life_ = 1000.0f;
424 			particle->renderer_ = TargetParticleRenderer::getInstance();
425 			particle->userData_ = new TargetParticleUserData(target_->getPlayerId());
426 		}
427 	}
428 }
429 
getTargetSize()430 float TargetRendererImpl::getTargetSize()
431 {
432 	// Target size
433 	float targetSize = target_->getLife().getFloatBoundingSize();
434 	float shieldSize = target_->getShield().getShieldBoundingSize().asFloat();
435 	float size = MAX(targetSize, shieldSize);
436 	return size;
437 }
438 
getTargetFade(float distance,float size)439 float TargetRendererImpl::getTargetFade(float distance, float size)
440 {
441 	// Figure out the drawing distance
442 	float drawCullingDistance = OptionsDisplay::instance()->getDrawCullingDistance() * size;
443 	float drawFadeStartDistance =  OptionsDisplay::instance()->getDrawFadeStartDistance();
444 	float drawFadeDistance = drawCullingDistance - drawFadeStartDistance;
445 	float fade = 1.0f;
446 	if (distance > drawFadeStartDistance)
447 	{
448 		fade = 1.0f - ((distance - drawFadeStartDistance) / drawFadeDistance);
449 	}
450 
451 	return fade;
452 }
453 
storeTarget2DPos()454 void TargetRendererImpl::storeTarget2DPos()
455 {
456 	if (target_->getTargetName().empty()) return;
457 
458 	Vector &tankTurretPos =
459 		target_->getLife().getFloatCenterPosition();
460 	Vector camDir =
461 		GLCamera::getCurrentCamera()->getLookAt() -
462 		GLCamera::getCurrentCamera()->getCurrentPos();
463 	Vector tankDir = tankTurretPos -
464 		GLCamera::getCurrentCamera()->getCurrentPos();
465 
466 	if (camDir.dotP(tankDir) < 0.0f)
467 	{
468 		posX_ = - 1000.0;
469 	}
470 	else
471 	{
472 		static GLdouble modelMatrix[16];
473 		static GLdouble projMatrix[16];
474 		static GLint viewport[4];
475 
476 		glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
477 		glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
478 		glGetIntegerv(GL_VIEWPORT, viewport);
479 
480 		viewport[2] = GLViewPort::getWidth();
481 		viewport[3] = GLViewPort::getHeight();
482 		gluProject(
483 			tankTurretPos[0],
484 			tankTurretPos[1],
485 			tankTurretPos[2],
486 			modelMatrix, projMatrix, viewport,
487 			&posX_,
488 			&posY_,
489 			&posZ_);
490 	}
491 }
492