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