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