src/objects.cpp

Go to the documentation of this file.
00001 #include "objects.h"
00002 
00003 OBJECTS::OBJECTS()
00004 {
00005         error_log.open((settings.GetSettingsDir() + "/logs/objects.log").c_str());
00006 //      UpdateSettings();
00007         
00008         sphere_reflection_loaded = false;
00009         
00010         object_list = NULL;
00011         model_list = NULL;
00012 }
00013 
00014 OBJECTS::~OBJECTS()
00015 {
00016         error_log.close();
00017         
00018         //deallocate objects and models
00019         DeleteAll();
00020 }
00021 
00022 void OBJECTS::DeleteAll()
00023 {
00024         for (map <string, TEXTURE_HANDLE>::iterator i = texture_db.begin(); i != texture_db.end(); i++)
00025         {
00026                 //glDeleteTextures(1, &(i->second));
00027                 i->second.Unload();
00028         }
00029         
00030         if (sphere_reflection_loaded)
00031         {
00032                 //glDeleteTextures(1, &sphere_reflection);
00033                 sphere_reflection.Unload();
00034         }
00035         
00036         texture_db.clear();
00037         
00038         while (object_list != NULL)
00039                 delobject();
00040         
00041         while (model_list != NULL)
00042                 delmodel();
00043 }
00044 
00045 void OBJECTS::delobject()
00046 {
00047         if (object_list == NULL)
00048                 return;
00049         
00050         //save old tree
00051         OBJECTNODE * old = object_list;
00052         object_list = object_list->next;
00053         delete old;
00054 }
00055 
00056 void OBJECTS::delmodel()
00057 {
00058         if (model_list == NULL)
00059                 return;
00060         
00061         //save old tree
00062         OBJECTMODEL * old = model_list;
00063         model_list = model_list->next;
00064         delete old;
00065 }
00066 
00067 void OBJECTS::UpdateSettings()
00068 {
00069         settings.Get( "display.view_distance", lod_far );
00070         settings.Get( "display.width", display_x );
00071         settings.Get( "display.height", display_y );
00072 }
00073 
00074 void OBJECTS::DrawObject(OBJECTNODE * object)
00075 {
00076         
00077         //int i;
00078         //float yoffset = 0.0f;
00079         float dx, dy, dz, rc;
00080         
00081         //range cull
00082         VERTEX objcenter = object->model->jmodel.GetBBOX().GetCenter();
00083         float temp = objcenter.x;
00084         objcenter.x = objcenter.y;
00085         objcenter.y = objcenter.z;
00086         objcenter.z = temp;
00087         VERTEX objpos = object->pos + objcenter;
00088         dx=objpos.x+cam.position.x; dy=objpos.y+cam.position.y; dz=objpos.z+cam.position.z;
00089     rc=dx*dx+dy*dy+dz*dz;
00090         
00091         bool zerotransform = false;
00092         if (object->pos.x == 0 && object->pos.y == 0 && object->pos.z == 0)
00093                 zerotransform = true;
00094         
00095         if (!object->model->skybox)
00096         {
00097                 lod_far += object->model->jmodel.GetRadius();
00098                 if (rc > lod_far*lod_far) return;
00099         
00100                 //use different techniques based on range
00101                 //frustum cull!
00102                 float bound, rd;
00103                 //if (rc > lod_far)
00104                 {
00105                         //bound = spread*2.0f;
00106                         bound = object->model->jmodel.GetRadius();
00107                         int i;
00108                         for (i=0;i<6;i++) 
00109                         {
00110                                 rd=cam.frustum[i][0]*objpos.x+
00111                                    cam.frustum[i][1]*objpos.y+
00112                                    cam.frustum[i][2]*objpos.z+
00113                                    cam.frustum[i][3];
00114                                 if (rd<=-bound)
00115                                 {
00116                                         return;
00117                                 }
00118                         }
00119                 }
00120                 
00121                 //model_list->jmodel.ReflectionTextureID(sphere_reflection, 1);
00122         }
00123         //else
00124                 //model_list->jmodel.NoTexture(1);
00125         
00126         //glPushAttrib(GL_ALL_ATTRIB_BITS);
00127         
00128         if (object->model->skybox)
00129         {
00130                 glPushMatrix();
00131                 glMatrixMode( GL_PROJECTION );
00132                 glPushMatrix();
00133                 glLoadIdentity( );
00134                 gluPerspective( 45.0f, (float)display_x / (float)display_y, 0.1f, 10000.0 );
00135                 glMatrixMode( GL_MODELVIEW );
00136                 GLdouble temp_matrix[16];
00137                 cam.PutTransformInto(temp_matrix);
00138                 glLoadMatrixd(temp_matrix);
00139                 glDepthMask(0);
00140                 glRotated(-90, 1,0,0);
00141                 glDisable(GL_FOG);
00142         }
00143         else if (!zerotransform)
00144         {
00145                 glPushMatrix();
00146                 GLfloat transform_matrix[16];
00147                 object->dir.GetMat(transform_matrix);
00148                 
00149                 glTranslatef(object->pos.x, object->pos.y, object->pos.z);
00150                 glMultMatrixf(transform_matrix);
00151         }
00152         
00153         if (object->model != NULL)
00154         {
00155                 if (object->model->fullbright)
00156                         glDisable(GL_LIGHTING);
00157                 else
00158                         glEnable(GL_LIGHTING);
00159                 
00160                 if (object->model->blend)
00161                 {
00162                         glDisable(GL_ALPHA_TEST);
00163                         glDepthMask(0);
00164                 }
00165                 
00166                 //glAlphaFunc(GL_GEQUAL, 1.0f);
00167                 
00168                 object->model->jmodel.DrawStatic();
00169                 
00170                 if (object->model->blend)
00171                 {
00172                         glEnable(GL_ALPHA_TEST);
00173                         glDepthMask(1);
00174                 }
00175                 //glEnable(GL_FOG);
00176         }
00177         else
00178                 cout << "NULL model" << endl;
00179         
00180         if (object->model->skybox)
00181         {
00182                 glDepthMask(1);
00183                 glMatrixMode( GL_PROJECTION );
00184                 glPopMatrix();
00185                 glMatrixMode( GL_MODELVIEW );
00186                 glPopMatrix();
00187                 glEnable(GL_FOG);
00188         }
00189         else if (!zerotransform)
00190                 glPopMatrix();
00191 }
00192 
00193 void OBJECTS::Draw(bool cull)
00194 {
00195         //setup gl flags
00196         //glEnable(GL_BLEND);
00197         //glDisable( GL_TEXTURE_2D );
00198         /*glEnable(GL_TEXTURE_2D);
00199         glBindTexture(GL_TEXTURE_2D,treetex[0]);
00200         glDisable( GL_LIGHTING);
00201         glAlphaFunc(GL_GREATER, 0.9f);
00202         glEnable(GL_ALPHA_TEST);
00203         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );*/
00204         //glBlendFunc( GL_ONE, GL_ONE );
00205         
00206         glPushAttrib(GL_ALL_ATTRIB_BITS);       
00207         glPushMatrix();
00208 
00209         //setup global opengl flags
00210         
00211         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
00212                 
00213         glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
00214         glEnable (GL_COLOR_MATERIAL);
00215         glColor3f (1.0, 1.0, 1.0);
00216         GLfloat specular [] = { 0.0, 0.0, 0.0, 0.0 };
00217         glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
00218         GLfloat shininess [] = { 0.0 };
00219         glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, shininess);
00220         
00221         
00222         glEnable(GL_BLEND);
00223         //glDisable(GL_DEPTH_TEST);
00224         glAlphaFunc(GL_GREATER, 0.9f);
00225         glEnable(GL_ALPHA_TEST);
00226         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00227         glCullFace(GL_BACK);
00228         if (cull)
00229                 glEnable(GL_CULL_FACE);
00230         else
00231                 glDisable(GL_CULL_FACE);
00232         //glDepthMask(0);
00233         glColor4f(1,1,1,1);
00234         
00235         glRotated(-90, 1,0,0);
00236         
00237         //skybox pass
00238         OBJECTNODE * curpos = object_list;
00239         while (curpos != NULL)
00240         {
00241                 if (curpos->model->skybox)
00242                         DrawObject(curpos);
00243                 curpos = curpos -> next;
00244         }
00245         
00246         //normal pass
00247         curpos = object_list;
00248         while (curpos != NULL)
00249         {
00250                 if (!curpos->model->skybox && !curpos->model->blend)
00251                         DrawObject(curpos);
00252                 curpos = curpos -> next;
00253         }
00254         
00255         //blend pass
00256         curpos = object_list;
00257         while (curpos != NULL)
00258         {
00259                 if (curpos->model->blend)
00260                         DrawObject(curpos);
00261                 curpos = curpos -> next;
00262         }
00263         
00264         glPopMatrix();
00265         glPopAttrib();
00266 
00267         
00268         //reset gl flags
00269         /*glDisable(GL_BLEND);
00270         glColor4f(1.0f,1.0f,1.0f,1.0f);
00271         glEnable( GL_TEXTURE_2D );
00272         glEnable( GL_LIGHTING);
00273         glDisable(GL_ALPHA_TEST);*/
00274 }
00275 
00276 OBJECTNODE * OBJECTS::Add(VERTEX pos, float rotation, string modelname, string texname, bool mip, bool fullbright, bool skybox, bool drv, bool col, bool blend, JOEPACK * pack, float f1, float f2, float bl, float bm, float rr, float rd)
00277 {
00278         OBJECTNODE * oldfirst = object_list;
00279         object_list = new OBJECTNODE;
00280         object_list->next = oldfirst;
00281         
00282         object_list->pos.x = pos.x;
00283         //object_list->pos.y = pos.y;
00284         object_list->pos.z = pos.z;
00285         
00286         object_list->driveable = drv;
00287         object_list->cancollide = col;
00288         
00289         object_list->friction1 = f1;
00290         object_list->friction2 = f2;
00291         
00292         object_list->bumplength = bl;
00293         object_list->bumpmag = bm;
00294         
00295         object_list->rolling_resistance_factor = rr;
00296         object_list->rolling_drag = rd;
00297         
00298         //if (pos.y == -1337)
00299         {
00300 //              object_list->pos.y = terrain.GetHeight(object_list->pos.x, object_list->pos.z) + pos.y;
00301         }
00302         
00303         //apply rotation (no longer used)
00304         //object_list->dir.Rotate(rotation, 0, 1, 0);
00305         
00306         OBJECTMODEL * mplist = model_list;
00307         
00308         bool found = false;
00309         int count = 0;
00310         while (mplist != NULL && !found)
00311         {
00312                 //cout << mplist->name << "," << modelname << endl;
00313                 if (mplist->name == modelname)
00314                 {
00315                         found = true;
00316                         object_list->model = mplist;
00317                 }
00318                 mplist = mplist -> next;
00319                 count++;
00320         }
00321         
00322         if (!found)
00323         {
00324                 object_list->model = AddModel(modelname, texname, mip, fullbright, skybox, blend, pack);
00325                 object_list->texture = texname;
00326         }
00327         
00328         return object_list;
00329 }
00330 
00331 OBJECTNODE::OBJECTNODE()
00332 {
00333         dir.LoadMultIdent();
00334 }
00335 
00336 OBJECTMODEL * OBJECTS::AddModel(string modelname, string texname, bool mip, bool fullbright, bool skybox, bool blend, JOEPACK * pack)
00337 {
00338         OBJECTMODEL * oldfirst = model_list;
00339         model_list = new OBJECTMODEL;
00340         model_list->next = oldfirst;
00341         
00342         model_list->name = modelname;
00343         model_list->jmodel.Load(path + "/" + modelname, false, pack);
00344         
00345         model_list->fullbright = fullbright;
00346         model_list->blend = blend;
00347         model_list->skybox = skybox;
00348         
00349         //search for the texture in our texture db
00350         map <string, TEXTURE_HANDLE>::iterator tslot = texture_db.find(texname);
00351         if (tslot == texture_db.end())
00352         {
00353                 TEXTURE_HANDLE newtexid;
00354                 newtexid.Load(path + "/" + texname, mip);
00355                 texture_db[texname] = newtexid;
00356                 //cout << texname << ": " << newtexid << endl;
00357                 model_list->jmodel.TextureID(&newtexid, 0);
00358         }
00359         else
00360         {
00361                 model_list->jmodel.TextureID(&(tslot->second), 0);
00362         }
00363         
00364         //model_list->jmodel.ReflectionTextureID(sphere_reflection, 1);
00365         
00366         //cout << "Addmodel: " << modelname << endl;
00367         return model_list;
00368 }
00369 
00370 extern void LoadingScreen(string loadtext);
00371 
00372 void OBJECTS::LoadObjectsFromFolder(string objectpath)
00373 {
00374         DeleteAll();
00375         collision.Clear();
00376         
00377         //sphere_reflection = textures.Load("weather/trackreflect.png", true);
00378         //sphere_reflection_loaded = true;
00379         
00380         JOEPACK pack;
00381         JOEPACK * packptr = NULL;
00382         
00383         if (pack.LoadPack(objectpath+"/objects.jpk"))
00384         {
00385                 packptr = &pack;
00386                 //cout << "Using object pack" << endl;
00387         }
00388         
00389         OBJECTNODE * added = NULL;
00390         
00391         ifstream o;
00392         
00393         o.open((objectpath+"/list.txt").c_str());
00394         
00395         path = objectpath;
00396         
00397         if (o)
00398         {
00399                 string m;
00400                 string t;
00401                 string extra;
00402                 bool mip;
00403                 bool fb, sb;
00404                 bool blend;
00405                 VERTEX p;
00406                 float r;
00407                 bool c, d;
00408                 float f1, f2;
00409                 float bl, bm;
00410                 float rr, rd;
00411                 
00412                 int count = 0;
00413                 
00414                 const int expectedparams = 14;
00415                 int numparams = expectedparams;
00416                 numparams = utility.iGetParam(o);
00417                 
00418                 if (numparams != expectedparams)
00419                 {
00420                         cerr << "Parameters per entry number incorrect, error in object list: " << objectpath+"/list.txt" << endl;
00421                         cerr << "Expected " << expectedparams << " parameters, got " << numparams << endl;
00422                         cerr << "Check the format.txt file in the VDrift-trackeditor/listedit/format.txt folder." << endl;
00423                         return;
00424                 }
00425                 
00426                 while (!o.eof())
00427                 {
00428                         if (count % 100 == 0)
00429                         {
00430                                 //char buffer[256];
00431                                 //sprintf(buffer, "Loading...\nLoading scenery objects\n%i", count);
00432                                 //LoadingScreen(buffer);
00433                                 string msg = "Loading...\nLoading scenery objects";
00434                                 for (int sn = 0; sn < count/100; sn++)
00435                                         msg = msg + ".";
00436                                 LoadingScreen(msg);
00437                         }
00438                         
00439                         m = utility.sGetParam(o);
00440                         t = utility.sGetParam(o);
00441                         mip = utility.bGetParam(o);
00442                         fb = utility.bGetParam(o);
00443                         sb = utility.bGetParam(o);
00444                         //p.x = utility.fGetParam(o);
00445                         blend = utility.bGetParam(o);
00446                         //p.y = utility.fGetParam(o);
00447                         //p.z = utility.fGetParam(o);
00448                         bl = utility.fGetParam(o);
00449                         bm = utility.fGetParam(o);
00450                         //r = utility.fGetParam(o);
00451                         p.zero();
00452                         r = 0;
00453                         d = utility.bGetParam(o);
00454                         c = utility.bGetParam(o);
00455                         f1 = utility.fGetParam(o);
00456                         f2 = utility.fGetParam(o);
00457                         rr = utility.fGetParam(o);
00458                         rd = utility.fGetParam(o);
00459                         
00460                         for (int i = 0; i < numparams - expectedparams; i++)
00461                         {
00462                                 extra = utility.sGetParam(o);
00463                         }
00464                         
00465                         added = NULL;
00466                         
00467                         if (m != "" && m != utility.GetEOFString())
00468                         {
00469                                 added = Add(p, r, m, t, mip, fb, sb, d, c, blend, packptr, f1, f2, bl, bm, rr, rd);
00470                                 count++;
00471                                 //cout << "added object " << m << "...";
00472                                 unsigned int i;
00473                                 for (i = 0; i < added->model->jmodel.GetFaces(); i++)
00474                                 {
00475                                         /*short vi[3];
00476                                         VERTEX tri[3];
00477                                         VERTEX norms[3];
00478                                         for (unsigned int v = 0; v < 3; v++)
00479                                         {
00480                                                 vi[v] = added->model->jmodel.GetFace(i)[v];
00481                                                 tri[v].Set(added->model->jmodel.GetVert(vi[v]));
00482                                                 norms[v].Set(added->model->jmodel.GetNorm(added->model->jmodel.GetNormIdx(i)[v]));
00483                                         }
00484                                         VERTEX norm;
00485                                         for (unsigned int v = 0; v < 3; v++)
00486                                                 norm = norm + norms[v];
00487                                         norm = norm.normalize();
00488                                         VERTEX tnorm = (tri[2] - tri[0]).cross(tri[1] - tri[0]);
00489                                         if (norm.dot(tnorm) > 0)
00490                                         {
00491                                                 short tvi = vi[1];
00492                                                 vi[1] = vi[2];
00493                                                 vi[2] = tvi;
00494                                         }
00495                                         collision.AddColNode(added, vi);*/
00496                                         collision.AddColNode(added, added->model->jmodel.GetFace(i));
00497                                 }
00498                                 //cout << "done" << endl;
00499                         }
00500                 }
00501                 
00502                 o.close();
00503 
00504                 collision.GenerateCollisionTree();
00505                 
00506                 GroupObjectListByTexture();
00507         }
00508         else
00509         {
00510                 error_log << "Couldn't open Object List: " << objectpath << "/list.txt" << endl;
00511         }
00512         
00513         if (packptr != NULL)
00514                 packptr->ClosePack();
00515 }
00516 
00517 bool OBJECTS::Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal, float seglen, OBJECTNODE * &colnode)
00518 {
00519         return collision.CollideAABB(origin, direction, outtri, closest, normal, seglen, colnode);
00520 }
00521 
00522 bool OBJECTS::CollideD(VERTEXD origin, VERTEXD direction, VERTEXD &outtri, bool closest, VERTEXD & normal, double seglen)
00523 {
00524         return collision.CollideAABB_double(origin, direction, outtri, closest, normal, seglen);
00525 }
00526 
00527 bool OBJECTS::CollideDriveable(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal)
00528 {
00529         return collision.CollideDriveable(origin, direction, outtri, closest, normal);
00530 }
00531 
00532 bool OBJECTS::CollideModel(VERTEX * modelverts, int numfaces, AABB bbox, VERTEX & outtri, bool closest, VERTEX & normal, float & depth)
00533 {
00534         return collision.CollideModelAABB(modelverts, numfaces, bbox, outtri, closest, normal, depth);
00535 }
00536 
00537 OBJCOLNODE::OBJCOLNODE()
00538 {
00539         object = NULL;
00540         int i;
00541         for (i = 0; i < 3; i++)
00542                 vertexIndex[i] = 0;
00543 }
00544 
00545 bool OBJCOLNODE::operator==(const OBJCOLNODE & other)
00546 {
00547         return (object == other.object && vertexIndex[0] == other.vertexIndex[0] &&
00548                         vertexIndex[1] == other.vertexIndex[1] &&
00549                         vertexIndex[2] == other.vertexIndex[2]);
00550 }
00551 
00552 bool OBJCOLNODE::EqualGeom(const OBJCOLNODE & other)
00553 {
00554         return (vertexIndex[0] == other.vertexIndex[0] &&
00555                         vertexIndex[1] == other.vertexIndex[1] &&
00556                         vertexIndex[2] == other.vertexIndex[2]);
00557 }
00558 
00559 bool OBJCOLNODE::operator<(const OBJCOLNODE & other)
00560 {
00561         bool output = false;
00562         
00563         int cmpresult = strcmp(object->model->name.c_str(),other.object->model->name.c_str());
00564         
00565         if (cmpresult < 0)
00566                 output = true;
00567         else if (cmpresult == 0)
00568         {       
00569                 if (vertexIndex[0] < other.vertexIndex[0])
00570                         output = true;
00571                 else if (vertexIndex[0] == other.vertexIndex[0])
00572                 {
00573                         if (vertexIndex[1] < other.vertexIndex[1])
00574                                 output = true;
00575                         else if (vertexIndex[1] == other.vertexIndex[1])
00576                         {
00577                                 if (vertexIndex[2] < other.vertexIndex[2])
00578                                         output = true;
00579                         }
00580                 }
00581         }
00582         
00583         return output;
00584 }
00585 
00586 OBJCOLNODE::OBJCOLNODE(const OBJCOLNODE & other)
00587 {
00588         object = other.object;
00589         vertexIndex[0] = other.vertexIndex[0];
00590         vertexIndex[1] = other.vertexIndex[1];
00591         vertexIndex[2] = other.vertexIndex[2];
00592 }
00593 
00594 OBJCOLNODE& OBJCOLNODE::operator= (const OBJCOLNODE &other)
00595 {
00596         object = other.object;
00597         vertexIndex[0] = other.vertexIndex[0];
00598         vertexIndex[1] = other.vertexIndex[1];
00599         vertexIndex[2] = other.vertexIndex[2];
00600         
00601         return *this;
00602 }
00603 
00604 void OBJCOLNODE::SortVerts()
00605 {
00606         short omin, omax, omid;
00607         omin = omax = omid = 0;
00608         bool havemin = false;
00609         bool havemax = false;
00610         for (int i = 0; i < 3; i++)
00611         {
00612                 if (!havemin)
00613                 {
00614                         omin = vertexIndex[i];
00615                         havemin = true;
00616                 }
00617 
00618                 if (!havemax)
00619                 {
00620                         omax = vertexIndex[i];
00621                         havemax = true;
00622                 }
00623                 
00624                 if (vertexIndex[i] < omin)
00625                         omin = vertexIndex[i];
00626                 if (vertexIndex[i] > omax)
00627                         omax = vertexIndex[i];
00628         }
00629         
00630         for (int i = 0; i < 3; i++)
00631         {
00632                 if (vertexIndex[i] > omin && vertexIndex[i] < omax)
00633                         omid = vertexIndex[i];
00634         }
00635         
00636         vertexIndex[0] = omin;
00637         vertexIndex[1] = omid;
00638         vertexIndex[2] = omax;
00639 }
00640 
00641 void OBJECTCOLLISION::AddColNode(OBJECTNODE * newobject, short * newvi)
00642 {
00643         OBJCOLNODE temp;
00644         temp.object = newobject;
00645         int i;
00646         for (i = 0; i < 3; i++)
00647                 temp.vertexIndex[i] = newvi[i];
00648         
00649         //temp.SortVerts();
00650         
00651         if (COLLIDE_AND_DRIVE_TOGETHER)
00652         {
00653                 if (newobject->cancollide || newobject->driveable)
00654                 {
00655                         colnodes.push_back(temp);
00656                         drvnodes.push_back(temp);
00657                 }
00658         }
00659         else
00660         {
00661                 if (newobject->cancollide)
00662                 {
00663                         colnodes.push_back(temp);
00664                 }
00665                 
00666                 if (newobject->driveable)
00667                 {
00668                         drvnodes.push_back(temp);
00669                 }
00670         }
00671 }
00672 
00673 bool OBJECTCOLLISION::CollideDriveable(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal)
00674 {
00675         list <OBJCOLNODE>::iterator i1 = drvnodes.begin();
00676         
00677         bool hadcollision = false;
00678         VERTEX curtri[3], tvert;
00679         int retval;
00680         float t,u,v;
00681         
00682         origin.z = -origin.z;
00683         
00684         int count = 0;
00685         
00686         while (i1 != drvnodes.end())
00687         {
00688                 //collide = curnode->model->jmodel.Collide(origin - curnode->pos, direction, tvert, closest);
00689                 count++;
00690                 
00691                 curtri[0].Set(i1->object->model->jmodel.GetVert(i1->vertexIndex[0]));
00692                 curtri[1].Set(i1->object->model->jmodel.GetVert(i1->vertexIndex[1]));
00693                 curtri[2].Set(i1->object->model->jmodel.GetVert(i1->vertexIndex[2]));
00694                 
00695                 //curtri = curtri + ((VERTEX) (i1->object)->pos);
00696                 int n;
00697                 for (n = 0; n < 3; n++)
00698                         curtri[n] = curtri[n] + i1->object->pos;
00699                         
00700                 retval = INTERSECT_FUNCTION(origin.v3(), direction.v3(),
00701                         curtri[0].v3(), curtri[1].v3(), curtri[2].v3(), 
00702                         &t, &u, &v);
00703                 
00704                 if (retval)
00705                 {
00706                         if (t < 0)
00707                         {
00708                                 //no collision
00709                                 retval = 0;
00710                         }
00711                         else
00712                         {
00713                                 //collision
00714                                 tvert = curtri[0].ScaleR(1-u-v) + curtri[1].ScaleR(u) + curtri[2].ScaleR(v);
00715                                 
00716                                 //calculate normal
00717                                 curtri[0].z = -curtri[0].z;
00718                                 curtri[1].z = -curtri[1].z;
00719                                 curtri[2].z = -curtri[2].z;
00720                                 normal = (curtri[2] - curtri[0]).cross(curtri[1] - curtri[0]);
00721                                 normal = normal.normalize();
00722                                 
00723                                 if (normal.dot(direction) > 0)
00724                                         normal.Scale(-1);
00725                                 
00726                                 if (!closest)
00727                                 {
00728                                         outtri = tvert;
00729                                         
00730                                         //implicit caching
00731                                         OBJCOLNODE temp;
00732                                         temp = *i1;
00733                                         
00734                                         //cout << colnodes.size() << endl;
00735                                         //cout << count << endl;
00736                                         
00737                                         drvnodes.erase(i1);
00738                                         drvnodes.insert(drvnodes.begin(), temp);
00739                                         
00740                                         return true;
00741                                 }
00742                         }
00743                 }
00744 
00745                 //collide = curnode->model->jmodel.Collide(curnode->pos - origin, direction, tvert, closest);
00746                 //tvert = ;
00747                 if (retval && closest)
00748                 {
00749                         if ((hadcollision && (origin - tvert).len() < (origin - outtri).len()) || !hadcollision)
00750                         {
00751                                 //outtri = tvert + curnode->pos;
00752                                 outtri = tvert;
00753                         }
00754                         
00755                         hadcollision = true;
00756                 }
00757                 
00758                 i1++;
00759         }
00760         
00761         if (closest && hadcollision)
00762         {
00763                 return true;
00764         }
00765         
00766         //cout << "nocol: " << count << endl;
00767         
00768         return false;
00769 }
00770 
00771 OBJCOLBRANCH::OBJCOLBRANCH()
00772 {
00773         left = NULL;
00774         right = NULL;
00775         leaves.clear();
00776 }
00777 
00778 void OBJCOLBRANCH::DeleteChildren()
00779 {
00780         leaves.clear();
00781         
00782         if (left != NULL)
00783         {
00784                 left->DeleteChildren();
00785                 delete left;
00786                 left = NULL;
00787         }
00788         
00789         if (right != NULL)
00790         {
00791                 right->DeleteChildren();
00792                 delete right;
00793                 right = NULL;
00794         }
00795 }
00796 
00797 void OBJECTCOLLISION::GenerateCollisionTree()
00798 {
00799         bool verbose = false;
00800         
00801         if (verbose)
00802                 cout << "Generating collision tree..." << endl;
00803         
00804         coltree.DeleteChildren();
00805         
00806         if (verbose)
00807                 cout << "deleted old tree" << endl;
00808         
00809         if (verbose)
00810                 cout << "Sorting collision nodes...";
00811         //colnodes.sort();
00812         if (verbose)
00813                 cout << "done" << endl;
00814         
00815         coltree.left = NULL;
00816         coltree.right = NULL;
00817         
00818         coltree.leaves.clear();
00819         
00820         //while (curnode != NULL)
00821         int count = 0;
00822         
00823         for (list <OBJCOLNODE>::iterator i = colnodes.begin(); i != colnodes.end(); i++)
00824         {
00825                 bool dup = false;
00826                 
00827                 /*if (i != colnodes.begin())
00828                 {
00829                         list <OBJCOLNODE>::iterator prev = i;
00830                         prev--;
00831                         if (*prev == *i)
00832                                 dup = true;
00833                 }*/
00834                 
00835                 if (!dup)
00836                 {
00837                         coltree.leaves.push_back(&(*i));
00838                         count++;
00839                 }
00840         }
00841         
00842         if (verbose)
00843                 cout << "copied leaves: " << count << "/" << colnodes.size() << endl;
00844         
00845         GenerateBranches(&coltree);
00846         
00847         if (verbose)
00848                 cout << "done" << endl;
00849 }
00850 
00851 void OBJECTCOLLISION::GenerateBranches(OBJCOLBRANCH * branch)
00852 {
00853         bool verbose = false;
00854         
00855         list <OBJCOLNODE *>::iterator i1 = branch->leaves.begin();
00856         
00857         //build total aabb and find average vert center
00858         VERTEX avgcenter;
00859         float maxv[3];
00860         float minv[3];
00861         bool havevals[6];
00862         int n = 0;
00863         for (n = 0; n < 6; n++)
00864                 havevals[n] = false;
00865         //maxvals.Set(-1e10,-1e10,-1e10);
00866         //minvals.Set(1e10,1e10,1e10);
00867         
00868         int numleaves = 0;
00869         
00870         for (i1 = branch->leaves.begin(); i1 != branch->leaves.end(); i1++)
00871                 numleaves++;
00872         
00873         i1 = branch->leaves.begin();
00874         while (i1 != branch->leaves.end())
00875         {
00876                 VERTEX p[3];
00877                 p[0].Set((*i1)->object->model->jmodel.GetVert((*i1)->vertexIndex[0]));
00878                 p[1].Set((*i1)->object->model->jmodel.GetVert((*i1)->vertexIndex[1]));
00879                 p[2].Set((*i1)->object->model->jmodel.GetVert((*i1)->vertexIndex[2]));
00880                 
00881                 int i, c;
00882                 for (c = 0; c < 3; c++)
00883                 {
00884                         float * v = p[c].v3();
00885                         for (i = 0; i < 3; i++)
00886                         {
00887                                 if (v[i] > maxv[i] || !havevals[i])
00888                                 {
00889                                         maxv[i] = v[i];
00890                                         havevals[i] = true;
00891                                 }
00892                                 if (v[i] < minv[i] || !havevals[i+3])
00893                                 {
00894                                         minv[i] = v[i];
00895                                         havevals[i+3] = true;
00896                                 }
00897                         }
00898                 }
00899                 
00900                 VERTEX pcenter = p[0] + p[1] + p[2];
00901                 pcenter.Scale(0.333333);
00902                 avgcenter = avgcenter + pcenter.ScaleR(1.0/numleaves);
00903                 
00904                 i1++;
00905         }
00906         
00907         VERTEX minvals, maxvals;
00908         minvals.Set(minv);
00909         maxvals.Set(maxv);
00910         branch->bbox.SetFromCorners(minvals, maxvals);
00911         if (verbose)
00912         {
00913                 cout << "Bounding box:" << endl;
00914                 branch->bbox.GetPos().DebugPrint();
00915                 branch->bbox.GetSize().DebugPrint();
00916                 branch->bbox.GetCenter().DebugPrint();
00917         }
00918         
00919         //find axis of maximum change
00920         VERTEX axismask;
00921         axismask.Set(1,0,0);
00922         if (maxvals.x - minvals.x > maxvals.y - minvals.y && maxvals.x - minvals.x > maxvals.z - minvals.z)
00923         {
00924                 axismask.Set(1,0,0);
00925         }
00926         else if (maxvals.y - minvals.y > maxvals.x - minvals.x && maxvals.y - minvals.y > maxvals.z - minvals.z)
00927         {
00928                 axismask.Set(0,1,0);
00929         }
00930         else if (maxvals.z - minvals.z > maxvals.y - minvals.y && maxvals.z - minvals.z > maxvals.x - minvals.x)
00931         {
00932                 axismask.Set(0,0,1);
00933         }
00934         
00935         int ll = 0;
00936         int lr = 0;
00937         
00938         //only propagate leaves if we're not a leaf
00939         if (numleaves > TRIANGLES_PER_BBOX)
00940         {
00941                 //create children
00942                 branch->left = new OBJCOLBRANCH;
00943                 branch->right = new OBJCOLBRANCH;
00944                 
00945                 int distributor = 0; //hack to stop infinite recursion
00946                 
00947                 //throw leaves into children
00948                 for (i1 = branch->leaves.begin(); i1 != branch->leaves.end(); i1++)
00949                 {
00950                         VERTEX p[3];
00951                         p[0].Set((*i1)->object->model->jmodel.GetVert((*i1)->vertexIndex[0]));
00952                         p[1].Set((*i1)->object->model->jmodel.GetVert((*i1)->vertexIndex[1]));
00953                         p[2].Set((*i1)->object->model->jmodel.GetVert((*i1)->vertexIndex[2]));
00954                         
00955                         VERTEX pcenter = p[0] + p[1] + p[2];
00956                         pcenter.Scale(0.333333);
00957                         
00958                         if (pcenter.dot(axismask) - avgcenter.dot(axismask) > 0.0)
00959                         {
00960                                 branch->right->leaves.push_back(*i1);
00961                                 distributor = 1;
00962                         }
00963                         else if (pcenter.dot(axismask) - avgcenter.dot(axismask) < 0.0)
00964                         {
00965                                 branch->left->leaves.push_back(*i1);
00966                                 distributor = 0;
00967                         }
00968                         else
00969                         {
00970                                 //leaf is right at average, distribute evenly
00971                                 if (distributor % 2 == 0)
00972                                         branch->right->leaves.push_back(*i1);
00973                                 else
00974                                         branch->left->leaves.push_back(*i1);
00975                                 
00976                                 distributor++;
00977                         }
00978                 }
00979                 
00980                 //clear out leaves
00981                 branch->leaves.clear();
00982                 
00983                 //count leaves of children
00984                 for (i1 = branch->left->leaves.begin(); i1 != branch->left->leaves.end(); i1++)
00985                         ll++;
00986                 for (i1 = branch->right->leaves.begin(); i1 != branch->right->leaves.end(); i1++)
00987                         lr++;
00988                 
00989                 if (verbose) cout << "Parent Leaves: " << numleaves << " L: " << ll << " R: " << lr << endl;
00990                 
00991                 if (ll == 0 || lr == 0)
00992                 {
00993                         if (lr != 0)
00994                         {
00995                                 for (i1 = branch->right->leaves.begin(); i1 != branch->right->leaves.end(); i1++)
00996                                         branch->leaves.push_back(*i1);
00997                                 branch->right->leaves.clear();
00998                         }
00999                         
01000                         if (ll != 0)
01001                         {
01002                                 for (i1 = branch->left->leaves.begin(); i1 != branch->left->leaves.end(); i1++)
01003                                         branch->leaves.push_back(*i1);
01004                                 branch->left->leaves.clear();
01005                         }
01006                         
01007                         delete branch->left;
01008                         branch->left = NULL;
01009                         
01010                         delete branch->right;
01011                         branch->right = NULL;
01012                 }
01013                 else
01014                 {
01015                         GenerateBranches(branch->left);
01016                         GenerateBranches(branch->right);
01017                 }
01018                 
01019                 /*if (ll == 0)
01020                 {
01021                         delete branch->left;
01022                         branch->left = NULL;
01023                 }
01024                 else if GenerateBranches(branch->left);
01025                 
01026                 if (lr == 0)
01027                 {
01028                         delete branch->right;
01029                         branch->right = NULL;
01030                 }
01031                 else GenerateBranches(branch->right);*/
01032         }
01033         else
01034         {
01035                 branch->right = NULL;
01036                 branch->left = NULL;
01037                 
01038                 if (verbose) cout << "(Leaf)" << endl;
01039         }
01040 }
01041 
01042 void OBJECTCOLLISION::Clear()
01043 {
01044         coltree.DeleteChildren();
01045         colnodes.clear();
01046         drvnodes.clear();
01047 }
01048 
01049 OBJECTCOLLISION::~OBJECTCOLLISION()
01050 {
01051         Clear();
01052 }
01053 
01054 bool OBJECTCOLLISION::CollideModelAABB(VERTEX * modelverts, int numfaces, AABB modelbbox, VERTEX & outtri, bool closest, VERTEX & normal, float & depth)
01055 {
01056         normal.zero();
01057         
01058         int testcount = 0;
01059         
01060         bool col = CollideBranchModel(modelverts, numfaces, modelbbox, outtri, closest, &coltree, normal, depth, testcount);
01061         
01062         //cout << "Leaf tests: " << testcount << endl;
01063         
01064         normal = normal.normalize();
01065         
01066         return col;
01067 }
01068 
01069 bool OBJECTCOLLISION::CollideAABB(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal, float seglen, OBJECTNODE * &colnode)
01070 {
01071         bool col = false;
01072         
01073         /*if (lastcolpatch != NULL)
01074         {
01075                 col = lastcolpatch->BEZIER_COLLIDE_FUNCTION(origin, direction, outtri);
01076                 if (col && !closest)
01077                 {
01078                         colpatch = lastcolpatch;
01079 
01080                         return true;
01081                 }
01082         }*/
01083         
01084         origin.z = -origin.z;
01085         int count = 0;
01086         col = CollideBranch(origin, direction, outtri, closest, &coltree, normal, seglen, count, colnode);
01087         //cout << count << endl;
01088         /*if (col)
01089                 lastcolpatch = colpatch;*/
01090         
01091         return col;
01092 }
01093 
01094 bool OBJECTCOLLISION::CollideAABB_double(VERTEXD origin, VERTEXD direction, VERTEXD &outtri, bool closest, VERTEXD & normal, double seglen)
01095 {
01096         bool col = false;
01097         
01098         origin.z = -origin.z;
01099         direction.z = -direction.z;
01100         
01101         col = CollideBranch_double(origin, direction, outtri, closest, &coltree, normal, seglen);
01102         
01103         return col;
01104 }
01105 
01106 bool OBJECTCOLLISION::CollideBranch(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, OBJCOLBRANCH * branch, VERTEX & normal, float seglen, int & testcount, OBJECTNODE * &colnode)
01107 {
01108         if (branch == NULL)
01109                 return false;
01110         
01111         bool verbose = false;
01112         bool collideverbose = false;
01113         
01114         if (verbose)
01115         {
01116                 if (branch->left != NULL && branch->right != NULL)
01117                 {
01118                         cout << "Parent" << endl;
01119                 }
01120                 else
01121                         cout << "Leaf" << endl;
01122         }
01123         
01124         //what to do if we're a leaf
01125         if (branch->left == NULL && branch->right == NULL)
01126         {
01127                 testcount++;
01128                 
01129                 bool hadcollision = false;
01130                 VERTEX curtri[3], tvert;
01131                 VERTEX tnorm;
01132                 float t,u,v;
01133                 
01134                 int retval = 0;
01135                 
01136                 list <OBJCOLNODE *>::iterator i1 = branch->leaves.begin();
01137                 
01138                 <