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