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