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