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