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