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 <sprites/MissileActionRenderer.h>
22 #include <sprites/ExplosionTextures.h>
23 #include <GLEXT/GLCameraFrustum.h>
24 #include <weapons/Accessory.h>
25 #include <actions/ShotProjectile.h>
26 #include <landscape/Landscape.h>
27 #include <landscapemap/LandscapeMaps.h>
28 #include <landscape/ShadowMap.h>
29 #include <graph/OptionsDisplay.h>
30 #include <common/Defines.h>
31 #include <target/TargetContainer.h>
32 #include <client/ScorchedClient.h>
33 #include <engine/ScorchedContext.h>
34 #include <graph/ParticleEngine.h>
35 #include <sound/Sound.h>
36 #include <tank/Tank.h>
37
MissileActionRenderer(int flareType,float scale,float spinSpeed,const Vector & rotationAxis)38 MissileActionRenderer::MissileActionRenderer(int flareType, float scale, float spinSpeed, const Vector &rotationAxis) :
39 flareType_(flareType), counter_(0.05f, 0.05f),
40 mesh_(0), scale_(scale), rotation_(180.0f),
41 flameemitter_(0), smokeemitter_(0), sound_(0),
42 rotationAxis_(rotationAxis),
43 spinSpeed_(spinSpeed)
44 {
45 frame_ = (float) rand();
46 }
47
~MissileActionRenderer()48 MissileActionRenderer::~MissileActionRenderer()
49 {
50 delete flameemitter_;
51 delete smokeemitter_;
52 delete sound_;
53 }
54
simulate(Action * action,float timepassed,bool & remove)55 void MissileActionRenderer::simulate(Action *action, float timepassed, bool &remove)
56 {
57 ShotProjectile *shot = (ShotProjectile *) action;
58 if (!flameemitter_)
59 {
60 flameTextureSet_ = ExplosionTextures::instance()->getTextureSetByName(
61 shot->getWeapon()->getFlameTexture());
62 flameemitter_ = new ParticleEmitter;
63 flameemitter_->setAttributes(
64 shot->getWeapon()->getFlameLife() / 2.0f, shot->getWeapon()->getFlameLife(), // Life
65 0.5f, 1.0f, // Mass
66 0.01f, 0.02f, // Friction
67 Vector(-0.05f, -0.1f, 0.3f), Vector(0.05f, 0.1f, 0.9f), // Velocity
68 shot->getWeapon()->getFlameStartColor1(), 0.9f, // StartColor1
69 shot->getWeapon()->getFlameStartColor2(), 1.0f, // StartColor2
70 shot->getWeapon()->getFlameEndColor1(), 0.0f, // EndColor1
71 shot->getWeapon()->getFlameEndColor2(), 0.1f, // EndColor2
72 shot->getWeapon()->getFlameStartSize() / 2.0f, shot->getWeapon()->getFlameStartSize() / 2.0f, shot->getWeapon()->getFlameStartSize(), shot->getWeapon()->getFlameStartSize(), // Start Size
73 shot->getWeapon()->getFlameEndSize() / 2.0f, shot->getWeapon()->getFlameEndSize() / 2.0f, shot->getWeapon()->getFlameEndSize(), shot->getWeapon()->getFlameEndSize(), // EndSize
74 Vector(0.0f, 0.0f, 10.0f), // Gravity
75 true,
76 true);
77 }
78 if (!smokeemitter_)
79 {
80 smokeTextureSet_ = ExplosionTextures::instance()->getTextureSetByName(
81 shot->getWeapon()->getSmokeTexture());
82 smokeemitter_ = new ParticleEmitter;
83 smokeemitter_->setAttributes(
84 shot->getWeapon()->getSmokeLife() / 2.0f, shot->getWeapon()->getSmokeLife(), // Life
85 0.2f, 0.5f, // Mass
86 0.01f, 0.02f, // Friction
87 Vector(-0.05f, -0.1f, 0.3f), Vector(0.05f, 0.1f, 0.9f), // Velocity
88 Vector(0.7f, 0.7f, 0.7f), 0.3f, // StartColor1
89 Vector(0.7f, 0.7f, 0.7f), 0.3f, // StartColor2
90 Vector(0.7f, 0.7f, 0.7f), 0.0f, // EndColor1
91 Vector(0.8f, 0.8f, 0.8f), 0.1f, // EndColor2
92 shot->getWeapon()->getSmokeStartSize() / 2.0f, shot->getWeapon()->getSmokeStartSize() / 2.0f, shot->getWeapon()->getSmokeStartSize(), shot->getWeapon()->getSmokeStartSize(), // Start Size
93 shot->getWeapon()->getSmokeEndSize() / 2.0f, shot->getWeapon()->getSmokeEndSize() / 2.0f, shot->getWeapon()->getSmokeEndSize(), shot->getWeapon()->getSmokeEndSize(), // EndSize
94 Vector(0.0f, 0.0f, 100.0f), // Gravity
95 false,
96 true);
97 }
98 if (!sound_)
99 {
100 const char *engineSound = shot->getWeapon()->getEngineSound();
101 if (0 != strcmp("none", engineSound))
102 {
103 SoundBuffer *rocket = Sound::instance()->fetchOrCreateBuffer(
104 S3D::getModFile(engineSound));
105 sound_ = new VirtualSoundSource(VirtualSoundPriority::eMissile, true, false);
106 sound_->setPosition(shot->getCurrentPosition().asVector());
107 sound_->setGain(0.25f);
108 sound_->play(rocket);
109 }
110 }
111 if (sound_)
112 {
113 sound_->setPosition(shot->getCurrentPosition().asVector());
114 sound_->setVelocity(shot->getCurrentVelocity().asVector());
115 }
116
117 Vector &actualPos = shot->getCurrentPosition().asVector();
118 Vector actualPos1;
119 actualPos1[0] = actualPos[0] - 0.25f;
120 actualPos1[1] = actualPos[1] - 0.25f;
121 actualPos1[2] = actualPos[2] - 0.25f;
122 Vector actualPos2;
123 actualPos2[0] = actualPos[0] + 0.25f;
124 actualPos2[1] = actualPos[1] + 0.25f;
125 actualPos2[2] = actualPos[2] + 0.25f;
126
127 // Rotate the shot
128 frame_ += timepassed * 20.0f;
129 rotation_ += shot->getCurrentVelocity().Magnitude().asFloat() * spinSpeed_;
130
131 // Add flame trail
132 if (shot->getWeapon()->getCreateFlame())
133 {
134 flameemitter_->emitLinear(2, actualPos1, actualPos2,
135 ScorchedClient::instance()->getParticleEngine(),
136 ParticleRendererQuads::getInstance(),
137 flameTextureSet_,
138 shot->getWeapon()->getAnimateFlameTexture());
139 }
140
141 // Add the smoke trail
142 if (shot->getWeapon()->getCreateSmoke())
143 {
144 if (counter_.nextDraw(timepassed))
145 {
146 Vector vel1 = shot->getCurrentVelocity().asVector();
147 Vector vel2;
148 vel1 *= -0.4f;
149 vel2 = vel1 * 0.7f;
150
151 actualPos1 -= shot->getCurrentVelocity().asVector() * 0.2f;
152 actualPos2 -= shot->getCurrentVelocity().asVector() * 0.2f;
153
154 smokeemitter_->setVelocity(vel1, vel2);
155 smokeemitter_->emitLinear(3, actualPos1, actualPos2,
156 ScorchedClient::instance()->getParticleEngine(),
157 ParticleRendererQuads::getInstance(),
158 smokeTextureSet_,
159 shot->getWeapon()->getAnimateSmokeTexture());
160 }
161 }
162 }
163
draw(Action * action)164 void MissileActionRenderer::draw(Action *action)
165 {
166 ShotProjectile *shot = (ShotProjectile *) action;
167 Vector &actualPos = shot->getCurrentPosition().asVector();
168 Vector &actualdir = shot->getCurrentVelocity().asVector();
169
170 if (shot->getWeapon()->getShowShotPath())
171 {
172 Tank *current =
173 action->getScorchedContext()->getTargetContainer().
174 getTankById(shot->getPlayerId());
175 if (current)
176 {
177 glColor3fv(current->getColor());
178 RenderTracer::instance()->drawSmokeTracer(
179 shot->getPositions());
180 }
181 }
182
183 // Check we can see the missile
184 if (!GLCameraFrustum::instance()->sphereInFrustum(actualPos, 1.0f))
185 {
186 return;
187 }
188
189 // Do we have a loaded mesh
190 if (!mesh_)
191 {
192 Tank *currentPlayer = action->
193 getScorchedContext()->getTargetContainer().getTankById(
194 shot->getPlayerId());
195 mesh_ = Accessory::getWeaponMesh(
196 shot->getWeapon()->getModelID(), currentPlayer);
197 }
198
199 // Draw the missile
200 mesh_->setScale(scale_);
201 mesh_->draw(actualPos, actualdir, flareType_, rotation_, rotationAxis_, frame_);
202
203 // Draw the missile shadow
204 float aboveGround =
205 actualPos[2] - ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().
206 getHeight((int) actualPos[0], (int) actualPos[1]).asFloat();
207 Landscape::instance()->getShadowMap().
208 addCircle(actualPos[0], actualPos[1], aboveGround / 10.0f);
209 }
210