]> git.jsancho.org Git - lugaru.git/blob - Source/Environment/Terrain.cpp
e85b71f5a954cccf6ad5b1f02b065fcb3fbfbcc3
[lugaru.git] / Source / Environment / 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 "Environment/Terrain.hpp"
22
23 #include "Game.hpp"
24 #include "Objects/Object.hpp"
25 #include "Utils/Folders.hpp"
26 #include "Tutorial.hpp"
27
28 extern XYZ viewer;
29 extern float viewdistance;
30 extern float fadestart;
31 extern int environment;
32 extern float texscale;
33 extern Light light;
34 extern float multiplier;
35 extern FRUSTUM frustum;
36 extern float texdetail;
37 extern int detail;
38 extern bool decals;
39 extern float blurness;
40 extern float targetblurness;
41 extern bool skyboxtexture;
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 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 std::string& fileName)
401 {
402     static long i, j;
403     static long x, y;
404     static float patch_size;
405
406     float temptexdetail = texdetail;
407
408     ImageRec texture;
409
410     //Load Image
411     if (!load_image(Folders::getResourcePath(fileName).c_str(), texture)) {
412         return false;
413     }
414
415     //Is it valid?
416     if (texture.bpp > 24) {
417         int bytesPerPixel = texture.bpp / 8;
418
419         int tempnum = 0;
420         for (i = 0; i < (long)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
421             if ((i + 1) % 4) {
422                 texture.data[tempnum] = texture.data[i];
423                 tempnum++;
424             }
425         }
426     }
427     texture.bpp = 24;
428     Game::LoadingScreen();
429
430     texdetail = temptexdetail;
431
432     size = texture.sizeX;
433
434     for (i = 0; i < size; i++) {
435         for (j = 0; j < size; j++) {
436             heightmap[size - 1 - i][j] = (float)((texture.data[(i + (j * size)) * texture.bpp / 8])) / 5;
437         }
438     }
439
440     Game::LoadingScreen();
441
442     float slopeness;
443
444     for (i = 0; i < subdivision; i++) {
445         for (j = 0; j < subdivision; j++) {
446             textureness[i][j] = -1;
447         }
448     }
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     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     Game::LoadingScreen();
511
512     for (i = 0; i < size; i++) {
513         for (j = 0; j < size; j++) {
514             if (opacityother[i][j] < .1)
515                 opacityother[i][j] = 0;
516             if (textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == -1) {
517                 if (!opacityother[i][j])
518                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = allfirst;
519                 if (opacityother[i][j] == 1)
520                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = allsecond;
521             }
522             if (opacityother[i][j] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
523                 textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
524             if (opacityother[i][j] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
525                 textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
526
527             x = i;
528             y = j;
529             if (i > 0) {
530                 i--;
531                 if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
532                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
533                 if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
534                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
535                 if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
536                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
537                 if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
538                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
539
540                 if (j > 0) {
541                     j--;
542                     if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
543                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
544                     if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
545                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
546                     if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
547                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
548                     if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
549                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
550                     j++;
551                 }
552
553                 if (j < size - 1) {
554                     j++;
555                     if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
556                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
557                     if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
558                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
559                     if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
560                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
561                     if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
562                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
563                     j--;
564                 }
565                 i++;
566             }
567
568             if (i < size - 1) {
569                 i++;
570                 if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
571                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
572                 if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
573                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
574                 if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
575                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
576                 if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
577                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
578
579                 if (j > 0) {
580                     j--;
581                     if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
582                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
583                     if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
584                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
585                     if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
586                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
587                     if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
588                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
589                     j++;
590                 }
591
592                 if (j < size - 1) {
593                     j++;
594                     if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
595                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
596                     if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
597                         textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
598                     if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
599                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
600                     if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
601                         textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
602                     j--;
603                 }
604                 i--;
605             }
606
607             if (j > 0) {
608                 j--;
609                 if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
610                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
611                 if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
612                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
613                 if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
614                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
615                 if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
616                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
617                 j++;
618             }
619
620             if (j < size - 1) {
621                 j++;
622                 if (opacityother[x][y] && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allfirst)
623                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
624                 if (opacityother[x][y] != 1 && textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] == allsecond)
625                     textureness[(int)(i * subdivision / size)][(int)(j * subdivision / size)] = mixed;
626                 if (opacityother[i][j] && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allfirst)
627                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
628                 if (opacityother[i][j] != 1 && textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] == allsecond)
629                     textureness[(int)(x * subdivision / size)][(int)(y * subdivision / size)] = mixed;
630                 j--;
631
632             }
633         }
634     }
635     Game::LoadingScreen();
636
637     patch_size = size / subdivision;
638     patch_elements = (patch_size) * (patch_size) * 54;
639     CalculateNormals();
640
641     return true;
642 }
643
644 void Terrain::CalculateNormals()
645 {
646     static int i, j;
647     static XYZ facenormal;
648     static XYZ p, q, a, b, c;
649
650     for (i = 0; i < size; i++) {
651         for (j = 0; j < size; j++) {
652             normals[i][j].x = 0;
653             normals[i][j].y = 0;
654             normals[i][j].z = 0;
655         }
656     }
657
658     for (i = 0; i < size - 1; i++) {
659         for (j = 0; j < size - 1; j++) {
660             a.x = i;
661             a.y = heightmap[i][j];
662             a.z = j;
663             b.x = i;
664             b.y = heightmap[i][j + 1];
665             b.z = j + 1;
666             c.x = i + 1;
667             c.y = heightmap[i + 1][j];
668             c.z = j;
669
670             p.x = b.x - a.x;
671             p.y = b.y - a.y;
672             p.z = b.z - a.z;
673             q.x = c.x - a.x;
674             q.y = c.y - a.y;
675             q.z = c.z - a.z;
676
677             CrossProduct(&p, &q, &facenormal);
678
679             facenormals[i][j] = facenormal;
680
681             normals[i][j] = normals[i][j] + facenormal;
682             normals[i][j + 1] = normals[i][j + 1] + facenormal;
683             normals[i + 1][j] = normals[i + 1][j] + facenormal;
684
685
686             a.x = i + 1;
687             a.y = heightmap[i + 1][j];
688             a.z = j;
689             b.x = i;
690             b.y = heightmap[i][j + 1];
691             b.z = j + 1;
692             c.x = i + 1;
693             c.y = heightmap[i + 1][j + 1];
694             c.z = j + 1;
695
696             p.x = b.x - a.x;
697             p.y = b.y - a.y;
698             p.z = b.z - a.z;
699             q.x = c.x - a.x;
700             q.y = c.y - a.y;
701             q.z = c.z - a.z;
702
703             CrossProduct(&p, &q, &facenormal);
704
705             normals[i + 1][j + 1] = normals[i + 1][j + 1] + facenormal;
706             normals[i][j + 1] = normals[i][j + 1] + facenormal;
707             normals[i + 1][j] = normals[i + 1][j] + facenormal;
708
709             Normalise(&facenormals[i][j]);
710         }
711     }
712
713     for (i = 0; i < size; i++) {
714         for (j = 0; j < size; j++) {
715             Normalise(&normals[i][j]);
716         }
717     }
718 }
719
720 void Terrain::drawpatch(int whichx, int whichy, float opacity)
721 {
722     if (opacity >= 1)
723         glDisable(GL_BLEND);
724     if (opacity < 1) {
725         glEnable(GL_BLEND);
726         UpdateTransparency(whichx, whichy);
727     }
728
729     glColor4f(1, 1, 1, 1);
730
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
755     glColor4f(1, 1, 1, 1);
756
757     //Set up vertex array
758     glEnableClientState(GL_VERTEX_ARRAY);
759     glEnableClientState(GL_COLOR_ARRAY);
760     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
761     glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
762     glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
763     glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
764
765     //Draw
766     glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
767
768     glDisableClientState(GL_VERTEX_ARRAY);
769     glDisableClientState(GL_COLOR_ARRAY);
770     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
771 }
772
773 void Terrain::drawpatchotherother(int whichx, int whichy, float opacity)
774 {
775     glEnable(GL_BLEND);
776     UpdateTransparencyotherother(whichx, whichy);
777
778     glMatrixMode(GL_TEXTURE);
779     glPushMatrix();
780     glScalef(6, 6, 6);
781
782     glColor4f(1, 1, 1, 1);
783
784     //Set up vertex array
785     glEnableClientState(GL_VERTEX_ARRAY);
786     glEnableClientState(GL_COLOR_ARRAY);
787     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
788     glVertexPointer(3, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[0 + whichx * patch_elements + whichy * patch_elements * subdivision]);
789     glColorPointer(4, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[3 + whichx * patch_elements + whichy * patch_elements * subdivision]);
790     glTexCoordPointer(2, GL_FLOAT, 9 * sizeof(GLfloat), &vArray[7 + whichx * patch_elements + whichy * patch_elements * subdivision]);
791
792     //Draw
793     glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy] * 3);
794
795     glDisableClientState(GL_VERTEX_ARRAY);
796     glDisableClientState(GL_COLOR_ARRAY);
797     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
798
799     glPopMatrix();
800     glMatrixMode(GL_MODELVIEW);
801 }
802
803
804 float Terrain::getHeight(float pointx, float pointz)
805 {
806     static int tilex, tiley;
807     static XYZ startpoint, endpoint, intersect, triangle[3];
808
809     pointx /= scale;
810     pointz /= scale;
811
812     if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
813         return 0;
814
815     startpoint.x = pointx;
816     startpoint.y = -1000;
817     startpoint.z = pointz;
818
819     endpoint = startpoint;
820     endpoint.y = 1000;
821
822     tilex = pointx;
823     tiley = pointz;
824
825     triangle[0].x = tilex;
826     triangle[0].z = tiley;
827     triangle[0].y = heightmap[tilex][tiley];
828
829     triangle[1].x = tilex + 1;
830     triangle[1].z = tiley;
831     triangle[1].y = heightmap[tilex + 1][tiley];
832
833     triangle[2].x = tilex;
834     triangle[2].z = tiley + 1;
835     triangle[2].y = heightmap[tilex][tiley + 1];
836
837     if (!LineFacetd(&startpoint, &endpoint, &triangle[0], &triangle[1], &triangle[2], &intersect)) {
838         triangle[0].x = tilex + 1;
839         triangle[0].z = tiley;
840         triangle[0].y = heightmap[tilex + 1][tiley];
841
842         triangle[1].x = tilex + 1;
843         triangle[1].z = tiley + 1;
844         triangle[1].y = heightmap[tilex + 1][tiley + 1];
845
846         triangle[2].x = tilex;
847         triangle[2].z = tiley + 1;
848         triangle[2].y = heightmap[tilex][tiley + 1];
849         LineFacetd(&startpoint, &endpoint, &triangle[0], &triangle[1], &triangle[2], &intersect);
850     }
851     return intersect.y * scale + getOpacity(pointx * scale, pointz * scale) / 8;
852 }
853
854 float Terrain::getOpacity(float pointx, float pointz)
855 {
856     static float height1, height2;
857     static int tilex, tiley;
858
859     pointx /= scale;
860     pointz /= scale;
861
862     if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
863         return 0;
864
865     tilex = pointx;
866     tiley = pointz;
867
868     height1 = opacityother[tilex][tiley] * (1 - (pointx - tilex)) + opacityother[tilex + 1][tiley] * (pointx - tilex);
869     height2 = opacityother[tilex][tiley + 1] * (1 - (pointx - tilex)) + opacityother[tilex + 1][tiley + 1] * (pointx - tilex);
870
871     return height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
872 }
873
874 XYZ Terrain::getNormal(float pointx, float pointz)
875 {
876     static XYZ height1, height2, total;
877     static int tilex, tiley;
878
879     pointx /= scale;
880     pointz /= scale;
881
882     height1 = 0;
883     if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
884         return height1;
885     tilex = pointx;
886     tiley = pointz;
887
888     height1 = normals[tilex][tiley] * (1 - (pointx - tilex)) + normals[tilex + 1][tiley] * (pointx - tilex);
889     height2 = normals[tilex][tiley + 1] * (1 - (pointx - tilex)) + normals[tilex + 1][tiley + 1] * (pointx - tilex);
890     total = height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
891     Normalise(&total);
892     return total;
893 }
894
895 XYZ Terrain::getLighting(float pointx, float pointz)
896 {
897     static XYZ height1, height2;
898     static int tilex, tiley;
899
900     pointx /= scale;
901     pointz /= scale;
902
903     height1 = 0;
904     if (pointx >= size - 1 || pointz >= size - 1 || pointx <= 0 || pointz <= 0)
905         return height1;
906     tilex = pointx;
907     tiley = pointz;
908
909     height1.x = colors[tilex][tiley][0] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][0] * (pointx - tilex);
910     height1.y = colors[tilex][tiley][1] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][1] * (pointx - tilex);
911     height1.z = colors[tilex][tiley][2] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley][2] * (pointx - tilex);
912     height2.x = colors[tilex][tiley + 1][0] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][0] * (pointx - tilex);
913     height2.y = colors[tilex][tiley + 1][1] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][1] * (pointx - tilex);
914     height2.z = colors[tilex][tiley + 1][2] * (1 - (pointx - tilex)) + colors[tilex + 1][tiley + 1][2] * (pointx - tilex);
915
916     return height1 * (1 - (pointz - tiley)) + height2 * (pointz - tiley);
917 }
918
919 void Terrain::draw(int layer)
920 {
921     static int i, j;
922     static float opacity;
923     static XYZ terrainpoint;
924     static float distance[subdivision][subdivision];
925
926     static int beginx, endx;
927     static int beginz, endz;
928
929     static float patch_size = size / subdivision * scale;
930     static float viewdistsquared;
931
932     viewdistsquared = viewdistance * viewdistance;
933
934     //Only nearby blocks
935     beginx = (viewer.x - viewdistance) / (patch_size) - 1;
936     if (beginx < 0)
937         beginx = 0;
938     beginz = (viewer.z - viewdistance) / (patch_size) - 1;
939     if (beginz < 0)
940         beginz = 0;
941
942     endx = (viewer.x + viewdistance) / (patch_size) + 1;
943     if (endx > subdivision)
944         endx = subdivision;
945     endz = (viewer.z + viewdistance) / (patch_size) + 1;
946     if (endz > subdivision)
947         endz = subdivision;
948
949     if (!layer) {
950         for (i = beginx; i < endx; i++) {
951             for (j = beginz; j < endz; j++) {
952                 terrainpoint.x = i * patch_size + (patch_size) / 2;
953                 terrainpoint.y = viewer.y; //heightmap[i][j]*scale;
954                 terrainpoint.z = j * patch_size + (patch_size) / 2;
955                 distance[i][j] = distsq(&viewer, &terrainpoint);
956             }
957         }
958     }
959     for (i = beginx; i < endx; i++) {
960         for (j = beginz; j < endz; j++) {
961             if (distance[i][j] < (viewdistance + patch_size) * (viewdistance + patch_size)) {
962                 opacity = 1;
963                 if (distance[i][j] > viewdistsquared * fadestart - viewdistsquared)
964                     opacity = 0;
965                 if (opacity == 1 && i != subdivision)
966                     if (distance[i + 1][j] > viewdistsquared * fadestart - viewdistsquared)
967                         opacity = 0;
968                 if (opacity == 1 && j != subdivision)
969                     if (distance[i][j + 1] > viewdistsquared * fadestart - viewdistsquared)
970                         opacity = 0;
971                 if (opacity == 1 && j != subdivision && i != subdivision)
972                     if (distance[i + 1][j + 1] > viewdistsquared * fadestart - viewdistsquared)
973                         opacity = 0;
974                 glMatrixMode(GL_MODELVIEW);
975                 glPushMatrix();
976                 if (frustum.CubeInFrustum(i * patch_size + patch_size * .5, avgypatch[i][j], j * patch_size + patch_size * .5, heightypatch[i][j] / 2)) {
977                     if (environment == desertenvironment && distance[i][j] > viewdistsquared / 4)
978                         glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness);
979                     else if (environment == desertenvironment)
980                         glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
981                     if (!layer && textureness[i][j] != allsecond)
982                         drawpatch(i, j, opacity);
983                     if (layer == 1 && textureness[i][j] != allfirst)
984                         drawpatchother(i, j, opacity);
985                     if (layer == 2 && textureness[i][j] != allfirst)
986                         drawpatchotherother(i, j, opacity);
987                 }
988                 glPopMatrix();
989             }
990         }
991     }
992     if (environment == desertenvironment)
993         glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
994 }
995
996 void Terrain::drawdecals()
997 {
998     if (decals) {
999         static int i;
1000         static float distancemult;
1001         static int lasttype;
1002
1003         static float viewdistsquared;
1004         static bool blend;
1005
1006         viewdistsquared = viewdistance * viewdistance;
1007         blend = 1;
1008
1009         lasttype = -1;
1010         glEnable(GL_BLEND);
1011         glDisable(GL_LIGHTING);
1012         glDisable(GL_CULL_FACE);
1013         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1014         glDepthMask(0);
1015         for (i = 0; i < numdecals; i++) {
1016             if (decaltype[i] == blooddecalfast && decalalivetime[i] < 2)
1017                 decalalivetime[i] = 2;
1018             if ((decaltype[i] == shadowdecal || decaltype[i] == shadowdecalpermanent) && decaltype[i] != lasttype) {
1019                 shadowtexture.bind();
1020                 if (!blend) {
1021                     blend = 1;
1022                     glAlphaFunc(GL_GREATER, 0.0001);
1023                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1024                 }
1025             }
1026             if (decaltype[i] == footprintdecal && decaltype[i] != lasttype) {
1027                 footprinttexture.bind();
1028                 if (!blend) {
1029                     blend = 1;
1030                     glAlphaFunc(GL_GREATER, 0.0001);
1031                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1032                 }
1033             }
1034             if (decaltype[i] == bodyprintdecal && decaltype[i] != lasttype) {
1035                 bodyprinttexture.bind();
1036                 if (!blend) {
1037                     blend = 1;
1038                     glAlphaFunc(GL_GREATER, 0.0001);
1039                     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1040                 }
1041             }
1042             if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalslow) && decaltype[i] != lasttype) {
1043                 bloodtexture.bind();
1044                 if (blend) {
1045                     blend = 0;
1046                     glAlphaFunc(GL_GREATER, 0.15);
1047                     glBlendFunc(GL_ONE, GL_ZERO);
1048                 }
1049             }
1050             if ((decaltype[i] == blooddecalfast) && decaltype[i] != lasttype) {
1051                 bloodtexture2.bind();
1052                 if (blend) {
1053                     blend = 0;
1054                     glAlphaFunc(GL_GREATER, 0.15);
1055                     glBlendFunc(GL_ONE, GL_ZERO);
1056                 }
1057             }
1058             if (decaltype[i] == shadowdecal || decaltype[i] == shadowdecalpermanent) {
1059                 distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
1060                 if (distancemult >= 1)
1061                     glColor4f(1, 1, 1, decalopacity[i]);
1062                 if (distancemult < 1)
1063                     glColor4f(1, 1, 1, decalopacity[i]*distancemult);
1064             }
1065             if (decaltype[i] == footprintdecal || decaltype[i] == bodyprintdecal) {
1066                 distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
1067                 if (distancemult >= 1) {
1068                     glColor4f(1, 1, 1, decalopacity[i]);
1069                     if (decalalivetime[i] > 3)
1070                         glColor4f(1, 1, 1, decalopacity[i] * (5 - decalalivetime[i]) / 2);
1071                 }
1072                 if (distancemult < 1) {
1073                     glColor4f(1, 1, 1, decalopacity[i]*distancemult);
1074                     if (decalalivetime[i] > 3)
1075                         glColor4f(1, 1, 1, decalopacity[i] * (5 - decalalivetime[i]) / 2 * distancemult);
1076                 }
1077             }
1078             if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow)) {
1079                 distancemult = (viewdistsquared - (distsq(&viewer, &decalposition[i]) - (viewdistsquared * fadestart)) * (1 / (1 - fadestart))) / viewdistsquared;
1080                 if (distancemult >= 1) {
1081                     glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]);
1082                     if (decalalivetime[i] < 4)
1083                         glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*decalalivetime[i]*.25);
1084                     if (decalalivetime[i] > 58)
1085                         glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i] * (60 - decalalivetime[i]) / 2);
1086                 }
1087                 if (distancemult < 1) {
1088                     glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*distancemult);
1089                     if (decalalivetime[i] < 4)
1090                         glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i]*decalalivetime[i]*distancemult * .25);
1091                     if (decalalivetime[i] > 58)
1092                         glColor4f(decalbrightness[i], decalbrightness[i], decalbrightness[i], decalopacity[i] * (60 - decalalivetime[i]) / 2 * distancemult);
1093                 }
1094             }
1095             lasttype = decaltype[i];
1096             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1097             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1098
1099             glMatrixMode(GL_MODELVIEW);
1100             glPushMatrix();
1101             glBegin(GL_TRIANGLES);
1102             for (int j = 0; j < 3; j++) {
1103                 glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]);
1104                 glVertex3f(decalvertex[i][j].x, decalvertex[i][j].y, decalvertex[i][j].z);
1105             }
1106             glEnd();
1107             glPopMatrix();
1108         }
1109         for (i = numdecals - 1; i >= 0; i--) {
1110             decalalivetime[i] += multiplier;
1111             if (decaltype[i] == blooddecalslow)
1112                 decalalivetime[i] -= multiplier * 2 / 3;
1113             if (decaltype[i] == blooddecalfast)
1114                 decalalivetime[i] += multiplier * 4;
1115             if (decaltype[i] == shadowdecal)
1116                 DeleteDecal(i);
1117             if (decaltype[i] == footprintdecal && decalalivetime[i] >= 5)
1118                 DeleteDecal(i);
1119             if (decaltype[i] == bodyprintdecal && decalalivetime[i] >= 5)
1120                 DeleteDecal(i);
1121             if ((decaltype[i] == blooddecal || decaltype[i] == blooddecalfast || decaltype[i] == blooddecalslow) && decalalivetime[i] >= 60)
1122                 DeleteDecal(i);
1123         }
1124         glAlphaFunc(GL_GREATER, 0.0001);
1125     }
1126 }
1127
1128 void Terrain::AddObject(XYZ where, float radius, int id)
1129 {
1130     XYZ points[4];
1131     if (id >= 0 && id < 10000)
1132         for (int i = 0; i < subdivision; i++) {
1133             for (int j = 0; j < subdivision; j++) {
1134                 if (patchobjectnum[i][j] < 300 - 1) {
1135                     bool done = false;
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 && Tutorial::active) {
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 (Object::objects[l]->type != treetrunktype) {
1385                         testpoint = terrainpoint;
1386                         testpoint2 = terrainpoint + lightloc * 50 * (1 - shadowed);
1387                         if (Object::objects[l]->model.LineCheck(&testpoint, &testpoint2, &col, &Object::objects[l]->position, &Object::objects[l]->yaw) != -1) {
1388                             shadowed = 1 - (findDistance(&terrainpoint, &col) / 50);
1389                         }
1390                     }
1391                 }
1392                 Game::LoadingScreen();
1393             }
1394             brightness = dotproduct(&lightloc, &normals[i][j]);
1395             if (shadowed)
1396                 brightness *= 1 - shadowed;
1397
1398             if (brightness > 1)
1399                 brightness = 1;
1400             if (brightness < 0)
1401                 brightness = 0;
1402
1403             colors[i][j][0] = light.color[0] * brightness + light.ambient[0];
1404             colors[i][j][1] = light.color[1] * brightness + light.ambient[1];
1405             colors[i][j][2] = light.color[2] * brightness + light.ambient[2];
1406
1407             if (colors[i][j][0] > 1) colors[i][j][0] = 1;
1408             if (colors[i][j][1] > 1) colors[i][j][1] = 1;
1409             if (colors[i][j][2] > 1) colors[i][j][2] = 1;
1410             if (colors[i][j][0] < 0) colors[i][j][0] = 0;
1411             if (colors[i][j][1] < 0) colors[i][j][1] = 0;
1412             if (colors[i][j][2] < 0) colors[i][j][2] = 0;
1413         }
1414     }
1415
1416     Game::LoadingScreen();
1417
1418     //Smooth shadows
1419     for (i = 0; i < size; i++) {
1420         for (j = 0; j < size; j++) {
1421             for (k = 0; k < 3; k++) {
1422                 total = 0;
1423                 todivide = 0;
1424                 if (i != 0) {
1425                     total += colors[j][i - 1][k];
1426                     todivide++;
1427                 }
1428                 if (i != size - 1) {
1429                     total += colors[j][i + 1][k];
1430                     todivide++;
1431                 }
1432                 if (j != 0) {
1433                     total += colors[j - 1][i][k];
1434                     todivide++;
1435                 }
1436                 if (j != size - 1) {
1437                     total += colors[j + 1][i][k];
1438                     todivide++;
1439                 }
1440                 if (i != 0 && j != 0) {
1441                     total += colors[j - 1][i - 1][k];
1442                     todivide++;
1443                 }
1444                 if (i != size - 1 && j != 0) {
1445                     total += colors[j - 1][i + 1][k];
1446                     todivide++;
1447                 }
1448                 if (j != size - 1 && i != size - 1) {
1449                     total += colors[j + 1][i + 1][k];
1450                     todivide++;
1451                 }
1452                 if (j != size - 1 && i != 0) {
1453                     total += colors[j + 1][i - 1][k];
1454                     todivide++;
1455                 }
1456                 total += colors[j][i][k];
1457                 todivide++;
1458
1459                 colors[j][i][k] = total / todivide;
1460             }
1461         }
1462     }
1463
1464     for (i = 0; i < subdivision; i++) {
1465         for (j = 0; j < subdivision; j++) {
1466             UpdateVertexArray(i, j);
1467         }
1468     }
1469 }
1470
1471 Terrain::Terrain()
1472 {
1473     size = 0;
1474
1475     memset(patchobjectnum, 0, sizeof(patchobjectnum));
1476     memset(patchobjects, 0, sizeof(patchobjects));
1477
1478     scale = 1.0f;
1479     type = 0;
1480     memset(heightmap, 0, sizeof(heightmap));
1481     memset(normals, 0, sizeof(normals));
1482     memset(facenormals, 0, sizeof(facenormals));
1483     memset(triangles, 0, sizeof(triangles));
1484     memset(colors, 0, sizeof(colors));
1485     memset(opacityother, 0, sizeof(opacityother));
1486     memset(texoffsetx, 0, sizeof(texoffsetx));
1487     memset(texoffsety, 0, sizeof(texoffsety));
1488     memset(numtris, 0, sizeof(numtris));
1489     memset(textureness, 0, sizeof(textureness));
1490
1491     memset(vArray, 0, sizeof(vArray));
1492
1493     memset(visible, 0, sizeof(visible));
1494     memset(avgypatch, 0, sizeof(avgypatch));
1495     memset(maxypatch, 0, sizeof(maxypatch));
1496     memset(minypatch, 0, sizeof(minypatch));
1497     memset(heightypatch, 0, sizeof(heightypatch));
1498
1499     patch_elements = 0;
1500
1501     memset(decaltexcoords, 0, sizeof(decaltexcoords));
1502     memset(decalvertex, 0, sizeof(decalvertex));
1503     memset(decaltype, 0, sizeof(decaltype));
1504     memset(decalopacity, 0, sizeof(decalopacity));
1505     memset(decalrotation, 0, sizeof(decalrotation));
1506     memset(decalalivetime, 0, sizeof(decalalivetime));
1507     memset(decalbrightness, 0, sizeof(decalbrightness));
1508     memset(decalposition, 0, sizeof(decalposition));
1509     numdecals = 0;
1510 }