src/track.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *            track.cc
00003  *
00004  *  Sat Nov 19 11:08:52 2005
00005  *  Copyright  2005  Joe Venzon
00006  *  joe@venzon.net
00007  ****************************************************************************/
00008 
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024  
00025 #include "track.h"
00026 
00027 ROADSTRIP::ROADSTRIP()
00028 {
00029         patchnodes = NULL;
00030 }
00031 
00032 void ROADSTRIP::ClearPatches()
00033 {
00034         coltree.DeleteChildren();
00035         coltree.leaves.clear();
00036         
00037         while (patchnodes != NULL)
00038         {
00039                 BEZIERNODE * oldfirst = patchnodes;
00040                 patchnodes = patchnodes->next;
00041                 delete oldfirst;
00042         }
00043 }
00044 
00045 BEZIER * ROADSTRIP::Add(BEZIER newpatch)
00046 {
00047         BEZIERNODE * lastnode = NULL;
00048         BEZIERNODE * curnode = patchnodes;
00049         
00050         while (curnode != NULL)
00051         {
00052                 lastnode = curnode;
00053                 curnode = curnode->next;
00054         }
00055 
00056         //only continue if there is a last node and it really is the last node
00057         if (lastnode != NULL && lastnode->next == NULL)
00058         {
00059                 lastnode->next = new BEZIERNODE;
00060                 lastnode->next->patch.CopyFrom(newpatch);
00061                 
00062                 //optional....
00063                 lastnode->patch.Attach(lastnode->next->patch);
00064                 return &(lastnode->next->patch);
00065         }
00066         
00067         if (patchnodes == NULL)
00068         {
00069                 patchnodes = new BEZIERNODE;
00070                 patchnodes->patch.CopyFrom(newpatch);
00071                 return &(patchnodes->patch);
00072         }
00073         
00074         return NULL;
00075 }
00076 
00077 BEZIER * ROADSTRIP::AddNew()
00078 {
00079         BEZIER newpatch;
00080         return Add(newpatch);
00081 }
00082 
00083 bool ROADSTRIP::ReadFrom(ifstream &openfile)
00084 {
00085         //optional....
00086         ClearPatches();
00087         
00088         lastcolpatch = NULL;
00089         
00090         if (!openfile)
00091                 return false;
00092         
00093         BEZIER * newpatch = NULL;
00094         BEZIER temppatch;
00095         
00096         int num;
00097         
00098         //the number of patches for this road
00099         openfile >> num;
00100         
00101         int i;
00102         
00103         for (i = 0; i < num; i++)
00104         {
00105                 //create a new patch and make it read from the file
00106                 if (!temppatch.ReadFrom(openfile))
00107                         return false;
00108                 newpatch = Add(temppatch);
00109         }
00110         
00111         if (num > 2 && newpatch != NULL)
00112         {
00113                 //close a looped track
00114                 if (newpatch->points[0][0].equals(patchnodes->patch.points[3][0]) && newpatch->points[0][3].equals(patchnodes->patch.points[3][3]))
00115                 {
00116                         newpatch->Attach(patchnodes->patch);
00117                 }
00118         }
00119         
00120         GenerateCollisionTree();
00121         
00122         return true;
00123 }
00124 
00125 bool ROADSTRIP::WriteTo(ofstream &openfile)
00126 {
00127         BEZIERNODE * curnode = patchnodes;
00128         
00129         openfile << NumPatches() << endl << endl;
00130                 
00131         while (curnode != NULL)
00132         {
00133                 curnode->patch.WriteTo(openfile);
00134                 openfile << endl;
00135                 
00136                 curnode = curnode->next;
00137         }
00138         
00139         return true;
00140 }
00141 
00142 int ROADSTRIP::NumPatches()
00143 {
00144         BEZIERNODE * curnode = patchnodes;
00145         
00146         int num = 0;
00147         
00148         while (curnode != NULL)
00149         {
00150                 num++;
00151                 
00152                 curnode = curnode->next;
00153         }
00154         
00155         return num;
00156 }
00157 
00158 bool ROADSTRIP::DeleteLastPatch()
00159 {
00160         BEZIERNODE * lastnode = NULL;
00161         BEZIERNODE * prevlastnode = NULL;
00162         BEZIERNODE * curnode = patchnodes;
00163         
00164         while (curnode != NULL)
00165         {
00166                 prevlastnode = lastnode;
00167                 lastnode = curnode;
00168                 curnode = curnode->next;
00169         }
00170 
00171         //only continue if there is a last node and it really is the last node
00172         if (lastnode != NULL && lastnode->next == NULL)
00173         {
00174                 if (prevlastnode != NULL)
00175                 {
00176                         delete prevlastnode->next;
00177                         prevlastnode->next = NULL;
00178                         return true;
00179                 }
00180                 else
00181                 {
00182                         delete patchnodes;
00183                         patchnodes = NULL;
00184                         return true;
00185                 }
00186         }
00187         
00188         return false;
00189 }
00190 
00191 BEZIER * ROADSTRIP::GetLastPatch()
00192 {
00193         BEZIERNODE * lastnode = NULL;
00194         BEZIERNODE * prevlastnode = NULL;
00195         BEZIERNODE * curnode = patchnodes;
00196         
00197         while (curnode != NULL)
00198         {
00199                 prevlastnode = lastnode;
00200                 lastnode = curnode;
00201                 curnode = curnode->next;
00202         }
00203 
00204         //only continue if there is a last node and it really is the last node
00205         if (lastnode != NULL && lastnode->next == NULL)
00206         {
00207                 if (prevlastnode != NULL)
00208                 {
00209                         return &(prevlastnode->next->patch);
00210                 }
00211                 else
00212                 {
00213                         return &(patchnodes->patch);
00214                 }
00215         }
00216         
00217         return NULL;
00218 }
00219 
00220 void ROADSTRIP::Visualize (bool wireframe, bool fill, VERTEX color)
00221 {
00222         //int tot = 0;
00223         
00224         BEZIERNODE * curnode = patchnodes;
00225         
00226         /*while (curnode != NULL)
00227         {
00228                 if (tot < 50) curnode->patch.Visualize(wireframe, fill, color);
00229                 curnode = curnode->next;
00230                 tot ++;
00231         }
00232         
00233         curnode = patchnodes;*/
00234         
00235         int count = 0;
00236         int drawn = 0;
00237         
00238         while (curnode != NULL)
00239         {
00240                 //if (tot - count < 50)
00241                 bool drawme = true;
00242                 //VERTEX pos = curnode->patch.center+cam.position;
00243                 VERTEX & pos = curnode->patch.center;
00244                 for (int i=0;i<6;i++) 
00245                 {
00246                         float rd=cam.frustum[i][0]*pos.x+
00247                            cam.frustum[i][1]*pos.y+
00248                            cam.frustum[i][2]*pos.z+
00249                            cam.frustum[i][3];
00250                         if (rd<=-curnode->patch.radius)
00251                         {
00252                                 drawme = false;
00253                         }
00254                 }
00255                 
00256                 if (drawme)
00257                 {
00258                         curnode->patch.Visualize(wireframe, fill, color);
00259                         drawn++;
00260                 }
00261                 
00262                 curnode = curnode->next;
00263                 count++;
00264         }
00265         
00266         //cout << drawn << "/" << count << endl;
00267 }
00268 
00269 bool ROADSTRIP::Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest)
00270 {
00271         BEZIER * cp;
00272         VERTEX normal;
00273         return Collide(origin, direction, outtri, closest, cp, normal);
00274 }
00275 
00276 bool ROADSTRIP::CollideBruteForce(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, BEZIER * & colpatch)
00277 {
00278         BEZIERNODE * curnode = patchnodes;
00279         BEZIERNODE * lastnode = patchnodes;
00280         
00281         bool collide;
00282         bool hadcollision = false;
00283         VERTEX tvert;
00284         VERTEX tnorm;
00285         
00286         int count = 0;
00287         
00288         while (curnode != NULL)
00289         {
00290                 //cout << "Patch " << count << endl;
00291                 
00292                 //curnode->patch.Visualize(wireframe, fill, color);
00293                 collide = curnode->patch.BEZIER_COLLIDE_FUNCTION(origin, direction, tvert, tnorm);
00294                 if (collide && !closest)
00295                 {
00296                         outtri = tvert;
00297                         colpatch = &(curnode->patch);
00298                         
00299                         //normal = tnorm;
00300                         
00301                         //implicit caching
00302                         lastnode->next = curnode->next;
00303                         if (lastnode != curnode)
00304                                 curnode->next = patchnodes;
00305                         patchnodes = curnode;
00306                         
00307                         return true;
00308                 }
00309                 else if (collide && closest)
00310                 {
00311                         if ((hadcollision && (origin - tvert).len() < (origin - outtri).len()) || !hadcollision)
00312                         {
00313                                 outtri = tvert;
00314                                 colpatch = &(curnode->patch);
00315                         }
00316                         
00317                         hadcollision = true;
00318                 }
00319                 
00320                 count++;
00321                 
00322                 lastnode = curnode;
00323                 curnode = curnode->next;
00324         }
00325         
00326         if (closest && hadcollision)
00327         {
00328                 return true;
00329         }
00330         
00331         return false;
00332 }
00333 
00334 bool ROADSTRIP::Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, BEZIER * & colpatch, VERTEX & normal)
00335 {
00336         bool col = false;
00337         
00338         /*if (lastcolpatch != NULL)
00339         {
00340                 col = lastcolpatch->BEZIER_COLLIDE_FUNCTION(origin, direction, outtri);
00341                 if (col && !closest)
00342                 {
00343                         colpatch = lastcolpatch;
00344 
00345                         return true;
00346                 }
00347         }*/
00348         
00349         col = CollideBranch(origin, direction, outtri, closest, colpatch, &coltree, normal);
00350         
00351         if (col)
00352                 lastcolpatch = colpatch;
00353         
00354         return col;
00355 }
00356 
00357 bool ROADSTRIP::CollideBranch(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, BEZIER * & colpatch, BEZIERCOLBRANCH * branch, VERTEX & normal)
00358 {
00359         if (branch == NULL)
00360                 return false;
00361         
00362         bool verbose = false;
00363         
00364         if (verbose)
00365         {
00366                 if (branch->left != NULL && branch->right != NULL)
00367                 {
00368                         cout << "Parent" << endl;
00369                 }
00370                 else
00371                         cout << "Leaf" << endl;
00372         }
00373         
00374         //what to do if we're a leaf
00375         if (branch->left == NULL && branch->right == NULL)
00376         {
00377                 bool collide;
00378                 bool hadcollision = false;
00379                 VERTEX tvert;
00380                 VERTEX tnorm;
00381                 
00382                 int count = 0;
00383                 
00384                 list <BEZIERNODE *>::iterator i1 = branch->leaves.begin();
00385                 
00386                 for (i1 = branch->leaves.begin(); i1 != branch->leaves.end(); i1++)
00387                 {
00388                         //cout << "Patch " << count << endl;
00389                         
00390                         //curnode->patch.Visualize(wireframe, fill, color);
00391                         collide = (*i1)->patch.BEZIER_COLLIDE_FUNCTION(origin, direction, tvert, tnorm);
00392                         if (collide && !closest)
00393                         {
00394                                 normal = tnorm;
00395                                 outtri = tvert;
00396                                 colpatch = &((*i1)->patch);
00397                                 
00398                                 //implicit caching
00399                                 /*lastnode->next = curnode->next;
00400                                 if (lastnode != curnode)
00401                                         curnode->next = patchnodes;
00402                                 patchnodes = curnode;*/
00403                                 
00404                                 return true;
00405                         }
00406                         else if (collide && closest)
00407                         {
00408                                 if ((hadcollision && (origin - tvert).len() < (origin - outtri).len()) || !hadcollision)
00409                                 {
00410                                         normal = tnorm;
00411                                         outtri = tvert;
00412                                         colpatch = &((*i1)->patch);
00413                                 }
00414                                 
00415                                 hadcollision = true;
00416                         }
00417                         
00418                         count++;
00419                 }
00420                 
00421                 if (closest && hadcollision)
00422                 {
00423                         return true;
00424                 }
00425                 
00426                 return false;
00427         }
00428         
00429         if (verbose)
00430         {
00431                 origin.DebugPrint();
00432                 branch->bbox.DebugPrint();
00433         }
00434         
00435         //check bounding box
00436         if (!branch->bbox.IntersectRay(origin, direction))
00437                 return false;
00438         
00439         if (verbose)
00440                 cout << "BBOX collision" << endl;
00441         
00442         bool rcol = false;
00443         bool lcol = false;
00444         
00445         BEZIER * r_colpatch, * l_colpatch;
00446         VERTEX r_outtri, l_outtri;
00447         
00448         if (right != NULL)
00449                 rcol = CollideBranch(origin, direction, r_outtri, closest, r_colpatch, branch->right, normal);
00450                 
00451         //collision on the right branch
00452         /*if (rcol && !closest)
00453         {
00454                 outtri = r_outtri;
00455                 colpatch = r_colpatch;
00456                 return rcol;
00457         }*/
00458         
00459         if (left != NULL)
00460                 lcol = CollideBranch(origin, direction, l_outtri, closest, l_colpatch, branch->left, normal);
00461         
00462         //collision on the left branch only
00463         if (lcol && !rcol)
00464         {
00465                 outtri = l_outtri;
00466                 colpatch = l_colpatch;
00467                 return lcol;
00468         }
00469         
00470         //collision on the right branch only
00471         if (rcol && !lcol)
00472         {
00473                 outtri = r_outtri;
00474                 colpatch = r_colpatch;
00475                 return rcol;
00476         }
00477         
00478         //collision on both branches
00479         if (lcol && rcol)
00480         {
00481                 if ((origin - r_outtri).len() < (origin - l_outtri).len())
00482                 {
00483                         outtri = r_outtri;
00484                         colpatch = r_colpatch;
00485                         return rcol;
00486                 }
00487                 else
00488                 {
00489                         outtri = l_outtri;
00490                         colpatch = l_colpatch;
00491                         return lcol;
00492                 }
00493         }
00494         
00495         return false;
00496 }
00497 
00498 void ROADSTRIP::GenerateCollisionTree()
00499 {
00500         bool verbose = false;
00501         
00502         BEZIERNODE * curnode = patchnodes;
00503         
00504         if (verbose)
00505                 cout << "Generating collision tree..." << endl;
00506         
00507         coltree.DeleteChildren();
00508         
00509         coltree.left = NULL;
00510         coltree.right = NULL;
00511         
00512         coltree.leaves.clear();
00513         
00514         while (curnode != NULL)
00515         {
00516                 coltree.leaves.push_back(curnode);
00517                 
00518                 curnode = curnode->next;
00519         }
00520         
00521         GenerateBranches(&coltree);
00522         
00523         if (verbose)
00524                 cout << "done" << endl;
00525 }
00526 
00527 void ROADSTRIP::GenerateBranches(BEZIERCOLBRANCH * branch)
00528 {
00529         bool verbose = false;
00530         
00531         list <BEZIERNODE *>::iterator i1 = branch->leaves.begin();
00532         
00533         //build total aabb and find average vert center
00534         VERTEX avgcenter;
00535         float maxv[3];
00536         float minv[3];
00537         bool havevals[6];
00538         int n = 0;
00539         for (n = 0; n < 3; n++)
00540         {
00541                 minv[n] = 0;
00542                 maxv[n] = 0;
00543         }
00544         for (n = 0; n < 6; n++)
00545                 havevals[n] = false;
00546         //maxvals.Set(-1e10,-1e10,-1e10);
00547         //minvals.Set(1e10,1e10,1e10);
00548         
00549         int numleaves = 0;
00550         
00551         for (i1 = branch->leaves.begin(); i1 != branch->leaves.end(); i1++)
00552                 numleaves++;
00553         
00554         i1 = branch->leaves.begin();
00555         while (i1 != branch->leaves.end())
00556         {
00557                 VERTEX p[4];
00558                 p[0] = (*i1)->patch.points[0][0];
00559                 p[1] = (*i1)->patch.points[0][3];
00560                 p[2] = (*i1)->patch.points[3][3];
00561                 p[3] = (*i1)->patch.points[3][0];
00562                 
00563                 int i, c;
00564                 for (c = 0; c < 4; c++)
00565                 {
00566                         float * v = p[c].v3();
00567                         for (i = 0; i < 3; i++)
00568                         {
00569                                 if (v[i] > maxv[i] || !havevals[i])
00570                                 {
00571                                         maxv[i] = v[i];
00572                                         havevals[i] = true;
00573                                 }
00574                                 if (v[i] < minv[i] || !havevals[i+3])
00575                                 {
00576                                         minv[i] = v[i];
00577                                         havevals[i+3] = true;
00578                                 }
00579                         }
00580                 }
00581                 
00582                 VERTEX pcenter = p[0] + p[1] + p[2] + p[3];
00583                 pcenter.Scale(0.25);
00584                 avgcenter = avgcenter + pcenter.ScaleR(1.0/numleaves);
00585                 
00586                 i1++;
00587         }
00588         
00589         VERTEX minvals, maxvals;
00590         minvals.Set(minv);
00591         maxvals.Set(maxv);
00592         branch->bbox.SetFromCorners(minvals, maxvals);
00593         if (verbose)
00594         {
00595                 cout << "Bounding box:" << endl;
00596                 branch->bbox.GetPos().DebugPrint();
00597                 branch->bbox.GetSize().DebugPrint();
00598                 branch->bbox.GetCenter().DebugPrint();
00599         }
00600         
00601         //find axis of maximum change
00602         VERTEX axismask;
00603         axismask.Set(1,0,0);
00604         if (maxvals.x - minvals.x > maxvals.y - minvals.y && maxvals.x - minvals.x > maxvals.z - minvals.z)
00605         {
00606                 axismask.Set(1,0,0);
00607         }
00608         else if (maxvals.y - minvals.y > maxvals.x - minvals.x && maxvals.y - minvals.y > maxvals.z - minvals.z)
00609         {
00610                 axismask.Set(0,1,0);
00611         }
00612         else if (maxvals.z - minvals.z > maxvals.y - minvals.y && maxvals.z - minvals.z > maxvals.x - minvals.x)
00613         {
00614                 axismask.Set(0,0,1);
00615         }
00616         
00617         int ll = 0;
00618         int lr = 0;
00619         
00620         //only propagate leaves if we're not a leaf
00621         if (numleaves > LEAVES_PER_BBOX)
00622         {
00623                 //create children
00624                 branch->left = new BEZIERCOLBRANCH;
00625                 branch->right = new BEZIERCOLBRANCH;
00626                 
00627                 int distributor = 0; //hack to stop infinite recursion
00628                 
00629                 //throw leaves into children
00630                 for (i1 = branch->leaves.begin(); i1 != branch->leaves.end(); i1++)
00631                 {
00632                         VERTEX p[4];
00633                         p[0] = (*i1)->patch.points[0][0];
00634                         p[1] = (*i1)->patch.points[0][3];
00635                         p[2] = (*i1)->patch.points[3][3];
00636                         p[3] = (*i1)->patch.points[3][0];
00637                         
00638                         VERTEX pcenter = p[0] + p[1] + p[2] + p[3];
00639                         pcenter.Scale(0.25);
00640                         
00641                         if (pcenter.dot(axismask) - avgcenter.dot(axismask) > 0.0)
00642                                 branch->right->leaves.push_back(*i1);
00643                         else if (pcenter.dot(axismask) - avgcenter.dot(axismask) < 0.0)
00644                                 branch->left->leaves.push_back(*i1);
00645                         else
00646                         {
00647                                 //leaf is right at average, distribute evenly
00648                                 if (distributor % 2 == 0)
00649                                         branch->right->leaves.push_back(*i1);
00650                                 else
00651                                         branch->left->leaves.push_back(*i1);
00652                                 
00653                                 distributor++;
00654                         }
00655                 }
00656                 
00657                 //clear out leaves
00658                 branch->leaves.clear();
00659                 
00660                 //count leaves of children
00661                 for (i1 = branch->left->leaves.begin(); i1 != branch->left->leaves.end(); i1++)
00662                         ll++;
00663                 for (i1 = branch->right->leaves.begin(); i1 != branch->right->leaves.end(); i1++)
00664                         lr++;
00665                 
00666                 if (verbose) cout << "Parent Leaves: " << numleaves << " L: " << ll << " R: " << lr << endl;
00667                 
00668                 if (ll == 0 || lr == 0)
00669                 {
00670                         if (lr != 0)
00671                         {
00672                                 for (i1 = branch->right->leaves.begin(); i1 != branch->right->leaves.end(); i1++)
00673                                         branch->leaves.push_back(*i1);
00674                                 branch->right->leaves.clear();
00675                         }
00676                         
00677                         if (ll != 0)
00678                         {
00679                                 for (i1 = branch->left->leaves.begin(); i1 != branch->left->leaves.end(); i1++)
00680                                         branch->leaves.push_back(*i1);
00681                                 branch->left->leaves.clear();
00682                         }
00683                         
00684                         delete branch->left;
00685                         branch->left = NULL;
00686                         
00687                         delete branch->right;
00688                         branch->right = NULL;
00689                 }
00690                 else
00691                 {
00692                         GenerateBranches(branch->left);
00693                         GenerateBranches(branch->right);
00694                 }
00695                 
00696                 /*if (ll == 0)
00697                 {
00698                         delete branch->left;
00699                         branch->left = NULL;
00700                 }
00701                 else GenerateBranches(branch->left);
00702                 
00703                 if (lr == 0)
00704                 {
00705                         delete branch->right;
00706                         branch->right = NULL;
00707                 }
00708                 else GenerateBranches(branch->right);*/
00709         }
00710         else
00711         {
00712                 branch->right = NULL;
00713                 branch->left = NULL;
00714                 
00715                 if (verbose) cout << "(Leaf)" << endl;
00716         }
00717 }
00718 
00719 
00720 //----------------- TRACK --------------
00721 
00722 
00723 TRACK::TRACK()
00724 {
00725         roads = NULL;
00726         lastelev = -100;
00727 }
00728 
00729 TRACK::~TRACK()
00730 {
00731         ClearRoads();
00732 }
00733 
00734 void TRACK::ClearRoads()
00735 {
00736         while (roads != NULL)
00737         {
00738                 ROADSTRIPNODE * oldfirst = roads;
00739                 roads = roads->next;
00740                 delete oldfirst;
00741         }
00742 }
00743 
00744 ROADSTRIP * TRACK::AddNewRoad()
00745 {
00746         /*ROADSTRIPNODE * oldfirst = roads;
00747         roads = new ROADSTRIPNODE;
00748         roads->next = oldfirst;
00749         
00750         return &(roads->road);*/
00751         
00752         ROADSTRIPNODE * lastnode = NULL;
00753         ROADSTRIPNODE * curnode = roads;
00754         
00755         while (curnode != NULL)
00756         {
00757                 lastnode = curnode;
00758                 curnode = curnode->next;
00759         }
00760 
00761         //only continue if there is a last node and it really is the last node
00762         if (lastnode != NULL && lastnode->next == NULL)
00763         {
00764                 lastnode->next = new ROADSTRIPNODE;
00765                 //lastnode->next->patch.CopyFrom(newpatch);
00766                 
00767                 //optional....
00768                 //lastnode->patch.Attach(lastnode->next->patch);
00769                 return &(lastnode->next->road);
00770         }
00771         
00772         if (roads == NULL)
00773         {
00774                 roads = new ROADSTRIPNODE;
00775                 return &(roads->road);
00776         }
00777         
00778         return NULL;
00779 }
00780 
00781 void TRACK::VisualizeRoads(bool wireframe, bool fill, ROADSTRIP * selectedroad)
00782 {
00783         ROADSTRIPNODE * curnode = roads;
00784         
00785         VERTEX color;
00786         color.zero();
00787         color.z = 1;
00788         
00789         //utility.seedrandom(1234);
00790         
00791         while (curnode != NULL)
00792         {
00793                 /*//randomize color!
00794                 color.x = utility.randf(0.0,1.0);
00795                 color.y = utility.randf(0.0,1.0);
00796                 color.z = utility.randf(0.0,1.0);
00797                 
00798                 if (color.len() < 0.1)
00799                 {
00800                         color.y = 1.0;
00801                 }
00802                 
00803                 float maxval = 0.0;
00804                 if (color.x > maxval)
00805                         maxval = color.x;
00806                 if (color.y > maxval)
00807                         maxval = color.y;
00808                 if (color.z > maxval)
00809                         maxval = color.z;
00810                 
00811                 color.x = (1.0/maxval)*color.x;
00812                 color.y = (1.0/maxval)*color.y;
00813                 color.z = (1.0/maxval)*color.z;*/
00814                 
00815                 color.zero();
00816                 if (&(curnode->road) == selectedroad)
00817                         color.y = 1;
00818                 else
00819                 {
00820                         color.y = 0.5;
00821                         color.z = 0.5;
00822                 }
00823                 
00824                 curnode->road.Visualize(wireframe, fill, color);
00825                 curnode = curnode->next;
00826         }
00827 }
00828 
00829 void TRACK::Write(string trackname)
00830 {
00831         ofstream trackfile;
00832         trackfile.open((settings.GetDataDir() + "/tracks/" + trackname + "/roads.trk").c_str());
00833         
00834         VERTEX sl = GetStart();
00835         trackfile << sl.x << " " << sl.y << " " << sl.z << endl << endl;
00836         
00837         trackfile << NumRoads() << endl << endl;
00838         
00839         ROADSTRIPNODE * curnode = roads;
00840         
00841         while (curnode != NULL && trackfile)
00842         {
00843                 curnode->road.WriteTo(trackfile);
00844                 curnode = curnode->next;
00845         }
00846 }
00847 
00848 int TRACK::NumRoads()
00849 {
00850         ROADSTRIPNODE * curnode = roads;
00851         
00852         int num = 0;
00853         
00854         while (curnode != NULL)
00855         {
00856                 num++;
00857                 curnode = curnode->next;
00858         }
00859         
00860         return num;
00861 }
00862 
00863 void TRACK::Load(string trackname)
00864 {       
00865         ifstream trackfile;
00866         trackfile.open((settings.GetDataDir() + "/tracks/" + trackname + "/roads.trk").c_str());
00867         
00868         CONFIGFILE trackconfig;
00869         trackconfig.Load((settings.GetDataDir() + "/tracks/" + trackname + "/track.txt").c_str());
00870         float tvert[3];
00871         VERTEX sl;
00872         trackconfig.GetParam("start position", tvert);
00873         string strcullfaces;
00874         trackconfig.GetParam("cull faces", strcullfaces);
00875         sl.Set(tvert);
00876         
00877         if (strcullfaces == "no")
00878                 cullfaces = false;
00879         else
00880                 cullfaces = true;
00881         
00882         int numroads, i;
00883         
00884         /*trackfile >> sl.x;
00885         trackfile >> sl.y;
00886         trackfile >> sl.z;*/
00887         
00888         SetStart(sl);
00889         
00890         VERTEX sov;
00891         trackconfig.GetParam("start orientation-xyz", tvert);
00892         sov.Set(tvert);
00893         QUATERNION so;
00894         so.x = sov.x;
00895         so.y = sov.y;
00896         so.z = sov.z;
00897         trackconfig.GetParam("start orientation-w", so.w);
00898         SetStartOrientation(so);
00899         
00900         if (trackfile)
00901         {
00902                 trackfile >> numroads;
00903         }
00904         else
00905         {
00906                 cout << "No track named " << trackname << ", creating a new one." << endl;
00907                 return;
00908         }
00909         
00910         ClearRoads();
00911         
00912         ROADSTRIP * newroad;
00913         
00914         for (i = 0; i < numroads && trackfile; i++)
00915         {
00916                 newroad = AddNewRoad();
00917                 newroad->ReadFrom(trackfile);
00918         }
00919         
00920         lapsequence.clear();
00921         int lapmarkers;
00922         if (trackconfig.GetParam("lap sequences", lapmarkers))
00923         {
00924                 for (int l = 0; l < lapmarkers; l++)
00925                 {
00926                         float lapraw[3];
00927                         stringstream lapname;
00928                         lapname << "lap sequence " << l;
00929                         trackconfig.GetParam(lapname.str(), lapraw);
00930                         lapsequence.push_back(GetBezier((int) lapraw[0], (int) lapraw[1]));
00931                 }
00932         }
00933         
00934         float f;
00935         trackconfig.GetParam("non-treaded friction coefficient", f);
00936         friction1 = f;
00937         trackconfig.GetParam("treaded friction coefficient", f);
00938         friction2 = f;
00939 }
00940 
00941 void TRACK::Delete(ROADSTRIP * striptodel)
00942 {
00943         bool deleted = false;
00944         
00945         ROADSTRIPNODE * lastnode = NULL;
00946         ROADSTRIPNODE * curnode = roads;
00947         
00948         while (curnode != NULL)
00949         {
00950                 /*
00951                 NOTE THAT THE BACKSPACE BUTTON NEEDS TO CALL THIS (AND CLEAR 
00952                  ACTIVESTRIP TO NULL) TO ENSURE THERE ARE NO EMPTY ROADS!
00953                 */
00954                 
00955                 if (striptodel == &(curnode->road))
00956                 {
00957                         curnode = curnode->next;
00958 
00959                         if (lastnode == NULL)
00960                         {
00961                                 roads = curnode;
00962                         }
00963                         else
00964                         {
00965                                 lastnode->next = curnode;
00966                         }
00967                         
00968                         delete striptodel;
00969                         
00970                         deleted = true;
00971                 }
00972                 else
00973                 {
00974                         lastnode = curnode;
00975                         curnode = curnode->next;
00976                 }
00977         }
00978         
00979         //fail safe stuff
00980         if (!deleted)
00981                 delete striptodel;
00982         
00983         striptodel = NULL;
00984 }
00985 
00986 bool TRACK::CollideRoads(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, ROADSTRIP * &collideroad, BEZIER * & collidepatch, VERTEX & normal)
00987 {
00988         ROADSTRIPNODE * curnode = roads;
00989         
00990         bool collide;
00991         bool hadcollision = false;
00992         VERTEX tvert;
00993         VERTEX tnorm;
00994         
00995         while (curnode != NULL)
00996         {
00997                 //curnode->patch.Visualize(wireframe, fill, color);
00998                 collide = curnode->road.Collide(origin, direction, tvert, closest, collidepatch, tnorm);
00999                 if (collide && !closest)
01000                 {
01001                         outtri = tvert;
01002                         collideroad = &(curnode->road);
01003                         normal = tnorm;
01004                         return true;
01005                 }
01006                 else if (collide && closest)
01007                 {
01008                         if ((hadcollision && (origin - tvert).len() < (origin - outtri).len()) || !hadcollision)
01009                         {
01010                                 normal = tnorm;
01011                                 outtri = tvert;
01012                                 collideroad = &(curnode->road);
01013                         }
01014                         
01015                         hadcollision = true;
01016                 }
01017                 
01018                 curnode = curnode->next;
01019         }
01020         
01021         if (closest && hadcollision)
01022         {
01023                 return true;
01024         }
01025         
01026         outtri = origin;
01027         return false;
01028 }
01029 
01030 bool TRACK::Collide(VERTEX origin, VERTEX direction, float seglen, VERTEX &outtri, bool closest, VERTEX & normal, float & dist)
01031 {
01032         bool verbose = false;
01033         
01034         bool col = false;
01035 
01036         dist = 0;
01037         
01038         VERTEX zero;
01039         
01040         if (direction.equals(zero))
01041                 return false;
01042         
01043         direction = direction.normalize();
01044         
01045         //ROADSTRIP * colstrip;
01046         //BEZIER * colpatch;
01047         
01048         normal.Set(0,1,0);
01049         
01050         /*col = CollideRoads(origin, direction, outtri, closest, colstrip, colpatch, normal);
01051         
01052         if (col)
01053         {
01054                 if (verbose)
01055                         cout << "track collision" << endl;
01056         }
01057         else
01058         {*/
01059                 //check for a model collision
01060                 OBJECTNODE * tnode;
01061                 col = objects.Collide(origin, direction, outtri, closest, normal, seglen, tnode);
01062                 //normal.Set(0,1,0);
01063                 //normal.DebugPrint();
01064                 if (col)
01065                 {
01066                         dist = (outtri - origin).len();
01067                         if (dist > seglen)
01068                                 return false;
01069                         if (verbose)
01070                         {
01071                                 cout << "model collision: " << dist << endl;
01072                                 //lastorigin.DebugPrint();
01073                                 outtri.DebugPrint();
01074                                 cout << endl;
01075                         }
01076                 }
01077         //}
01078         
01079         //if (!col && verbose) cout << "no collision" << endl;
01080 
01081         //normal.DebugPrint();
01082         
01083         if (normal.nan())
01084         {
01085                 cout << "Detected NaN in normal vector" << endl;
01086                 normal.Set(0,1,0);
01087         }
01088         
01089         if (outtri.nan())
01090         {
01091                 cout << "Detected NaN in collision point" << endl;
01092                 outtri = origin;
01093         }
01094         
01095         if (!(dist <= 0 || dist > 0))
01096         {
01097                 cout << "Detected NaN in collision distance" << endl;
01098                 dist = 0;
01099         }
01100         
01101         return col;
01102 }
01103 
01104 bool TRACK::CollideD(VERTEXD origin, VERTEXD direction, double seglen, VERTEXD &outtri, bool closest, VERTEXD & normal, double & dist)
01105 {
01106         bool verbose = false;
01107         
01108         bool col = false;
01109 
01110         dist = 0;
01111         
01112         if (direction.x == 0 && direction.y == 0 && direction.z == 0)
01113                 return false;
01114         
01115         direction = direction.normalize();
01116         
01117         //ROADSTRIP * colstrip;
01118         //BEZIER * colpatch;
01119         
01120         normal.Set(0,1,0);
01121         
01122 
01123         //check for a model collision
01124         col = objects.CollideD(origin, direction, outtri, closest, normal, seglen);
01125         //normal.Set(0,1,0);
01126         //normal.DebugPrint();
01127         if (col)
01128         {
01129                 dist = (outtri - origin).len();
01130                 //if (dist > seglen || (outtri-origin).dot(direction) >= 0)
01131                 /*if (dist > seglen)
01132                 {
01133                         //cout << "weird dist length (track.cpp)" << endl;
01134                         return false;
01135                 }*/
01136                 if (verbose)
01137                 {
01138                         cout << "model collision: " << dist << endl;
01139                         //lastorigin.DebugPrint();
01140                         outtri.DebugPrint();
01141                         cout << endl;
01142                 }
01143         }
01144         
01145         //if (!col && verbose) cout << "no collision" << endl;
01146 
01147         //normal.DebugPrint();
01148         
01149         if (normal.nan())
01150         {
01151                 cout << "Detected NaN in normal vector" << endl;
01152                 normal.Set(0,1,0);
01153         }
01154         
01155         if (outtri.nan())
01156         {
01157                 cout << "Detected NaN in collision point" << endl;
01158                 outtri = origin;
01159         }
01160         
01161         if (!(dist <= 0 || dist > 0))
01162         {
01163                 cout << "Detected NaN in collision distance" << endl;
01164                 dist = 0;
01165         }
01166         
01167         return col;
01168 }
01169 
01170 double TRACK::Elevation(VERTEX origin)
01171 {
01172         VERTEX normal;
01173         return Elevation(origin, normal);
01174 }
01175 
01176 double TRACK::Elevation(VERTEX origin, VERTEX & normal)
01177 {
01178         origin.y += 1000;
01179         return ElevationSeg(origin, normal, 10000.0f);
01180 }
01181 
01182 double TRACK::ElevationSeg(VERTEX origin, VERTEX & normal, float seglen)
01183 {
01184         BEZIER * colpatch;
01185         OBJECTNODE * colnode;
01186         return ElevationSeg(origin, normal, seglen, colpatch, colnode);
01187 }
01188 
01189 double TRACK::ElevationSeg(VERTEX origin, VERTEX & normal, float seglen, BEZIER * &colpatch, OBJECTNODE * &colnode)
01190 {
01191         if (origin.nan())
01192         {
01193                 cout << "Detected NaN in origin vector" << endl;
01194         }
01195         
01196         if (!(seglen < 0 || seglen >= 0))
01197         {
01198                 cout << "Detected NaN in seglen" << endl;
01199         }
01200         
01201         bool verbose = false;
01202         
01203         //origin.y = 1000;
01204         VERTEX dir;
01205         dir.y = -1;
01206         double elev = -100000;
01207         VERTEX colpt;
01208         bool col = false;
01209         bool bezcol = false;
01210         bool modelcol = false;
01211         
01212         ROADSTRIP * colstrip;
01213         //BEZIER * colpatch;
01214         
01215         normal.Set(0,1,0);
01216         
01217         //bool closest = false;
01218         bool closest = true;
01219         
01220         colnode = NULL;
01221         colpatch = NULL;
01222         
01223         col = CollideRoads(origin, dir, colpt, closest, colstrip, colpatch, normal);
01224         
01225         //if (Collide(origin, dir, colpt, true))
01226         //if (0)
01227         if (col)
01228         {
01229                 bezcol = true;
01230                 elev = colpt.y;
01231                 if (verbose)
01232                         cout << "track collision" << endl;
01233                 /*colpatch->points[0][0].DebugPrint();
01234                 colpatch->points[0][3].DebugPrint();
01235                 colpatch->points[3][0].DebugPrint();
01236                 colpatch->points[3][3].DebugPrint();*/
01237         }
01238         else
01239         {
01240                 if (objects.GetCollideAndDriveTogether())
01241                 {
01242                         colpatch = NULL;
01243                         
01244                         closest = true;
01245                         col = objects.Collide(origin, dir, colpt, closest, normal, seglen, colnode);
01246                         if (col)
01247                         {
01248                                 elev = colpt.y;
01249                                 modelcol = true;
01250                         }
01251                         else
01252                                 elev = origin.y - seglen;
01253                 }
01254                 else
01255                 {
01256                         //check for a model collision
01257                         closest = false;
01258                         col = objects.CollideDriveable(origin, dir, colpt, closest, normal);
01259                         //normal.Set(0,1,0);
01260                         //normal.DebugPrint();
01261                         if (col)
01262                         {
01263                                 elev = colpt.y;
01264                                 if (verbose)
01265                                         cout << "model collision" << endl;
01266                         }
01267                 }
01268         }
01269         
01270         if (!col && verbose)
01271                 cout << "no collision" << endl;
01272         
01273         //normal.DebugPrint();
01274         
01275         if (col)
01276         {
01277                 if (normal.nan())
01278                 {
01279                         cout << "Detected NaN in normal vector " << bezcol << " " << modelcol << endl;
01280                         normal.Set(0,1,0);
01281                 }
01282                 
01283                 if (!(elev < 0 || elev >= 0))
01284                 {
01285                         cout << "Detected NaN in elevation " << bezcol << " " << modelcol << endl;
01286                         /*cout << "bezcol: " << bezcol << endl;
01287                         cout << "modelcol: " << modelcol << endl;
01288                         origin.DebugPrint();
01289                         dir.DebugPrint();*/
01290                         return -100000;
01291                 }
01292         }
01293         
01294         return elev;
0129