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