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