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