]> git.jsancho.org Git - lugaru.git/blob - Source/Graphic/Models.cpp
Cleaned Terrain Decal handling
[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     numdecals = 0;
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     //allow decals
611     if (!decaltexcoords) {
612         decaltexcoords = (float***)malloc(sizeof(float**)*max_model_decals);
613         for (i = 0; i < max_model_decals; i++) {
614             decaltexcoords[i] = (float**)malloc(sizeof(float*) * 3);
615             for (j = 0; j < 3; j++) {
616                 decaltexcoords[i][j] = (float*)malloc(sizeof(float) * 2);
617             }
618         }
619         decalvertex = (XYZ**)malloc(sizeof(XYZ*)*max_model_decals);
620         for (i = 0; i < max_model_decals; i++) {
621             decalvertex[i] = (XYZ*)malloc(sizeof(XYZ) * 3);
622         }
623
624         decaltype = (int*)malloc(sizeof(int) * max_model_decals);
625         decalopacity = (float*)malloc(sizeof(float) * max_model_decals);
626         decalrotation = (float*)malloc(sizeof(float) * max_model_decals);
627         decalalivetime = (float*)malloc(sizeof(float) * max_model_decals);
628         decalposition = (XYZ*)malloc(sizeof(XYZ) * max_model_decals);
629     }
630
631     return true;
632 }
633
634 bool Model::loadraw(const std::string& filename)
635 {
636     FILE *tfile;
637     long i;
638
639     LOGFUNC;
640
641     LOG(std::string("Loading raw...") + filename);
642
643     type = rawtype;
644     color = 0;
645
646     tfile = Folders::openMandatoryFile( Folders::getResourcePath(filename), "rb" );
647
648     // read model settings
649
650     fseek(tfile, 0, SEEK_SET);
651     funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
652
653     // read the model data
654     deallocate();
655
656     numpossible = 0;
657
658     owner = (int*)malloc(sizeof(int) * vertexNum);
659     possible = (int*)malloc(sizeof(int) * TriangleNum);
660     vertex = (XYZ*)malloc(sizeof(XYZ) * vertexNum);
661     Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle) * TriangleNum);
662     vArray = (GLfloat*)malloc(sizeof(GLfloat) * TriangleNum * 24);
663
664
665     for (i = 0; i < vertexNum; i++) {
666         funpackf(tfile, "Bf Bf Bf", &vertex[i].x, &vertex[i].y, &vertex[i].z);
667     }
668
669     for (i = 0; i < TriangleNum; i++) {
670         short vertex[ 6];
671         funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
672         Triangles[i].vertex[ 0] = vertex[ 0];
673         Triangles[i].vertex[ 1] = vertex[ 2];
674         Triangles[i].vertex[ 2] = vertex[ 4];
675         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
676         funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
677     }
678
679
680     fclose(tfile);
681
682     for (i = 0; i < vertexNum; i++) {
683         owner[i] = -1;
684     }
685
686     return true;
687 }
688
689
690 void Model::UniformTexCoords()
691 {
692     static int i;
693     for (i = 0; i < TriangleNum; i++) {
694         Triangles[i].gy[0] = vertex[Triangles[i].vertex[0]].y;
695         Triangles[i].gy[1] = vertex[Triangles[i].vertex[1]].y;
696         Triangles[i].gy[2] = vertex[Triangles[i].vertex[2]].y;
697         Triangles[i].gx[0] = vertex[Triangles[i].vertex[0]].x;
698         Triangles[i].gx[1] = vertex[Triangles[i].vertex[1]].x;
699         Triangles[i].gx[2] = vertex[Triangles[i].vertex[2]].x;
700     }
701     UpdateVertexArray();
702 }
703
704
705 void Model::FlipTexCoords()
706 {
707     static int i;
708     for (i = 0; i < TriangleNum; i++) {
709         Triangles[i].gy[0] = -Triangles[i].gy[0];
710         Triangles[i].gy[1] = -Triangles[i].gy[1];
711         Triangles[i].gy[2] = -Triangles[i].gy[2];
712     }
713     UpdateVertexArray();
714 }
715
716 void Model::ScaleTexCoords(float howmuch)
717 {
718     static int i;
719     for (i = 0; i < TriangleNum; i++) {
720         Triangles[i].gx[0] *= howmuch;
721         Triangles[i].gx[1] *= howmuch;
722         Triangles[i].gx[2] *= howmuch;
723         Triangles[i].gy[0] *= howmuch;
724         Triangles[i].gy[1] *= howmuch;
725         Triangles[i].gy[2] *= howmuch;
726     }
727     UpdateVertexArray();
728 }
729
730 void Model::Scale(float xscale, float yscale, float zscale)
731 {
732     static int i;
733     for (i = 0; i < vertexNum; i++) {
734         vertex[i].x *= xscale;
735         vertex[i].y *= yscale;
736         vertex[i].z *= zscale;
737     }
738     UpdateVertexArray();
739
740     static int j;
741
742     boundingsphereradius = 0;
743     for (i = 0; i < vertexNum; i++) {
744         for (j = 0; j < vertexNum; j++) {
745             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
746                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
747                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
748             }
749         }
750     }
751     boundingsphereradius = fast_sqrt(boundingsphereradius);
752 }
753
754 void Model::ScaleNormals(float xscale, float yscale, float zscale)
755 {
756     if (type != normaltype && type != decalstype)
757         return;
758     static int i;
759     for (i = 0; i < vertexNum; i++) {
760         normals[i].x *= xscale;
761         normals[i].y *= yscale;
762         normals[i].z *= zscale;
763     }
764     for (i = 0; i < TriangleNum; i++) {
765         facenormals[i].x *= xscale;
766         facenormals[i].y *= yscale;
767         facenormals[i].z *= zscale;
768     }
769     UpdateVertexArray();
770 }
771
772 void Model::Translate(float xtrans, float ytrans, float ztrans)
773 {
774     static int i;
775     for (i = 0; i < vertexNum; i++) {
776         vertex[i].x += xtrans;
777         vertex[i].y += ytrans;
778         vertex[i].z += ztrans;
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 void Model::Rotate(float xang, float yang, float zang)
796 {
797     static int i;
798     for (i = 0; i < vertexNum; i++) {
799         vertex[i] = DoRotation(vertex[i], xang, yang, zang);
800     }
801     UpdateVertexArray();
802
803     static int j;
804     boundingsphereradius = 0;
805     for (i = 0; i < vertexNum; i++) {
806         for (j = 0; j < vertexNum; j++) {
807             if (j != i && distsq(&vertex[j], &vertex[i]) / 2 > boundingsphereradius) {
808                 boundingsphereradius = distsq(&vertex[j], &vertex[i]) / 2;
809                 boundingspherecenter = (vertex[i] + vertex[j]) / 2;
810             }
811         }
812     }
813     boundingsphereradius = fast_sqrt(boundingsphereradius);
814 }
815
816
817 void Model::CalculateNormals(bool facenormalise)
818 {
819     Game::LoadingScreen();
820     static int i;
821     if (type != normaltype && type != decalstype)
822         return;
823
824     for (i = 0; i < vertexNum; i++) {
825         normals[i].x = 0;
826         normals[i].y = 0;
827         normals[i].z = 0;
828     }
829
830     for (i = 0; i < TriangleNum; i++) {
831         CrossProduct(vertex[Triangles[i].vertex[1]] - vertex[Triangles[i].vertex[0]], vertex[Triangles[i].vertex[2]] - vertex[Triangles[i].vertex[0]], &facenormals[i]);
832
833         normals[Triangles[i].vertex[0]].x += facenormals[i].x;
834         normals[Triangles[i].vertex[0]].y += facenormals[i].y;
835         normals[Triangles[i].vertex[0]].z += facenormals[i].z;
836
837         normals[Triangles[i].vertex[1]].x += facenormals[i].x;
838         normals[Triangles[i].vertex[1]].y += facenormals[i].y;
839         normals[Triangles[i].vertex[1]].z += facenormals[i].z;
840
841         normals[Triangles[i].vertex[2]].x += facenormals[i].x;
842         normals[Triangles[i].vertex[2]].y += facenormals[i].y;
843         normals[Triangles[i].vertex[2]].z += facenormals[i].z;
844         if (facenormalise)
845             Normalise(&facenormals[i]);
846     }
847     for (i = 0; i < vertexNum; i++) {
848         Normalise(&normals[i]);
849         normals[i] *= -1;
850     }
851     UpdateVertexArrayNoTex();
852 }
853
854 void Model::drawimmediate()
855 {
856     textureptr.bind();
857     glBegin(GL_TRIANGLES);
858     for (int i = 0; i < TriangleNum; i++) {
859         glTexCoord2f(Triangles[i].gx[0], Triangles[i].gy[0]);
860         if (color)
861             glColor3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
862         if (!color && !flat)
863             glNormal3f(normals[Triangles[i].vertex[0]].x, normals[Triangles[i].vertex[0]].y, normals[Triangles[i].vertex[0]].z);
864         if (!color && flat)
865             glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
866         glVertex3f(vertex[Triangles[i].vertex[0]].x, vertex[Triangles[i].vertex[0]].y, vertex[Triangles[i].vertex[0]].z);
867
868         glTexCoord2f(Triangles[i].gx[1], Triangles[i].gy[1]);
869         if (color)
870             glColor3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
871         if (!color && !flat)
872             glNormal3f(normals[Triangles[i].vertex[1]].x, normals[Triangles[i].vertex[1]].y, normals[Triangles[i].vertex[1]].z);
873         if (!color && flat)
874             glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
875         glVertex3f(vertex[Triangles[i].vertex[1]].x, vertex[Triangles[i].vertex[1]].y, vertex[Triangles[i].vertex[1]].z);
876
877         glTexCoord2f(Triangles[i].gx[2], Triangles[i].gy[2]);
878         if (color)
879             glColor3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
880         if (!color && !flat)
881             glNormal3f(normals[Triangles[i].vertex[2]].x, normals[Triangles[i].vertex[2]].y, normals[Triangles[i].vertex[2]].z);
882         if (!color && flat)
883             glNormal3f(facenormals[i].x, facenormals[i].y, facenormals[i].y);
884         glVertex3f(vertex[Triangles[i].vertex[2]].x, vertex[Triangles[i].vertex[2]].y, vertex[Triangles[i].vertex[2]].z);
885     }
886     glEnd();
887 }
888
889 void Model::draw()
890 {
891     if (type != normaltype && type != decalstype)
892         return;
893
894     glEnableClientState(GL_NORMAL_ARRAY);
895     glEnableClientState(GL_VERTEX_ARRAY);
896     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
897
898     if (!color)
899         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
900     if (color)
901         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
902     textureptr.bind();
903
904     glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
905
906     if (!color)
907         glDisableClientState(GL_NORMAL_ARRAY);
908     if (color)
909         glDisableClientState(GL_COLOR_ARRAY);
910     glDisableClientState(GL_VERTEX_ARRAY);
911     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
912 }
913
914 //TODO: phase out in favor of Texture
915 void Model::drawdifftex(GLuint texture)
916 {
917     glEnableClientState(GL_NORMAL_ARRAY);
918     glEnableClientState(GL_VERTEX_ARRAY);
919     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
920     if (!color)
921         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
922     if (color)
923         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
924
925     glBindTexture(GL_TEXTURE_2D, (unsigned long)texture);
926     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
927     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
928
929     glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
930
931     if (!color)
932         glDisableClientState(GL_NORMAL_ARRAY);
933     if (color)
934         glDisableClientState(GL_COLOR_ARRAY);
935     glDisableClientState(GL_VERTEX_ARRAY);
936     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
937 }
938
939 void Model::drawdifftex(Texture texture)
940 {
941     glEnableClientState(GL_NORMAL_ARRAY);
942     glEnableClientState(GL_VERTEX_ARRAY);
943     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
944     if (!color)
945         glInterleavedArrays( GL_T2F_N3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
946     if (color)
947         glInterleavedArrays( GL_T2F_C3F_V3F, 8 * sizeof(GLfloat), &vArray[0]);
948
949     texture.bind();
950     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
951     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
952
953     glDrawArrays(GL_TRIANGLES, 0, TriangleNum * 3);
954
955     if (!color)
956         glDisableClientState(GL_NORMAL_ARRAY);
957     if (color)
958         glDisableClientState(GL_COLOR_ARRAY);
959     glDisableClientState(GL_VERTEX_ARRAY);
960     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
961 }
962
963 void Model::drawdecals(Texture shadowtexture, Texture bloodtexture, Texture bloodtexture2, Texture breaktexture)
964 {
965     if (decalstoggle) {
966         if (type != decalstype)
967             return;
968         static int i;
969         static int lasttype;
970         static bool blend;
971
972         blend = 1;
973
974         lasttype = -1;
975         glEnable(GL_BLEND);
976         glDisable(GL_LIGHTING);
977         glDisable(GL_CULL_FACE);
978         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
979         glDepthMask(0);
980         if (numdecals > max_model_decals)
981             numdecals = max_model_decals;
982         for (i = 0; i < numdecals; i++) {
983             if (decaltype[i] == blooddecalfast && decalalivetime[i] < 2)
984                 decalalivetime[i] = 2;
985
986             if (decaltype[i] == shadowdecal && decaltype[i] != lasttype) {
987                 shadowtexture.bind();
988                 if (!blend) {
989                     blend = 1;
990                     glAlphaFunc(GL_GREATER, 0.0001);
991                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
992                 }
993             }
994             if (decaltype[i] == breakdecal && decaltype[i] != lasttype) {
995                 breaktexture.bind();
996                 if (!blend) {
997                     blend = 1;
998                     glAlphaFunc(GL_GREATER, 0.0001);
999                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1000                 }
1001             }
1002             if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalslow) && decaltype[i] != lasttype) {
1003                 bloodtexture.bind();
1004                 if (blend) {
1005                     blend = 0;
1006                     glAlphaFunc(GL_GREATER, 0.15);
1007                     glBlendFunc(GL_ONE, GL_ZERO);
1008                 }
1009             }
1010             if ((decaltype[i] == blooddecalfast) && decaltype[i] != lasttype) {
1011                 bloodtexture2.bind();
1012                 if (blend) {
1013                     blend = 0;
1014                     glAlphaFunc(GL_GREATER, 0.15);
1015                     glBlendFunc(GL_ONE, GL_ZERO);
1016                 }
1017             }
1018             if (decaltype[i] == shadowdecal) {
1019                 glColor4f(1, 1, 1, decalopacity[i]);
1020             }
1021             if (decaltype[i] == breakdecal) {
1022                 glColor4f(1, 1, 1, decalopacity[i]);
1023                 if (decalalivetime[i] > 58)
1024                     glColor4f(1, 1, 1, decalopacity[i] * (60 - decalalivetime[i]) / 2);
1025             }
1026             if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow)) {
1027                 glColor4f(1, 1, 1, decalopacity[i]);
1028                 if (decalalivetime[i] < 4)
1029                     glColor4f(1, 1, 1, decalopacity[i]*decalalivetime[i]*.25);
1030                 if (decalalivetime[i] > 58)
1031                     glColor4f(1, 1, 1, decalopacity[i] * (60 - decalalivetime[i]) / 2);
1032             }
1033             lasttype = decaltype[i];
1034             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1035             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1036
1037             glMatrixMode(GL_MODELVIEW);
1038             glPushMatrix();
1039             glBegin(GL_TRIANGLES);
1040             for (int j = 0; j < 3; j++) {
1041                 glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]);
1042                 glVertex3f(decalvertex[i][j].x, decalvertex[i][j].y, decalvertex[i][j].z);
1043             }
1044             glEnd();
1045             glPopMatrix();
1046         }
1047         for (i = numdecals - 1; i >= 0; i--) {
1048             decalalivetime[i] += multiplier;
1049             if (decaltype[i] == blooddecalslow)
1050                 decalalivetime[i] -= multiplier * 2 / 3;
1051             if (decaltype[i] == blooddecalfast)
1052                 decalalivetime[i] += multiplier * 4;
1053             if (decaltype[i] == shadowdecal)
1054                 DeleteDecal(i);
1055             if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow) && decalalivetime[i] >= 60)
1056                 DeleteDecal(i);
1057         }
1058         glAlphaFunc(GL_GREATER, 0.0001);
1059         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1060     }
1061 }
1062
1063 void Model::DeleteDecal(int which)
1064 {
1065     if (decalstoggle) {
1066         if (type != decalstype)
1067             return;
1068         decaltype[which] = decaltype[numdecals - 1];
1069         decalposition[which] = decalposition[numdecals - 1];
1070         for (int i = 0; i < 3; i++) {
1071             decalvertex[which][i] = decalvertex[numdecals - 1][i];
1072             decaltexcoords[which][i][0] = decaltexcoords[numdecals - 1][i][0];
1073             decaltexcoords[which][i][1] = decaltexcoords[numdecals - 1][i][1];
1074         }
1075         decalrotation[which] = decalrotation[numdecals - 1];
1076         decalalivetime[which] = decalalivetime[numdecals - 1];
1077         decalopacity[which] = decalopacity[numdecals - 1];
1078         numdecals--;
1079     }
1080 }
1081
1082 void Model::MakeDecal(int atype, XYZ *where, float *size, float *opacity, float *rotation)
1083 {
1084     if (decalstoggle) {
1085         if (type != decalstype)
1086             return;
1087
1088         static float placex, placez;
1089         static XYZ rot;
1090         static float distance;
1091         static int i, j;
1092
1093         if (*opacity > 0)
1094             if (distsq(where, &boundingspherecenter) < (boundingsphereradius + *size) * (boundingsphereradius + *size))
1095                 for (i = 0; i < TriangleNum; i++) {
1096                     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)) {
1097                         decalposition[numdecals] = *where;
1098                         decaltype[numdecals] = atype;
1099                         decalrotation[numdecals] = *rotation;
1100                         decalalivetime[numdecals] = 0;
1101                         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);
1102                         decalopacity[numdecals] = *opacity - distance / 10;
1103
1104                         if (decalopacity[numdecals > 0]) {
1105                             placex = vertex[Triangles[i].vertex[0]].x;
1106                             placez = vertex[Triangles[i].vertex[0]].z;
1107
1108                             decaltexcoords[numdecals][0][0] = (placex - where->x) / (*size) / 2 + .5;
1109                             decaltexcoords[numdecals][0][1] = (placez - where->z) / (*size) / 2 + .5;
1110
1111                             decalvertex[numdecals][0].x = placex;
1112                             decalvertex[numdecals][0].z = placez;
1113                             decalvertex[numdecals][0].y = vertex[Triangles[i].vertex[0]].y;
1114
1115
1116                             placex = vertex[Triangles[i].vertex[1]].x;
1117                             placez = vertex[Triangles[i].vertex[1]].z;
1118
1119                             decaltexcoords[numdecals][1][0] = (placex - where->x) / (*size) / 2 + .5;
1120                             decaltexcoords[numdecals][1][1] = (placez - where->z) / (*size) / 2 + .5;
1121
1122                             decalvertex[numdecals][1].x = placex;
1123                             decalvertex[numdecals][1].z = placez;
1124                             decalvertex[numdecals][1].y = vertex[Triangles[i].vertex[1]].y;
1125
1126
1127                             placex = vertex[Triangles[i].vertex[2]].x;
1128                             placez = vertex[Triangles[i].vertex[2]].z;
1129
1130                             decaltexcoords[numdecals][2][0] = (placex - where->x) / (*size) / 2 + .5;
1131                             decaltexcoords[numdecals][2][1] = (placez - where->z) / (*size) / 2 + .5;
1132
1133                             decalvertex[numdecals][2].x = placex;
1134                             decalvertex[numdecals][2].z = placez;
1135                             decalvertex[numdecals][2].y = vertex[Triangles[i].vertex[2]].y;
1136
1137                             if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
1138                                 if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
1139                                     if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
1140                                         if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
1141                                             if (decalrotation[numdecals]) {
1142                                                 for (j = 0; j < 3; j++) {
1143                                                     rot.y = 0;
1144                                                     rot.x = decaltexcoords[numdecals][j][0] - .5;
1145                                                     rot.z = decaltexcoords[numdecals][j][1] - .5;
1146                                                     rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
1147                                                     decaltexcoords[numdecals][j][0] = rot.x + .5;
1148                                                     decaltexcoords[numdecals][j][1] = rot.z + .5;
1149                                                 }
1150                                             }
1151                                             if (numdecals < max_model_decals - 1)
1152                                                 numdecals++;
1153                                         }
1154                         }
1155                     }
1156                 }
1157     }
1158 }
1159
1160 void Model::MakeDecal(int atype, XYZ where, float size, float opacity, float rotation)
1161 {
1162     if (decalstoggle) {
1163         if (type != decalstype)
1164             return;
1165
1166         static float placex, placez;
1167         static XYZ rot;
1168         static float distance;
1169         static int i, j;
1170
1171         if (opacity > 0)
1172             if (distsq(&where, &boundingspherecenter) < (boundingsphereradius + size) * (boundingsphereradius + size))
1173                 for (i = 0; i < TriangleNum; i++) {
1174                     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))));
1175                     if (distance < .02 && abs(facenormals[i].y) > abs(facenormals[i].x) && abs(facenormals[i].y) > abs(facenormals[i].z)) {
1176                         decalposition[numdecals] = where;
1177                         decaltype[numdecals] = atype;
1178                         decalrotation[numdecals] = rotation;
1179                         decalalivetime[numdecals] = 0;
1180                         decalopacity[numdecals] = opacity - distance / 10;
1181
1182                         if (decalopacity[numdecals > 0]) {
1183                             placex = vertex[Triangles[i].vertex[0]].x;
1184                             placez = vertex[Triangles[i].vertex[0]].z;
1185
1186                             decaltexcoords[numdecals][0][0] = (placex - where.x) / (size) / 2 + .5;
1187                             decaltexcoords[numdecals][0][1] = (placez - where.z) / (size) / 2 + .5;
1188
1189                             decalvertex[numdecals][0].x = placex;
1190                             decalvertex[numdecals][0].z = placez;
1191                             decalvertex[numdecals][0].y = vertex[Triangles[i].vertex[0]].y;
1192
1193
1194                             placex = vertex[Triangles[i].vertex[1]].x;
1195                             placez = vertex[Triangles[i].vertex[1]].z;
1196
1197                             decaltexcoords[numdecals][1][0] = (placex - where.x) / (size) / 2 + .5;
1198                             decaltexcoords[numdecals][1][1] = (placez - where.z) / (size) / 2 + .5;
1199
1200                             decalvertex[numdecals][1].x = placex;
1201                             decalvertex[numdecals][1].z = placez;
1202                             decalvertex[numdecals][1].y = vertex[Triangles[i].vertex[1]].y;
1203
1204
1205                             placex = vertex[Triangles[i].vertex[2]].x;
1206                             placez = vertex[Triangles[i].vertex[2]].z;
1207
1208                             decaltexcoords[numdecals][2][0] = (placex - where.x) / (size) / 2 + .5;
1209                             decaltexcoords[numdecals][2][1] = (placez - where.z) / (size) / 2 + .5;
1210
1211                             decalvertex[numdecals][2].x = placex;
1212                             decalvertex[numdecals][2].z = placez;
1213                             decalvertex[numdecals][2].y = vertex[Triangles[i].vertex[2]].y;
1214
1215                             if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
1216                                 if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
1217                                     if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
1218                                         if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
1219                                             if (decalrotation[numdecals]) {
1220                                                 for (j = 0; j < 3; j++) {
1221                                                     rot.y = 0;
1222                                                     rot.x = decaltexcoords[numdecals][j][0] - .5;
1223                                                     rot.z = decaltexcoords[numdecals][j][1] - .5;
1224                                                     rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
1225                                                     decaltexcoords[numdecals][j][0] = rot.x + .5;
1226                                                     decaltexcoords[numdecals][j][1] = rot.z + .5;
1227                                                 }
1228                                             }
1229                                             if (numdecals < max_model_decals - 1)
1230                                                 numdecals++;
1231                                         }
1232                         }
1233                     } else if (distance < .02 && abs(facenormals[i].x) > abs(facenormals[i].y) && abs(facenormals[i].x) > abs(facenormals[i].z)) {
1234                         decalposition[numdecals] = where;
1235                         decaltype[numdecals] = atype;
1236                         decalrotation[numdecals] = rotation;
1237                         decalalivetime[numdecals] = 0;
1238                         decalopacity[numdecals] = opacity - distance / 10;
1239
1240                         if (decalopacity[numdecals > 0]) {
1241                             placex = vertex[Triangles[i].vertex[0]].y;
1242                             placez = vertex[Triangles[i].vertex[0]].z;
1243
1244                             decaltexcoords[numdecals][0][0] = (placex - where.y) / (size) / 2 + .5;
1245                             decaltexcoords[numdecals][0][1] = (placez - where.z) / (size) / 2 + .5;
1246
1247                             decalvertex[numdecals][0].x = vertex[Triangles[i].vertex[0]].x;
1248                             decalvertex[numdecals][0].z = placez;
1249                             decalvertex[numdecals][0].y = placex;
1250
1251
1252                             placex = vertex[Triangles[i].vertex[1]].y;
1253                             placez = vertex[Triangles[i].vertex[1]].z;
1254
1255                             decaltexcoords[numdecals][1][0] = (placex - where.y) / (size) / 2 + .5;
1256                             decaltexcoords[numdecals][1][1] = (placez - where.z) / (size) / 2 + .5;
1257
1258                             decalvertex[numdecals][1].x = vertex[Triangles[i].vertex[1]].x;
1259                             decalvertex[numdecals][1].z = placez;
1260                             decalvertex[numdecals][1].y = placex;
1261
1262
1263                             placex = vertex[Triangles[i].vertex[2]].y;
1264                             placez = vertex[Triangles[i].vertex[2]].z;
1265
1266                             decaltexcoords[numdecals][2][0] = (placex - where.y) / (size) / 2 + .5;
1267                             decaltexcoords[numdecals][2][1] = (placez - where.z) / (size) / 2 + .5;
1268
1269                             decalvertex[numdecals][2].x = vertex[Triangles[i].vertex[2]].x;
1270                             decalvertex[numdecals][2].z = placez;
1271                             decalvertex[numdecals][2].y = placex;
1272
1273                             if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
1274                                 if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
1275                                     if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
1276                                         if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
1277                                             if (decalrotation[numdecals]) {
1278                                                 for (j = 0; j < 3; j++) {
1279                                                     rot.y = 0;
1280                                                     rot.x = decaltexcoords[numdecals][j][0] - .5;
1281                                                     rot.z = decaltexcoords[numdecals][j][1] - .5;
1282                                                     rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
1283                                                     decaltexcoords[numdecals][j][0] = rot.x + .5;
1284                                                     decaltexcoords[numdecals][j][1] = rot.z + .5;
1285                                                 }
1286                                             }
1287                                             if (numdecals < max_model_decals - 1)
1288                                                 numdecals++;
1289                                         }
1290                         }
1291                     } else if (distance < .02 && abs(facenormals[i].z) > abs(facenormals[i].y) && abs(facenormals[i].z) > abs(facenormals[i].x)) {
1292                         decalposition[numdecals] = where;
1293                         decaltype[numdecals] = atype;
1294                         decalrotation[numdecals] = rotation;
1295                         decalalivetime[numdecals] = 0;
1296                         decalopacity[numdecals] = opacity - distance / 10;
1297
1298                         if (decalopacity[numdecals > 0]) {
1299                             placex = vertex[Triangles[i].vertex[0]].x;
1300                             placez = vertex[Triangles[i].vertex[0]].y;
1301
1302                             decaltexcoords[numdecals][0][0] = (placex - where.x) / (size) / 2 + .5;
1303                             decaltexcoords[numdecals][0][1] = (placez - where.y) / (size) / 2 + .5;
1304
1305                             decalvertex[numdecals][0].x = placex;
1306                             decalvertex[numdecals][0].z = vertex[Triangles[i].vertex[0]].z;
1307                             decalvertex[numdecals][0].y = placez;
1308
1309
1310                             placex = vertex[Triangles[i].vertex[1]].x;
1311                             placez = vertex[Triangles[i].vertex[1]].y;
1312
1313                             decaltexcoords[numdecals][1][0] = (placex - where.x) / (size) / 2 + .5;
1314                             decaltexcoords[numdecals][1][1] = (placez - where.y) / (size) / 2 + .5;
1315
1316                             decalvertex[numdecals][1].x = placex;
1317                             decalvertex[numdecals][1].z = vertex[Triangles[i].vertex[1]].z;
1318                             decalvertex[numdecals][1].y = placez;
1319
1320
1321                             placex = vertex[Triangles[i].vertex[2]].x;
1322                             placez = vertex[Triangles[i].vertex[2]].y;
1323
1324                             decaltexcoords[numdecals][2][0] = (placex - where.x) / (size) / 2 + .5;
1325                             decaltexcoords[numdecals][2][1] = (placez - where.y) / (size) / 2 + .5;
1326
1327                             decalvertex[numdecals][2].x = placex;
1328                             decalvertex[numdecals][2].z = vertex[Triangles[i].vertex[2]].z;
1329                             decalvertex[numdecals][2].y = placez;
1330
1331                             if (!(decaltexcoords[numdecals][0][0] < 0 && decaltexcoords[numdecals][1][0] < 0 && decaltexcoords[numdecals][2][0] < 0))
1332                                 if (!(decaltexcoords[numdecals][0][1] < 0 && decaltexcoords[numdecals][1][1] < 0 && decaltexcoords[numdecals][2][1] < 0))
1333                                     if (!(decaltexcoords[numdecals][0][0] > 1 && decaltexcoords[numdecals][1][0] > 1 && decaltexcoords[numdecals][2][0] > 1))
1334                                         if (!(decaltexcoords[numdecals][0][1] > 1 && decaltexcoords[numdecals][1][1] > 1 && decaltexcoords[numdecals][2][1] > 1)) {
1335                                             if (decalrotation[numdecals]) {
1336                                                 for (j = 0; j < 3; j++) {
1337                                                     rot.y = 0;
1338                                                     rot.x = decaltexcoords[numdecals][j][0] - .5;
1339                                                     rot.z = decaltexcoords[numdecals][j][1] - .5;
1340                                                     rot = DoRotation(rot, 0, -decalrotation[numdecals], 0);
1341                                                     decaltexcoords[numdecals][j][0] = rot.x + .5;
1342                                                     decaltexcoords[numdecals][j][1] = rot.z + .5;
1343                                                 }
1344                                             }
1345                                             if (numdecals < max_model_decals - 1)
1346                                                 numdecals++;
1347                                         }
1348                         }
1349                     }
1350                 }
1351     }
1352 }
1353
1354 Model::~Model()
1355 {
1356     deallocate();
1357 }
1358
1359 void Model::deallocate()
1360 {
1361     int i = 0, j = 0;
1362
1363     if (owner)
1364         free(owner);
1365     owner = 0;
1366
1367     if (possible)
1368         free(possible);
1369     possible = 0;
1370
1371     if (vertex)
1372         free(vertex);
1373     vertex = 0;
1374
1375     if (normals)
1376         free(normals);
1377     normals = 0;
1378
1379     if (facenormals)
1380         free(facenormals);
1381     facenormals = 0;
1382
1383     if (Triangles)
1384         free(Triangles);
1385     Triangles = 0;
1386
1387     if (vArray)
1388         free(vArray);
1389     vArray = 0;
1390
1391
1392     //allow decals
1393     if (decaltexcoords) {
1394         for (i = 0; i < max_model_decals; i++) {
1395             for (j = 0; j < 3; j++) {
1396                 free(decaltexcoords[i][j]);
1397             }
1398             free(decaltexcoords[i]);
1399         }
1400         free(decaltexcoords);
1401     }
1402     decaltexcoords = 0;
1403
1404
1405     if (decalvertex) {
1406         for (i = 0; i < max_model_decals; i++) {
1407             free(decalvertex[i]);
1408         }
1409         free(decalvertex);
1410     }
1411     decalvertex = 0;
1412
1413
1414     free(decaltype);
1415     decaltype = 0;
1416
1417     free(decalopacity);
1418     decalopacity = 0;
1419
1420     free(decalrotation);
1421     decalrotation = 0;
1422
1423     free(decalalivetime);
1424     decalalivetime = 0;
1425
1426     free(decalposition);
1427     decalposition = 0;
1428
1429 }
1430
1431 Model::Model()
1432   : vertexNum(0), TriangleNum(0),
1433     hastexture(0),
1434     type(0), oldtype(0),
1435     possible(0),
1436     owner(0),
1437     vertex(0),
1438     normals(0),
1439     facenormals(0),
1440     Triangles(0),
1441     vArray(0)
1442 {
1443     memset(&modelTexture, 0, sizeof(modelTexture));
1444     numpossible = 0;
1445     color = 0;
1446
1447     boundingspherecenter = 0;
1448     boundingsphereradius = 0;
1449
1450     decaltexcoords = 0;
1451     decalvertex = 0;
1452     decaltype = 0;
1453     decalopacity = 0;
1454     decalrotation = 0;
1455     decalalivetime = 0;
1456     decalposition = 0;
1457
1458     numdecals = 0;
1459
1460     flat = 0;
1461
1462     type = nothing;
1463 }