]> git.jsancho.org Git - lugaru.git/blob - Source/Sprite.cpp
d96d09e0ef08eda17c3106c6d36cae813366c5ed
[lugaru.git] / Source / 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 "Sprite.h"
22 #include "Person.h"
23 #include "Game.h"
24 extern XYZ viewer;
25 extern float viewdistance;
26 extern float fadestart;
27 extern int environment;
28 extern float texscale;
29 extern Light light;
30 extern float multiplier;
31 extern float gravity;
32 extern Terrain terrain;
33 extern Objects objects;
34 extern int detail;
35 extern XYZ viewerfacing;
36 extern int bloodtoggle;
37 extern XYZ windvector;
38
39 // init statics
40 Texture Sprite::cloudtexture;
41 Texture Sprite::cloudimpacttexture;
42 Texture Sprite::bloodtexture;
43 Texture Sprite::flametexture;
44 Texture Sprite::bloodflametexture;
45 Texture Sprite::smoketexture;
46 Texture Sprite::snowflaketexture;
47 Texture Sprite::shinetexture;
48 Texture Sprite::splintertexture;
49 Texture Sprite::leaftexture;
50 Texture Sprite::toothtexture;
51
52 float Sprite::checkdelay = 0;
53
54 vector<Sprite*> Sprite::sprites = vector<Sprite*>();
55
56 //Functions
57 void Sprite::Draw()
58 {
59     int k;
60     static float M[16];
61     static XYZ point;
62     static float distancemult;
63     static int lasttype;
64     static int lastspecial;
65     static int whichpatchx, whichpatchz;
66     static XYZ start, end, colpoint;
67     static bool check;
68     static bool blend;
69     static float tempmult;
70     static XYZ difference;
71     static float lightcolor[3];
72     static float viewdistsquared = viewdistance * viewdistance;
73     static XYZ tempviewer;
74
75     tempviewer = viewer + viewerfacing * 6;
76     check = 0;
77
78     lightcolor[0] = light.color[0] * .5 + light.ambient[0];
79     lightcolor[1] = light.color[1] * .5 + light.ambient[1];
80     lightcolor[2] = light.color[2] * .5 + light.ambient[2];
81
82     checkdelay -= multiplier * 10;
83
84     if (checkdelay <= 0) {
85         check = 1;
86         checkdelay = 1;
87     }
88
89     lasttype = -1;
90     lastspecial = -1;
91     glEnable(GL_BLEND);
92     glDisable(GL_LIGHTING);
93     glDisable(GL_CULL_FACE);
94     glEnable(GL_TEXTURE_2D);
95     blend = 1;
96     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
97     glDepthMask(0);
98     glAlphaFunc(GL_GREATER, 0.0001);
99     for (unsigned i = 0; i < sprites.size(); i++) {
100         if (lasttype != sprites[i]->type) {
101             switch (sprites[i]->type) {
102             case cloudsprite:
103                 cloudtexture.bind();
104                 if (!blend) {
105                     blend = 1;
106                     glAlphaFunc(GL_GREATER, 0.0001);
107                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
108                 }
109                 break;
110             case cloudimpactsprite:
111                 cloudimpacttexture.bind();
112                 if (!blend) {
113                     blend = 1;
114                     glAlphaFunc(GL_GREATER, 0.0001);
115                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
116                 }
117                 break;
118             case breathsprite:
119                 cloudimpacttexture.bind();
120                 if (!blend) {
121                     blend = 1;
122                     glAlphaFunc(GL_GREATER, 0.0001);
123                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
124                 }
125                 break;
126             case smoketype:
127                 smoketexture.bind();
128                 if (!blend) {
129                     blend = 1;
130                     glAlphaFunc(GL_GREATER, 0.0001);
131                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
132                 }
133                 break;
134             case bloodsprite:
135                 bloodtexture.bind();
136                 if (!blend) {
137                     blend = 1;
138                     glAlphaFunc(GL_GREATER, 0.0001);
139                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
140                 }
141                 break;
142             case splintersprite :
143                 if (lastspecial != sprites[i]->special) {
144                     if (sprites[i]->special == 0)
145                         splintertexture.bind();
146                     if (sprites[i]->special == 1)
147                         leaftexture.bind();
148                     if (sprites[i]->special == 2)
149                         snowflaketexture.bind();
150                     if (sprites[i]->special == 3)
151                         toothtexture.bind();
152                     if (!blend) {
153                         blend = 1;
154                         glAlphaFunc(GL_GREATER, 0.0001);
155                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
156                     }
157                 }
158                 break;
159             case snowsprite:
160                 snowflaketexture.bind();
161                 if (!blend) {
162                     blend = 1;
163                     glAlphaFunc(GL_GREATER, 0.0001);
164                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
165                 }
166                 break;
167             case weaponshinesprite:
168                 shinetexture.bind();
169                 if (blend) {
170                     blend = 0;
171                     glAlphaFunc(GL_GREATER, 0.001);
172                     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
173                 }
174                 break;
175             case flamesprite:
176             case weaponflamesprite:
177                 flametexture.bind();
178                 if (blend || lasttype == bloodflamesprite) {
179                     blend = 0;
180                     glAlphaFunc(GL_GREATER, 0.3);
181                     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
182                 }
183                 break;
184             case bloodflamesprite:
185                 bloodflametexture.bind();
186                 if (blend) {
187                     blend = 0;
188                     glAlphaFunc(GL_GREATER, 0.3);
189                     glBlendFunc(GL_ONE, GL_ZERO);
190                 }
191                 break;
192             }
193         }
194         if (sprites[i]->type == snowsprite)
195             distancemult = (144 - (distsq(&tempviewer, &sprites[i]->position) - (144 * fadestart)) * (1 / (1 - fadestart))) / 144;
196         else
197             distancemult = (viewdistsquared - (distsq(&viewer, &sprites[i]->position) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
198         if (sprites[i]->type == flamesprite) {
199             if (distancemult >= 1)
200                 glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity);
201             else
202                 glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity * distancemult);
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         lasttype = sprites[i]->type;
210         lastspecial = sprites[i]->special;
211         glMatrixMode(GL_MODELVIEW);
212         glPushMatrix();
213         glTranslatef(sprites[i]->position.x, sprites[i]->position.y, sprites[i]->position.z);
214         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite)) {
215             difference = viewer - sprites[i]->position;
216             Normalise(&difference);
217             glTranslatef(difference.x * sprites[i]->size / 4, difference.y * sprites[i]->size / 4, difference.z * sprites[i]->size / 4);
218         }
219         if (sprites[i]->type == snowsprite) {
220             glRotatef(sprites[i]->rotation * .2, 0, .3, 1);
221             glTranslatef(1, 0, 0);
222         }
223         glGetFloatv(GL_MODELVIEW_MATRIX, M);
224         point.x = M[12];
225         point.y = M[13];
226         point.z = M[14];
227         glLoadIdentity();
228         glTranslatef(point.x, point.y, point.z);
229
230         glRotatef(sprites[i]->rotation, 0, 0, 1);
231
232         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
233             if (sprites[i]->alivetime < .14)
234                 glScalef(sprites[i]->alivetime / .14, sprites[i]->alivetime / .14, sprites[i]->alivetime / .14);
235         }
236         if (sprites[i]->type == smoketype || sprites[i]->type == snowsprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == breathsprite) {
237             if (sprites[i]->alivetime < .3) {
238                 if (distancemult >= 1)
239                     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);
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 * distancemult * sprites[i]->alivetime / .3);
242             }
243         }
244         if (sprites[i]->type == splintersprite && sprites[i]->special > 0 && sprites[i]->special != 3) {
245             if (sprites[i]->alivetime < .2) {
246                 if (distancemult >= 1)
247                     glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->alivetime / .2);
248                 else
249                     glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], distancemult * sprites[i]->alivetime / .2);
250             } else {
251                 if (distancemult >= 1)
252                     glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
253                 else
254                     glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
255             }
256         }
257         if (sprites[i]->type == splintersprite && (sprites[i]->special == 0 || sprites[i]->special == 3)) {
258             if (distancemult >= 1)
259                 glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
260             else
261                 glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
262         }
263
264         glBegin(GL_TRIANGLES);
265         glTexCoord2f(1.0f, 1.0f);
266         glVertex3f( .5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
267         glTexCoord2f(0.0f, 1.0f);
268         glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
269         glTexCoord2f(1.0f, 0.0f);
270         glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
271         glTexCoord2f(0.0f, 0.0f);
272         glVertex3f(-.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
273         glTexCoord2f(1.0f, 0.0f);
274         glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
275         glTexCoord2f(0.0f, 1.0f);
276         glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
277         glEnd();
278         glPopMatrix();
279     }
280     tempmult = multiplier;
281     for (int i = sprites.size() - 1; i >= 0; i--) {
282         multiplier = tempmult;
283         if (sprites[i]->type != snowsprite) {
284             sprites[i]->position += sprites[i]->velocity * multiplier;
285             sprites[i]->velocity += windvector * multiplier;
286         }
287         if (sprites[i]->type == flamesprite || sprites[i]->type == smoketype)
288             sprites[i]->position += windvector * multiplier / 2;
289         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite))
290             multiplier *= sprites[i]->speed * .7;
291         sprites[i]->alivetime += multiplier;
292
293         if (sprites[i]->type == cloudsprite || sprites[i]->type == cloudimpactsprite) {
294             sprites[i]->opacity -= multiplier / 2;
295             sprites[i]->size += multiplier / 2;
296             sprites[i]->velocity.y += gravity * multiplier * .25;
297         }
298         if (sprites[i]->type == breathsprite) {
299             sprites[i]->opacity -= multiplier / 2;
300             sprites[i]->size += multiplier / 2;
301             if (findLength(&sprites[i]->velocity) <= multiplier) {
302                 sprites[i]->velocity = 0;
303             } else {
304                 XYZ slowdown;
305                 slowdown = sprites[i]->velocity * -1;
306                 Normalise(&slowdown);
307                 slowdown *= multiplier;
308                 sprites[i]->velocity += slowdown;
309             }
310         }
311         if (sprites[i]->type == snowsprite) {
312             sprites[i]->size -= multiplier / 120;
313             sprites[i]->rotation += multiplier * 360;
314             sprites[i]->position.y -= multiplier;
315             sprites[i]->position += windvector * multiplier;
316             if (sprites[i]->position.y < tempviewer.y - 6) sprites[i]->position.y += 12;
317             if (sprites[i]->position.y > tempviewer.y + 6) sprites[i]->position.y -= 12;
318             if (sprites[i]->position.z < tempviewer.z - 6) sprites[i]->position.z += 12;
319             if (sprites[i]->position.z > tempviewer.z + 6) sprites[i]->position.z -= 12;
320             if (sprites[i]->position.x < tempviewer.x - 6) sprites[i]->position.x += 12;
321             if (sprites[i]->position.x > tempviewer.x + 6) sprites[i]->position.x -= 12;
322         }
323         if (sprites[i]->type == bloodsprite) {
324             bool spritehit = 0;
325             sprites[i]->rotation += multiplier * 100;
326             sprites[i]->velocity.y += gravity * multiplier;
327             if (check) {
328                 XYZ where, startpoint, endpoint, movepoint, footpoint;
329                 float rotationpoint;
330                 int whichtri;
331
332                 for (unsigned j = 0; j < Person::players.size(); j++) {
333                     if (!spritehit && Person::players[j]->dead && sprites[i]->alivetime > .1) {
334                         where = sprites[i]->oldposition;
335                         where -= Person::players[j]->coords;
336                         if (!Person::players[j]->skeleton.free)
337                             where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
338                         startpoint = where;
339                         where = sprites[i]->position;
340                         where -= Person::players[j]->coords;
341                         if (!Person::players[j]->skeleton.free)
342                             where = DoRotation(where, 0, -Person::players[j]->yaw, 0);
343                         endpoint = where;
344
345                         movepoint = 0;
346                         rotationpoint = 0;
347                         whichtri = Person::players[j]->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
348                         if (whichtri != -1) {
349                             spritehit = 1;
350                             Person::players[j]->DoBloodBigWhere(0, 160, sprites[i]->oldposition);
351                             DeleteSprite(i);
352                         }
353                     }
354                 }
355
356                 whichpatchx = sprites[i]->position.x / (terrain.size / subdivision * terrain.scale);
357                 whichpatchz = sprites[i]->position.z / (terrain.size / subdivision * terrain.scale);
358                 if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision)
359                     if (terrain.patchobjectnum[whichpatchx][whichpatchz]) {
360                         if (!spritehit)
361                             for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
362                                 k = terrain.patchobjects[whichpatchx][whichpatchz][j];
363                                 start = sprites[i]->oldposition;
364                                 end = sprites[i]->position;
365                                 if (!spritehit)
366                                     if (objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]) != -1) {
367                                         if (detail == 2 || (detail == 1 && abs(Random() % 4) == 0) || (detail == 0 && abs(Random() % 8) == 0))
368                                             objects.model[k].MakeDecal(blooddecalfast, DoRotation(colpoint - objects.position[k], 0, -objects.yaw[k], 0), sprites[i]->size * 1.6, .5, Random() % 360);
369                                         DeleteSprite(i);
370                                         spritehit = 1;
371                                     }
372                             }
373                     }
374                 if (!spritehit)
375                     if (sprites[i]->position.y < terrain.getHeight(sprites[i]->position.x, sprites[i]->position.z)) {
376                         terrain.MakeDecal(blooddecalfast, sprites[i]->position, sprites[i]->size * 1.6, .6, Random() % 360);
377                         DeleteSprite(i);
378                     }
379             }
380         }
381         if (sprites[i]->type == splintersprite) {
382             sprites[i]->rotation += sprites[i]->rotatespeed * multiplier;
383             sprites[i]->opacity -= multiplier / 2;
384             if (sprites[i]->special == 0 || sprites[i]->special == 2 || sprites[i]->special == 3)
385                 sprites[i]->velocity.y += gravity * multiplier;
386             if (sprites[i]->special == 1)
387                 sprites[i]->velocity.y += gravity * multiplier * .5;
388         }
389         if (sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite) {
390             sprites[i]->rotation += multiplier * sprites[i]->rotatespeed;
391             sprites[i]->opacity -= multiplier * 5 / 4;
392             if (sprites[i]->type != weaponshinesprite && sprites[i]->type != bloodflamesprite)
393                 if (sprites[i]->opacity < .5 && sprites[i]->opacity + multiplier * 5 / 4 >= .5 && (abs(Random() % 4) == 0 || (sprites[i]->initialsize > 2 && Random() % 2 == 0)))
394                     MakeSprite(smoketype, sprites[i]->position, sprites[i]->velocity, .9, .9, .6, sprites[i]->size * 1.2, .4);
395             if (sprites[i]->alivetime > .14 && (sprites[i]->type == flamesprite)) {
396                 sprites[i]->velocity = 0;
397                 sprites[i]->velocity.y = 1.5;
398             }
399         }
400         if (sprites[i]->type == smoketype) {
401             sprites[i]->opacity -= multiplier / 3 / sprites[i]->initialsize;
402             sprites[i]->color[0] -= multiplier;
403             sprites[i]->color[1] -= multiplier;
404             sprites[i]->color[2] -= multiplier;
405             if (sprites[i]->color[0] < .6)
406                 sprites[i]->color[0] = .6;
407             if (sprites[i]->color[1] < .6)
408                 sprites[i]->color[1] = .6;
409             if (sprites[i]->color[2] < .6)
410                 sprites[i]->color[2] = .6;
411             sprites[i]->size += multiplier;
412             sprites[i]->velocity = 0;
413             sprites[i]->velocity.y = 1.5;
414             sprites[i]->rotation += multiplier * sprites[i]->rotatespeed / 5;
415         }
416         if (sprites[i]->opacity <= 0 || sprites[i]->size <= 0)
417             DeleteSprite(i);
418     }
419     if (check)
420         for (int i = sprites.size() - 1; i >= 0; i--) {
421             sprites[i]->oldposition = sprites[i]->position;
422         }
423     glAlphaFunc(GL_GREATER, 0.0001);
424     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
425 }
426
427 void Sprite::DeleteSprite(int i)
428 {
429     sprites.erase(sprites.begin() + i);
430 }
431
432 void Sprite::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity)
433 {
434     if (sprites.size() < max_sprites - 1) {
435         sprites.push_back(new Sprite());
436         if ((atype != bloodsprite && atype != bloodflamesprite) || bloodtoggle) {
437             sprites.back()->special = 0;
438             sprites.back()->type = atype;
439             sprites.back()->position = where;
440             sprites.back()->oldposition = where;
441             sprites.back()->velocity = avelocity;
442             sprites.back()->alivetime = 0;
443             sprites.back()->opacity = aopacity;
444             sprites.back()->size = asize;
445             sprites.back()->initialsize = asize;
446             sprites.back()->color[0] = red;
447             sprites.back()->color[1] = green;
448             sprites.back()->color[2] = blue;
449             sprites.back()->rotatespeed = abs(Random() % 720) - 360;
450             sprites.back()->speed = float(abs(Random() % 100)) / 200 + 1.5;
451         }
452     }
453 }
454
455 Sprite::Sprite()
456 {
457     oldposition = 0;
458     position = 0;
459     velocity = 0;
460     size = 0;
461     initialsize = 0;
462     type = 0;
463     special = 0;
464     memset(color, 0, sizeof(color));
465     opacity = 0;
466     rotation = 0;
467     alivetime = 0;
468     speed = 0;
469     rotatespeed = 0;
470 }
471
472 void Sprite::clearTextures()
473 {
474     toothtexture.destroy();
475     cloudtexture.destroy();
476     cloudimpacttexture.destroy();
477     bloodtexture.destroy();
478     flametexture.destroy();
479     bloodflametexture.destroy();
480     smoketexture.destroy();
481     snowflaketexture.destroy();
482     shinetexture.destroy();
483     splintertexture.destroy();
484     leaftexture.destroy();
485 }
486