2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2017 - Lugaru contributors (see AUTHORS file)
5 This file is part of Lugaru.
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Lugaru. If not, see <http://www.gnu.org/licenses/>.
21 #include "Graphic/Sprite.hpp"
24 #include "Objects/Person.hpp"
27 extern float viewdistance;
28 extern float fadestart;
29 extern int environment;
30 extern float texscale;
32 extern float multiplier;
34 extern Terrain terrain;
36 extern XYZ viewerfacing;
37 extern int bloodtoggle;
38 extern XYZ windvector;
41 Texture Sprite::cloudtexture;
42 Texture Sprite::cloudimpacttexture;
43 Texture Sprite::bloodtexture;
44 Texture Sprite::flametexture;
45 Texture Sprite::bloodflametexture;
46 Texture Sprite::smoketexture;
47 Texture Sprite::snowflaketexture;
48 Texture Sprite::shinetexture;
49 Texture Sprite::splintertexture;
50 Texture Sprite::leaftexture;
51 Texture Sprite::toothtexture;
53 float Sprite::checkdelay = 0;
55 vector<Sprite*> Sprite::sprites = vector<Sprite*>();
63 static float distancemult;
65 static int lastspecial;
66 static int whichpatchx, whichpatchz;
67 static XYZ start, end, colpoint;
70 static float tempmult;
71 static XYZ difference;
72 static float lightcolor[3];
73 static float viewdistsquared = viewdistance * viewdistance;
74 static XYZ tempviewer;
76 tempviewer = viewer + viewerfacing * 6;
79 lightcolor[0] = light.color[0] * .5 + light.ambient[0];
80 lightcolor[1] = light.color[1] * .5 + light.ambient[1];
81 lightcolor[2] = light.color[2] * .5 + light.ambient[2];
83 checkdelay -= multiplier * 10;
85 if (checkdelay <= 0) {
93 glDisable(GL_LIGHTING);
94 glDisable(GL_CULL_FACE);
95 glEnable(GL_TEXTURE_2D);
97 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
99 glAlphaFunc(GL_GREATER, 0.0001);
100 for (unsigned i = 0; i < sprites.size(); i++) {
101 if (lasttype != sprites[i]->type) {
102 switch (sprites[i]->type) {
107 glAlphaFunc(GL_GREATER, 0.0001);
108 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
112 case cloudimpactsprite:
113 cloudimpacttexture.bind();
116 glAlphaFunc(GL_GREATER, 0.0001);
117 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
124 glAlphaFunc(GL_GREATER, 0.0001);
125 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
132 glAlphaFunc(GL_GREATER, 0.0001);
133 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
137 if (lastspecial != sprites[i]->special) {
138 if (sprites[i]->special == 0) {
139 splintertexture.bind();
141 if (sprites[i]->special == 1) {
144 if (sprites[i]->special == 2) {
145 snowflaketexture.bind();
147 if (sprites[i]->special == 3) {
152 glAlphaFunc(GL_GREATER, 0.0001);
153 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
158 snowflaketexture.bind();
161 glAlphaFunc(GL_GREATER, 0.0001);
162 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
165 case weaponshinesprite:
169 glAlphaFunc(GL_GREATER, 0.001);
170 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
174 case weaponflamesprite:
176 if (blend || lasttype == bloodflamesprite) {
178 glAlphaFunc(GL_GREATER, 0.3);
179 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
182 case bloodflamesprite:
183 bloodflametexture.bind();
186 glAlphaFunc(GL_GREATER, 0.3);
187 glBlendFunc(GL_ONE, GL_ZERO);
192 if (sprites[i]->type == snowsprite) {
193 distancemult = (144 - (distsq(&tempviewer, &sprites[i]->position) - (144 * fadestart)) * (1 / (1 - fadestart))) / 144;
195 distancemult = (viewdistsquared - (distsq(&viewer, &sprites[i]->position) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
197 if (sprites[i]->type == flamesprite) {
198 if (distancemult >= 1) {
199 glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity);
201 glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity * distancemult);
204 if (distancemult >= 1) {
205 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], sprites[i]->opacity);
207 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], sprites[i]->opacity * distancemult);
210 lasttype = sprites[i]->type;
211 lastspecial = sprites[i]->special;
212 glMatrixMode(GL_MODELVIEW);
214 glTranslatef(sprites[i]->position.x, sprites[i]->position.y, sprites[i]->position.z);
215 if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite)) {
216 difference = viewer - sprites[i]->position;
217 Normalise(&difference);
218 glTranslatef(difference.x * sprites[i]->size / 4, difference.y * sprites[i]->size / 4, difference.z * sprites[i]->size / 4);
220 if (sprites[i]->type == snowsprite) {
221 glRotatef(sprites[i]->rotation * .2, 0, .3, 1);
222 glTranslatef(1, 0, 0);
224 glGetFloatv(GL_MODELVIEW_MATRIX, M);
229 glTranslatef(point.x, point.y, point.z);
231 glRotatef(sprites[i]->rotation, 0, 0, 1);
233 if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
234 if (sprites[i]->alivetime < .14) {
235 glScalef(sprites[i]->alivetime / .14, sprites[i]->alivetime / .14, sprites[i]->alivetime / .14);
238 if (sprites[i]->type == smoketype || sprites[i]->type == snowsprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == breathsprite) {
239 if (sprites[i]->alivetime < .3) {
240 if (distancemult >= 1) {
241 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], sprites[i]->opacity * sprites[i]->alivetime / .3);
243 if (distancemult < 1) {
244 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], sprites[i]->opacity * distancemult * sprites[i]->alivetime / .3);
248 if (sprites[i]->type == splintersprite && sprites[i]->special > 0 && sprites[i]->special != 3) {
249 if (sprites[i]->alivetime < .2) {
250 if (distancemult >= 1) {
251 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], sprites[i]->alivetime / .2);
253 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], distancemult * sprites[i]->alivetime / .2);
256 if (distancemult >= 1) {
257 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], 1);
259 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], distancemult);
263 if (sprites[i]->type == splintersprite && (sprites[i]->special == 0 || sprites[i]->special == 3)) {
264 if (distancemult >= 1) {
265 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], 1);
267 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], distancemult);
271 glBegin(GL_TRIANGLES);
272 glTexCoord2f(1.0f, 1.0f);
273 glVertex3f(.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
274 glTexCoord2f(0.0f, 1.0f);
275 glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
276 glTexCoord2f(1.0f, 0.0f);
277 glVertex3f(.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
278 glTexCoord2f(0.0f, 0.0f);
279 glVertex3f(-.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
280 glTexCoord2f(1.0f, 0.0f);
281 glVertex3f(.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
282 glTexCoord2f(0.0f, 1.0f);
283 glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
287 tempmult = multiplier;
288 for (int i = sprites.size() - 1; i >= 0; i--) {
289 multiplier = tempmult;
290 if (sprites[i]->type != snowsprite) {
291 sprites[i]->position += sprites[i]->velocity * multiplier;
292 sprites[i]->velocity += windvector * multiplier;
294 if (sprites[i]->type == flamesprite || sprites[i]->type == smoketype) {
295 sprites[i]->position += windvector * multiplier / 2;
297 if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
298 multiplier *= sprites[i]->speed * .7;
300 sprites[i]->alivetime += multiplier;
302 if (sprites[i]->type == cloudsprite || sprites[i]->type == cloudimpactsprite) {
303 sprites[i]->opacity -= multiplier / 2;
304 sprites[i]->size += multiplier / 2;
305 sprites[i]->velocity.y += gravity * multiplier * .25;
307 if (sprites[i]->type == breathsprite) {
308 sprites[i]->opacity -= multiplier / 2;
309 sprites[i]->size += multiplier / 2;
310 if (findLength(&sprites[i]->velocity) <= multiplier) {
311 sprites[i]->velocity = 0;
314 slowdown = sprites[i]->velocity * -1;
315 Normalise(&slowdown);
316 slowdown *= multiplier;
317 sprites[i]->velocity += slowdown;
320 if (sprites[i]->type == snowsprite) {
321 sprites[i]->size -= multiplier / 120;
322 sprites[i]->rotation += multiplier * 360;
323 sprites[i]->position.y -= multiplier;
324 sprites[i]->position += windvector * multiplier;
325 if (sprites[i]->position.y < tempviewer.y - 6) {
326 sprites[i]->position.y += 12;
328 if (sprites[i]->position.y > tempviewer.y + 6) {
329 sprites[i]->position.y -= 12;
331 if (sprites[i]->position.z < tempviewer.z - 6) {
332 sprites[i]->position.z += 12;
334 if (sprites[i]->position.z > tempviewer.z + 6) {
335 sprites[i]->position.z -= 12;
337 if (sprites[i]->position.x < tempviewer.x - 6) {
338 sprites[i]->position.x += 12;
340 if (sprites[i]->position.x > tempviewer.x + 6) {
341 sprites[i]->position.x -= 12;
344 if (sprites[i]->type == bloodsprite) {
346 sprites[i]->rotation += multiplier * 100;
347 sprites[i]->velocity.y += gravity * multiplier;
349 XYZ where, startpoint, endpoint, movepoint, footpoint;
353 for (unsigned j = 0; j < Person::players.size(); j++) {
354 if (!spritehit && Person::players[j]->dead && sprites[i]->alivetime > .1) {
355 where = sprites[i]->oldposition;
356 where -= Person::players[j]->coords;
357 if (!Person::players[j]->skeleton.free) {
358 where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
361 where = sprites[i]->position;
362 where -= Person::players[j]->coords;
363 if (!Person::players[j]->skeleton.free) {
364 where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
370 whichtri = Person::players[j]->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
371 if (whichtri != -1) {
373 Person::players[j]->DoBloodBigWhere(0, 160, sprites[i]->oldposition);
379 whichpatchx = sprites[i]->position.x / (terrain.size / subdivision * terrain.scale);
380 whichpatchz = sprites[i]->position.z / (terrain.size / subdivision * terrain.scale);
381 if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
383 for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) {
384 k = terrain.patchobjects[whichpatchx][whichpatchz][j];
385 start = sprites[i]->oldposition;
386 end = sprites[i]->position;
388 if (Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw) != -1) {
389 if (detail == 2 || (detail == 1 && abs(Random() % 4) == 0) || (detail == 0 && abs(Random() % 8) == 0)) {
390 Object::objects[k]->model.MakeDecal(blooddecalfast, DoRotation(colpoint - Object::objects[k]->position, 0, -Object::objects[k]->yaw, 0), sprites[i]->size * 1.6, .5, Random() % 360);
400 if (sprites[i]->position.y < terrain.getHeight(sprites[i]->position.x, sprites[i]->position.z)) {
401 terrain.MakeDecal(blooddecalfast, sprites[i]->position, sprites[i]->size * 1.6, .6, Random() % 360);
407 if (sprites[i]->type == splintersprite) {
408 sprites[i]->rotation += sprites[i]->rotatespeed * multiplier;
409 sprites[i]->opacity -= multiplier / 2;
410 if (sprites[i]->special == 0 || sprites[i]->special == 2 || sprites[i]->special == 3) {
411 sprites[i]->velocity.y += gravity * multiplier;
413 if (sprites[i]->special == 1) {
414 sprites[i]->velocity.y += gravity * multiplier * .5;
417 if (sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite) {
418 sprites[i]->rotation += multiplier * sprites[i]->rotatespeed;
419 sprites[i]->opacity -= multiplier * 5 / 4;
420 if (sprites[i]->type != weaponshinesprite && sprites[i]->type != bloodflamesprite) {
421 if (sprites[i]->opacity < .5 && sprites[i]->opacity + multiplier * 5 / 4 >= .5 && (abs(Random() % 4) == 0 || (sprites[i]->initialsize > 2 && Random() % 2 == 0))) {
422 MakeSprite(smoketype, sprites[i]->position, sprites[i]->velocity, .9, .9, .6, sprites[i]->size * 1.2, .4);
425 if (sprites[i]->alivetime > .14 && (sprites[i]->type == flamesprite)) {
426 sprites[i]->velocity = 0;
427 sprites[i]->velocity.y = 1.5;
430 if (sprites[i]->type == smoketype) {
431 sprites[i]->opacity -= multiplier / 3 / sprites[i]->initialsize;
432 sprites[i]->color[0] -= multiplier;
433 sprites[i]->color[1] -= multiplier;
434 sprites[i]->color[2] -= multiplier;
435 if (sprites[i]->color[0] < .6) {
436 sprites[i]->color[0] = .6;
438 if (sprites[i]->color[1] < .6) {
439 sprites[i]->color[1] = .6;
441 if (sprites[i]->color[2] < .6) {
442 sprites[i]->color[2] = .6;
444 sprites[i]->size += multiplier;
445 sprites[i]->velocity = 0;
446 sprites[i]->velocity.y = 1.5;
447 sprites[i]->rotation += multiplier * sprites[i]->rotatespeed / 5;
449 if (sprites[i]->opacity <= 0 || sprites[i]->size <= 0) {
454 for (int i = sprites.size() - 1; i >= 0; i--) {
455 sprites[i]->oldposition = sprites[i]->position;
458 glAlphaFunc(GL_GREATER, 0.0001);
459 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
462 void Sprite::DeleteSprite(int i)
464 sprites.erase(sprites.begin() + i);
467 void Sprite::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity)
469 if (sprites.size() < max_sprites - 1) {
470 sprites.push_back(new Sprite());
471 if ((atype != bloodsprite && atype != bloodflamesprite) || bloodtoggle) {
472 sprites.back()->special = 0;
473 sprites.back()->type = atype;
474 sprites.back()->position = where;
475 sprites.back()->oldposition = where;
476 sprites.back()->velocity = avelocity;
477 sprites.back()->alivetime = 0;
478 sprites.back()->opacity = aopacity;
479 sprites.back()->size = asize;
480 sprites.back()->initialsize = asize;
481 sprites.back()->color[0] = red;
482 sprites.back()->color[1] = green;
483 sprites.back()->color[2] = blue;
484 sprites.back()->rotatespeed = abs(Random() % 720) - 360;
485 sprites.back()->speed = float(abs(Random() % 100)) / 200 + 1.5;
499 memset(color, 0, sizeof(color));