]> git.jsancho.org Git - lugaru.git/blob - Source/Graphic/Sprite.cpp
c2b2d9ef6da625a79bf492bd4bdd11be853912b1
[lugaru.git] / Source / Graphic / Sprite.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
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.
11
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.
16
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/>.
19 */
20
21 #include "Graphic/Sprite.hpp"
22
23 #include "Game.hpp"
24 #include "Objects/Person.hpp"
25
26 extern XYZ viewer;
27 extern float viewdistance;
28 extern float fadestart;
29 extern int environment;
30 extern float texscale;
31 extern Light light;
32 extern float multiplier;
33 extern float gravity;
34 extern Terrain terrain;
35 extern int detail;
36 extern XYZ viewerfacing;
37 extern int bloodtoggle;
38 extern XYZ windvector;
39
40 // init statics
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;
52
53 float Sprite::checkdelay = 0;
54
55 vector<Sprite*> Sprite::sprites = vector<Sprite*>();
56
57 //Functions
58 void Sprite::Draw()
59 {
60     int k;
61     static float M[16];
62     static XYZ point;
63     static float distancemult;
64     static int lasttype;
65     static int lastspecial;
66     static int whichpatchx, whichpatchz;
67     static XYZ start, end, colpoint;
68     static bool check;
69     static bool blend;
70     static float tempmult;
71     static XYZ difference;
72     static float lightcolor[3];
73     static float viewdistsquared = viewdistance * viewdistance;
74     static XYZ tempviewer;
75
76     tempviewer = viewer + viewerfacing * 6;
77     check = 0;
78
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];
82
83     checkdelay -= multiplier * 10;
84
85     if (checkdelay <= 0) {
86         check = 1;
87         checkdelay = 1;
88     }
89
90     lasttype = -1;
91     lastspecial = -1;
92     glEnable(GL_BLEND);
93     glDisable(GL_LIGHTING);
94     glDisable(GL_CULL_FACE);
95     glEnable(GL_TEXTURE_2D);
96     blend = 1;
97     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
98     glDepthMask(0);
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) {
103                 case cloudsprite:
104                     cloudtexture.bind();
105                     if (!blend) {
106                         blend = 1;
107                         glAlphaFunc(GL_GREATER, 0.0001);
108                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109                     }
110                     break;
111                 case breathsprite:
112                 case cloudimpactsprite:
113                     cloudimpacttexture.bind();
114                     if (!blend) {
115                         blend = 1;
116                         glAlphaFunc(GL_GREATER, 0.0001);
117                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
118                     }
119                     break;
120                 case smoketype:
121                     smoketexture.bind();
122                     if (!blend) {
123                         blend = 1;
124                         glAlphaFunc(GL_GREATER, 0.0001);
125                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
126                     }
127                     break;
128                 case bloodsprite:
129                     bloodtexture.bind();
130                     if (!blend) {
131                         blend = 1;
132                         glAlphaFunc(GL_GREATER, 0.0001);
133                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
134                     }
135                     break;
136                 case splintersprite:
137                     if (lastspecial != sprites[i]->special) {
138                         if (sprites[i]->special == 0) {
139                             splintertexture.bind();
140                         }
141                         if (sprites[i]->special == 1) {
142                             leaftexture.bind();
143                         }
144                         if (sprites[i]->special == 2) {
145                             snowflaketexture.bind();
146                         }
147                         if (sprites[i]->special == 3) {
148                             toothtexture.bind();
149                         }
150                         if (!blend) {
151                             blend = 1;
152                             glAlphaFunc(GL_GREATER, 0.0001);
153                             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
154                         }
155                     }
156                     break;
157                 case snowsprite:
158                     snowflaketexture.bind();
159                     if (!blend) {
160                         blend = 1;
161                         glAlphaFunc(GL_GREATER, 0.0001);
162                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
163                     }
164                     break;
165                 case weaponshinesprite:
166                     shinetexture.bind();
167                     if (blend) {
168                         blend = 0;
169                         glAlphaFunc(GL_GREATER, 0.001);
170                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
171                     }
172                     break;
173                 case flamesprite:
174                 case weaponflamesprite:
175                     flametexture.bind();
176                     if (blend || lasttype == bloodflamesprite) {
177                         blend = 0;
178                         glAlphaFunc(GL_GREATER, 0.3);
179                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
180                     }
181                     break;
182                 case bloodflamesprite:
183                     bloodflametexture.bind();
184                     if (blend) {
185                         blend = 0;
186                         glAlphaFunc(GL_GREATER, 0.3);
187                         glBlendFunc(GL_ONE, GL_ZERO);
188                     }
189                     break;
190             }
191         }
192         if (sprites[i]->type == snowsprite) {
193             distancemult = (144 - (distsq(&tempviewer, &sprites[i]->position) - (144 * fadestart)) * (1 / (1 - fadestart))) / 144;
194         } else {
195             distancemult = (viewdistsquared - (distsq(&viewer, &sprites[i]->position) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
196         }
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);
200             } else {
201                 glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity * distancemult);
202             }
203         } else {
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);
206             } else {
207                 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], sprites[i]->opacity * distancemult);
208             }
209         }
210         lasttype = sprites[i]->type;
211         lastspecial = sprites[i]->special;
212         glMatrixMode(GL_MODELVIEW);
213         glPushMatrix();
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);
219         }
220         if (sprites[i]->type == snowsprite) {
221             glRotatef(sprites[i]->rotation * .2, 0, .3, 1);
222             glTranslatef(1, 0, 0);
223         }
224         glGetFloatv(GL_MODELVIEW_MATRIX, M);
225         point.x = M[12];
226         point.y = M[13];
227         point.z = M[14];
228         glLoadIdentity();
229         glTranslatef(point.x, point.y, point.z);
230
231         glRotatef(sprites[i]->rotation, 0, 0, 1);
232
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);
236             }
237         }
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);
242                 }
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);
245                 }
246             }
247         }
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);
252                 } else {
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);
254                 }
255             } else {
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);
258                 } else {
259                     glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], distancemult);
260                 }
261             }
262         }
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);
266             } else {
267                 glColor4f(sprites[i]->color[0] * lightcolor[0], sprites[i]->color[1] * lightcolor[1], sprites[i]->color[2] * lightcolor[2], distancemult);
268             }
269         }
270
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);
284         glEnd();
285         glPopMatrix();
286     }
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;
293         }
294         if (sprites[i]->type == flamesprite || sprites[i]->type == smoketype) {
295             sprites[i]->position += windvector * multiplier / 2;
296         }
297         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
298             multiplier *= sprites[i]->speed * .7;
299         }
300         sprites[i]->alivetime += multiplier;
301
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;
306         }
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;
312             } else {
313                 XYZ slowdown;
314                 slowdown = sprites[i]->velocity * -1;
315                 Normalise(&slowdown);
316                 slowdown *= multiplier;
317                 sprites[i]->velocity += slowdown;
318             }
319         }
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;
327             }
328             if (sprites[i]->position.y > tempviewer.y + 6) {
329                 sprites[i]->position.y -= 12;
330             }
331             if (sprites[i]->position.z < tempviewer.z - 6) {
332                 sprites[i]->position.z += 12;
333             }
334             if (sprites[i]->position.z > tempviewer.z + 6) {
335                 sprites[i]->position.z -= 12;
336             }
337             if (sprites[i]->position.x < tempviewer.x - 6) {
338                 sprites[i]->position.x += 12;
339             }
340             if (sprites[i]->position.x > tempviewer.x + 6) {
341                 sprites[i]->position.x -= 12;
342             }
343         }
344         if (sprites[i]->type == bloodsprite) {
345             bool spritehit = 0;
346             sprites[i]->rotation += multiplier * 100;
347             sprites[i]->velocity.y += gravity * multiplier;
348             if (check) {
349                 XYZ where, startpoint, endpoint, movepoint, footpoint;
350                 float rotationpoint;
351                 int whichtri;
352
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);
359                         }
360                         startpoint = where;
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);
365                         }
366                         endpoint = where;
367
368                         movepoint = 0;
369                         rotationpoint = 0;
370                         whichtri = Person::players[j]->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
371                         if (whichtri != -1) {
372                             spritehit = 1;
373                             Person::players[j]->DoBloodBigWhere(0, 160, sprites[i]->oldposition);
374                             DeleteSprite(i);
375                         }
376                     }
377                 }
378
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) {
382                     if (!spritehit) {
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;
387                             if (!spritehit) {
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);
391                                     }
392                                     DeleteSprite(i);
393                                     spritehit = 1;
394                                 }
395                             }
396                         }
397                     }
398                 }
399                 if (!spritehit) {
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);
402                         DeleteSprite(i);
403                     }
404                 }
405             }
406         }
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;
412             }
413             if (sprites[i]->special == 1) {
414                 sprites[i]->velocity.y += gravity * multiplier * .5;
415             }
416         }
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);
423                 }
424             }
425             if (sprites[i]->alivetime > .14 && (sprites[i]->type == flamesprite)) {
426                 sprites[i]->velocity = 0;
427                 sprites[i]->velocity.y = 1.5;
428             }
429         }
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;
437             }
438             if (sprites[i]->color[1] < .6) {
439                 sprites[i]->color[1] = .6;
440             }
441             if (sprites[i]->color[2] < .6) {
442                 sprites[i]->color[2] = .6;
443             }
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;
448         }
449         if (sprites[i]->opacity <= 0 || sprites[i]->size <= 0) {
450             DeleteSprite(i);
451         }
452     }
453     if (check) {
454         for (int i = sprites.size() - 1; i >= 0; i--) {
455             sprites[i]->oldposition = sprites[i]->position;
456         }
457     }
458     glAlphaFunc(GL_GREATER, 0.0001);
459     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
460 }
461
462 void Sprite::DeleteSprite(int i)
463 {
464     sprites.erase(sprites.begin() + i);
465 }
466
467 void Sprite::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity)
468 {
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;
486         }
487     }
488 }
489
490 Sprite::Sprite()
491 {
492     oldposition = 0;
493     position = 0;
494     velocity = 0;
495     size = 0;
496     initialsize = 0;
497     type = 0;
498     special = 0;
499     memset(color, 0, sizeof(color));
500     opacity = 0;
501     rotation = 0;
502     alivetime = 0;
503     speed = 0;
504     rotatespeed = 0;
505 }