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