]> git.jsancho.org Git - lugaru.git/blob - Source/Sprite.cpp
c3ac298cc958685170bac4ee845731d5a3f5a9ec
[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
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program 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.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21
22 #include "Sprite.h"
23 #include "Person.h"
24 #include "Game.h"
25 extern XYZ viewer;
26 extern float viewdistance;
27 extern float fadestart;
28 extern int environment;
29 extern float texscale;
30 extern Light light;
31 extern float multiplier;
32 extern float gravity;
33 extern Terrain terrain;
34 extern Objects objects;
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 i, j, 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 (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 cloudimpactsprite:
112                 cloudimpacttexture.bind();
113                 if (!blend) {
114                     blend = 1;
115                     glAlphaFunc(GL_GREATER, 0.0001);
116                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
117                 }
118                 break;
119             case breathsprite:
120                 cloudimpacttexture.bind();
121                 if (!blend) {
122                     blend = 1;
123                     glAlphaFunc(GL_GREATER, 0.0001);
124                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
125                 }
126                 break;
127             case smoketype:
128                 smoketexture.bind();
129                 if (!blend) {
130                     blend = 1;
131                     glAlphaFunc(GL_GREATER, 0.0001);
132                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
133                 }
134                 break;
135             case bloodsprite:
136                 bloodtexture.bind();
137                 if (!blend) {
138                     blend = 1;
139                     glAlphaFunc(GL_GREATER, 0.0001);
140                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
141                 }
142                 break;
143             case splintersprite :
144                 if (lastspecial != sprites[i]->special) {
145                     if (sprites[i]->special == 0)splintertexture.bind();
146                     if (sprites[i]->special == 1)leaftexture.bind();
147                     if (sprites[i]->special == 2)snowflaketexture.bind();
148                     if (sprites[i]->special == 3)toothtexture.bind();
149                     if (!blend) {
150                         blend = 1;
151                         glAlphaFunc(GL_GREATER, 0.0001);
152                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
153                     }
154                 }
155                 break;
156             case snowsprite:
157                 snowflaketexture.bind();
158                 if (!blend) {
159                     blend = 1;
160                     glAlphaFunc(GL_GREATER, 0.0001);
161                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
162                 }
163                 break;
164             case weaponshinesprite:
165                 shinetexture.bind();
166                 if (blend) {
167                     blend = 0;
168                     glAlphaFunc(GL_GREATER, 0.001);
169                     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
170                 }
171                 break;
172             case flamesprite:
173             case weaponflamesprite:
174                 flametexture.bind();
175                 if (blend || lasttype == bloodflamesprite) {
176                     blend = 0;
177                     glAlphaFunc(GL_GREATER, 0.3);
178                     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
179                 }
180                 break;
181             case bloodflamesprite:
182                 bloodflametexture.bind();
183                 if (blend) {
184                     blend = 0;
185                     glAlphaFunc(GL_GREATER, 0.3);
186                     glBlendFunc(GL_ONE, GL_ZERO);
187                 }
188                 break;
189             }
190         }
191         if (sprites[i]->type == snowsprite)
192             distancemult = (144 - (distsq(&tempviewer, &sprites[i]->position) - (144 * fadestart)) * (1 / (1 - fadestart))) / 144;
193         else
194             distancemult = (viewdistsquared - (distsq(&viewer, &sprites[i]->position) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
195         if (sprites[i]->type == flamesprite) {
196             if (distancemult >= 1) glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity);
197             else glColor4f(sprites[i]->color[0], sprites[i]->color[1], sprites[i]->color[2], sprites[i]->opacity * distancemult);
198         } else {
199             if (distancemult >= 1) glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity);
200             else glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->opacity * distancemult);
201         }
202         lasttype = sprites[i]->type;
203         lastspecial = sprites[i]->special;
204         glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
205         glPushMatrix();
206         glTranslatef(sprites[i]->position.x, sprites[i]->position.y, sprites[i]->position.z);
207         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite)) {
208             difference = viewer - sprites[i]->position;
209             Normalise(&difference);
210             glTranslatef(difference.x * sprites[i]->size / 4, difference.y * sprites[i]->size / 4, difference.z * sprites[i]->size / 4);
211         }
212         if (sprites[i]->type == snowsprite) {
213             glRotatef(sprites[i]->rotation * .2, 0, .3, 1);
214             glTranslatef(1, 0, 0);
215         }
216         glGetFloatv(GL_MODELVIEW_MATRIX, M);
217         point.x = M[12];
218         point.y = M[13];
219         point.z = M[14];
220         glLoadIdentity();
221         glTranslatef(point.x, point.y, point.z);
222
223         glRotatef(sprites[i]->rotation, 0, 0, 1);
224
225         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite)) {
226             if (sprites[i]->alivetime < .14)glScalef(sprites[i]->alivetime / .14, sprites[i]->alivetime / .14, sprites[i]->alivetime / .14);
227         }
228         if (sprites[i]->type == smoketype || sprites[i]->type == snowsprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == breathsprite) {
229             if (sprites[i]->alivetime < .3) {
230                 if (distancemult >= 1)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);
231                 if (distancemult < 1)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);
232             }
233         }
234         if (sprites[i]->type == splintersprite && sprites[i]->special > 0 && sprites[i]->special != 3) {
235             if (sprites[i]->alivetime < .2) {
236                 if (distancemult >= 1) glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], sprites[i]->alivetime / .2);
237                 else glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], distancemult * sprites[i]->alivetime / .2);
238             } else {
239                 if (distancemult >= 1) glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
240                 else glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
241             }
242         }
243         if (sprites[i]->type == splintersprite && (sprites[i]->special == 0 || sprites[i]->special == 3)) {
244             if (distancemult >= 1) glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
245             else glColor4f(sprites[i]->color[0]*lightcolor[0], sprites[i]->color[1]*lightcolor[1], sprites[i]->color[2]*lightcolor[2], 1);
246         }
247
248         glBegin(GL_TRIANGLES);
249         glTexCoord2f(1.0f, 1.0f);
250         glVertex3f( .5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
251         glTexCoord2f(0.0f, 1.0f);
252         glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
253         glTexCoord2f(1.0f, 0.0f);
254         glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
255         glTexCoord2f(0.0f, 0.0f);
256         glVertex3f(-.5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
257         glTexCoord2f(1.0f, 0.0f);
258         glVertex3f( .5 * sprites[i]->size, -.5 * sprites[i]->size, 0.0f);
259         glTexCoord2f(0.0f, 1.0f);
260         glVertex3f(-.5 * sprites[i]->size, .5 * sprites[i]->size, 0.0f);
261         glEnd();
262         glPopMatrix();
263     }
264     tempmult = multiplier;
265     for (i = sprites.size() - 1; i >= 0; i--) {
266         multiplier = tempmult;
267         if (sprites[i]->type != snowsprite) {
268             sprites[i]->position += sprites[i]->velocity * multiplier;
269             sprites[i]->velocity += windvector * multiplier;
270         }
271         if (sprites[i]->type == flamesprite || sprites[i]->type == smoketype)sprites[i]->position += windvector * multiplier / 2;
272         if ((sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite))
273             multiplier *= sprites[i]->speed * .7;
274         sprites[i]->alivetime += multiplier;
275
276         if (sprites[i]->type == cloudsprite || sprites[i]->type == cloudimpactsprite) {
277             sprites[i]->opacity -= multiplier / 2;
278             sprites[i]->size += multiplier / 2;
279             sprites[i]->velocity.y += gravity * multiplier * .25;
280         }
281         if (sprites[i]->type == breathsprite) {
282             sprites[i]->opacity -= multiplier / 2;
283             sprites[i]->size += multiplier / 2;
284             if (findLength(&sprites[i]->velocity) <= multiplier)sprites[i]->velocity = 0;
285             else {
286                 XYZ slowdown;
287                 slowdown = sprites[i]->velocity * -1;
288                 Normalise(&slowdown);
289                 slowdown *= multiplier;
290                 sprites[i]->velocity += slowdown;
291             }
292         }
293         if (sprites[i]->type == snowsprite) {
294             sprites[i]->size -= multiplier / 120;
295             sprites[i]->rotation += multiplier * 360;
296             sprites[i]->position.y -= multiplier;
297             sprites[i]->position += windvector * multiplier;
298             if (sprites[i]->position.y < tempviewer.y - 6)sprites[i]->position.y += 12;
299             if (sprites[i]->position.y > tempviewer.y + 6)sprites[i]->position.y -= 12;
300             if (sprites[i]->position.z < tempviewer.z - 6)sprites[i]->position.z += 12;
301             if (sprites[i]->position.z > tempviewer.z + 6)sprites[i]->position.z -= 12;
302             if (sprites[i]->position.x < tempviewer.x - 6)sprites[i]->position.x += 12;
303             if (sprites[i]->position.x > tempviewer.x + 6)sprites[i]->position.x -= 12;
304         }
305         if (sprites[i]->type == bloodsprite) {
306             bool spritehit = 0;
307             sprites[i]->rotation += multiplier * 100;
308             sprites[i]->velocity.y += gravity * multiplier;
309             if (check) {
310                 XYZ where, startpoint, endpoint, movepoint, footpoint;
311                 float rotationpoint;
312                 int whichtri;
313
314                 for (j = 0; j < numplayers; j++) {
315                     if (!spritehit && player[j].dead && sprites[i]->alivetime > .1) {
316                         where = sprites[i]->oldposition;
317                         where -= player[j].coords;
318                         if (!player[j].skeleton.free)where = DoRotation(where, 0, -player[j].yaw, 0);
319                         startpoint = where;
320                         where = sprites[i]->position;
321                         where -= player[j].coords;
322                         if (!player[j].skeleton.free)where = DoRotation(where, 0, -player[j].yaw, 0);
323                         endpoint = where;
324
325                         movepoint = 0;
326                         rotationpoint = 0;
327                         whichtri = player[j].skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
328                         if (whichtri != -1) {
329                             spritehit = 1;
330                             player[j].DoBloodBigWhere(0, 160, sprites[i]->oldposition);
331                             DeleteSprite(i);
332                         }
333                     }
334                 }
335
336                 whichpatchx = sprites[i]->position.x / (terrain.size / subdivision * terrain.scale);
337                 whichpatchz = sprites[i]->position.z / (terrain.size / subdivision * terrain.scale);
338                 if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision)
339                     if (terrain.patchobjectnum[whichpatchx][whichpatchz]) {
340                         if (!spritehit)
341                             for (j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
342                                 k = terrain.patchobjects[whichpatchx][whichpatchz][j];
343                                 start = sprites[i]->oldposition;
344                                 end = sprites[i]->position;
345                                 if (!spritehit)
346                                     if (objects.model[k].LineCheck(&start, &end, &colpoint, &objects.position[k], &objects.yaw[k]) != -1) {
347                                         if (detail == 2 || (detail == 1 && abs(Random() % 4) == 0) || (detail == 0 && abs(Random() % 8) == 0))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);
348                                         DeleteSprite(i);
349                                         spritehit = 1;
350                                     }
351                             }
352                     }
353                 if (!spritehit)
354                     if (sprites[i]->position.y < terrain.getHeight(sprites[i]->position.x, sprites[i]->position.z)) {
355                         terrain.MakeDecal(blooddecalfast, sprites[i]->position, sprites[i]->size * 1.6/*+abs((float)(Random()%100))/2400*/, .6, Random() % 360);
356                         DeleteSprite(i);
357                     }
358             }
359         }
360         if (sprites[i]->type == splintersprite) {
361             sprites[i]->rotation += sprites[i]->rotatespeed * multiplier;
362             sprites[i]->opacity -= multiplier / 2;
363             if (sprites[i]->special == 0 || sprites[i]->special == 2 || sprites[i]->special == 3)sprites[i]->velocity.y += gravity * multiplier;
364             if (sprites[i]->special == 1)sprites[i]->velocity.y += gravity * multiplier * .5;
365         }
366         if (sprites[i]->type == flamesprite || sprites[i]->type == weaponflamesprite || sprites[i]->type == weaponshinesprite || sprites[i]->type == bloodflamesprite) {
367             sprites[i]->rotation += multiplier * sprites[i]->rotatespeed;
368             sprites[i]->opacity -= multiplier * 5 / 4;
369             if (sprites[i]->type != weaponshinesprite && sprites[i]->type != bloodflamesprite)
370                 if (sprites[i]->opacity < .5 && sprites[i]->opacity + multiplier * 5 / 4 >= .5 && (abs(Random() % 4) == 0 || (sprites[i]->initialsize > 2 && Random() % 2 == 0)))
371                     MakeSprite(smoketype, sprites[i]->position, sprites[i]->velocity, .9, .9, .6, sprites[i]->size * 1.2, .4);
372             if (sprites[i]->alivetime > .14 && (sprites[i]->type == flamesprite)) {
373                 sprites[i]->velocity = 0;
374                 sprites[i]->velocity.y = 1.5;
375             }
376         }
377         if (sprites[i]->type == smoketype) {
378             sprites[i]->opacity -= multiplier / 3 / sprites[i]->initialsize;
379             sprites[i]->color[0] -= multiplier;
380             sprites[i]->color[1] -= multiplier;
381             sprites[i]->color[2] -= multiplier;
382             if (sprites[i]->color[0] < .6)sprites[i]->color[0] = .6;
383             if (sprites[i]->color[1] < .6)sprites[i]->color[1] = .6;
384             if (sprites[i]->color[2] < .6)sprites[i]->color[2] = .6;
385             sprites[i]->size += multiplier;
386             sprites[i]->velocity = 0;
387             sprites[i]->velocity.y = 1.5;
388             sprites[i]->rotation += multiplier * sprites[i]->rotatespeed / 5;
389         }
390         if (sprites[i]->opacity <= 0 || sprites[i]->size <= 0)DeleteSprite(i);
391     }
392     if (check)
393         for (i = sprites.size() - 1; i >= 0; i--) {
394             sprites[i]->oldposition = sprites[i]->position;
395         }
396     glAlphaFunc(GL_GREATER, 0.0001);
397     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
398 }
399
400 void Sprite::DeleteSprite(int i)
401 {
402     sprites.erase(sprites.begin() + i);
403 }
404
405 void Sprite::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity)
406 {
407     if (sprites.size() < max_sprites - 1) {
408         sprites.push_back(new Sprite());
409         if ((atype != bloodsprite && atype != bloodflamesprite) || bloodtoggle) {
410             sprites.back()->special = 0;
411             sprites.back()->type = atype;
412             sprites.back()->position = where;
413             sprites.back()->oldposition = where;
414             sprites.back()->velocity = avelocity;
415             sprites.back()->alivetime = 0;
416             sprites.back()->opacity = aopacity;
417             sprites.back()->size = asize;
418             sprites.back()->initialsize = asize;
419             sprites.back()->color[0] = red;
420             sprites.back()->color[1] = green;
421             sprites.back()->color[2] = blue;
422             sprites.back()->rotatespeed = abs(Random() % 720) - 360;
423             sprites.back()->speed = float(abs(Random() % 100)) / 200 + 1.5;
424         }
425     }
426 }
427
428 Sprite::Sprite()
429 {
430     oldposition = 0;
431     position = 0;
432     velocity = 0;
433     size = 0;
434     initialsize = 0;
435     type = 0;
436     special = 0;
437     memset(color, 0, sizeof(color));
438     opacity = 0;
439     rotation = 0;
440     alivetime = 0;
441     speed = 0;
442     rotatespeed = 0;
443 }
444
445 void Sprite::clearTextures()
446 {
447     toothtexture.destroy();
448     cloudtexture.destroy();
449     cloudimpacttexture.destroy();
450     bloodtexture.destroy();
451     flametexture.destroy();
452     bloodflametexture.destroy();
453     smoketexture.destroy();
454     snowflaketexture.destroy();
455     shinetexture.destroy();
456     splintertexture.destroy();
457     leaftexture.destroy();
458 }
459