]> git.jsancho.org Git - lugaru.git/blob - Source/Graphic/Models.cpp
Removed unused members in Model class
[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     decals.clear();
541     color = 0;
542
543     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
544
545     // read model settings
546
547     fseek(tfile, 0, SEEK_SET);
548     funpackf(tfile, "Bs Bs", &vertexNum, &triangleNum);
549
550     // read the model data
551
552     deallocate();
553
554     possible.clear();
555
556     owner = (int*)malloc(sizeof(int) * vertexNum);
557     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
558     normals = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
559     Triangles.resize(triangleNum);
560     vArray = (GLfloat*)malloc(sizeof(GLfloat) * triangleNum * 24);
561
562     for (i = 0; i < vertexNum; i++) {
563         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
564     }
565
566     for (i = 0; i < triangleNum; i++) {
567         short vertex[6];
568         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[0], &vertex[1], &vertex[2], &vertex[3], &vertex[4], &vertex[5]);
569         Triangles[i].vertex[0] = vertex[0];
570         Triangles[i].vertex[1] = vertex[2];
571         Triangles[i].vertex[2] = vertex[4];
572         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
573         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
574     }
575
576
577     modelTexture.xsz = 0;
578
579     fclose(tfile);
580
581     UpdateVertexArray();
582
583     for (i = 0; i < vertexNum; i++) {
584         owner[i] = -1;
585     }
586
587     boundingsphereradius = 0;
588     for (i = 0; i < vertexNum; i++) {
589         for (j = 0; j < vertexNum; j++) {
590             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
591                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
592                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
593             }
594         }
595     }
596     boundingsphereradius = fast_sqrt(boundingsphereradius);
597
598     return true;
599 }
600
601 bool Model::loadraw(const std::string& filename)
602 {
603     FILE *tfile;
604     long i;
605     short triangleNum;
606
607     LOGFUNC;
608
609     LOG(std::string("Loading raw...") + filename);
610
611     type = rawtype;
612     color = 0;
613
614     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
615
616     // read model settings
617
618     fseek(tfile, 0, SEEK_SET);
619     funpackf(tfile, "Bs Bs", &vertexNum, &triangleNum);
620
621     // read the model data
622     deallocate();
623
624     possible.clear();
625
626     owner = (int*)malloc(sizeof(int) * vertexNum);
627     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
628     Triangles.resize(triangleNum);
629     vArray = (GLfloat*)malloc(sizeof(GLfloat) * triangleNum * 24);
630
631
632     for (i = 0; i < vertexNum; i++) {
633         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
634     }
635
636     for (i = 0; i < triangleNum; i++) {
637         short vertex[6];
638         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[0], &vertex[1], &vertex[2], &vertex[3], &vertex[4], &vertex[5]);
639         Triangles[i].vertex[0] = vertex[0];
640         Triangles[i].vertex[1] = vertex[2];
641         Triangles[i].vertex[2] = vertex[4];
642         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
643         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
644     }
645
646
647     fclose(tfile);
648
649     for (i = 0; i < vertexNum; i++) {
650         owner[i] = -1;
651     }
652
653     return true;
654 }
655
656
657 void Model::UniformTexCoords()
658 {
659     for (unsigned int i = 0; i < Triangles.size(); i++) {
660         Triangles[i].gy[0] = vertex[Triangles[i].vertex[0]].y;
661         Triangles[i].gy[1] = vertex[Triangles[i].vertex[1]].y;
662         Triangles[i].gy[2] = vertex[Triangles[i].vertex[2]].y;
663         Triangles[i].gx[0] = vertex[Triangles[i].vertex[0]].x;
664         Triangles[i].gx[1] = vertex[Triangles[i].vertex[1]].x;
665         Triangles[i].gx[2] = vertex[Triangles[i].vertex[2]].x;
666     }
667     UpdateVertexArray();
668 }
669
670
671 void Model::FlipTexCoords()
672 {
673     for (unsigned int i = 0; i < Triangles.size(); i++) {
674         Triangles[i].gy[0] = -Triangles[i].gy[0];
675         Triangles[i].gy[1] = -Triangles[i].gy[1];
676         Triangles[i].gy[2] = -Triangles[i].gy[2];
677     }
678     UpdateVertexArray();
679 }
680
681 void Model::ScaleTexCoords(float howmuch)
682 {
683     for (unsigned int i = 0; i < Triangles.size(); i++) {
684         Triangles[i].gx[0] *= howmuch;
685         Triangles[i].gx[1] *= howmuch;
686         Triangles[i].gx[2] *= howmuch;
687         Triangles[i].gy[0] *= howmuch;
688         Triangles[i].gy[1] *= howmuch;
689         Triangles[i].gy[2] *= howmuch;
690     }
691     UpdateVertexArray();
692 }
693
694 void Model::Scale(float xscale, float yscale, float zscale)
695 {
696     static int i;
697     for (i = 0; i < vertexNum; i++) {
698         vertex[i].x *= xscale;
699         vertex[i].y *= yscale;
700         vertex[i].z *= zscale;
701     }
702     UpdateVertexArray();
703
704     static int j;
705
706     boundingsphereradius = 0;
707     for (i = 0; i < vertexNum; i++) {
708         for (j = 0; j < vertexNum; j++) {
709             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
710                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
711                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
712             }
713         }
714     }
715     boundingsphereradius = fast_sqrt(boundingsphereradius);
716 }
717
718 void Model::ScaleNormals(float xscale, float yscale, float zscale)
719 {
720     if (type != normaltype && type != decalstype)
721         return;
722
723     for (int i = 0; i < vertexNum; i++) {
724         normals[i].x *= xscale;
725         normals[i].y *= yscale;
726         normals[i].z *= zscale;
727     }
728     for (unsigned int i = 0; i < Triangles.size(); i++) {
729         Triangles[i].facenormal.x *= xscale;
730         Triangles[i].facenormal.y *= yscale;
731         Triangles[i].facenormal.z *= zscale;
732     }
733     UpdateVertexArray();
734 }
735
736 void Model::Translate(float xtrans, float ytrans, float ztrans)
737 {
738     static int i;
739     for (i = 0; i < vertexNum; i++) {
740         vertex[i].x += xtrans;
741         vertex[i].y += ytrans;
742         vertex[i].z += ztrans;
743     }
744     UpdateVertexArray();
745
746     static int j;
747     boundingsphereradius = 0;
748     for (i = 0; i < vertexNum; i++) {
749         for (j = 0; j < vertexNum; j++) {
750             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
751                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
752                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
753             }
754         }
755     }
756     boundingsphereradius = fast_sqrt(boundingsphereradius);
757 }
758
759 void Model::Rotate(float xang, float yang, float zang)
760 {
761     static int i;
762     for (i = 0; i < vertexNum; i++) {
763         vertex[i] = DoRotation(vertex[i], xang, yang, zang);
764     }
765     UpdateVertexArray();
766
767     static int j;
768     boundingsphereradius = 0;
769     for (i = 0; i < vertexNum; i++) {
770         for (j = 0; j < vertexNum; j++) {
771             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
772                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
773                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
774             }
775         }
776     }
777     boundingsphereradius = fast_sqrt(boundingsphereradius);
778 }
779
780
781 void Model::CalculateNormals(bool facenormalise)
782 {
783     Game::LoadingScreen();
784
785     if (type != normaltype && type != decalstype)
786         return;
787
788     for (int i = 0; i < vertexNum; i++) {
789         normals[i].x = 0;
790         normals[i].y = 0;
791         normals[i].z = 0;
792     }
793
794     for (unsigned int i = 0; i < Triangles.size(); i++) {
795         CrossProduct(vertex[Triangles[i].vertex[1]] - vertex[Triangles[i].vertex[0]], vertex[Triangles[i].vertex[2]] - vertex[Triangles[i].vertex[0]], &Triangles[i].facenormal);
796
797         normals[Triangles[i].vertex[0]].x += Triangles[i].facenormal.x;
798         normals[Triangles[i].vertex[0]].y += Triangles[i].facenormal.y;
799         normals[Triangles[i].vertex[0]].z += Triangles[i].facenormal.z;
800
801         normals[Triangles[i].vertex[1]].x += Triangles[i].facenormal.x;
802         normals[Triangles[i].vertex[1]].y += Triangles[i].facenormal.y;
803         normals[Triangles[i].vertex[1]].z += Triangles[i].facenormal.z;
804
805         normals[Triangles[i].vertex[2]].x += Triangles[i].facenormal.x;
806         normals[Triangles[i].vertex[2]].y += Triangles[i].facenormal.y;
807         normals[Triangles[i].vertex[2]].z += Triangles[i].facenormal.z;
808         if (facenormalise)
809             Normalise(&Triangles[i].facenormal);
810     }
811     for (int i = 0; i < vertexNum; i++) {
812         Normalise(&normals[i]);
813         normals[i] *= -1;
814     }
815     UpdateVertexArrayNoTex();
816 }
817
818 void Model::drawimmediate()
819 {
820     textureptr.bind();
821     glBegin(GL_TRIANGLES);
822     for (unsigned int i = 0; i < Triangles.size(); i++) {
823         glTexCoord2f(Triangles[i].gx[0], Triangles[i].gy[0]);
824         if (color) {
825             glColor3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
826         } else if (flat) {
827             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
828         } else {
829             glNormal3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
830         }
831         glVertex3f(vertex[Triangles[i].vertex[0]].x, vertex[Triangles[i].vertex[0]].y, vertex[Triangles[i].vertex[0]].z);
832
833         glTexCoord2f(Triangles[i].gx[1], Triangles[i].gy[1]);
834         if (color) {
835             glColor3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
836         } else if (flat) {
837             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
838         } else {
839             glNormal3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
840         }
841         glVertex3f(vertex[Triangles[i].vertex[1]].x, vertex[Triangles[i].vertex[1]].y, vertex[Triangles[i].vertex[1]].z);
842
843         glTexCoord2f(Triangles[i].gx[2], Triangles[i].gy[2]);
844         if (color) {
845             glColor3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
846         } else if (flat) {
847             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
848         } else {
849             glNormal3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
850         }
851         glVertex3f(vertex[Triangles[i].vertex[2]].x, vertex[Triangles[i].vertex[2]].y, vertex[Triangles[i].vertex[2]].z);
852     }
853     glEnd();
854 }
855
856 void Model::draw()
857 {
858     if (type != normaltype && type != decalstype)
859         return;
860
861     glEnableClientState(GL_NORMAL_ARRAY);
862     glEnableClientState(GL_VERTEX_ARRAY);
863     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
864
865     if (color) {
866         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
867     } else {
868         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
869     }
870     textureptr.bind();
871
872     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
873
874     if (color) {
875         glDisableClientState(GL_COLOR_ARRAY);
876     } else {
877         glDisableClientState(GL_NORMAL_ARRAY);
878     }
879     glDisableClientState(GL_VERTEX_ARRAY);
880     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
881 }
882
883 void Model::drawdifftex(Texture texture)
884 {
885     glEnableClientState(GL_NORMAL_ARRAY);
886     glEnableClientState(GL_VERTEX_ARRAY);
887     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
888     if (color) {
889         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
890     } else {
891         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
892     }
893
894     texture.bind();
895     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
896     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
897
898     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
899
900     if (color) {
901         glDisableClientState(GL_COLOR_ARRAY);
902     } else {
903         glDisableClientState(GL_NORMAL_ARRAY);
904     }
905     glDisableClientState(GL_VERTEX_ARRAY);
906     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
907 }
908
909 void Model::drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture)
910 {
911     if (decalstoggle) {
912         if (type != decalstype)
913             return;
914         static int lasttype;
915         static bool blend;
916
917         blend = 1;
918
919         lasttype = -1;
920         glEnable(GL_BLEND);
921         glDisable(GL_LIGHTING);
922         glDisable(GL_CULL_FACE);
923         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
924         glDepthMask(0);
925         for (unsigned int i = 0; i < decals.size(); i++) {
926             if (decals[i].type == blooddecalfast && decals[i].alivetime < 2)
927                 decals[i].alivetime = 2;
928
929             if (decals[i].type != lasttype) {
930                 if (decals[i].type == shadowdecal) {
931                     shadowtexture.bind();
932                     if (!blend) {
933                         blend = 1;
934                         glAlphaFunc(GL_GREATER, 0.0001);
935                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
936                     }
937                 }
938                 if (decals[i].type == breakdecal) {
939                     breaktexture.bind();
940                     if (!blend) {
941                         blend = 1;
942                         glAlphaFunc(GL_GREATER, 0.0001);
943                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
944                     }
945                 }
946                 if (decals[i].type == blooddecal || decals[i].type == blooddecalslow) {
947                     bloodtexture.bind();
948                     if (blend) {
949                         blend = 0;
950                         glAlphaFunc(GL_GREATER, 0.15);
951                         glBlendFunc(GL_ONE, GL_ZERO);
952                     }
953                 }
954                 if (decals[i].type == blooddecalfast) {
955                     bloodtexture2.bind();
956                     if (blend) {
957                         blend = 0;
958                         glAlphaFunc(GL_GREATER, 0.15);
959                         glBlendFunc(GL_ONE, GL_ZERO);
960                     }
961                 }
962             }
963             if (decals[i].type == shadowdecal) {
964                 glColor4f(1, 1, 1, decals[i].opacity);
965             }
966             if (decals[i].type == breakdecal) {
967                 glColor4f(1, 1, 1, decals[i].opacity);
968                 if (decals[i].alivetime > 58)
969                     glColor4f(1, 1, 1, decals[i].opacity * (60 - decals[i].alivetime) / 2);
970             }
971             if ((decals[i].type == blooddecal || decals[i].type == blooddecalfast || decals[i].type == blooddecalslow)) {
972                 glColor4f(1, 1, 1, decals[i].opacity);
973                 if (decals[i].alivetime < 4)
974                     glColor4f(1, 1, 1, decals[i].opacity*decals[i].alivetime*.25);
975                 if (decals[i].alivetime > 58)
976                     glColor4f(1, 1, 1, decals[i].opacity * (60 - decals[i].alivetime) / 2);
977             }
978             lasttype = decals[i].type;
979             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
980             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
981
982             glMatrixMode(GL_MODELVIEW);
983             glPushMatrix();
984             glBegin(GL_TRIANGLES);
985             for (int j = 0; j < 3; j++) {
986                 glTexCoord2f(decals[i].texcoords[j][0], decals[i].texcoords[j][1]);
987                 glVertex3f(decals[i].vertex[j].x, decals[i].vertex[j].y, decals[i].vertex[j].z);
988             }
989             glEnd();
990             glPopMatrix();
991         }
992         for (int i = decals.size() - 1; i >= 0; i--) {
993             decals[i].alivetime += multiplier;
994             if (decals[i].type == blooddecalslow)
995                 decals[i].alivetime -= multiplier * 2 / 3;
996             if (decals[i].type == blooddecalfast)
997                 decals[i].alivetime += multiplier * 4;
998             if (decals[i].type == shadowdecal)
999                 DeleteDecal(i);
1000             if ((decals[i].type == blooddecal || decals[i].type == blooddecalfast || decals[i].type == blooddecalslow) && decals[i].alivetime >= 60)
1001                 DeleteDecal(i);
1002         }
1003         glAlphaFunc(GL_GREATER, 0.0001);
1004         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1005     }
1006 }
1007
1008 void Model::DeleteDecal(int which)
1009 {
1010     if (decalstoggle) {
1011         if (type != decalstype)
1012             return;
1013         decals.erase(decals.begin() + which);
1014     }
1015 }
1016
1017 void Model::MakeDecal(decal_type atype, XYZ *where, float *size, float *opacity, float *rotation)
1018 {
1019     if (decalstoggle) {
1020         if (type != decalstype)
1021             return;
1022
1023         static XYZ rot;
1024         static float distance;
1025
1026         if (*opacity > 0)
1027             if (distsq(where, &boundingspherecenter) < (boundingsphereradius + *size) * (boundingsphereradius + *size))
1028                 for (unsigned int i = 0; i < Triangles.size(); i++) {
1029                     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)) {
1030                         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);
1031
1032                         if (*opacity - distance / 10 > 0) {
1033                             Decal decal(*where, atype, *opacity - distance / 10, *rotation, *size, *this, i, 0);
1034
1035                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1036                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1037                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1038                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1039                                             if (decal.rotation) {
1040                                                 for (int j = 0; j < 3; j++) {
1041                                                     rot.y = 0;
1042                                                     rot.x = decal.texcoords[j][0] - .5;
1043                                                     rot.z = decal.texcoords[j][1] - .5;
1044                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1045                                                     decal.texcoords[j][0] = rot.x + .5;
1046                                                     decal.texcoords[j][1] = rot.z + .5;
1047                                                 }
1048                                             }
1049                                             if (decals.size() < max_model_decals - 1) {
1050                                                 decals.push_back(decal);
1051                                             }
1052                                         }
1053                         }
1054                     }
1055                 }
1056     }
1057 }
1058
1059 void Model::MakeDecal(decal_type atype, XYZ where, float size, float opacity, float rotation)
1060 {
1061     if (decalstoggle) {
1062         if (type != decalstype)
1063             return;
1064
1065         static XYZ rot;
1066         static float distance;
1067
1068         if (opacity > 0)
1069             if (distsq(&where, &boundingspherecenter) < (boundingsphereradius + size) * (boundingsphereradius + size))
1070                 for (unsigned int i = 0; i < Triangles.size(); i++) {
1071                     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))));
1072                     if (distance < .02 && abs(Triangles[i].facenormal.y) > abs(Triangles[i].facenormal.x) && abs(Triangles[i].facenormal.y) > abs(Triangles[i].facenormal.z)) {
1073                         if (opacity - distance / 10 > 0) {
1074                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 0);
1075
1076                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1077                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1078                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1079                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1080                                             if (decal.rotation) {
1081                                                 for (int j = 0; j < 3; j++) {
1082                                                     rot.y = 0;
1083                                                     rot.x = decal.texcoords[j][0] - .5;
1084                                                     rot.z = decal.texcoords[j][1] - .5;
1085                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1086                                                     decal.texcoords[j][0] = rot.x + .5;
1087                                                     decal.texcoords[j][1] = rot.z + .5;
1088                                                 }
1089                                             }
1090                                             if (decals.size() < max_model_decals - 1) {
1091                                                 decals.push_back(decal);
1092                                             }
1093                                         }
1094                         }
1095                     } else if (distance < .02 && abs(Triangles[i].facenormal.x) > abs(Triangles[i].facenormal.y) && abs(Triangles[i].facenormal.x) > abs(Triangles[i].facenormal.z)) {
1096                         if (opacity - distance / 10 > 0) {
1097                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 1);
1098
1099                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1100                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1101                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1102                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1103                                             if (decal.rotation) {
1104                                                 for (int j = 0; j < 3; j++) {
1105                                                     rot.y = 0;
1106                                                     rot.x = decal.texcoords[j][0] - .5;
1107                                                     rot.z = decal.texcoords[j][1] - .5;
1108                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1109                                                     decal.texcoords[j][0] = rot.x + .5;
1110                                                     decal.texcoords[j][1] = rot.z + .5;
1111                                                 }
1112                                             }
1113                                             if (decals.size() < max_model_decals - 1) {
1114                                                 decals.push_back(decal);
1115                                             }
1116                                         }
1117                         }
1118                     } else if (distance < .02 && abs(Triangles[i].facenormal.z) > abs(Triangles[i].facenormal.y) && abs(Triangles[i].facenormal.z) > abs(Triangles[i].facenormal.x)) {
1119                         if (opacity - distance / 10 > 0) {
1120                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 2);
1121
1122                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1123                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1124                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1125                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1126                                             if (decal.rotation) {
1127                                                 for (int j = 0; j < 3; j++) {
1128                                                     rot.y = 0;
1129                                                     rot.x = decal.texcoords[j][0] - .5;
1130                                                     rot.z = decal.texcoords[j][1] - .5;
1131                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1132                                                     decal.texcoords[j][0] = rot.x + .5;
1133                                                     decal.texcoords[j][1] = rot.z + .5;
1134                                                 }
1135                                             }
1136                                             if (decals.size() < max_model_decals - 1) {
1137                                                 decals.push_back(decal);
1138                                             }
1139                                         }
1140                         }
1141                     }
1142                 }
1143     }
1144 }
1145
1146 void Model::deleteDeadDecals()
1147 {
1148     for (int i = decals.size() - 1; i >= 0; i--) {
1149         if ((decals[i].type == blooddecal || decals[i].type == blooddecalslow) && decals[i].alivetime < 2) {
1150             DeleteDecal(i);
1151         }
1152     }
1153 }
1154
1155 Model::~Model()
1156 {
1157     deallocate();
1158 }
1159
1160 void Model::deallocate()
1161 {
1162     if (owner)
1163         free(owner);
1164     owner = 0;
1165
1166     if (vertex)
1167         free(vertex);
1168     vertex = 0;
1169
1170     if (normals)
1171         free(normals);
1172     normals = 0;
1173
1174     if (vArray)
1175         free(vArray);
1176     vArray = 0;
1177 }
1178
1179 Model::Model()
1180   : vertexNum(0),
1181     type(0),
1182     owner(0),
1183     vertex(0),
1184     normals(0),
1185     vArray(0)
1186 {
1187     memset(&modelTexture, 0, sizeof(modelTexture));
1188     color = 0;
1189
1190     boundingspherecenter = 0;
1191     boundingsphereradius = 0;
1192
1193     flat = 0;
1194
1195     type = nothing;
1196 }