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