]> git.jsancho.org Git - lugaru.git/blob - Source/Graphic/Models.cpp
Replaced Model::possible with a vector
[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     int 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     int 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     int 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     int 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         if (!color && !flat)
827             glNormal3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
828         if (!color && flat)
829             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
830         glVertex3f(vertex[Triangles[i].vertex[0]].x, vertex[Triangles[i].vertex[0]].y, vertex[Triangles[i].vertex[0]].z);
831
832         glTexCoord2f(Triangles[i].gx[1], Triangles[i].gy[1]);
833         if (color)
834             glColor3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
835         if (!color && !flat)
836             glNormal3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
837         if (!color && flat)
838             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
839         glVertex3f(vertex[Triangles[i].vertex[1]].x, vertex[Triangles[i].vertex[1]].y, vertex[Triangles[i].vertex[1]].z);
840
841         glTexCoord2f(Triangles[i].gx[2], Triangles[i].gy[2]);
842         if (color)
843             glColor3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
844         if (!color && !flat)
845             glNormal3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
846         if (!color && flat)
847             glNormal3f(Triangles[i].facenormal.x, Triangles[i].facenormal.y, Triangles[i].facenormal.y);
848         glVertex3f(vertex[Triangles[i].vertex[2]].x, vertex[Triangles[i].vertex[2]].y, vertex[Triangles[i].vertex[2]].z);
849     }
850     glEnd();
851 }
852
853 void Model::draw()
854 {
855     if (type != normaltype && type != decalstype)
856         return;
857
858     glEnableClientState(GL_NORMAL_ARRAY);
859     glEnableClientState(GL_VERTEX_ARRAY);
860     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
861
862     if (!color)
863         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
864     if (color)
865         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
866     textureptr.bind();
867
868     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
869
870     if (!color)
871         glDisableClientState(GL_NORMAL_ARRAY);
872     if (color)
873         glDisableClientState(GL_COLOR_ARRAY);
874     glDisableClientState(GL_VERTEX_ARRAY);
875     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
876 }
877
878 //TODO: phase out in favor of Texture
879 void Model::drawdifftex(GLuint texture)
880 {
881     glEnableClientState(GL_NORMAL_ARRAY);
882     glEnableClientState(GL_VERTEX_ARRAY);
883     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
884     if (!color)
885         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
886     if (color)
887         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
888
889     glBindTexture(GL_TEXTURE_2D, (unsigned long)texture);
890     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
891     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
892
893     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
894
895     if (!color)
896         glDisableClientState(GL_NORMAL_ARRAY);
897     if (color)
898         glDisableClientState(GL_COLOR_ARRAY);
899     glDisableClientState(GL_VERTEX_ARRAY);
900     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
901 }
902
903 void Model::drawdifftex(Texture texture)
904 {
905     glEnableClientState(GL_NORMAL_ARRAY);
906     glEnableClientState(GL_VERTEX_ARRAY);
907     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
908     if (!color)
909         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
910     if (color)
911         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
912
913     texture.bind();
914     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
915     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
916
917     glDrawArrays(GL_TRIANGLES, 0, Triangles.size() * 3);
918
919     if (!color)
920         glDisableClientState(GL_NORMAL_ARRAY);
921     if (color)
922         glDisableClientState(GL_COLOR_ARRAY);
923     glDisableClientState(GL_VERTEX_ARRAY);
924     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
925 }
926
927 void Model::drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture)
928 {
929     if (decalstoggle) {
930         if (type != decalstype)
931             return;
932         static int lasttype;
933         static bool blend;
934
935         blend = 1;
936
937         lasttype = -1;
938         glEnable(GL_BLEND);
939         glDisable(GL_LIGHTING);
940         glDisable(GL_CULL_FACE);
941         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
942         glDepthMask(0);
943         for (unsigned int i = 0; i < decals.size(); i++) {
944             if (decals[i].type == blooddecalfast && decals[i].alivetime < 2)
945                 decals[i].alivetime = 2;
946
947             if (decals[i].type != lasttype) {
948                 if (decals[i].type == shadowdecal) {
949                     shadowtexture.bind();
950                     if (!blend) {
951                         blend = 1;
952                         glAlphaFunc(GL_GREATER, 0.0001);
953                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
954                     }
955                 }
956                 if (decals[i].type == breakdecal) {
957                     breaktexture.bind();
958                     if (!blend) {
959                         blend = 1;
960                         glAlphaFunc(GL_GREATER, 0.0001);
961                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
962                     }
963                 }
964                 if (decals[i].type == blooddecal || decals[i].type == blooddecalslow) {
965                     bloodtexture.bind();
966                     if (blend) {
967                         blend = 0;
968                         glAlphaFunc(GL_GREATER, 0.15);
969                         glBlendFunc(GL_ONE, GL_ZERO);
970                     }
971                 }
972                 if (decals[i].type == blooddecalfast) {
973                     bloodtexture2.bind();
974                     if (blend) {
975                         blend = 0;
976                         glAlphaFunc(GL_GREATER, 0.15);
977                         glBlendFunc(GL_ONE, GL_ZERO);
978                     }
979                 }
980             }
981             if (decals[i].type == shadowdecal) {
982                 glColor4f(1, 1, 1, decals[i].opacity);
983             }
984             if (decals[i].type == breakdecal) {
985                 glColor4f(1, 1, 1, decals[i].opacity);
986                 if (decals[i].alivetime > 58)
987                     glColor4f(1, 1, 1, decals[i].opacity * (60 - decals[i].alivetime) / 2);
988             }
989             if ((decals[i].type == blooddecal || decals[i].type == blooddecalfast || decals[i].type == blooddecalslow)) {
990                 glColor4f(1, 1, 1, decals[i].opacity);
991                 if (decals[i].alivetime < 4)
992                     glColor4f(1, 1, 1, decals[i].opacity*decals[i].alivetime*.25);
993                 if (decals[i].alivetime > 58)
994                     glColor4f(1, 1, 1, decals[i].opacity * (60 - decals[i].alivetime) / 2);
995             }
996             lasttype = decals[i].type;
997             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
998             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
999
1000             glMatrixMode(GL_MODELVIEW);
1001             glPushMatrix();
1002             glBegin(GL_TRIANGLES);
1003             for (int j = 0; j < 3; j++) {
1004                 glTexCoord2f(decals[i].texcoords[j][0], decals[i].texcoords[j][1]);
1005                 glVertex3f(decals[i].vertex[j].x, decals[i].vertex[j].y, decals[i].vertex[j].z);
1006             }
1007             glEnd();
1008             glPopMatrix();
1009         }
1010         for (int i = decals.size() - 1; i >= 0; i--) {
1011             decals[i].alivetime += multiplier;
1012             if (decals[i].type == blooddecalslow)
1013                 decals[i].alivetime -= multiplier * 2 / 3;
1014             if (decals[i].type == blooddecalfast)
1015                 decals[i].alivetime += multiplier * 4;
1016             if (decals[i].type == shadowdecal)
1017                 DeleteDecal(i);
1018             if ((decals[i].type == blooddecal || decals[i].type == blooddecalfast || decals[i].type == blooddecalslow) && decals[i].alivetime >= 60)
1019                 DeleteDecal(i);
1020         }
1021         glAlphaFunc(GL_GREATER, 0.0001);
1022         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1023     }
1024 }
1025
1026 void Model::DeleteDecal(int which)
1027 {
1028     if (decalstoggle) {
1029         if (type != decalstype)
1030             return;
1031         decals.erase(decals.begin() + which);
1032     }
1033 }
1034
1035 void Model::MakeDecal(decal_type atype, XYZ *where, float *size, float *opacity, float *rotation)
1036 {
1037     if (decalstoggle) {
1038         if (type != decalstype)
1039             return;
1040
1041         static XYZ rot;
1042         static float distance;
1043
1044         if (*opacity > 0)
1045             if (distsq(where, &boundingspherecenter) < (boundingsphereradius + *size) * (boundingsphereradius + *size))
1046                 for (unsigned int i = 0; i < Triangles.size(); i++) {
1047                     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)) {
1048                         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);
1049
1050                         if (*opacity - distance / 10 > 0) {
1051                             Decal decal(*where, atype, *opacity - distance / 10, *rotation, *size, *this, i, 0);
1052
1053                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1054                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1055                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1056                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1057                                             if (decal.rotation) {
1058                                                 for (int j = 0; j < 3; j++) {
1059                                                     rot.y = 0;
1060                                                     rot.x = decal.texcoords[j][0] - .5;
1061                                                     rot.z = decal.texcoords[j][1] - .5;
1062                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1063                                                     decal.texcoords[j][0] = rot.x + .5;
1064                                                     decal.texcoords[j][1] = rot.z + .5;
1065                                                 }
1066                                             }
1067                                             if (decals.size() < max_model_decals - 1) {
1068                                                 decals.push_back(decal);
1069                                             }
1070                                         }
1071                         }
1072                     }
1073                 }
1074     }
1075 }
1076
1077 void Model::MakeDecal(decal_type atype, XYZ where, float size, float opacity, float rotation)
1078 {
1079     if (decalstoggle) {
1080         if (type != decalstype)
1081             return;
1082
1083         static XYZ rot;
1084         static float distance;
1085
1086         if (opacity > 0)
1087             if (distsq(&where, &boundingspherecenter) < (boundingsphereradius + size) * (boundingsphereradius + size))
1088                 for (unsigned int i = 0; i < Triangles.size(); i++) {
1089                     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))));
1090                     if (distance < .02 && abs(Triangles[i].facenormal.y) > abs(Triangles[i].facenormal.x) && abs(Triangles[i].facenormal.y) > abs(Triangles[i].facenormal.z)) {
1091                         if (opacity - distance / 10 > 0) {
1092                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 0);
1093
1094                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1095                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1096                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1097                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1098                                             if (decal.rotation) {
1099                                                 for (int j = 0; j < 3; j++) {
1100                                                     rot.y = 0;
1101                                                     rot.x = decal.texcoords[j][0] - .5;
1102                                                     rot.z = decal.texcoords[j][1] - .5;
1103                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1104                                                     decal.texcoords[j][0] = rot.x + .5;
1105                                                     decal.texcoords[j][1] = rot.z + .5;
1106                                                 }
1107                                             }
1108                                             if (decals.size() < max_model_decals - 1) {
1109                                                 decals.push_back(decal);
1110                                             }
1111                                         }
1112                         }
1113                     } else if (distance < .02 && abs(Triangles[i].facenormal.x) > abs(Triangles[i].facenormal.y) && abs(Triangles[i].facenormal.x) > abs(Triangles[i].facenormal.z)) {
1114                         if (opacity - distance / 10 > 0) {
1115                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 1);
1116
1117                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1118                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1119                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1120                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1121                                             if (decal.rotation) {
1122                                                 for (int j = 0; j < 3; j++) {
1123                                                     rot.y = 0;
1124                                                     rot.x = decal.texcoords[j][0] - .5;
1125                                                     rot.z = decal.texcoords[j][1] - .5;
1126                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1127                                                     decal.texcoords[j][0] = rot.x + .5;
1128                                                     decal.texcoords[j][1] = rot.z + .5;
1129                                                 }
1130                                             }
1131                                             if (decals.size() < max_model_decals - 1) {
1132                                                 decals.push_back(decal);
1133                                             }
1134                                         }
1135                         }
1136                     } else if (distance < .02 && abs(Triangles[i].facenormal.z) > abs(Triangles[i].facenormal.y) && abs(Triangles[i].facenormal.z) > abs(Triangles[i].facenormal.x)) {
1137                         if (opacity - distance / 10 > 0) {
1138                             Decal decal(where, atype, opacity - distance / 10, rotation, size, *this, i, 2);
1139
1140                             if (!(decal.texcoords[0][0] < 0 && decal.texcoords[1][0] < 0 && decal.texcoords[2][0] < 0))
1141                                 if (!(decal.texcoords[0][1] < 0 && decal.texcoords[1][1] < 0 && decal.texcoords[2][1] < 0))
1142                                     if (!(decal.texcoords[0][0] > 1 && decal.texcoords[1][0] > 1 && decal.texcoords[2][0] > 1))
1143                                         if (!(decal.texcoords[0][1] > 1 && decal.texcoords[1][1] > 1 && decal.texcoords[2][1] > 1)) {
1144                                             if (decal.rotation) {
1145                                                 for (int j = 0; j < 3; j++) {
1146                                                     rot.y = 0;
1147                                                     rot.x = decal.texcoords[j][0] - .5;
1148                                                     rot.z = decal.texcoords[j][1] - .5;
1149                                                     rot = DoRotation(rot, 0, -decal.rotation, 0);
1150                                                     decal.texcoords[j][0] = rot.x + .5;
1151                                                     decal.texcoords[j][1] = rot.z + .5;
1152                                                 }
1153                                             }
1154                                             if (decals.size() < max_model_decals - 1) {
1155                                                 decals.push_back(decal);
1156                                             }
1157                                         }
1158                         }
1159                     }
1160                 }
1161     }
1162 }
1163
1164 void Model::deleteDeadDecals()
1165 {
1166     for (int i = decals.size() - 1; i >= 0; i--) {
1167         if ((decals[i].type == blooddecal || decals[i].type == blooddecalslow) && decals[i].alivetime < 2) {
1168             DeleteDecal(i);
1169         }
1170     }
1171 }
1172
1173 Model::~Model()
1174 {
1175     deallocate();
1176 }
1177
1178 void Model::deallocate()
1179 {
1180     if (owner)
1181         free(owner);
1182     owner = 0;
1183
1184     if (vertex)
1185         free(vertex);
1186     vertex = 0;
1187
1188     if (normals)
1189         free(normals);
1190     normals = 0;
1191
1192     if (vArray)
1193         free(vArray);
1194     vArray = 0;
1195 }
1196
1197 Model::Model()
1198   : vertexNum(0),
1199     hastexture(0),
1200     type(0), oldtype(0),
1201     owner(0),
1202     vertex(0),
1203     normals(0),
1204     vArray(0)
1205 {
1206     memset(&modelTexture, 0, sizeof(modelTexture));
1207     color = 0;
1208
1209     boundingspherecenter = 0;
1210     boundingsphereradius = 0;
1211
1212     flat = 0;
1213
1214     type = nothing;
1215 }