]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Object.cpp
Moved creatures skins to PersonType class
[lugaru.git] / Source / Objects / Object.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2017 - 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)
74     : Object()
75 {
76     scale = _scale;
77     type = _type;
78     position = _position;
79     yaw = _yaw;
80     pitch = _pitch;
81
82     switch (type) {
83         case boxtype:
84             model.loaddecal("Models/Box.solid");
85             friction = 1.5;
86             break;
87         case cooltype:
88             model.loaddecal("Models/Cool.solid");
89             friction = 1.5;
90             break;
91         case walltype:
92             model.loaddecal("Models/Wall.solid");
93             friction = 1.5;
94             break;
95         case tunneltype:
96             model.loaddecal("Models/Tunnel.solid");
97             friction = 1.5;
98             break;
99         case chimneytype:
100             model.loaddecal("Models/Chimney.solid");
101             friction = 1.5;
102             break;
103         case spiketype:
104             model.load("Models/Spike.solid");
105             friction = .4;
106             break;
107         case weirdtype:
108             model.loaddecal("Models/Weird.solid");
109             friction = 1.5;
110             break;
111         case rocktype:
112             model.loaddecal("Models/Rock.solid");
113             if (scale > .5) {
114                 friction = 1.5;
115             } else {
116                 friction = .5;
117             }
118             break;
119         case treetrunktype:
120             model.load("Models/TreeTrunk.solid");
121             friction = .4;
122             break;
123         case treeleavestype:
124             scale += fabs((float)(Random() % 100) / 900) * scale;
125             model.load("Models/Leaves.solid");
126             friction = 0;
127             break;
128         case bushtype:
129             position.y = terrain.getHeight(position.x, position.z) - .3;
130             model.load("Models/Bush.solid");
131             break;
132         case platformtype:
133             model.loaddecal("Models/Platform.solid");
134             model.Rotate(90, 0, 0);
135             friction = 1.5;
136             break;
137         case firetype:
138             onfire = true;
139             break;
140     }
141
142     if (friction == 1.5 && fabs(pitch) > 5) {
143         friction = .5;
144     }
145
146     if (type == boxtype || type == cooltype || type == spiketype || type == weirdtype || type == walltype || type == chimneytype || type == tunneltype || type == platformtype) {
147         model.ScaleTexCoords(scale * 1.5);
148     }
149     if (type == rocktype) {
150         model.ScaleTexCoords(scale * 3);
151     }
152     model.flat = 1;
153     if (type == treetrunktype || type == treeleavestype || type == rocktype) {
154         model.flat = 0;
155     }
156     model.Scale(.3 * scale, .3 * scale, .3 * scale);
157     model.Rotate(90, 1, 1);
158     model.Rotate(pitch, 0, 0);
159     if (type == rocktype) {
160         model.Rotate(yaw * 5, 0, 0);
161     }
162     model.CalculateNormals(1);
163     model.ScaleNormals(-1, -1, -1);
164 }
165
166 void Object::handleFire()
167 {
168     if (type == firetype) {
169         onfire = 1;
170     }
171     if (onfire) {
172         XYZ spawnpoint;
173         if ((type == bushtype) || (type == firetype)) {
174             flamedelay -= multiplier * 3;
175         } else if (type == treeleavestype) {
176             flamedelay -= multiplier * 4;
177         }
178         while ((flamedelay < 0) && onfire) {
179             flamedelay += .006;
180             if ((type == bushtype) || (type == firetype)) {
181                 spawnpoint.x = ((float)(Random() % 100)) / 30 * scale;
182                 spawnpoint.y = ((float)(Random() % 100) + 60) / 30 * scale;
183                 spawnpoint.z = 0;
184                 spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
185                 spawnpoint += position;
186                 Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 5 * scale, 1);
187             } else if (type == treeleavestype) {
188                 spawnpoint.x = ((float)(Random() % 100)) / 80 * scale;
189                 spawnpoint.y = ((float)(Random() % 100) + 80) / 12 * scale;
190                 spawnpoint.z = 0;
191                 spawnpoint = DoRotation(spawnpoint, 0, Random() % 360, 0);
192                 spawnpoint += position;
193                 Sprite::MakeSprite(flamesprite, spawnpoint, spawnpoint * 0, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 6, 1);
194             }
195         }
196     }
197 }
198
199 void Object::doShadows(XYZ lightloc)
200 {
201     XYZ testpoint, testpoint2, terrainpoint, col;
202     int patchx, patchz;
203     if (type != treeleavestype && type != treetrunktype && type != bushtype && type != firetype) {
204         for (int j = 0; j < model.vertexNum; j++) {
205             terrainpoint = position + DoRotation(model.vertex[j] + model.normals[j] * .1, 0, yaw, 0);
206             shadowed = 0;
207             patchx = terrainpoint.x / (terrain.size / subdivision * terrain.scale);
208             patchz = terrainpoint.z / (terrain.size / subdivision * terrain.scale);
209             if (patchx >= 0 && patchz >= 0 && patchx < subdivision && patchz < subdivision) {
210                 for (unsigned int k = 0; k < terrain.patchobjects[patchx][patchz].size(); k++) {
211                     unsigned 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             if (shadowed > 0) {
222                 col = model.normals[j] - DoRotation(lightloc * shadowed, 0, -yaw, 0);
223                 Normalise(&col);
224                 for (unsigned int k = 0; k < model.Triangles.size(); k++) {
225                     if (model.Triangles[k].vertex[0] == j) {
226                         int l = k * 24;
227                         model.vArray[l + 2] = col.x;
228                         model.vArray[l + 3] = col.y;
229                         model.vArray[l + 4] = col.z;
230                     }
231                     if (model.Triangles[k].vertex[1] == j) {
232                         int l = k * 24;
233                         model.vArray[l + 10] = col.x;
234                         model.vArray[l + 11] = col.y;
235                         model.vArray[l + 12] = col.z;
236                     }
237                     if (model.Triangles[k].vertex[2] == j) {
238                         int l = k * 24;
239                         model.vArray[l + 18] = col.x;
240                         model.vArray[l + 19] = col.y;
241                         model.vArray[l + 20] = col.z;
242                     }
243                 }
244             }
245         }
246     }
247     shadowed = 0;
248 }
249
250 void Object::handleRot(int divide)
251 {
252     messedwith -= multiplier;
253     if (rotxvel || rotx) {
254         if (rotx > 0) {
255             rotxvel -= multiplier * 8 * fabs(rotx);
256         }
257         if (rotx < 0) {
258             rotxvel += multiplier * 8 * fabs(rotx);
259         }
260         if (rotx > 0) {
261             rotxvel -= multiplier * 4;
262         }
263         if (rotx < 0) {
264             rotxvel += multiplier * 4;
265         }
266         if (rotxvel > 0) {
267             rotxvel -= multiplier * 4;
268         }
269         if (rotxvel < 0) {
270             rotxvel += multiplier * 4;
271         }
272         if (fabs(rotx) < multiplier * 4) {
273             rotx = 0;
274         }
275         if (fabs(rotxvel) < multiplier * 4) {
276             rotxvel = 0;
277         }
278
279         rotx += rotxvel * multiplier * 4;
280     }
281     if (rotyvel || roty) {
282         if (roty > 0) {
283             rotyvel -= multiplier * 8 * fabs(roty);
284         }
285         if (roty < 0) {
286             rotyvel += multiplier * 8 * fabs(roty);
287         }
288         if (roty > 0) {
289             rotyvel -= multiplier * 4;
290         }
291         if (roty < 0) {
292             rotyvel += multiplier * 4;
293         }
294         if (rotyvel > 0) {
295             rotyvel -= multiplier * 4;
296         }
297         if (rotyvel < 0) {
298             rotyvel += multiplier * 4;
299         }
300         if (fabs(roty) < multiplier * 4) {
301             roty = 0;
302         }
303         if (fabs(rotyvel) < multiplier * 4) {
304             rotyvel = 0;
305         }
306
307         roty += rotyvel * multiplier * 4;
308     }
309     if (roty) {
310         glRotatef(roty / divide, 1, 0, 0);
311     }
312     if (rotx) {
313         glRotatef(-rotx / divide, 0, 0, 1);
314     }
315     if (rotx > 10) {
316         rotx = 10;
317     }
318     if (rotx < -10) {
319         rotx = -10;
320     }
321     if (roty > 10) {
322         roty = 10;
323     }
324     if (roty < -10) {
325         roty = -10;
326     }
327 }
328
329 void Object::draw()
330 {
331     static float distance;
332     static XYZ moved, terrainlight;
333     bool hidden;
334     if (type == firetype) {
335         return;
336     }
337     moved = DoRotation(model.boundingspherecenter, 0, yaw, 0);
338     if (type == tunneltype || frustum.SphereInFrustum(position.x + moved.x, position.y + moved.y, position.z + moved.z, model.boundingsphereradius)) {
339         distance = distsq(&viewer, &position);
340         distance *= 1.2;
341         hidden = !(distsqflat(&viewer, &position) > playerdist + 3 || (type != bushtype && type != treeleavestype));
342         if (!hidden) {
343
344             if (detail == 2 && distance > viewdistance * viewdistance / 4 && environment == desertenvironment) {
345                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness);
346             } else {
347                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
348             }
349             distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
350             if (distance > 1) {
351                 distance = 1;
352             }
353             if (distance > 0) {
354
355                 if (occluded < 6) {
356                     glMatrixMode(GL_MODELVIEW);
357                     glPushMatrix();
358                     if (!model.color) {
359                         glEnable(GL_LIGHTING);
360                     } else {
361                         glDisable(GL_LIGHTING);
362                     }
363                     glDepthMask(1);
364                     glTranslatef(position.x, position.y, position.z);
365                     if (type == bushtype) {
366                         handleRot(1);
367                     }
368                     if (type == treetrunktype || type == treeleavestype) {
369                         if (type == treetrunktype || environment == desertenvironment) {
370                             handleRot(6);
371                         } else {
372                             handleRot(4);
373                         }
374                     }
375                     if (environment == snowyenvironment) {
376                         if (type == treeleavestype) {
377                             glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
378                         }
379                         if (type == treetrunktype) {
380                             glRotatef((sin(windvar + position.x * .3) + .5) * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
381                         }
382                         if (type == bushtype) {
383                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
384                         }
385                     }
386                     if (environment == grassyenvironment) {
387                         if (type == treeleavestype) {
388                             glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
389                         }
390                         if (type == treetrunktype) {
391                             glRotatef((sin(windvar + position.x * .3) + .5) * .5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
392                         }
393                         if (type == bushtype) {
394                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
395                         }
396                     }
397                     if (environment == desertenvironment) {
398                         if (type == bushtype) {
399                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
400                         }
401                     }
402                     glRotatef(yaw, 0, 1, 0);
403                     glColor4f((1 - shadowed) / 2 + .5, (1 - shadowed) / 2 + .5, (1 - shadowed) / 2 + .5, distance);
404                     if (distance >= 1) {
405                         glDisable(GL_BLEND);
406                         glAlphaFunc(GL_GREATER, 0.5);
407                     } else {
408                         glEnable(GL_BLEND);
409                         glAlphaFunc(GL_GREATER, 0.1);
410                     }
411                     if (type != treetrunktype && type != treeleavestype && type != bushtype && type != rocktype) {
412                         glEnable(GL_CULL_FACE);
413                         glAlphaFunc(GL_GREATER, 0.0001);
414                         model.drawdifftex(boxtextureptr);
415                         model.drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
416                     }
417                     if (type == rocktype) {
418                         glEnable(GL_CULL_FACE);
419                         glAlphaFunc(GL_GREATER, 0.0001);
420                         glColor4f((1 - shadowed) / 2 + light.ambient[0], (1 - shadowed) / 2 + light.ambient[1], (1 - shadowed) / 2 + light.ambient[2], distance);
421                         model.drawdifftex(rocktextureptr);
422                         model.drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
423                     }
424                     if (type == treeleavestype) {
425                         glDisable(GL_CULL_FACE);
426                         glDisable(GL_LIGHTING);
427                         terrainlight = terrain.getLighting(position.x, position.z);
428                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
429                         if (distance < 1) {
430                             glAlphaFunc(GL_GREATER, 0.2);
431                         }
432                         model.drawdifftex(treetextureptr);
433                     }
434                     if (type == bushtype) {
435                         glDisable(GL_CULL_FACE);
436                         glDisable(GL_LIGHTING);
437                         terrainlight = terrain.getLighting(position.x, position.z);
438                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
439                         if (distance < 1) {
440                             glAlphaFunc(GL_GREATER, 0.2);
441                         }
442                         model.drawdifftex(bushtextureptr);
443                     }
444                     if (type == treetrunktype) {
445                         glEnable(GL_CULL_FACE);
446                         terrainlight = terrain.getLighting(position.x, position.z);
447                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
448                         model.drawdifftex(treetextureptr);
449                     }
450                     glPopMatrix();
451                 }
452             }
453         }
454     }
455 }
456
457 void Object::drawSecondPass()
458 {
459     static float distance;
460     static XYZ moved, terrainlight;
461     bool hidden;
462     if (type != treeleavestype && type != bushtype) {
463         return;
464     }
465     moved = DoRotation(model.boundingspherecenter, 0, yaw, 0);
466     if (frustum.SphereInFrustum(position.x + moved.x, position.y + moved.y, position.z + moved.z, model.boundingsphereradius)) {
467         hidden = distsqflat(&viewer, &position) <= playerdist + 3;
468         if (hidden) {
469             distance = 1;
470             glMatrixMode(GL_MODELVIEW);
471             glPushMatrix();
472             glEnable(GL_LIGHTING);
473             glDepthMask(1);
474             glTranslatef(position.x, position.y, position.z);
475             if (type == bushtype) {
476                 handleRot(1);
477             }
478             if (type == treetrunktype || type == treeleavestype) {
479                 handleRot(2);
480             }
481             if (environment == snowyenvironment) {
482                 if (type == treeleavestype) {
483                     glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
484                 }
485                 if (type == treetrunktype) {
486                     glRotatef((sin(windvar + position.x * .3) + .5) * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
487                 }
488                 if (type == bushtype) {
489                     glRotatef((sin(windvar + position.x * .3) + .5) * 4 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
490                 }
491             }
492             if (environment == grassyenvironment) {
493                 if (type == treeleavestype) {
494                     glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
495                 }
496                 if (type == treetrunktype) {
497                     glRotatef((sin(windvar + position.x * .3) + .5) * .5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
498                 }
499                 if (type == bushtype) {
500                     glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
501                 }
502             }
503             glRotatef(yaw, 0, 1, 0);
504             glColor4f(1, 1, 1, distance);
505             if (type == treeleavestype) {
506                 glDisable(GL_CULL_FACE);
507                 glDisable(GL_LIGHTING);
508                 terrainlight = terrain.getLighting(position.x, position.z);
509                 glDepthMask(0);
510                 glEnable(GL_BLEND);
511                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
512                 glAlphaFunc(GL_GREATER, 0);
513                 glDisable(GL_ALPHA_TEST);
514                 model.drawdifftex(treetextureptr);
515             }
516             if (type == bushtype) {
517                 glDisable(GL_CULL_FACE);
518                 glDisable(GL_LIGHTING);
519                 terrainlight = terrain.getLighting(position.x, position.z);
520                 glDepthMask(0);
521                 glEnable(GL_BLEND);
522                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
523                 glAlphaFunc(GL_GREATER, 0);
524                 glDisable(GL_ALPHA_TEST);
525                 model.drawdifftex(bushtextureptr);
526             }
527             glPopMatrix();
528         }
529     }
530 }
531
532 void Object::ComputeCenter()
533 {
534     center = 0;
535     for (unsigned i = 0; i < objects.size(); i++) {
536         center += objects[i]->position;
537     }
538     center /= objects.size();
539 }
540
541 void Object::ComputeRadius()
542 {
543     float maxdistance = 0;
544     float tempdist;
545     for (unsigned int i = 0; i < objects.size(); i++) {
546         tempdist = distsq(&center, &objects[i]->position);
547         if (tempdist > maxdistance) {
548             maxdistance = tempdist;
549         }
550     }
551     radius = fast_sqrt(maxdistance);
552 }
553
554 void Object::LoadObjectsFromFile(FILE* tfile, bool skip)
555 {
556     int numobjects;
557     int type;
558     XYZ position;
559     float yaw, pitch, scale;
560     float lastscale = 1.0f;
561     funpackf(tfile, "Bi", &numobjects);
562     if (!skip) {
563         objects.clear();
564     }
565     for (int i = 0; i < numobjects; i++) {
566         funpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", &type, &yaw, &pitch, &position.x, &position.y, &position.z, &scale);
567         if (!skip) {
568             if (type == treeleavestype) {
569                 scale = lastscale;
570             }
571             objects.emplace_back(new Object(object_type(type), position, yaw, pitch, scale));
572             lastscale = scale;
573         }
574     }
575 }
576
577 void Object::addToTerrain(unsigned id)
578 {
579     if ((type != treeleavestype) && (type != bushtype) && (type != firetype)) {
580         terrain.AddObject(position + DoRotation(model.boundingspherecenter, 0, yaw, 0), model.boundingsphereradius, id);
581     }
582
583     if (detail == 2) {
584         if ((type == treetrunktype) && (position.y < (terrain.getHeight(position.x, position.z) + 1))) {
585             terrain.MakeDecal(shadowdecalpermanent, position, 2, .4, 0);
586         }
587
588         if ((type == bushtype) && (position.y < (terrain.getHeight(position.x, position.z) + 1))) {
589             terrain.MakeDecal(shadowdecalpermanent, position, 1, .4, 0);
590         }
591     }
592 }
593
594 void Object::AddObjectsToTerrain()
595 {
596     for (unsigned i = 0; i < objects.size(); i++) {
597         objects[i]->addToTerrain(i);
598     }
599 }
600
601 void Object::SphereCheckPossible(XYZ* p1, float radius)
602 {
603     int whichpatchx = p1->x / (terrain.size / subdivision * terrain.scale);
604     int whichpatchz = p1->z / (terrain.size / subdivision * terrain.scale);
605
606     if (whichpatchx >= 0 && whichpatchz >= 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
607         if (terrain.patchobjects[whichpatchx][whichpatchz].size() < 500) {
608             for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) {
609                 unsigned int i = terrain.patchobjects[whichpatchx][whichpatchz][j];
610                 objects[i]->possible = false;
611                 if (objects[i]->model.SphereCheckPossible(p1, radius, &objects[i]->position, &objects[i]->yaw) != -1) {
612                     objects[i]->possible = true;
613                 }
614             }
615         }
616     }
617 }
618
619 void Object::Draw()
620 {
621     for (unsigned i = 0; i < objects.size(); i++) {
622         objects[i]->draw();
623     }
624
625     glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
626     for (unsigned i = 0; i < objects.size(); i++) {
627         objects[i]->drawSecondPass();
628     }
629     if (environment == desertenvironment) {
630         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
631     }
632     glEnable(GL_ALPHA_TEST);
633     SetUpLight(&light, 0);
634 }
635
636 void Object::DeleteObject(int which)
637 {
638     objects.erase(objects.begin() + which);
639     terrain.DeleteObject(which);
640 }
641
642 void Object::MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale)
643 {
644     if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
645         unsigned nextid = objects.size();
646         objects.emplace_back(new Object(object_type(atype), where, ayaw, apitch, ascale));
647         objects.back()->addToTerrain(nextid);
648     }
649 }
650
651 void Object::DoStuff()
652 {
653     for (unsigned i = 0; i < objects.size(); i++) {
654         objects[i]->handleFire();
655     }
656 }
657
658 void Object::DoShadows()
659 {
660     XYZ lightloc;
661     lightloc = light.location;
662     if (!skyboxtexture) {
663         lightloc = 0;
664     }
665     lightloc.y += 10;
666     Normalise(&lightloc);
667
668     for (unsigned i = 0; i < objects.size(); i++) {
669         objects[i]->doShadows(lightloc);
670     }
671 }
672
673 int Object::checkcollide(XYZ startpoint, XYZ endpoint)
674 {
675     float minx, minz, maxx, maxz, miny, maxy;
676
677     minx = min(startpoint.x, endpoint.x) - 1;
678     miny = min(startpoint.y, endpoint.y) - 1;
679     minz = min(startpoint.z, endpoint.z) - 1;
680     maxx = max(startpoint.x, endpoint.x) + 1;
681     maxy = max(startpoint.y, endpoint.y) + 1;
682     maxz = max(startpoint.z, endpoint.z) + 1;
683
684     for (unsigned int i = 0; i < objects.size(); i++) {
685         if (checkcollide(startpoint, endpoint, i, minx, miny, minz, maxx, maxy, maxz) != -1) {
686             return (int)i;
687         }
688     }
689
690     return -1;
691 }
692
693 int Object::checkcollide(XYZ startpoint, XYZ endpoint, int what)
694 {
695     float minx, minz, maxx, maxz, miny, maxy;
696
697     minx = min(startpoint.x, endpoint.x) - 1;
698     miny = min(startpoint.y, endpoint.y) - 1;
699     minz = min(startpoint.z, endpoint.z) - 1;
700     maxx = max(startpoint.x, endpoint.x) + 1;
701     maxy = max(startpoint.y, endpoint.y) + 1;
702     maxz = max(startpoint.z, endpoint.z) + 1;
703
704     return checkcollide(startpoint, endpoint, what, minx, miny, minz, maxx, maxy, maxz);
705 }
706
707 int Object::checkcollide(XYZ startpoint, XYZ endpoint, int what, float minx, float miny, float minz, float maxx, float maxy, float maxz)
708 {
709     XYZ colpoint, colviewer, coltarget;
710
711     if (what == 1000) {
712         if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1) {
713             return what;
714         }
715     } else {
716         if (objects[what]->position.x > minx - objects[what]->model.boundingsphereradius &&
717             objects[what]->position.x < maxx + objects[what]->model.boundingsphereradius &&
718             objects[what]->position.y > miny - objects[what]->model.boundingsphereradius &&
719             objects[what]->position.y < maxy + objects[what]->model.boundingsphereradius &&
720             objects[what]->position.z > minz - objects[what]->model.boundingsphereradius &&
721             objects[what]->position.z < maxz + objects[what]->model.boundingsphereradius) {
722             if (objects[what]->type != treeleavestype &&
723                 objects[what]->type != bushtype &&
724                 objects[what]->type != firetype) {
725                 colviewer = startpoint;
726                 coltarget = endpoint;
727                 if (objects[what]->model.LineCheck(&colviewer, &coltarget, &colpoint, &objects[what]->position, &objects[what]->yaw) != -1) {
728                     return what;
729                 }
730             }
731         }
732     }
733
734     return -1;
735 }
736
737 //~ Object::~Objects()
738 //~ {
739 //~ boxtextureptr.destroy();
740 //~ treetextureptr.destroy();
741 //~ bushtextureptr.destroy();
742 //~ rocktextureptr.destroy();
743 //~ }