1 /*
2  Copyright (c) 2013 yvt
3 
4  This file is part of OpenSpades.
5 
6  OpenSpades 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 3 of the License, or
9  (at your option) any later version.
10 
11  OpenSpades 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
17  along with OpenSpades.  If not, see <http://www.gnu.org/licenses/>.
18 
19  */
20 
21 #include "ParticleSpriteEntity.h"
22 #include <Core/Debug.h>
23 #include "GameMap.h"
24 #include "World.h"
25 
26 namespace spades {
27 	namespace client {
ParticleSpriteEntity(Client * cli,IImage * image,Vector4 color)28 		ParticleSpriteEntity::ParticleSpriteEntity(Client *cli, IImage *image, Vector4 color)
29 		    : image(image), color(color) {
30 			position = MakeVector3(0, 0, 0);
31 			velocity = MakeVector3(0, 0, 0);
32 			radius = 1.f;
33 			radiusVelocity = 0.f;
34 			angle = 0.f;
35 			rotationVelocity = 0.f;
36 			velocityDamp = 1;
37 			gravityScale = 1.f;
38 			lifetime = 1.f;
39 			radiusDamp = 1.f;
40 			time = 0.f;
41 			fadeInDuration = .1f;
42 			fadeOutDuration = .5f;
43 			additive = false;
44 			blockHitAction = Delete;
45 
46 			if (image != NULL)
47 				image->AddRef();
48 
49 			renderer = cli->GetRenderer();
50 			if (cli->GetWorld())
51 				map = cli->GetWorld()->GetMap();
52 			else
53 				map = NULL;
54 		}
55 
~ParticleSpriteEntity()56 		ParticleSpriteEntity::~ParticleSpriteEntity() {
57 			if (image != NULL) {
58 				image->Release();
59 			}
60 		}
61 
SetLifeTime(float lifeTime,float fadeIn,float fadeOut)62 		void ParticleSpriteEntity::SetLifeTime(float lifeTime, float fadeIn, float fadeOut) {
63 			lifetime = lifeTime;
64 			fadeInDuration = fadeIn;
65 			fadeOutDuration = fadeOut;
66 		}
SetTrajectory(Vector3 pos,Vector3 vel,float damp,float grav)67 		void ParticleSpriteEntity::SetTrajectory(Vector3 pos, Vector3 vel, float damp, float grav) {
68 			position = pos;
69 			velocity = vel;
70 			velocityDamp = damp;
71 			gravityScale = grav;
72 		}
73 
SetRotation(float initialAngle,float angleVelocity)74 		void ParticleSpriteEntity::SetRotation(float initialAngle, float angleVelocity) {
75 			angle = initialAngle;
76 			rotationVelocity = angleVelocity;
77 		}
78 
SetRadius(float initialRadius,float radiusVelocity,float damp)79 		void ParticleSpriteEntity::SetRadius(float initialRadius, float radiusVelocity,
80 		                                     float damp) {
81 			radius = initialRadius;
82 			this->radiusVelocity = radiusVelocity;
83 			radiusDamp = damp;
84 		}
85 
Update(float dt)86 		bool ParticleSpriteEntity::Update(float dt) {
87 			SPADES_MARK_FUNCTION_DEBUG();
88 			Vector3 lastPos = position;
89 
90 			time += dt;
91 			if (time > lifetime)
92 				return false;
93 
94 			position += velocity * dt;
95 			velocity.z += 32.f * dt * gravityScale;
96 
97 			// TODO: control clip action
98 			if (blockHitAction != Ignore && map) {
99 				if (map->ClipWorld(position.x, position.y, position.z)) {
100 					if (blockHitAction == Delete) {
101 						return false;
102 					} else {
103 						IntVector3 lp2 = lastPos.Floor();
104 						IntVector3 lp = position.Floor();
105 						if (lp.z != lp2.z && ((lp.x == lp2.x && lp.y == lp2.y) ||
106 						                      !map->ClipWorld(lp.x, lp.y, lp2.z)))
107 							velocity.z = -velocity.z;
108 						else if (lp.x != lp2.x && ((lp.y == lp2.y && lp.z == lp2.z) ||
109 						                           !map->ClipWorld(lp2.x, lp.y, lp.z)))
110 							velocity.x = -velocity.x;
111 						else if (lp.y != lp2.y && ((lp.x == lp2.x && lp.z == lp2.z) ||
112 						                           !map->ClipWorld(lp.x, lp2.y, lp.z)))
113 							velocity.y = -velocity.y;
114 						velocity *= .36f;
115 						position = lastPos;
116 					}
117 				}
118 			}
119 
120 			// radius
121 			if (radiusVelocity != 0.f)
122 				radius += radiusVelocity * dt;
123 
124 			if (rotationVelocity != 0.f)
125 				angle += rotationVelocity * dt;
126 
127 			if (velocityDamp != 1.f)
128 				velocity *= powf(velocityDamp, dt);
129 
130 			if (radiusDamp != 1.f)
131 				radiusVelocity *= powf(radiusDamp, dt);
132 
133 			return true;
134 		}
135 
Render3D()136 		void ParticleSpriteEntity::Render3D() {
137 			SPADES_MARK_FUNCTION_DEBUG();
138 
139 			float fade = 1.f;
140 			if (time < fadeInDuration) {
141 				fade *= time / fadeInDuration;
142 			}
143 			if (time > lifetime - fadeOutDuration) {
144 				fade *= (lifetime - time) / fadeOutDuration;
145 			}
146 
147 			Vector4 col = color;
148 			col.w *= fade;
149 
150 			// premultiplied alpha!
151 			col.x *= col.w;
152 			col.y *= col.w;
153 			col.z *= col.w;
154 
155 			if (additive)
156 				col.w = 0.f;
157 
158 			renderer->SetColorAlphaPremultiplied(col);
159 			renderer->AddSprite(image, position, radius, angle);
160 		}
SetImage(IImage * img)161 		void ParticleSpriteEntity::SetImage(IImage *img) {
162 			if (img == image)
163 				return;
164 			if (image != NULL)
165 				image->Release();
166 			image = img;
167 			if (image != NULL)
168 				image->AddRef();
169 		}
170 	}
171 }
172