]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Object.cpp
Applied clang-format on all files
[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)
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         if (rotx < 0)
257             rotxvel += multiplier * 8 * fabs(rotx);
258         if (rotx > 0)
259             rotxvel -= multiplier * 4;
260         if (rotx < 0)
261             rotxvel += multiplier * 4;
262         if (rotxvel > 0)
263             rotxvel -= multiplier * 4;
264         if (rotxvel < 0)
265             rotxvel += multiplier * 4;
266         if (fabs(rotx) < multiplier * 4)
267             rotx = 0;
268         if (fabs(rotxvel) < multiplier * 4)
269             rotxvel = 0;
270
271         rotx += rotxvel * multiplier * 4;
272     }
273     if (rotyvel || roty) {
274         if (roty > 0)
275             rotyvel -= multiplier * 8 * fabs(roty);
276         if (roty < 0)
277             rotyvel += multiplier * 8 * fabs(roty);
278         if (roty > 0)
279             rotyvel -= multiplier * 4;
280         if (roty < 0)
281             rotyvel += multiplier * 4;
282         if (rotyvel > 0)
283             rotyvel -= multiplier * 4;
284         if (rotyvel < 0)
285             rotyvel += multiplier * 4;
286         if (fabs(roty) < multiplier * 4)
287             roty = 0;
288         if (fabs(rotyvel) < multiplier * 4)
289             rotyvel = 0;
290
291         roty += rotyvel * multiplier * 4;
292     }
293     if (roty) {
294         glRotatef(roty / divide, 1, 0, 0);
295     }
296     if (rotx) {
297         glRotatef(-rotx / divide, 0, 0, 1);
298     }
299     if (rotx > 10)
300         rotx = 10;
301     if (rotx < -10)
302         rotx = -10;
303     if (roty > 10)
304         roty = 10;
305     if (roty < -10)
306         roty = -10;
307 }
308
309 void Object::draw()
310 {
311     static float distance;
312     static XYZ moved, terrainlight;
313     bool hidden;
314     if (type == firetype) {
315         return;
316     }
317     moved = DoRotation(model.boundingspherecenter, 0, yaw, 0);
318     if (type == tunneltype || frustum.SphereInFrustum(position.x + moved.x, position.y + moved.y, position.z + moved.z, model.boundingsphereradius)) {
319         distance = distsq(&viewer, &position);
320         distance *= 1.2;
321         hidden = !(distsqflat(&viewer, &position) > playerdist + 3 || (type != bushtype && type != treeleavestype));
322         if (!hidden) {
323
324             if (detail == 2 && distance > viewdistance * viewdistance / 4 && environment == desertenvironment)
325                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness);
326             else
327                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
328             distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
329             if (distance > 1)
330                 distance = 1;
331             if (distance > 0) {
332
333                 if (occluded < 6) {
334                     glMatrixMode(GL_MODELVIEW);
335                     glPushMatrix();
336                     if (!model.color)
337                         glEnable(GL_LIGHTING);
338                     else
339                         glDisable(GL_LIGHTING);
340                     glDepthMask(1);
341                     glTranslatef(position.x, position.y, position.z);
342                     if (type == bushtype) {
343                         handleRot(1);
344                     }
345                     if (type == treetrunktype || type == treeleavestype) {
346                         if (type == treetrunktype || environment == desertenvironment) {
347                             handleRot(6);
348                         } else {
349                             handleRot(4);
350                         }
351                     }
352                     if (environment == snowyenvironment) {
353                         if (type == treeleavestype) {
354                             glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
355                         }
356                         if (type == treetrunktype) {
357                             glRotatef((sin(windvar + position.x * .3) + .5) * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
358                         }
359                         if (type == bushtype) {
360                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
361                         }
362                     }
363                     if (environment == grassyenvironment) {
364                         if (type == treeleavestype) {
365                             glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
366                         }
367                         if (type == treetrunktype) {
368                             glRotatef((sin(windvar + position.x * .3) + .5) * .5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
369                         }
370                         if (type == bushtype) {
371                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
372                         }
373                     }
374                     if (environment == desertenvironment) {
375                         if (type == bushtype) {
376                             glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
377                         }
378                     }
379                     glRotatef(yaw, 0, 1, 0);
380                     glColor4f((1 - shadowed) / 2 + .5, (1 - shadowed) / 2 + .5, (1 - shadowed) / 2 + .5, distance);
381                     if (distance >= 1) {
382                         glDisable(GL_BLEND);
383                         glAlphaFunc(GL_GREATER, 0.5);
384                     } else {
385                         glEnable(GL_BLEND);
386                         glAlphaFunc(GL_GREATER, 0.1);
387                     }
388                     if (type != treetrunktype && type != treeleavestype && type != bushtype && type != rocktype) {
389                         glEnable(GL_CULL_FACE);
390                         glAlphaFunc(GL_GREATER, 0.0001);
391                         model.drawdifftex(boxtextureptr);
392                         model.drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
393                     }
394                     if (type == rocktype) {
395                         glEnable(GL_CULL_FACE);
396                         glAlphaFunc(GL_GREATER, 0.0001);
397                         glColor4f((1 - shadowed) / 2 + light.ambient[0], (1 - shadowed) / 2 + light.ambient[1], (1 - shadowed) / 2 + light.ambient[2], distance);
398                         model.drawdifftex(rocktextureptr);
399                         model.drawdecals(terrain.shadowtexture, terrain.bloodtexture, terrain.bloodtexture2, terrain.breaktexture);
400                     }
401                     if (type == treeleavestype) {
402                         glDisable(GL_CULL_FACE);
403                         glDisable(GL_LIGHTING);
404                         terrainlight = terrain.getLighting(position.x, position.z);
405                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
406                         if (distance < 1) {
407                             glAlphaFunc(GL_GREATER, 0.2);
408                         }
409                         model.drawdifftex(treetextureptr);
410                     }
411                     if (type == bushtype) {
412                         glDisable(GL_CULL_FACE);
413                         glDisable(GL_LIGHTING);
414                         terrainlight = terrain.getLighting(position.x, position.z);
415                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
416                         if (distance < 1) {
417                             glAlphaFunc(GL_GREATER, 0.2);
418                         }
419                         model.drawdifftex(bushtextureptr);
420                     }
421                     if (type == treetrunktype) {
422                         glEnable(GL_CULL_FACE);
423                         terrainlight = terrain.getLighting(position.x, position.z);
424                         glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, distance);
425                         model.drawdifftex(treetextureptr);
426                     }
427                     glPopMatrix();
428                 }
429             }
430         }
431     }
432 }
433
434 void Object::drawSecondPass()
435 {
436     static float distance;
437     static XYZ moved, terrainlight;
438     bool hidden;
439     if (type != treeleavestype && type != bushtype) {
440         return;
441     }
442     moved = DoRotation(model.boundingspherecenter, 0, yaw, 0);
443     if (frustum.SphereInFrustum(position.x + moved.x, position.y + moved.y, position.z + moved.z, model.boundingsphereradius)) {
444         hidden = distsqflat(&viewer, &position) <= playerdist + 3;
445         if (hidden) {
446             distance = 1;
447             glMatrixMode(GL_MODELVIEW);
448             glPushMatrix();
449             glEnable(GL_LIGHTING);
450             glDepthMask(1);
451             glTranslatef(position.x, position.y, position.z);
452             if (type == bushtype) {
453                 handleRot(1);
454             }
455             if (type == treetrunktype || type == treeleavestype) {
456                 handleRot(2);
457             }
458             if (environment == snowyenvironment) {
459                 if (type == treeleavestype) {
460                     glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
461                 }
462                 if (type == treetrunktype) {
463                     glRotatef((sin(windvar + position.x * .3) + .5) * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
464                 }
465                 if (type == bushtype) {
466                     glRotatef((sin(windvar + position.x * .3) + .5) * 4 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
467                 }
468             }
469             if (environment == grassyenvironment) {
470                 if (type == treeleavestype) {
471                     glRotatef((sin(windvar + position.x * .3) + .5) * 1.5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
472                 }
473                 if (type == treetrunktype) {
474                     glRotatef((sin(windvar + position.x * .3) + .5) * .5 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
475                 }
476                 if (type == bushtype) {
477                     glRotatef((sin(windvar + position.x * .3) + .5) * 4 * .5 * (sin(windvar * 2 + position.x * .3) + 1) / 2, 1, 0, 0);
478                 }
479             }
480             glRotatef(yaw, 0, 1, 0);
481             glColor4f(1, 1, 1, distance);
482             if (type == treeleavestype) {
483                 glDisable(GL_CULL_FACE);
484                 glDisable(GL_LIGHTING);
485                 terrainlight = terrain.getLighting(position.x, position.z);
486                 glDepthMask(0);
487                 glEnable(GL_BLEND);
488                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
489                 glAlphaFunc(GL_GREATER, 0);
490                 glDisable(GL_ALPHA_TEST);
491                 model.drawdifftex(treetextureptr);
492             }
493             if (type == bushtype) {
494                 glDisable(GL_CULL_FACE);
495                 glDisable(GL_LIGHTING);
496                 terrainlight = terrain.getLighting(position.x, position.z);
497                 glDepthMask(0);
498                 glEnable(GL_BLEND);
499                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, .3);
500                 glAlphaFunc(GL_GREATER, 0);
501                 glDisable(GL_ALPHA_TEST);
502                 model.drawdifftex(bushtextureptr);
503             }
504             glPopMatrix();
505         }
506     }
507 }
508
509 void Object::ComputeCenter()
510 {
511     center = 0;
512     for (unsigned i = 0; i < objects.size(); i++) {
513         center += objects[i]->position;
514     }
515     center /= objects.size();
516 }
517
518 void Object::ComputeRadius()
519 {
520     float maxdistance = 0;
521     float tempdist;
522     for (unsigned int i = 0; i < objects.size(); i++) {
523         tempdist = distsq(&center, &objects[i]->position);
524         if (tempdist > maxdistance) {
525             maxdistance = tempdist;
526         }
527     }
528     radius = fast_sqrt(maxdistance);
529 }
530
531 void Object::LoadObjectsFromFile(FILE* tfile, bool skip)
532 {
533     int numobjects;
534     int type;
535     XYZ position;
536     float yaw, pitch, scale, lastscale;
537     funpackf(tfile, "Bi", &numobjects);
538     if (!skip) {
539         objects.clear();
540     }
541     for (int i = 0; i < numobjects; i++) {
542         funpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", &type, &yaw, &pitch, &position.x, &position.y, &position.z, &scale);
543         if (!skip) {
544             if (type == treeleavestype) {
545                 scale = lastscale;
546             }
547             objects.emplace_back(new Object(object_type(type), position, yaw, pitch, scale));
548             lastscale = scale;
549         }
550     }
551 }
552
553 void Object::addToTerrain(unsigned id)
554 {
555     if ((type != treeleavestype) && (type != bushtype) && (type != firetype)) {
556         terrain.AddObject(position + DoRotation(model.boundingspherecenter, 0, yaw, 0), model.boundingsphereradius, id);
557     }
558
559     if (detail == 2) {
560         if ((type == treetrunktype) && (position.y < (terrain.getHeight(position.x, position.z) + 1))) {
561             terrain.MakeDecal(shadowdecalpermanent, position, 2, .4, 0);
562         }
563
564         if ((type == bushtype) && (position.y < (terrain.getHeight(position.x, position.z) + 1))) {
565             terrain.MakeDecal(shadowdecalpermanent, position, 1, .4, 0);
566         }
567     }
568 }
569
570 void Object::AddObjectsToTerrain()
571 {
572     for (unsigned i = 0; i < objects.size(); i++) {
573         objects[i]->addToTerrain(i);
574     }
575 }
576
577 void Object::SphereCheckPossible(XYZ* p1, float radius)
578 {
579     int whichpatchx = p1->x / (terrain.size / subdivision * terrain.scale);
580     int whichpatchz = p1->z / (terrain.size / subdivision * terrain.scale);
581
582     if (whichpatchx >= 0 && whichpatchz >= 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
583         if (terrain.patchobjects[whichpatchx][whichpatchz].size() < 500) {
584             for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) {
585                 unsigned int i = terrain.patchobjects[whichpatchx][whichpatchz][j];
586                 objects[i]->possible = false;
587                 if (objects[i]->model.SphereCheckPossible(p1, radius, &objects[i]->position, &objects[i]->yaw) != -1) {
588                     objects[i]->possible = true;
589                 }
590             }
591         }
592     }
593 }
594
595 void Object::Draw()
596 {
597     for (unsigned i = 0; i < objects.size(); i++) {
598         objects[i]->draw();
599     }
600
601     glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
602     for (unsigned i = 0; i < objects.size(); i++) {
603         objects[i]->drawSecondPass();
604     }
605     if (environment == desertenvironment) {
606         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
607     }
608     glEnable(GL_ALPHA_TEST);
609     SetUpLight(&light, 0);
610 }
611
612 void Object::DeleteObject(int which)
613 {
614     objects.erase(objects.begin() + which);
615 }
616
617 void Object::MakeObject(int atype, XYZ where, float ayaw, float apitch, float ascale)
618 {
619     if ((atype != treeleavestype && atype != bushtype) || foliage == 1) {
620         unsigned nextid = objects.size();
621         objects.emplace_back(new Object(object_type(atype), where, ayaw, apitch, ascale));
622         objects.back()->addToTerrain(nextid);
623     }
624 }
625
626 void Object::DoStuff()
627 {
628     for (unsigned i = 0; i < objects.size(); i++) {
629         objects[i]->handleFire();
630     }
631 }
632
633 void Object::DoShadows()
634 {
635     XYZ lightloc;
636     lightloc = light.location;
637     if (!skyboxtexture)
638         lightloc = 0;
639     lightloc.y += 10;
640     Normalise(&lightloc);
641
642     for (unsigned i = 0; i < objects.size(); i++) {
643         objects[i]->doShadows(lightloc);
644     }
645 }
646
647 int Object::checkcollide(XYZ startpoint, XYZ endpoint)
648 {
649     float minx, minz, maxx, maxz, miny, maxy;
650
651     minx = min(startpoint.x, endpoint.x) - 1;
652     miny = min(startpoint.y, endpoint.y) - 1;
653     minz = min(startpoint.z, endpoint.z) - 1;
654     maxx = max(startpoint.x, endpoint.x) + 1;
655     maxy = max(startpoint.y, endpoint.y) + 1;
656     maxz = max(startpoint.z, endpoint.z) + 1;
657
658     for (unsigned int i = 0; i < objects.size(); i++) {
659         if (checkcollide(startpoint, endpoint, i, minx, miny, minz, maxx, maxy, maxz) != -1) {
660             return (int)i;
661         }
662     }
663
664     return -1;
665 }
666
667 int Object::checkcollide(XYZ startpoint, XYZ endpoint, int what)
668 {
669     float minx, minz, maxx, maxz, miny, maxy;
670
671     minx = min(startpoint.x, endpoint.x) - 1;
672     miny = min(startpoint.y, endpoint.y) - 1;
673     minz = min(startpoint.z, endpoint.z) - 1;
674     maxx = max(startpoint.x, endpoint.x) + 1;
675     maxy = max(startpoint.y, endpoint.y) + 1;
676     maxz = max(startpoint.z, endpoint.z) + 1;
677
678     return checkcollide(startpoint, endpoint, what, minx, miny, minz, maxx, maxy, maxz);
679 }
680
681 int Object::checkcollide(XYZ startpoint, XYZ endpoint, int what, float minx, float miny, float minz, float maxx, float maxy, float maxz)
682 {
683     XYZ colpoint, colviewer, coltarget;
684
685     if (what == 1000) {
686         if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1) {
687             return what;
688         }
689     } else {
690         if (objects[what]->position.x > minx - objects[what]->model.boundingsphereradius &&
691             objects[what]->position.x < maxx + objects[what]->model.boundingsphereradius &&
692             objects[what]->position.y > miny - objects[what]->model.boundingsphereradius &&
693             objects[what]->position.y < maxy + objects[what]->model.boundingsphereradius &&
694             objects[what]->position.z > minz - objects[what]->model.boundingsphereradius &&
695             objects[what]->position.z < maxz + objects[what]->model.boundingsphereradius) {
696             if (objects[what]->type != treeleavestype &&
697                 objects[what]->type != bushtype &&
698                 objects[what]->type != firetype) {
699                 colviewer = startpoint;
700                 coltarget = endpoint;
701                 if (objects[what]->model.LineCheck(&colviewer, &coltarget, &colpoint, &objects[what]->position, &objects[what]->yaw) != -1) {
702                     return what;
703                 }
704             }
705         }
706     }
707
708     return -1;
709 }
710
711 //~ Object::~Objects()
712 //~ {
713 //~ boxtextureptr.destroy();
714 //~ treetextureptr.destroy();
715 //~ bushtextureptr.destroy();
716 //~ rocktextureptr.destroy();
717 //~ }