]> git.jsancho.org Git - lugaru.git/blob - Source/Graphic/Models.cpp
Fixes #74 Shadow glitch (was using decal.vertex instead of model.vertex)
[lugaru.git] / Source / Graphic / Models.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/Models.hpp"
22
23 #include "Game.hpp"
24 #include "Utils/Folders.hpp"
25
26 extern float multiplier;
27 extern float viewdistance;
28 extern XYZ viewer;
29 extern float fadestart;
30 extern float texdetail;
31 extern bool decalstoggle;
32
33 int Model::LineCheck(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
34 {
35     static float distance;
36     static float olddistance;
37     static int intersecting;
38     static int firstintersecting;
39     static XYZ point;
40
41     *p1 = *p1 - *move;
42     *p2 = *p2 - *move;
43     if (*rotate)
44         *p1 = DoRotation(*p1, 0, -*rotate, 0);
45     if (*rotate)
46         *p2 = DoRotation(*p2, 0, -*rotate, 0);
47     if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
48         return -1;
49     firstintersecting = -1;
50
51     for (unsigned int j = 0; j < Triangles.size(); j++) {
52         intersecting = LineFacetd(p1, p2, &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], &Triangles[j].facenormal, &point);
53         distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
54         if ((distance < olddistance || firstintersecting == -1) && intersecting) {
55             olddistance = distance;
56             firstintersecting = j;
57             *p = point;
58         }
59     }
60
61     if (*rotate)
62         *p = DoRotation(*p, 0, *rotate, 0);
63     *p = *p + *move;
64     return firstintersecting;
65 }
66
67 int Model::LineCheckPossible(XYZ *p1, XYZ *p2, XYZ *p, XYZ *move, float *rotate)
68 {
69     static float distance;
70     static float olddistance;
71     static int intersecting;
72     static int firstintersecting;
73     static XYZ point;
74
75     *p1 = *p1 - *move;
76     *p2 = *p2 - *move;
77     if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
78         return -1;
79     firstintersecting = -1;
80     if (*rotate)
81         *p1 = DoRotation(*p1, 0, -*rotate, 0);
82     if (*rotate)
83         *p2 = DoRotation(*p2, 0, -*rotate, 0);
84
85     for (unsigned int j = 0; j < possible.size(); j++) {
86         if (possible[j] < Triangles.size()) {
87             intersecting = LineFacetd(p1, p2, &vertex[Triangles[possible[j]].vertex[0]], &vertex[Triangles[possible[j]].vertex[1]], &vertex[Triangles[possible[j]].vertex[2]], &Triangles[possible[j]].facenormal, &point);
88             distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
89             if ((distance < olddistance || firstintersecting == -1) && intersecting) {
90                 olddistance = distance;
91                 firstintersecting = possible[j];
92                 *p = point;
93             }
94         }
95     }
96
97     if (*rotate)
98         *p = DoRotation(*p, 0, *rotate, 0);
99     *p = *p + *move;
100     return firstintersecting;
101 }
102
103 int Model::LineCheckSlidePossible(XYZ *p1, XYZ *p2, XYZ *move, float *rotate)
104 {
105     static float distance;
106     static float olddistance;
107     static int intersecting;
108     static int firstintersecting;
109     static XYZ point;
110
111     *p1 = *p1 - *move;
112     *p2 = *p2 - *move;
113     if (!sphere_line_intersection(p1, p2, &boundingspherecenter, &boundingsphereradius))
114         return -1;
115     firstintersecting = -1;
116     if (*rotate)
117         *p1 = DoRotation(*p1, 0, -*rotate, 0);
118     if (*rotate)
119         *p2 = DoRotation(*p2, 0, -*rotate, 0);
120
121     for (unsigned int j = 0; j < possible.size(); j++) {
122         if (possible[j] < Triangles.size()) {
123             intersecting = LineFacetd(p1, p2, &vertex[Triangles[possible[j]].vertex[0]], &vertex[Triangles[possible[j]].vertex[1]], &vertex[Triangles[possible[j]].vertex[2]], &Triangles[possible[j]].facenormal, &point);
124             distance = (point.x - p1->x) * (point.x - p1->x) + (point.y - p1->y) * (point.y - p1->y) + (point.z - p1->z) * (point.z - p1->z);
125             if ((distance < olddistance || firstintersecting == -1) && intersecting) {
126                 olddistance = distance;
127                 firstintersecting = possible[j];
128             }
129         }
130     }
131
132     if (firstintersecting > 0) {
133         distance = abs((Triangles[firstintersecting].facenormal.x * p2->x) + (Triangles[firstintersecting].facenormal.y * p2->y) + (Triangles[firstintersecting].facenormal.z * p2->z) - ((Triangles[firstintersecting].facenormal.x * vertex[Triangles[firstintersecting].vertex[0]].x) + (Triangles[firstintersecting].facenormal.y * vertex[Triangles[firstintersecting].vertex[0]].y) + (Triangles[firstintersecting].facenormal.z * vertex[Triangles[firstintersecting].vertex[0]].z)));
134         *p2 -= Triangles[firstintersecting].facenormal * distance;
135     }
136
137     if (*rotate)
138         *p2 = DoRotation(*p2, 0, *rotate, 0);
139     *p2 = *p2 + *move;
140     return firstintersecting;
141 }
142
143 int Model::SphereCheck(XYZ *p1, float radius, XYZ *p, XYZ *move, float *rotate)
144 {
145     static int i;
146     static float distance;
147     static float olddistance;
148     static int intersecting;
149     static int firstintersecting;
150     static XYZ point;
151     static XYZ oldp1;
152
153     firstintersecting = -1;
154
155     oldp1 = *p1;
156     *p1 = *p1 - *move;
157     if (*rotate)
158         *p1 = DoRotation(*p1, 0, -*rotate, 0);
159     if (distsq(p1, &boundingspherecenter) > radius * radius + boundingsphereradius * boundingsphereradius)
160         return -1;
161
162     for (i = 0; i < 4; i++) {
163         for (unsigned int j = 0; j < Triangles.size(); j++) {
164             intersecting = 0;
165             distance = abs((Triangles[j].facenormal.x * p1->x) + (Triangles[j].facenormal.y * p1->y) + (Triangles[j].facenormal.z * p1->z) - ((Triangles[j].facenormal.x * vertex[Triangles[j].vertex[0]].x) + (Triangles[j].facenormal.y * vertex[Triangles[j].vertex[0]].y) + (Triangles[j].facenormal.z * vertex[Triangles[j].vertex[0]].z)));
166             if (distance < radius) {
167                 point = *p1 - Triangles[j].facenormal * distance;
168                 if (PointInTriangle( &point, Triangles[j].facenormal, &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))
169                     intersecting = 1;
170                 if (!intersecting)
171                     intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], p1, &radius);
172                 if (!intersecting)
173                     intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], p1, &radius);
174                 if (!intersecting)
175                     intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[2]], p1, &radius);
176                 if (intersecting) {
177                     *p1 += Triangles[j].facenormal * (distance - radius);
178                 }
179             }
180             if ((distance < olddistance || firstintersecting == -1) && intersecting) {
181                 olddistance = distance;
182                 firstintersecting = j;
183                 *p = point;
184             }
185         }
186     }
187     if (*rotate)
188         *p = DoRotation(*p, 0, *rotate, 0);
189     *p = *p + *move;
190     if (*rotate)
191         *p1 = DoRotation(*p1, 0, *rotate, 0);
192     *p1 += *move;
193     return firstintersecting;
194 }
195
196 int Model::SphereCheckPossible(XYZ *p1, float radius, XYZ *move, float *rotate)
197 {
198     static float distance;
199     static float olddistance;
200     static int intersecting;
201     static int firstintersecting;
202     static XYZ point;
203     static XYZ oldp1;
204
205     firstintersecting = -1;
206
207     oldp1 = *p1;
208     *p1 = *p1 - *move;
209
210     possible.clear();
211
212     if (*rotate)
213         *p1 = DoRotation(*p1, 0, -*rotate, 0);
214     if (distsq(p1, &boundingspherecenter) > radius * radius + boundingsphereradius * boundingsphereradius) {
215         *p1 = oldp1;
216         return -1;
217     }
218
219     for (unsigned int j = 0; j < Triangles.size(); j++) {
220         intersecting = 0;
221         distance = abs((Triangles[j].facenormal.x * p1->x) + (Triangles[j].facenormal.y * p1->y) + (Triangles[j].facenormal.z * p1->z) - ((Triangles[j].facenormal.x * vertex[Triangles[j].vertex[0]].x) + (Triangles[j].facenormal.y * vertex[Triangles[j].vertex[0]].y) + (Triangles[j].facenormal.z * vertex[Triangles[j].vertex[0]].z)));
222         if (distance < radius) {
223             point = *p1 - Triangles[j].facenormal * distance;
224             if (PointInTriangle( &point, Triangles[j].facenormal, &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))
225                 intersecting = 1;
226             if (!intersecting)
227                 intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], p1, &radius);
228             if (!intersecting)
229                 intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]], p1, &radius);
230             if (!intersecting)
231                 intersecting = sphere_line_intersection(&vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[2]], p1, &radius);
232             if (intersecting) {
233                 possible.push_back(j);
234             }
235         }
236         if ((distance < olddistance || firstintersecting == -1) && intersecting) {
237             olddistance = distance;
238             firstintersecting = j;
239         }
240     }
241     if (*rotate)
242         *p1 = DoRotation(*p1, 0, *rotate, 0);
243     *p1 += *move;
244
245     return firstintersecting;
246 }
247
248
249 void Model::UpdateVertexArray()
250 {
251     if (type != normaltype && type != decalstype)
252         return;
253
254     if (flat) {
255         for (unsigned int i = 0; i < Triangles.size(); i++) {
256             unsigned int j = i * 24;
257             vArray[j + 0] = Triangles[i].gx[0];
258             vArray[j + 1] = Triangles[i].gy[0];
259             vArray[j + 2] = Triangles[i].facenormal.x * -1;
260             vArray[j + 3] = Triangles[i].facenormal.y * -1;
261             vArray[j + 4] = Triangles[i].facenormal.z * -1;
262             vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
263             vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
264             vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
265
266             vArray[j + 8] = Triangles[i].gx[1];
267             vArray[j + 9] = Triangles[i].gy[1];
268             vArray[j + 10] = Triangles[i].facenormal.x * -1;
269             vArray[j + 11] = Triangles[i].facenormal.y * -1;
270             vArray[j + 12] = Triangles[i].facenormal.z * -1;
271             vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
272             vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
273             vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
274
275             vArray[j + 16] = Triangles[i].gx[2];
276             vArray[j + 17] = Triangles[i].gy[2];
277             vArray[j + 18] = Triangles[i].facenormal.x * -1;
278             vArray[j + 19] = Triangles[i].facenormal.y * -1;
279             vArray[j + 20] = Triangles[i].facenormal.z * -1;
280             vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
281             vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
282             vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
283         }
284     } else {
285         for (unsigned int i = 0; i < Triangles.size(); i++) {
286             unsigned int j = i * 24;
287             vArray[j + 0] = Triangles[i].gx[0];
288             vArray[j + 1] = Triangles[i].gy[0];
289             vArray[j + 2] = normals[Triangles[i].vertex[0]].x;
290             vArray[j + 3] = normals[Triangles[i].vertex[0]].y;
291             vArray[j + 4] = normals[Triangles[i].vertex[0]].z;
292             vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
293             vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
294             vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
295
296             vArray[j + 8] = Triangles[i].gx[1];
297             vArray[j + 9] = Triangles[i].gy[1];
298             vArray[j + 10] = normals[Triangles[i].vertex[1]].x;
299             vArray[j + 11] = normals[Triangles[i].vertex[1]].y;
300             vArray[j + 12] = normals[Triangles[i].vertex[1]].z;
301             vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
302             vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
303             vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
304
305             vArray[j + 16] = Triangles[i].gx[2];
306             vArray[j + 17] = Triangles[i].gy[2];
307             vArray[j + 18] = normals[Triangles[i].vertex[2]].x;
308             vArray[j + 19] = normals[Triangles[i].vertex[2]].y;
309             vArray[j + 20] = normals[Triangles[i].vertex[2]].z;
310             vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
311             vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
312             vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
313         }
314     }
315 }
316
317 void Model::UpdateVertexArrayNoTex()
318 {
319     if (type != normaltype && type != decalstype)
320         return;
321
322     if (flat) {
323         for (unsigned int i = 0; i < Triangles.size(); i++) {
324             unsigned int j = i * 24;
325             vArray[j + 2] = Triangles[i].facenormal.x * -1;
326             vArray[j + 3] = Triangles[i].facenormal.y * -1;
327             vArray[j + 4] = Triangles[i].facenormal.z * -1;
328             vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
329             vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
330             vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
331
332             vArray[j + 10] = Triangles[i].facenormal.x * -1;
333             vArray[j + 11] = Triangles[i].facenormal.y * -1;
334             vArray[j + 12] = Triangles[i].facenormal.z * -1;
335             vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
336             vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
337             vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
338
339             vArray[j + 18] = Triangles[i].facenormal.x * -1;
340             vArray[j + 19] = Triangles[i].facenormal.y * -1;
341             vArray[j + 20] = Triangles[i].facenormal.z * -1;
342             vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
343             vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
344             vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
345         }
346     } else {
347         for (unsigned int i = 0; i < Triangles.size(); i++) {
348             unsigned int j = i * 24;
349             vArray[j + 2] = normals[Triangles[i].vertex[0]].x;
350             vArray[j + 3] = normals[Triangles[i].vertex[0]].y;
351             vArray[j + 4] = normals[Triangles[i].vertex[0]].z;
352             vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
353             vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
354             vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
355
356             vArray[j + 10] = normals[Triangles[i].vertex[1]].x;
357             vArray[j + 11] = normals[Triangles[i].vertex[1]].y;
358             vArray[j + 12] = normals[Triangles[i].vertex[1]].z;
359             vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
360             vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
361             vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
362
363             vArray[j + 18] = normals[Triangles[i].vertex[2]].x;
364             vArray[j + 19] = normals[Triangles[i].vertex[2]].y;
365             vArray[j + 20] = normals[Triangles[i].vertex[2]].z;
366             vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
367             vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
368             vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
369         }
370     }
371 }
372
373 void Model::UpdateVertexArrayNoTexNoNorm()
374 {
375     if (type != normaltype && type != decalstype)
376         return;
377
378     for (unsigned int i = 0; i < Triangles.size(); i++) {
379         unsigned int j = i * 24;
380         vArray[j + 5] = vertex[Triangles[i].vertex[0]].x;
381         vArray[j + 6] = vertex[Triangles[i].vertex[0]].y;
382         vArray[j + 7] = vertex[Triangles[i].vertex[0]].z;
383
384         vArray[j + 13] = vertex[Triangles[i].vertex[1]].x;
385         vArray[j + 14] = vertex[Triangles[i].vertex[1]].y;
386         vArray[j + 15] = vertex[Triangles[i].vertex[1]].z;
387
388         vArray[j + 21] = vertex[Triangles[i].vertex[2]].x;
389         vArray[j + 22] = vertex[Triangles[i].vertex[2]].y;
390         vArray[j + 23] = vertex[Triangles[i].vertex[2]].z;
391     }
392 }
393
394 bool Model::loadnotex(const std::string& filename)
395 {
396     FILE *tfile;
397     long i;
398     short triangleNum;
399
400     type = notextype;
401     color = 0;
402
403     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
404
405     // read model settings
406
407     fseek(tfile, 0, SEEK_SET);
408     funpackf(tfile, "Bs Bs", &vertexNum, &triangleNum);
409
410     // read the model data
411     deallocate();
412
413     possible.clear();
414
415     owner = (int*)malloc(sizeof(int) * vertexNum);
416     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
417     Triangles.resize(triangleNum);
418     vArray = (GLfloat*)malloc(sizeof(GLfloat) * triangleNum * 24);
419
420     for (i = 0; i < vertexNum; i++) {
421         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
422     }
423
424     for (i = 0; i < triangleNum; i++) {
425         short vertex[6];
426         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[0], &vertex[1], &vertex[2], &vertex[3], &vertex[4], &vertex[5]);
427         Triangles[i].vertex[0] = vertex[0];
428         Triangles[i].vertex[1] = vertex[2];
429         Triangles[i].vertex[2] = vertex[4];
430         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
431         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
432     }
433
434     fclose(tfile);
435
436     UpdateVertexArray();
437
438     for (i = 0; i < vertexNum; i++) {
439         owner[i] = -1;
440     }
441
442     boundingsphereradius = 0;
443     for (i = 0; i < vertexNum; i++) {
444         for (int j = 0; j < vertexNum; j++) {
445             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
446                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
447                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
448             }
449         }
450     }
451     boundingsphereradius = fast_sqrt(boundingsphereradius);
452
453     return true;
454 }
455
456
457 bool Model::load(const std::string& filename)
458 {
459     FILE *tfile;
460     long i;
461     short triangleNum;
462
463     LOGFUNC;
464
465     LOG(std::string("Loading model...") + filename);
466
467     Game::LoadingScreen();
468
469     type = normaltype;
470     color = 0;
471
472     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
473
474     // read model settings
475
476     fseek(tfile, 0, SEEK_SET);
477     funpackf(tfile, "Bs Bs", &vertexNum, &triangleNum);
478
479     // read the model data
480     deallocate();
481
482     possible.clear();
483
484     owner = (int*)malloc(sizeof(int) * vertexNum);
485     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
486     normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
487     Triangles.resize(triangleNum);
488     vArray = (GLfloat*)malloc(sizeof(GLfloat) * triangleNum * 24);
489
490     for (i = 0; i < vertexNum; i++) {
491         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
492     }
493
494     for (i = 0; i < triangleNum; i++) {
495         short vertex[6];
496         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[0], &vertex[1], &vertex[2], &vertex[3], &vertex[4], &vertex[5]);
497         Triangles[i].vertex[0] = vertex[0];
498         Triangles[i].vertex[1] = vertex[2];
499         Triangles[i].vertex[2] = vertex[4];
500         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
501         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
502     }
503
504     modelTexture.xsz = 0;
505
506     fclose(tfile);
507
508     UpdateVertexArray();
509
510     for (i = 0; i < vertexNum; i++) {
511         owner[i] = -1;
512     }
513
514     static int j;
515     boundingsphereradius = 0;
516     for (i = 0; i < vertexNum; i++) {
517         for (j = 0; j < vertexNum; j++) {
518             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
519                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
520                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
521             }
522         }
523     }
524     boundingsphereradius = fast_sqrt(boundingsphereradius);
525
526     return true;
527 }
528
529 bool Model::loaddecal(const std::string& filename)
530 {
531     FILE *tfile;
532     long i, j;
533     short triangleNum;
534
535     LOGFUNC;
536
537     LOG(std::string("Loading decal...") + Folders::getResourcePath(filename));
538
539     type = decalstype;
540     color = 0;
541
542     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
543
544     // read model settings
545
546     fseek(tfile, 0, SEEK_SET);
547     funpackf(tfile, "Bs Bs", &vertexNum, &triangleNum);
548
549     // read the model data
550
551     deallocate();
552
553     possible.clear();
554
555     owner = (int*)malloc(sizeof(int) * vertexNum);
556     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
557     normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
558     Triangles.resize(triangleNum);
559     vArray = (GLfloat*)malloc(sizeof(GLfloat) * triangleNum * 24);
560
561     for (i = 0; i < vertexNum; i++) {
562         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
563     }
564
565     for (i = 0; i < triangleNum; i++) {
566         short vertex[6];
567         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[0], &vertex[1], &vertex[2], &vertex[3], &vertex[4], &vertex[5]);
568         Triangles[i].vertex[0] = vertex[0];
569         Triangles[i].vertex[1] = vertex[2];
570         Triangles[i].vertex[2] = vertex[4];
571         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
572         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
573     }
574
575
576     modelTexture.xsz = 0;
577
578     fclose(tfile);
579
580     UpdateVertexArray();
581
582     for (i = 0; i < vertexNum; i++) {
583         owner[i] = -1;
584     }
585
586     boundingsphereradius = 0;
587     for (i = 0; i < vertexNum; i++) {
588         for (j = 0; j < vertexNum; j++) {
589             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
590                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
591                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
592             }
593         }
594     }
595     boundingsphereradius = fast_sqrt(boundingsphereradius);
596
597     return true;
598 }
599
600 bool Model::loadraw(const std::string& filename)
601 {
602     FILE *tfile;
603     long i;
604     short triangleNum;
605
606     LOGFUNC;
607
608     LOG(std::string("Loading raw...") + filename);
609
610     type = rawtype;
611     color = 0;
612
613     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
614
615     // read model settings
616
617     fseek(tfile, 0, SEEK_SET);
618     funpackf(tfile, "Bs Bs", &vertexNum, &triangleNum);
619
620     // read the model data
621     deallocate();
622
623     possible.clear();
624
625     owner = (int*)malloc(sizeof(int) * vertexNum);
626     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
627     Triangles.resize(triangleNum);
628     vArray = (GLfloat*)malloc(sizeof(GLfloat) * triangleNum * 24);
629
630
631     for (i = 0; i < vertexNum; i++) {
632         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
633     }
634
635     for (i = 0; i < triangleNum; i++) {
636         short vertex[6];
637         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[0], &vertex[1], &vertex[2], &vertex[3], &vertex[4], &vertex[5]);
638         Triangles[i].vertex[0] = vertex[0];
639         Triangles[i].vertex[1] = vertex[2];
640         Triangles[i].vertex[2] = vertex[4];
641         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
642         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
643     }
644
645
646     fclose(tfile);
647
648     for (i = 0; i < vertexNum; i++) {
649         owner[i] = -1;
650     }
651
652     return true;
653 }
654
655
656 void Model::UniformTexCoords()
657 {
658     for (unsigned int i = 0; i < Triangles.size(); i++) {
659         Triangles[i].gy[0] = vertex[Triangles[i].vertex[0]].y;
660         Triangles[i].gy[1] = vertex[Triangles[i].vertex[1]].y;
661         Triangles[i].gy[2] = vertex[Triangles[i].vertex[2]].y;
662         Triangles[i].gx[0] = vertex[Triangles[i].vertex[0]].x;
663         Triangles[i].gx[1] = vertex[Triangles[i].vertex[1]].x;
664         Triangles[i].gx[2] = vertex[Triangles[i].vertex[2]].x;
665     }
666     UpdateVertexArray();
667 }
668
669
670 void Model::FlipTexCoords()
671 {
672     for (unsigned int i = 0; i < Triangles.size(); i++) {
673         Triangles[i].gy[0] = -Triangles[i].gy[0];
674         Triangles[i].gy[1] = -Triangles[i].gy[1];
675         Triangles[i].gy[2] = -Triangles[i].gy[2];
676     }
677     UpdateVertexArray();
678 }
679
680 void Model::ScaleTexCoords(float howmuch)
681 {
682     for (unsigned int i = 0; i < Triangles.size(); i++) {
683         Triangles[i].gx[0] *= howmuch;
684         Triangles[i].gx[1] *= howmuch;
685         Triangles[i].gx[2] *= howmuch;
686         Triangles[i].gy[0] *= howmuch;
687         Triangles[i].gy[1] *= howmuch;
688         Triangles[i].gy[2] *= howmuch;
689     }
690     UpdateVertexArray();
691 }
692
693 void Model::Scale(float xscale, float yscale, float zscale)
694 {
695     static int i;
696     for (i = 0; i < vertexNum; i++) {
697         vertex[i].x *= xscale;
698         vertex[i].y *= yscale;
699         vertex[i].z *= zscale;
700     }
701     UpdateVertexArray();
702
703     static int j;
704
705     boundingsphereradius = 0;
706     for (i = 0; i < vertexNum; i++) {
707         for (j = 0; j < vertexNum; j++) {
708             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
709                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
710                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
711             }
712         }
713     }
714     boundingsphereradius = fast_sqrt(boundingsphereradius);
715 }
716
717 void Model::ScaleNormals(float xscale, float yscale, float zscale)
718 {
719     if (type != normaltype && type != decalstype)
720         return;
721
722     for (int i = 0; i < vertexNum; i++) {
723         normals[i].x *= xscale;
724         normals[i].y *= yscale;
725         normals[i].z *= zscale;
726     }
727     for (unsigned int i = 0; i < Triangles.size(); i++) {
728         Triangles[i].facenormal.x *= xscale;
729         Triangles[i].facenormal.y *= yscale;
730         Triangles[i].facenormal.z *= zscale;
731     }
732     UpdateVertexArray();
733 }
734
735 void Model::Translate(float xtrans, float ytrans, float ztrans)
736 {
737     static int i;
738     for (i = 0; i < vertexNum; i++) {
739         vertex[i].x += xtrans;
740         vertex[i].y += ytrans;
741         vertex[i].z += ztrans;
742     }
743     UpdateVertexArray();
744
745     static int j;
746     boundingsphereradius = 0;
747     for (i = 0; i < vertexNum; i++) {
748         for (j = 0; j < vertexNum; j++) {
749             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
750                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
751                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
752             }
753         }
754     }
755     boundingsphereradius = fast_sqrt(boundingsphereradius);
756 }
757
758 void Model::Rotate(float xang, float yang, float zang)
759 {
760     static int i;
761     for (i = 0; i < vertexNum; i++) {
762         vertex[i] = DoRotation(vertex[i], xang, yang, zang);
763     }
764     UpdateVertexArray();
765
766     static int j;
767     boundingsphereradius = 0;
768     for (i = 0; i < vertexNum; i++) {
769         for (j = 0; j < vertexNum; j++) {
770             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
771                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
772                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
773             }
774         }
775     }
776     boundingsphereradius = fast_sqrt(boundingsphereradius);
777 }
778
779
780 void Model::CalculateNormals(bool facenormalise)
781 {
782     Game::LoadingScreen();
783
784     if (type != normaltype && type != decalstype)
785         return;
786
787     for (int i = 0; i < vertexNum; i++) {
788         normals[i].x = 0;
789         normals[i].y = 0;
790         normals[i].z = 0;
791     }
792
793     for (unsigned int i = 0; i < Triangles.size(); i++) {
794         CrossProduct(vertex[Triangles[i].vertex[1]] - vertex[Triangles[i].vertex[0]], vertex[Triangles[i].vertex[2]] - vertex[Triangles[i].vertex[0]], &Triangles[i].facenormal);
795
796         normals[Triangles[i].vertex[0]].x += Triangles[i].facenormal.x;
797         normals[Triangles[i].vertex[0]].y += Triangles[i].facenormal.y;
798         normals[Triangles[i].vertex[0]].z += Triangles[i].facenormal.z;
799
800         normals[Triangles[i].vertex[1]].x += Triangles[i].facenormal.x;
801         normals[Triangles[i].vertex[1]].y += Triangles[i].facenormal.y;
802         normals[Triangles[i].vertex[1]].z += Triangles[i].facenormal.z;
803
804         normals[Triangles[i].vertex[2]].x += Triangles[i].facenormal.x;
805         normals[Triangles[i].vertex[2]].y += Triangles[i].facenormal.y;
806         normals[Triangles[i].vertex[2]].z += Triangles[i].facenormal.z;
807         if (facenormalise)
808             Normalise(&Triangles[i].facenormal);
809     }
810     for (int i = 0; i < vertexNum; i++) {
811         Normalise(&normals[i]);
812         normals[i] *= -1;
813     }
814     UpdateVertexArrayNoTex();
815 }
816
817 void Model::drawimmediate()
818 {
819     textureptr.bind();
820     glBegin(GL_TRIANGLES);
821     for (unsigned int i = 0; i < Triangles.size(); i++) {
822         glTexCoord2f(Triangles[i].gx[0], Triangles[i].gy[0]);
823         if (color) {
824             glColor3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
825         } else if (flat) {
826             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
827         } else {
828             glNormal3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
829         }
830         glVertex3f(vertex[Triangles[i].vertex[0]].x, vertex[Triangles[i].vertex[0]].y, vertex[Triangles[i].vertex[0]].z);
831
832         glTexCoord2f(Triangles[i].gx[1], Triangles[i].gy[1]);
833         if (color) {
834             glColor3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
835         } else if (flat) {
836             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
837         } else {
838             glNormal3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
839         }
840         glVertex3f(vertex[Triangles[i].vertex[1]].x, vertex[Triangles[i].vertex[1]].y, vertex[Triangles[i].vertex[1]].z);
841
842         glTexCoord2f(Triangles[i].gx[2], Triangles[i].gy[2]);
843         if (color) {
844             glColor3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
845         } else if (flat) {
846             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
847         } else {
848             glNormal3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
849         }
850         glVertex3f(vertex[Triangles[i].vertex[2]].x, vertex[Triangles[i].vertex[2]].y, vertex[Triangles[i].vertex[2]].z);
851     }
852     glEnd();
853 }
854
855 void Model::draw()
856 {
857     if (type != normaltype && type != decalstype)
858         return;
859
860     glEnableClientState(GL_NORMAL_ARRAY);
861     glEnableClientState(GL_VERTEX_ARRAY);
862     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
863
864     if (color) {
865         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
866     } else {
867         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
868     }
869     textureptr.bind();
870
871     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
872
873     if (color) {
874         glDisableClientState(GL_COLOR_ARRAY);
875     } else {
876         glDisableClientState(GL_NORMAL_ARRAY);
877     }
878     glDisableClientState(GL_VERTEX_ARRAY);
879     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
880 }
881
882 void Model::drawdifftex(Texture texture)
883 {
884     glEnableClientState(GL_NORMAL_ARRAY);
885     glEnableClientState(GL_VERTEX_ARRAY);
886     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
887     if (color) {
888         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
889     } else {
890         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
891     }
892
893     texture.bind();
894     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
895     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
896
897     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
898
899     if (color) {
900         glDisableClientState(GL_COLOR_ARRAY);
901     } else {
902         glDisableClientState(GL_NORMAL_ARRAY);
903     }
904     glDisableClientState(GL_VERTEX_ARRAY);
905     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
906 }
907
908 void Model::drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture)
909 {
910     if (decalstoggle) {
911         if (type != decalstype) {
912             return;
913         }
914
915         bool blend = true;
916         int lasttype = -1;
917
918         glEnable(GL_BLEND);
919         glDisable(GL_LIGHTING);
920         glDisable(GL_CULL_FACE);
921         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
922         glDepthMask(0);
923         for (unsigned int i = 0; i < decals.size(); i++) {
924             if (decals[i].type == blooddecalfast && decals[i].alivetime < 2)
925                 decals[i].alivetime = 2;
926
927             if (decals[i].type != lasttype) {
928                 if (decals[i].type == shadowdecal) {
929                     shadowtexture.bind();
930                     if (!blend) {
931                         blend = 1;
932                         glAlphaFunc(GL_GREATER, 0.0001);
933                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
934                     }
935                 }
936                 if (decals[i].type == breakdecal) {
937                     breaktexture.bind();
938                     if (!blend) {
939                         blend = 1;
940                         glAlphaFunc(GL_GREATER, 0.0001);
941                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
942                     }
943                 }
944                 if (decals[i].type == blooddecal || decals[i].type == blooddecalslow) {
945                     bloodtexture.bind();
946                     if (blend) {
947                         blend = 0;
948                         glAlphaFunc(GL_GREATER, 0.15);
949                         glBlendFunc(GL_ONE, GL_ZERO);
950                     }
951                 }
952                 if (decals[i].type == blooddecalfast) {
953                     bloodtexture2.bind();
954                     if (blend) {
955                         blend = 0;
956                         glAlphaFunc(GL_GREATER, 0.15);
957                         glBlendFunc(GL_ONE, GL_ZERO);
958                     }
959                 }
960             }
961             if (decals[i].type == shadowdecal) {
962                 glColor4f(1, 1, 1, decals[i].opacity);
963             }
964             if (decals[i].type == breakdecal) {
965                 glColor4f(1, 1, 1, decals[i].opacity);
966                 if (decals[i].alivetime > 58)
967                     glColor4f(1, 1, 1, decals[i].opacity * (60 - decals[i].alivetime) / 2);
968             }
969             if ((decals[i].type == blooddecal || decals[i].type == blooddecalfast || decals[i].type == blooddecalslow)) {
970                 glColor4f(1, 1, 1, decals[i].opacity);
971                 if (decals[i].alivetime < 4)
972                     glColor4f(1, 1, 1, decals[i].opacity*decals[i].alivetime*.25);
973                 if (decals[i].alivetime > 58)
974                     glColor4f(1, 1, 1, decals[i].opacity * (60 - decals[i].alivetime) / 2);
975             }
976             lasttype = decals[i].type;
977             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
978             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
979
980             glMatrixMode(GL_MODELVIEW);
981             glPushMatrix();
982             glBegin(GL_TRIANGLES);
983             for (int j = 0; j < 3; j++) {
984                 glTexCoord2f(decals[i].texcoords[j][0], decals[i].texcoords[j][1]);
985                 glVertex3f(decals[i].vertex[j].x, decals[i].vertex[j].y, decals[i].vertex[j].z);
986             }
987             glEnd();
988             glPopMatrix();
989         }
990         for (int i = decals.size() - 1; i >= 0; i--) {
991             decals[i].alivetime += multiplier;
992             if (decals[i].type == blooddecalslow)
993                 decals[i].alivetime -= multiplier * 2 / 3;
994             if (decals[i].type == blooddecalfast)
995                 decals[i].alivetime += multiplier * 4;
996             if (decals[i].type == shadowdecal)
997                 DeleteDecal(i);
998             if ((decals[i].type == blooddecal || decals[i].type == blooddecalfast || decals[i].type == blooddecalslow) && decals[i].alivetime >= 60)
999                 DeleteDecal(i);
1000         }
1001         glAlphaFunc(GL_GREATER, 0.0001);
1002         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1003     }
1004 }
1005
1006 void Model::DeleteDecal(int which)
1007 {
1008     if (decalstoggle) {
1009         if (type != decalstype)
1010             return;
1011         decals.erase(decals.begin() + which);
1012     }
1013 }
1014
1015 void Model::MakeDecal(decal_type atype, XYZ *where, float *size, float *opacity, float *rotation)
1016 {
1017     if (decalstoggle) {
1018         if (type != decalstype)
1019             return;
1020
1021         static XYZ rot;
1022         static float distance;
1023
1024         if (*opacity > 0)
1025             if (distsq(where, &boundingspherecenter) < (boundingsphereradius + *size) * (boundingsphereradius + *size))
1026                 for (unsigned int i = 0; i < Triangles.size(); i++) {
1027                     if (Triangles[i].facenormal.y < -.1 && (vertex[Triangles[i].vertex[0]].y < where->y || vertex[Triangles[i].vertex[1]].y < where->y || vertex[Triangles[i].vertex[2]].y < where->y)) {
1028                         distance = abs(((Triangles[i].facenormal.x * where->x) + (Triangles[i].facenormal.y * where->y) + (Triangles[i].facenormal.z * where->z) - ((Triangles[i].facenormal.x * vertex[Triangles[i].vertex[0]].x) + (Triangles[i].facenormal.y * vertex[Triangles[i].vertex[0]].y) + (Triangles[i].facenormal.z * vertex[Triangles[i].vertex[0]].z))) / Triangles[i].facenormal.y);
1029
1030                         if ((*opacity - distance / 10) > 0) {
1031                             Decal decal(*where, atype, *opacity - distance / 10, *rotation, *size, *this, i, 0);
1032
1033                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1034                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1035                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1036                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1037                                             if (decal.rotation) {
1038                                                 for (int j = 0; j < 3; j++) {
1039                                                     rot.y = 0;
1040                                                     rot.x = decal.texcoords[j][0] - .5;
1041                                                     rot.z = decal.texcoords[j][1] - .5;
1042                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1043                                                     decal.texcoords[j][0] = rot.x + .5;
1044                                                     decal.texcoords[j][1] = rot.z + .5;
1045                                                 }
1046                                             }
1047                                             if (decals.size() < max_model_decals - 1) {
1048                                                 decals.push_back(decal);
1049                                             }
1050                                         }
1051                         }
1052                     }
1053                 }
1054     }
1055 }
1056
1057 void Model::MakeDecal(decal_type atype, XYZ where, float size, float opacity, float rotation)
1058 {
1059     if (decalstoggle) {
1060         if (type != decalstype)
1061             return;
1062
1063         static XYZ rot;
1064         static float distance;
1065
1066         if (opacity > 0)
1067             if (distsq(&where, &boundingspherecenter) < (boundingsphereradius + size) * (boundingsphereradius + size))
1068                 for (unsigned int i = 0; i < Triangles.size(); i++) {
1069                     distance = abs(((Triangles[i].facenormal.x * where.x) + (Triangles[i].facenormal.y * where.y) + (Triangles[i].facenormal.z * where.z) - ((Triangles[i].facenormal.x * vertex[Triangles[i].vertex[0]].x) + (Triangles[i].facenormal.y * vertex[Triangles[i].vertex[0]].y) + (Triangles[i].facenormal.z * vertex[Triangles[i].vertex[0]].z))));
1070                     if (distance < .02 && abs(Triangles[i].facenormal.y) > abs(Triangles[i].facenormal.x) && abs(Triangles[i].facenormal.y) > abs(Triangles[i].facenormal.z)) {
1071                         if ((opacity - distance / 10) > 0) {
1072                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 0);
1073
1074                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1075                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1076                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1077                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1078                                             if (decal.rotation) {
1079                                                 for (int j = 0; j < 3; j++) {
1080                                                     rot.y = 0;
1081                                                     rot.x = decal.texcoords[j][0] - .5;
1082                                                     rot.z = decal.texcoords[j][1] - .5;
1083                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1084                                                     decal.texcoords[j][0] = rot.x + .5;
1085                                                     decal.texcoords[j][1] = rot.z + .5;
1086                                                 }
1087                                             }
1088                                             if (decals.size() < max_model_decals - 1) {
1089                                                 decals.push_back(decal);
1090                                             }
1091                                         }
1092                         }
1093                     } else if (distance < .02 && abs(Triangles[i].facenormal.x) > abs(Triangles[i].facenormal.y) && abs(Triangles[i].facenormal.x) > abs(Triangles[i].facenormal.z)) {
1094                         if ((opacity - distance / 10) > 0) {
1095                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 1);
1096
1097                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1098                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1099                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1100                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1101                                             if (decal.rotation) {
1102                                                 for (int j = 0; j < 3; j++) {
1103                                                     rot.y = 0;
1104                                                     rot.x = decal.texcoords[j][0] - .5;
1105                                                     rot.z = decal.texcoords[j][1] - .5;
1106                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1107                                                     decal.texcoords[j][0] = rot.x + .5;
1108                                                     decal.texcoords[j][1] = rot.z + .5;
1109                                                 }
1110                                             }
1111                                             if (decals.size() < max_model_decals - 1) {
1112                                                 decals.push_back(decal);
1113                                             }
1114                                         }
1115                         }
1116                     } else if (distance < .02 && abs(Triangles[i].facenormal.z) > abs(Triangles[i].facenormal.y) && abs(Triangles[i].facenormal.z) > abs(Triangles[i].facenormal.x)) {
1117                         if ((opacity - distance / 10) > 0) {
1118                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 2);
1119
1120                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1121                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1122                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1123                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1124                                             if (decal.rotation) {
1125                                                 for (int j = 0; j < 3; j++) {
1126                                                     rot.y = 0;
1127                                                     rot.x = decal.texcoords[j][0] - .5;
1128                                                     rot.z = decal.texcoords[j][1] - .5;
1129                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1130                                                     decal.texcoords[j][0] = rot.x + .5;
1131                                                     decal.texcoords[j][1] = rot.z + .5;
1132                                                 }
1133                                             }
1134                                             if (decals.size() < max_model_decals - 1) {
1135                                                 decals.push_back(decal);
1136                                             }
1137                                         }
1138                         }
1139                     }
1140                 }
1141     }
1142 }
1143
1144 void Model::deleteDeadDecals()
1145 {
1146     for (int i = decals.size() - 1; i >= 0; i--) {
1147         if ((decals[i].type == blooddecal || decals[i].type == blooddecalslow) && decals[i].alivetime < 2) {
1148             DeleteDecal(i);
1149         }
1150     }
1151 }
1152
1153 Model::~Model()
1154 {
1155     deallocate();
1156 }
1157
1158 void Model::deallocate()
1159 {
1160     if (owner)
1161         free(owner);
1162     owner = 0;
1163
1164     if (vertex)
1165         free(vertex);
1166     vertex = 0;
1167
1168     if (normals)
1169         free(normals);
1170     normals = 0;
1171
1172     if (vArray)
1173         free(vArray);
1174     vArray = 0;
1175
1176     decals.clear();
1177 }
1178
1179 Model::Model()
1180   : vertexNum(0),
1181     type(nothing),
1182     owner(0),
1183     vertex(0),
1184     normals(0),
1185     vArray(0),
1186     color(0),
1187     boundingspherecenter(),
1188     boundingsphereradius(0),
1189     flat(false)
1190 {
1191     memset(&modelTexture, 0, sizeof(modelTexture));
1192 }