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