]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Object.cpp
Fixed warnings, removed unused attributes, broken audio output setting, and so on
[lugaru.git] / Source / Objects / Object.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 "Objects/Object.hpp"
22
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 float gravity;
31 extern FRUSTUM frustum;
32 extern Terrain terrain;
33 extern bool foliage;
34 extern int detail;
35 extern float blurness;
36 extern float windvar;
37 extern float playerdist;
38 extern bool skyboxtexture;
39
40 std::vector<std::unique_ptr<Object>> Object::objects;
41 XYZ Object::center;
42 float Object::radius = 0;
43 Texture Object::boxtextureptr;
44 Texture Object::treetextureptr;
45 Texture Object::bushtextureptr;
46 Texture Object::rocktextureptr;
47
48 //Functions
49
50 Object::Object() :
51     position(),
52     type(boxtype),
53     yaw(0),
54     pitch(0),
55     rotx(0),
56     rotxvel(0),
57     roty(0),
58     rotyvel(0),
59     possible(false),
60     model(),
61     displaymodel(),
62     friction(0),
63     scale(0),
64     messedwith(0),
65     checked(0),
66     shadowed(0),
67     occluded(0),
68     onfire(false),
69     flamedelay(0)
70 {
71 }
72
73 Object::Object(object_type _type, XYZ _position, float _yaw, float _pitch, float _scale) : Object()
74 {
75     scale = _scale;
76     type = _type;
77     position = _position;
78     yaw = _yaw;
79     pitch = _pitch;
80
81     switch(type) {
82         case boxtype:
83             model.loaddecal("Models/Box.solid");
84             friction = 1.5;
85             break;
86         case cooltype:
87             model.loaddecal("Models/Cool.solid");
88             friction = 1.5;
89             break;
90         case walltype:
91             model.loaddecal("Models/Wall.solid");
92             friction = 1.5;
93             break;
94         case tunneltype:
95             model.loaddecal("Models/Tunnel.solid");
96             friction = 1.5;
97             break;
98         case chimneytype:
99             model.loaddecal("Models/Chimney.solid");
100             friction = 1.5;
101             break;
102         case spiketype:
103             model.load("Models/Spike.solid");
104             friction = .4;
105             break;
106         case weirdtype:
107             model.loaddecal("Models/Weird.solid");
108             friction = 1.5;
109             break;
110         case rocktype:
111             model.loaddecal("Models/Rock.solid");
112             if (scale > .5) {
113                 friction = 1.5;
114             } else {
115                 friction = .5;
116             }
117             break;
118         case treetrunktype:
119             model.load("Models/TreeTrunk.solid");
120             friction = .4;
121             break;
122         case treeleavestype:
123             scale += fabs((float)(Random() % 100) / 900) * scale;
124             model.load("Models/Leaves.solid");
125             friction = 0;
126             break;
127         case bushtype:
128             position.y = terrain.getHeight(position.x, position.z) - .3;
129             model.load("Models/Bush.solid");
130             break;
131         case platformtype:
132             model.loaddecal("Models/Platform.solid");
133             model.Rotate(90, 0, 0);
134             friction = 1.5;
135             break;
136         case firetype:
137             onfire = true;
138             break;
139     }
140
141     if (friction == 1.5 && fabs(pitch) > 5) {
142         friction = .5;
143     }
144
145     if (type == boxtype || type == cooltype || type == spiketype || type == weirdtype || type == walltype || type == chimneytype || type == tunneltype || type == platformtype) {
146         model.ScaleTexCoords(scale * 1.5);
147     }
148     if (type == rocktype) {
149         model.ScaleTexCoords(scale * 3);
150     }
151     model.flat = 1;
152     if (type == treetrunktype || type == treeleavestype || type == rocktype) {
153         model.flat = 0;
154     }
155     model.Scale(.3 * scale, .3 * scale, .3 * scale);
156     model.Rotate(90, 1, 1);
157     model.Rotate(pitch, 0, 0);
158     if (type == rocktype) {
159         model.Rotate(yaw * 5, 0, 0);
160     }
161     model.CalculateNormals(1);
162     model.ScaleNormals(-1, -1, -1);
163 }
164
165 void Object::handleFire()
166 {
167     if (type == firetype) {
168         onfire = 1;
169     }
170     if (onfire) {
171         XYZ spawnpoint;
172         if ((type == bushtype) || (type == firetype)) {
173             flamedelay -= multiplier * 3;
174         } else if (type == treeleavestype) {
175             flamedelay -= multiplier * 4;
176         }
177         while ((flamedelay < 0) && onfire) {
178             flamedelay += .006;
179             if ((type == bushtype) || (type == firetype)) {
180                 spawnpoint.x = ((float)(Random() % 100)) / 30 * scale;
181                 spawnpoint.y = ((float)(Random() % 100) + 60) / 30 * scale;
182                 spawnpoint.z = 0;
183                 spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
184                 spawnpoint += position;
185                 Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 5 * scale, 1);
186             } else if (type == treeleavestype) {
187                 spawnpoint.x = ((float)(Random() % 100)) / 80 * scale;
188                 spawnpoint.y = ((float)(Random() % 100) + 80) / 12 * scale;
189                 spawnpoint.z = 0;
190                 spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
191                 spawnpoint += position;
192                 Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 6, 1);
193             }
194         }
195     }
196 }
197
198 void Object::doShadows(XYZ lightloc)
199 {
200     XYZ testpoint, testpoint2, terrainpoint, col;
201     int patchx, patchz;
202     if (type != treeleavestype && type != treetrunktype && type != bushtype && type != firetype) {
203         for (int j = 0; j < model.vertexNum; j++) {
204             terrainpoint = position + DoRotation(model.vertex[j] + model.normals[j] * .1, 0, yaw, 0);
205             shadowed = 0;
206             patchx = terrainpoint.x / (terrain.size / subdivision * terrain.scale);
207             patchz = terrainpoint.z / (terrain.size / subdivision * terrain.scale);
208             if (patchx >= 0 && patchz >= 0 && patchx < subdivision && patchz < subdivision) {
209                 if (terrain.patchobjectnum[patchx][patchz]) {
210                     for (int k = 0; k < terrain.patchobjectnum[patchx][patchz]; k++) {
211                         int l = terrain.patchobjects[patchx][patchz][k];
212                         if (objects[l]->type != treetrunktype) {
213                             testpoint = terrainpoint;
214                             testpoint2 = terrainpoint + lightloc * 50 * (1 - shadowed);
215                             if (objects[l]->model.LineCheck(&testpoint, &testpoint2, &col, &objects[l]->position, &objects[l]->yaw) != -1) {
216                                 shadowed = 1 - (findDistance(&terrainpoint, &col) / 50);
217                             }
218                         }
219                     }
220                 }
221             }
222             if (shadowed > 0) {
223                 col = model.normals[j] - DoRotation(lightloc * shadowed, 0, -yaw, 0);
224                 Normalise(&col);
225                 for (int k = 0; k < model.TriangleNum; k++) {
226                     if (model.Triangles[k].vertex[0] == j) {
227                         int l = k * 24;
228                         model.vArray[l + 2] = col.x;
229                         model.vArray[l + 3] = col.y;
230                         model.vArray[l + 4] = col.z;
231                     }
232                     if (model.Triangles[k].vertex[1] == j) {
233                         int l = k * 24;
234                         model.vArray[l + 10] = col.x;
235                         model.vArray[l + 11] = col.y;
236                         model.vArray[l + 12] = col.z;
237                     }
238                     if (model.Triangles[k].vertex[2] == j) {
239                         int l = k * 24;
240                         model.vArray[l + 18] = col.x;
241                         model.vArray[l + 19] = col.y;
242                         model.vArray[l + 20] = col.z;
243                     }
244                 }
245             }
246         }
247     }
248     shadowed = 0;
249 }
250
251 void Object::draw()
252 {
253     static float distance;
254     static XYZ moved, terrainlight;
255     bool hidden;
256     if (type == firetype) {
257         return;
258     }
259     moved = DoRotation(model.boundingspherecenter, 0, yaw, 0);
260     if (type == tunneltype || frustum.SphereInFrustum(position.x + moved.x, position.y + moved.y, position.z + moved.z, model.boundingsphereradius)) {
261         distance = distsq(&viewer, &position);
262         distance *= 1.2;
263         hidden = !(distsqflat(&viewer, &position) > playerdist + 3 || (type != bushtype && type != treeleavestype));
264         if (!hidden) {
265
266             if (detail == 2 && distance > viewdistance * viewdistance / 4 && environment == desertenvironment)
267                 glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness );
268             else
269                 glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
270             distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
271             if (distance > 1)
272                 distance = 1;
273             if (distance > 0) {
274
275                 if (occluded < 6) {
276                     glMatrixMode(GL_MODELVIEW);
277                     glPushMatrix();
278                     if (!model.color)
279                         glEnable(GL_LIGHTING);
280                     else
281                         glDisable(GL_LIGHTING);
282                     glDepthMask(1);
283                     glTranslatef(position.x, position.y, position.z);
284                     if (type == bushtype) {
285                         messedwith -= multiplier;
286                         if (rotxvel || rotx) {
287                             if (rotx > 0) rotxvel -= multiplier * 8 * fabs(rotx);
288                             if (rotx < 0) rotxvel += multiplier * 8 * fabs(rotx);
289                             if (rotx > 0) rotxvel -= multiplier * 4;
290                             if (rotx < 0) rotxvel += multiplier * 4;
291                             if (rotxvel > 0) rotxvel -= multiplier * 4;
292                             if (rotxvel < 0) rotxvel += multiplier * 4;
293                             if (fabs(rotx) < multiplier * 4)
294                                 rotx = 0;
295                             if (fabs(rotxvel) < multiplier * 4)
296                                 rotxvel = 0;
297
298                             rotx += rotxvel * multiplier * 4;
299                         }
300                         if (rotyvel || roty) {
301                             if (roty > 0) rotyvel -= multiplier * 8 * fabs(roty);
302                             if (roty < 0) rotyvel += multiplier * 8 * fabs(roty);
303                             if (roty > 0) rotyvel -= multiplier * 4;
304                             if (roty < 0) rotyvel += multiplier * 4;
305                             if (rotyvel > 0) rotyvel -= multiplier * 4;
306                             if (rotyvel < 0) rotyvel += multiplier * 4;
307                             if (fabs(roty) < multiplier * 4)
308                                 roty = 0;
309                             if (fabs(rotyvel) < multiplier * 4)
310                                 rotyvel = 0;
311
312                             roty += rotyvel * multiplier * 4;
313                         }
314                         if (roty) {
315                             glRotatef(roty, 1, 0, 0);
316                         }
317                         if (rotx) {
318                             glRotatef(-rotx, 0, 0, 1);
319                         }
320                         if (rotx > 10)
321                             rotx = 10;
322                         if (rotx < -10)
323                             rotx = -10;
324                         if (roty > 10)
325                             roty = 10;
326                         if (roty < -10)
327                             roty = -10;
328                     }
329                     if (type == treetrunktype || type == treeleavestype) {
330                         if (type == treetrunktype || environment == desertenvironment) {
331                             messedwith -= multiplier;
332                             if (rotxvel || rotx) {
333                                 if (rotx > 0) rotxvel -= multiplier * 8 * fabs(rotx);
334                                 if (rotx < 0) rotxvel += multiplier * 8 * fabs(rotx);
335                                 if (rotx > 0) rotxvel -= multiplier * 4;
336                                 if (rotx < 0) rotxvel += multiplier * 4;
337                                 if (rotxvel > 0) rotxvel -= multiplier * 4;
338                                 if (rotxvel < 0) rotxvel += multiplier * 4;
339                                 if (fabs(rotx) < multiplier * 4)
340                                     rotx = 0;
341                                 if (fabs(rotxvel) < multiplier * 4)
342                                     rotxvel = 0;
343
344                                 rotx += rotxvel * multiplier * 4;
345                             }
346                             if (rotyvel || roty) {
347                                 if (roty > 0) rotyvel -= multiplier * 8 * fabs(roty);
348                                 if (roty < 0) rotyvel += multiplier * 8 * fabs(roty);
349                                 if (roty > 0) rotyvel -= multiplier * 4;
350                                 if (roty < 0) rotyvel += multiplier * 4;
351                                 if (rotyvel > 0) rotyvel -= multiplier * 4;
352                                 if (rotyvel < 0) rotyvel += multiplier * 4;
353                                 if (fabs(roty) < multiplier * 4)
354                                     roty = 0;
355                                 if (fabs(rotyvel) < multiplier * 4)
356                                     rotyvel = 0;
357
358                                 roty += rotyvel * multiplier * 4;
359                             }
360                             if (roty) {
361                                 glRotatef(roty / 6, 1, 0, 0);
362                             }
363                             if (rotx) {
364                                 glRotatef(-rotx / 6, 0, 0, 1);
365                             }
366                             if (rotx > 10)
367                                 rotx = 10;
368                             if (rotx < -10)
369                                 rotx = -10;
370                             if (roty > 10)
371                                 roty = 10;
372                             if (roty < -10)
373                                 roty = -10;
374                         } else {
375                             messedwith -= multiplier;
376                             if (rotxvel || rotx) {
377                                 if (rotx > 0) rotxvel -= multiplier * 8 * fabs(rotx);
378                                 if (rotx < 0) rotxvel += multiplier * 8 * fabs(rotx);
379                                 if (rotx > 0) rotxvel -= multiplier * 4;
380                                 if (rotx < 0) rotxvel += multiplier * 4;
381                                 if (rotxvel > 0) rotxvel -= multiplier * 4;
382                                 if (rotxvel < 0) rotxvel += multiplier * 4;
383                                 if (fabs(rotx) < multiplier * 4)
384                                     rotx = 0;
385                                 if (fabs(rotxvel) < multiplier * 4)
386                                     rotxvel = 0;
387
388                                 rotx += rotxvel * multiplier * 4;
389                             }
390                             if (rotyvel || roty) {
391                                 if (roty > 0) rotyvel -= multiplier * 8 * fabs(roty);
392                                 if (roty < 0) rotyvel += multiplier * 8 * fabs(roty);
393                                 if (roty > 0) rotyvel -= multiplier * 4;
394                                 if (roty < 0) rotyvel += multiplier * 4;
395                                 if (rotyvel > 0) rotyvel -= multiplier * 4;
396                                 if (rotyvel < 0) rotyvel += multiplier * 4;
397                                 if (fabs(roty) < multiplier * 4)
398                                     roty = 0;
399                                 if (fabs(rotyvel) < multiplier * 4)
400                                     rotyvel = 0;
401
402                                 roty += rotyvel * multiplier * 4;
403                             }
404                             if (roty) {
405                                 glRotatef(roty / 4, 1, 0, 0);
406                             }
407                             if (rotx) {
408                                 glRotatef(-rotx / 4, 0, 0, 1);
409                             }
410                             if (rotx > 10)
411                                 rotx = 10;
412                             if (rotx < -10)
413                                 rotx = -10;
414                             if (roty > 10)
415                                 roty = 10;
416                             if (roty < -10)
417                                 roty = -10;
418                         }
419
420                     }
421                     if (/*detail==2&&*/environment == snowyenvironment) {
422                         if (type == treeleavestype) {
423                             glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
424                         }
425                         if (type == treetrunktype) {
426                             glRotatef((sin(windvar + position.x * .3) + .5)*.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
427                         }
428                         if (type == bushtype) {
429                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
430                         }
431                     }
432                     if (/*detail==2&&*/environment == grassyenvironment) {
433                         if (type == treeleavestype) {
434                             glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
435                         }
436                         if (type == treetrunktype) {
437                             glRotatef((sin(windvar + position.x * .3) + .5)*.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
438                         }
439                         if (type == bushtype) {
440                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
441                         }
442                     }
443                     if (/*detail==2&&*/environment == desertenvironment) {
444                         if (type == bushtype) {
445                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
446                         }
447                     }
448                     glRotatef(yaw, 0, 1, 0);
449                     if (distance > 1)
450                         distance = 1;
451                     glColor4f((1 - shadowed) / 2 + .5, (1 - shadowed) / 2 + .5, (1 - shadowed) / 2 + .5, distance);
452                     if (distance >= 1) {
453                         glDisable(GL_BLEND);
454                         glAlphaFunc(GL_GREATER, 0.5);
455                     }
456                     if (distance < 1) {
457                         glEnable(GL_BLEND);
458                         glAlphaFunc(GL_GREATER, 0.1);
459                     }
460                     if (type != treetrunktype && type != treeleavestype && type != bushtype && type != rocktype) {
461                         glEnable(GL_CULL_FACE);
462                         glAlphaFunc(GL_GREATER, 0.0001);
463                         model.drawdifftex(boxtextureptr);
464                         model.drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
465                     }
466                     if (type == rocktype) {
467                         glEnable(GL_CULL_FACE);
468                         glAlphaFunc(GL_GREATER, 0.0001);
469                         glColor4f((1 - shadowed) / 2 + light.ambient[0], (1 - shadowed) / 2 + light.ambient[1], (1 - shadowed) / 2 + light.ambient[2], distance);
470                         model.drawdifftex(rocktextureptr);
471                         model.drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
472                     }
473                     if (type == treeleavestype) {
474                         glDisable(GL_CULL_FACE);
475                         glDisable(GL_LIGHTING);
476                         terrainlight = terrain.getLighting(position.x, position.z);
477                         if (!hidden) {
478                             glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
479                             if (distance < 1)
480                                 glAlphaFunc(GL_GREATER, 0.2);
481                         }
482                         if (hidden) {
483                             glDepthMask(0);
484                             glEnable(GL_BLEND);
485                             glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance / 3);
486                             glAlphaFunc(GL_GREATER, 0);
487                         }
488                         model.drawdifftex(treetextureptr);
489                     }
490                     if (type == bushtype) {
491                         glDisable(GL_CULL_FACE);
492                         glDisable(GL_LIGHTING);
493                         terrainlight = terrain.getLighting(position.x, position.z);
494                         if (!hidden) {
495                             glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
496                             if (distance < 1)
497                                 glAlphaFunc(GL_GREATER, 0.2);
498                         }
499                         if (hidden) {
500                             glDepthMask(0);
501                             glEnable(GL_BLEND);
502                             glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance / 3);
503                             glAlphaFunc(GL_GREATER, 0);
504                         }
505                         model.drawdifftex(bushtextureptr);
506                     }
507                     if (type == treetrunktype) {
508                         glEnable(GL_CULL_FACE);
509                         terrainlight = terrain.getLighting(position.x, position.z);
510                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
511                         model.drawdifftex(treetextureptr);
512                     }
513                     glPopMatrix();
514                 }
515             }
516         }
517     }
518 }
519
520 void Object::drawSecondPass()
521 {
522     static float distance;
523     static XYZ moved, terrainlight;
524     bool hidden;
525     if (type != treeleavestype && type != bushtype) {
526         return;
527     }
528     moved = DoRotation(model.boundingspherecenter, 0, yaw, 0);
529     if (frustum.SphereInFrustum(position.x + moved.x, position.y + moved.y, position.z + moved.z, model.boundingsphereradius)) {
530         hidden = distsqflat(&viewer, &position) <= playerdist + 3;
531         if (hidden) {
532             distance = 1;
533             glMatrixMode(GL_MODELVIEW);
534             glPushMatrix();
535             glEnable(GL_LIGHTING);
536             glDepthMask(1);
537             glTranslatef(position.x, position.y, position.z);
538             if (type == bushtype) {
539                 messedwith -= multiplier;
540                 if (rotxvel || rotx) {
541                     if (rotx > 0) rotxvel -= multiplier * 8 * fabs(rotx);
542                     if (rotx < 0) rotxvel += multiplier * 8 * fabs(rotx);
543                     if (rotx > 0) rotxvel -= multiplier * 4;
544                     if (rotx < 0) rotxvel += multiplier * 4;
545                     if (rotxvel > 0) rotxvel -= multiplier * 4;
546                     if (rotxvel < 0) rotxvel += multiplier * 4;
547                     if (fabs(rotx) < multiplier * 4)
548                         rotx = 0;
549                     if (fabs(rotxvel) < multiplier * 4)
550                         rotxvel = 0;
551
552                     rotx += rotxvel * multiplier * 4;
553                 }
554                 if (rotyvel || roty) {
555                     if (roty > 0) rotyvel -= multiplier * 8 * fabs(roty);
556                     if (roty < 0) rotyvel += multiplier * 8 * fabs(roty);
557                     if (roty > 0) rotyvel -= multiplier * 4;
558                     if (roty < 0) rotyvel += multiplier * 4;
559                     if (rotyvel > 0) rotyvel -= multiplier * 4;
560                     if (rotyvel < 0) rotyvel += multiplier * 4;
561                     if (fabs(roty) < multiplier * 4)
562                         roty = 0;
563                     if (fabs(rotyvel) < multiplier * 4)
564                         rotyvel = 0;
565
566                     roty += rotyvel * multiplier * 4;
567                 }
568                 if (roty) {
569                     glRotatef(roty, 1, 0, 0);
570                 }
571                 if (rotx) {
572                     glRotatef(-rotx, 0, 0, 1);
573                 }
574                 if (rotx > 10)
575                     rotx = 10;
576                 if (rotx < -10)
577                     rotx = -10;
578                 if (roty > 10)
579                     roty = 10;
580                 if (roty < -10)
581                     roty = -10;
582             }
583             if (type == treetrunktype || type == treeleavestype) {
584                 messedwith -= multiplier;
585                 if (rotxvel || rotx) {
586                     if (rotx > 0) rotxvel -= multiplier * 8 * fabs(rotx);
587                     if (rotx < 0) rotxvel += multiplier * 8 * fabs(rotx);
588                     if (rotx > 0) rotxvel -= multiplier * 4;
589                     if (rotx < 0) rotxvel += multiplier * 4;
590                     if (rotxvel > 0) rotxvel -= multiplier * 4;
591                     if (rotxvel < 0) rotxvel += multiplier * 4;
592                     if (fabs(rotx) < multiplier * 4)
593                         rotx = 0;
594                     if (fabs(rotxvel) < multiplier * 4)
595                         rotxvel = 0;
596
597                     rotx += rotxvel * multiplier * 4;
598                 }
599                 if (rotyvel || roty) {
600                     if (roty > 0) rotyvel -= multiplier * 8 * fabs(roty);
601                     if (roty < 0) rotyvel += multiplier * 8 * fabs(roty);
602                     if (roty > 0) rotyvel -= multiplier * 4;
603                     if (roty < 0) rotyvel += multiplier * 4;
604                     if (rotyvel > 0) rotyvel -= multiplier * 4;
605                     if (rotyvel < 0) rotyvel += multiplier * 4;
606                     if (fabs(roty) < multiplier * 4)
607                         roty = 0;
608                     if (fabs(rotyvel) < multiplier * 4)
609                         rotyvel = 0;
610
611                     roty += rotyvel * multiplier * 4;
612                 }
613                 if (roty) {
614                     glRotatef(roty / 2, 1, 0, 0);
615                 }
616                 if (rotx) {
617                     glRotatef(-rotx / 2, 0, 0, 1);
618                 }
619                 if (rotx > 10)
620                     rotx = 10;
621                 if (rotx < -10)
622                     rotx = -10;
623                 if (roty > 10)
624                     roty = 10;
625                 if (roty < -10)
626                     roty = -10;
627             }
628             if (environment == snowyenvironment) {
629                 if (type == treeleavestype) {
630                     glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
631                 }
632                 if (type == treetrunktype) {
633                     glRotatef((sin(windvar + position.x * .3) + .5)*.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
634                 }
635                 if (type == bushtype) {
636                     glRotatef((sin(windvar + position.x * .3) + .5) * 4 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
637                 }
638             }
639             if (environment == grassyenvironment) {
640                 if (type == treeleavestype) {
641                     glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
642                 }
643                 if (type == treetrunktype) {
644                     glRotatef((sin(windvar + position.x * .3) + .5)*.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
645                 }
646                 if (type == bushtype) {
647                     glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
648                 }
649             }
650             glRotatef(yaw, 0, 1, 0);
651             glColor4f(1, 1, 1, distance);
652             if (type == treeleavestype) {
653                 glDisable(GL_CULL_FACE);
654                 glDisable(GL_LIGHTING);
655                 terrainlight = terrain.getLighting(position.x, position.z);
656                 glDepthMask(0);
657                 glEnable(GL_BLEND);
658                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
659                 glAlphaFunc(GL_GREATER, 0);
660                 glDisable(GL_ALPHA_TEST);
661                 model.drawdifftex(treetextureptr);
662             }
663             if (type == bushtype) {
664                 glDisable(GL_CULL_FACE);
665                 glDisable(GL_LIGHTING);
666                 terrainlight = terrain.getLighting(position.x, position.z);
667                 glDepthMask(0);
668                 glEnable(GL_BLEND);
669                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
670                 glAlphaFunc(GL_GREATER, 0);
671                 glDisable(GL_ALPHA_TEST);
672                 model.drawdifftex(bushtextureptr);
673             }
674             glPopMatrix();
675         }
676     }
677 }
678
679 void Object::ComputeCenter()
680 {
681     center = 0;
682     for (unsigned i = 0; i < objects.size(); i++) {
683         center += objects[i]->position;
684     }
685     center /= objects.size();
686 }
687
688 void Object::ComputeRadius()
689 {
690     float maxdistance = 0;
691     float tempdist;
692     for (unsigned int i = 0; i < objects.size(); i++) {
693         tempdist = distsq(&center, &objects[i]->position);
694         if (tempdist > maxdistance) {
695             maxdistance = tempdist;
696         }
697     }
698     radius = fast_sqrt(maxdistance);
699 }
700
701 void Object::LoadObjectsFromFile(FILE* tfile, bool skip)
702 {
703     int numobjects;
704     int type;
705     XYZ position;
706     float yaw, pitch, scale, lastscale;
707     funpackf(tfile, "Bi", &numobjects);
708     if (!skip) {
709         objects.clear();
710     }
711     for (int i = 0; i < numobjects; i++) {
712         funpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", &type, &yaw, &pitch, &position.x, &position.y, &position.z, &scale);
713         if (!skip) {
714             if (type == treeleavestype) {
715                 scale = lastscale;
716             }
717             objects.emplace_back(new Object(object_type(type), position, yaw, pitch, scale));
718             lastscale = scale;
719         }
720     }
721 }
722
723 void Object::addToTerrain(unsigned id)
724 {
725     if ((type != treeleavestype) && (type != bushtype) && (type != firetype)) {
726         terrain.AddObject(position + DoRotation(model.boundingspherecenter, 0, yaw, 0), model.boundingsphereradius, id);
727     }
728
729     if (detail == 2) {
730         if ((type == treetrunktype) && (position.y < (terrain.getHeight(position.x, position.z) + 1))) {
731             terrain.MakeDecal(shadowdecalpermanent, position, 2, .4, 0);
732         }
733
734         if ((type == bushtype) && (position.y < (terrain.getHeight(position.x, position.z) + 1))) {
735             terrain.MakeDecal(shadowdecalpermanent, position, 1, .4, 0);
736         }
737     }
738 }
739
740 void Object::AddObjectsToTerrain()
741 {
742     for (unsigned i = 0; i < objects.size(); i++) {
743         objects[i]->addToTerrain(i);
744     }
745 }
746
747 void Object::SphereCheckPossible(XYZ *p1, float radius)
748 {
749     int whichpatchx = p1->x / (terrain.size / subdivision * terrain.scale);
750     int whichpatchz = p1->z / (terrain.size / subdivision * terrain.scale);
751
752     if (whichpatchx >= 0 && whichpatchz >= 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
753         if (terrain.patchobjectnum[whichpatchx][whichpatchz] > 0 && terrain.patchobjectnum[whichpatchx][whichpatchz] < 500) {
754             for (int j = 0; j < terrain.patchobjectnum[whichpatchx][whichpatchz]; j++) {
755                 int i = terrain.patchobjects[whichpatchx][whichpatchz][j];
756                 objects[i]->possible = false;
757                 if (objects[i]->model.SphereCheckPossible(p1, radius, &objects[i]->position, &objects[i]->yaw) != -1) {
758                     objects[i]->possible = true;
759                 }
760             }
761         }
762     }
763 }
764
765 void Object::Draw()
766 {
767     for (unsigned i = 0; i < objects.size(); i++) {
768         objects[i]->draw();
769     }
770
771     glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
772     for (unsigned i = 0; i < objects.size(); i++) {
773         objects[i]->drawSecondPass();
774     }
775     if (environment == desertenvironment) {
776         glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
777     }
778     glEnable(GL_ALPHA_TEST);
779     SetUpLight(&light, 0);
780 }
781
782 void Object::DeleteObject(int which)
783 {
784     objects.erase(objects.begin() + which);
785 }
786
787 void Object::MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale)
788 {
789     if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
790         unsigned nextid = objects.size();
791         objects.emplace_back(new Object(object_type(atype), where, ayaw, apitch, ascale));
792         objects.back()->addToTerrain(nextid);
793     }
794 }
795
796 void Object::DoStuff()
797 {
798     for (unsigned i = 0; i < objects.size(); i++) {
799         objects[i]->handleFire();
800     }
801 }
802
803 void Object::DoShadows()
804 {
805     XYZ lightloc;
806     lightloc = light.location;
807     if (!skyboxtexture)
808         lightloc = 0;
809     lightloc.y += 10;
810     Normalise(&lightloc);
811
812     for (unsigned i = 0; i < objects.size(); i++) {
813         objects[i]->doShadows(lightloc);
814     }
815 }
816
817 int Object::checkcollide(XYZ startpoint, XYZ endpoint)
818 {
819     float minx, minz, maxx, maxz, miny, maxy;
820
821     minx = min(startpoint.x, endpoint.x) - 1;
822     miny = min(startpoint.y, endpoint.y) - 1;
823     minz = min(startpoint.z, endpoint.z) - 1;
824     maxx = max(startpoint.x, endpoint.x) + 1;
825     maxy = max(startpoint.y, endpoint.y) + 1;
826     maxz = max(startpoint.z, endpoint.z) + 1;
827
828     for (unsigned int i = 0; i < objects.size(); i++) {
829         if (checkcollide(startpoint, endpoint, i, minx, miny, minz, maxx, maxy, maxz) != -1) {
830             return (int) i;
831         }
832     }
833
834     return -1;
835 }
836
837 int Object::checkcollide(XYZ startpoint, XYZ endpoint, int what)
838 {
839     float minx, minz, maxx, maxz, miny, maxy;
840
841     minx = min(startpoint.x, endpoint.x) - 1;
842     miny = min(startpoint.y, endpoint.y) - 1;
843     minz = min(startpoint.z, endpoint.z) - 1;
844     maxx = max(startpoint.x, endpoint.x) + 1;
845     maxy = max(startpoint.y, endpoint.y) + 1;
846     maxz = max(startpoint.z, endpoint.z) + 1;
847
848     return checkcollide(startpoint, endpoint, what, minx, miny, minz, maxx, maxy, maxz);
849 }
850
851 int Object::checkcollide(XYZ startpoint, XYZ endpoint, int what, float minx, float miny, float minz, float maxx, float maxy, float maxz)
852 {
853     XYZ colpoint, colviewer, coltarget;
854
855     if (what == 1000) {
856         if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1) {
857             return what;
858         }
859     } else {
860         if (     objects[what]->position.x > minx - objects[what]->model.boundingsphereradius &&
861                  objects[what]->position.x < maxx + objects[what]->model.boundingsphereradius &&
862                  objects[what]->position.y > miny - objects[what]->model.boundingsphereradius &&
863                  objects[what]->position.y < maxy + objects[what]->model.boundingsphereradius &&
864                  objects[what]->position.z > minz - objects[what]->model.boundingsphereradius &&
865                  objects[what]->position.z < maxz + objects[what]->model.boundingsphereradius) {
866             if (     objects[what]->type != treeleavestype &&
867                      objects[what]->type != bushtype &&
868                      objects[what]->type != firetype) {
869                 colviewer = startpoint;
870                 coltarget = endpoint;
871                 if (objects[what]->model.LineCheck(&colviewer, &coltarget, &colpoint, &objects[what]->position, &objects[what]->yaw) != -1) {
872                     return what;
873                 }
874             }
875         }
876     }
877
878     return -1;
879 }
880
881 //~ Object::~Objects()
882 //~ {
883     //~ boxtextureptr.destroy();
884     //~ treetextureptr.destroy();
885     //~ bushtextureptr.destroy();
886     //~ rocktextureptr.destroy();
887 //~ }