00001 00005 /* Copyright © 2009, 2010 James Legg. 00006 This program is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 */ 00011 #include "Track.h" 00012 00013 #include "stream_loader.h" 00014 #include "FormErrors.h" 00015 00016 #include <Debug.h> 00017 00018 /* gcc >= 4.3 Depreciates hash_set & hash_map, causing warnings to be emited when 00019 * including boost graph library headers. 00020 * We don't need the hash-based storage selectors anyway, so turn them off. 00021 */ 00022 #define BOOST_NO_HASH 00023 #include <boost/graph/adjacency_list.hpp> 00024 #include <boost/graph/dijkstra_shortest_paths.hpp> 00025 #undef BOOST_NO_HASH 00026 00027 #include <cmath> 00028 00029 const unsigned int track_newest_version = 3; 00030 00031 namespace Track 00032 { 00033 00034 Track::Track(std::istream & source, const Theme & theme, bool editor_in) 00035 : file_version(int_from_stream(source)) 00036 , theme(theme) 00037 , path(source, theme, this, editor_in) 00038 , editor(editor_in) 00039 { 00040 if (file_version == 0) throw CorruptedError(); 00041 if (file_version == 3) m_lighting = Lighting(source); 00042 if (file_version > track_newest_version) throw NewVersionError(); 00043 // version 1 contained some extra information, but we can ignore it 00044 // since it would have been at the end of the file. 00045 scan_theme(); 00046 } 00047 00048 Track::Track(const Theme & theme, bool editor_in) 00049 : file_version(0) 00050 , theme(theme) 00051 , path(theme, this, editor_in) 00052 , editor(editor_in) 00053 { 00054 scan_theme(); 00055 } 00056 00057 00058 Track::~Track() 00059 { 00060 00061 } 00062 00063 const Path & Track::get_path() const 00064 { 00065 return path; 00066 } 00067 00068 Path & Track::get_path() 00069 { 00070 return path; 00071 } 00072 00073 std::ostream & operator<<(std::ostream & destination, const Track & track) 00074 { 00075 destination << track_newest_version << ' '; 00076 destination << track.path << ' ' << track.get_lighting() << ' '; 00077 // the space at the end of the file prevents an error reading the last 00078 // number. end of file is not end of number, apparently. 00079 return destination; 00080 } 00081 00082 const Theme & Track::get_theme() const 00083 { 00084 return theme; 00085 } 00086 00090 template <class A> 00091 class CollisionDeallocator 00092 { 00093 public: 00097 CollisionDeallocator(A *mesh) 00098 : m_mesh(mesh) 00099 {}; 00104 template <class T> 00105 void operator ()(T shape) 00106 { 00107 delete shape; 00108 delete m_mesh; 00109 } 00110 private: 00112 A *m_mesh; 00113 00114 }; 00115 00116 boost::shared_ptr<btCollisionShape> Track::get_collision_shape() const 00117 { 00118 btTriangleMesh * shape = new btTriangleMesh; 00119 path.add_collision_faces(*shape); 00120 00121 boost::shared_ptr<btCollisionShape> result(new btBvhTriangleMeshShape(shape, true), 00122 CollisionDeallocator<btTriangleMesh>(shape)); 00123 return result; 00124 } 00125 00126 boost::shared_ptr<btCollisionShape> Track::get_floor_shape() const 00127 { 00128 btTriangleMesh * shape = new btTriangleMesh; 00129 path.add_floor_faces(*shape); 00130 boost::shared_ptr<btCollisionShape> result(new btBvhTriangleMeshShape(shape, true), 00131 CollisionDeallocator<btTriangleMesh>(shape)); 00132 return result; 00133 } 00134 00135 const MeshFaces & Track::get_ai_mesh() const 00136 { 00137 return m_ai_mesh; 00138 } 00139 00140 void Track::update_ai_mesh() 00141 { 00142 // reset incase this was used before a change. 00143 DEBUG_MESSAGE("Finding AI navigation mesh."); 00144 m_ai_mesh = MeshFaces(); 00145 path.add_ai_faces(m_ai_mesh); 00146 // Merge vertices near each other, so the mesh can be navigated cleanly 00147 // by the AI cars. 00148 m_ai_mesh.merge_doubles(); 00149 00150 // Find the connectivity graph. 00151 scan_ai_graph(); 00152 m_ai_graph = m_ai_mesh.get_connectivity(); 00153 } 00154 00155 struct EdgeProperties 00156 { 00157 float distance; 00158 }; 00159 00160 void Track::scan_ai_graph() 00161 { 00162 /* We want to set the u texture coordinate to a number indicating how far 00163 * into a lap a position is. This number is called lap_position. 00164 * 0.0 means the start of the lap. lap_position should vary linearly with 00165 * distance from the start. 00166 * We create a graph related to the navigation graph to run dijkstra's 00167 * algorithm on. We use the minimum distances assigned to each node as the 00168 * lap_position. 00169 * The new graph is a variation on the graph of connected vertices on the 00170 * ai mesh. The vertices along the starting plane are split so that faces 00171 * on either side of the starting plane are not connected across the 00172 * starting plane. 00173 * A source node is created which has 0 distance to all vertices along the 00174 * starting plane connecting with faces infront of it. Similarly, a sink 00175 * node is created with 0 distance to the nodes in the starting plane 00176 * connecting with faces behind it. This way position along the starting 00177 * plane doesn't matter, and it doesn't mess with ordering cars near the 00178 * starting plane. 00179 * 00180 * A possible improvement to this algorithm would take note of splits 00181 * where the paths are very different lengths. Currently this sort of 00182 * thing could happen: 00183 * | 6 | 00184 * |5 ^ 7| < goes backwards here. The long path should be scaled down so 00185 * | | \8\ that lap_position varies between 00186 * |4| \8\ the values at the start and end of the 00187 * | | \7\ split section. 00188 * |3| \6\ 00189 * | | /5/ 00190 * |2| /4/ 00191 * | | /3/ 00192 * |1| /2/ 00193 * | _ 1| 00194 * |0 0| 00195 * 00196 * You could say this would be bad level design, but if the short path 00197 * requires going much slower than the long path, or the long path 00198 * provides an additional benifit (e.g. pit lane), the track could be 00199 * well balanced and still suffer from this. 00200 * 00201 * This could be done with a graph layout algorithm, though care must be 00202 * taken to insure the starting vertices stay at 0 and the ending vertices 00203 * have the largest value. 00204 */ 00205 DEBUG_MESSAGE("scan_ai_graph: Getting vertex graph"); 00206 MeshFaces::VertexGraph graph = m_ai_mesh.get_vertex_graph(); 00207 // Add source and sink. 00208 MeshFaces::VertexGraph::vertex_descriptor source_descriptor; 00209 { 00210 source_descriptor = boost::add_vertex(graph); 00211 DEBUG_MESSAGE("Source node is " << source_descriptor); 00212 } 00213 MeshFaces::VertexGraph::vertex_descriptor sink_descriptor; 00214 { 00215 sink_descriptor = boost::add_vertex(graph); 00216 DEBUG_MESSAGE("Sink node is " << sink_descriptor); 00217 } 00218 00219 // split start and end vertices, which lie along the start/finish plane. 00220 // First, what is the plane? 00221 btVector3 start_point = path.find_start_position(); 00222 btVector3 start_plane_normal; 00223 btScalar start_plane_distance; 00224 path.find_start_plane(start_plane_normal, start_plane_distance); 00225 // Find the vertices we want. 00226 std::vector<MeshFaces::VertexGraph::vertex_descriptor> start_vertices; 00227 std::pair<MeshFaces::VertexGraph::vertex_iterator, 00228 MeshFaces::VertexGraph::vertex_iterator> its; 00229 for (its = boost::vertices(graph); its.first != its.second; its.first++) 00230 { 00231 MeshFaces::VertexGraph::vertex_descriptor vertex = *(its.first); 00232 btVector3 position = graph[vertex]; 00233 // find distance from plane. 00234 btScalar to_plane = start_plane_normal.dot(position) + start_plane_distance; 00235 if (std::abs(to_plane) < 0.001) 00236 { 00237 // close enough to start plane to be in it. 00238 // Is it near enough to the start, or is it somewhere in the distance? 00244 if (start_point.distance2(position) < 289.0) 00245 { 00246 // It will do. 00247 start_vertices.push_back(vertex); 00248 DEBUG_MESSAGE("Vertex " << vertex << " is on the start plane, distance^2=" << to_plane << "."); 00249 } 00250 } 00251 } 00252 // add copies of the vertices found to the graph. 00253 std::vector<MeshFaces::VertexGraph::vertex_descriptor> finish_vertices; 00254 for (std::vector<MeshFaces::VertexGraph::vertex_descriptor>::iterator it = start_vertices.begin(); 00255 it != start_vertices.end(); 00256 it++) 00257 { 00258 finish_vertices.push_back(boost::add_vertex(graph[*it], (graph))); 00259 DEBUG_MESSAGE("Vertex " << finish_vertices.back() << " is the end of track equivalent to vertex " << *it); 00260 } 00261 // now work out which edges should be moved from start to finish. 00262 std::vector<MeshFaces::VertexGraph::vertex_descriptor>::iterator start_it, finish_it; 00263 for (start_it = start_vertices.begin(), finish_it = finish_vertices.begin(); 00264 start_it != start_vertices.end(); 00265 start_it++, finish_it++) 00266 { 00267 typedef MeshFaces::VertexGraph::out_edge_iterator OutEdgeIterator; 00268 std::pair<OutEdgeIterator, OutEdgeIterator> its; 00269 for (its = boost::out_edges(*start_it, graph); 00270 its.first != its.second; 00271 its.first++) 00272 { 00273 // which side of the plane does this edge take it? 00274 MeshFaces::VertexGraph::vertex_descriptor target = boost::target(*(its.first), graph); 00275 // which side of the plane? 00276 btScalar plane_distance = start_plane_normal.dot(graph[target]) + start_plane_distance; 00277 if (plane_distance < -0.001) 00278 { 00279 // behind the plane. Move the edge to the other side. 00280 DEBUG_MESSAGE("Moving edge " << *(its.first) << " from start vertex " << *start_it << " to finish vertex " << *finish_it << "."); 00281 boost::add_edge(*finish_it, target, graph[*(its.first)], graph); 00282 boost::remove_edge(*(its.first), graph); 00283 // edge iterators invalidated. Start again. 00287 its = boost::out_edges(*start_it, graph); 00288 } 00289 } 00290 } 00291 // Link up start to source vertex. 00292 for (std::vector<MeshFaces::VertexGraph::vertex_descriptor>::iterator it = start_vertices.begin(); 00293 it != start_vertices.end(); 00294 it++) 00295 { 00296 // Use a large length to prevent the shortest path of nearby nodes 00297 // going backwards. 00298 boost::add_edge(source_descriptor, *it, MeshFaces::FaceEdgePointers(0, 0, 0, 100.0), graph); 00299 } 00300 // Link up finish to sink vertex. 00301 for (std::vector<MeshFaces::VertexGraph::vertex_descriptor>::iterator it = finish_vertices.begin(); 00302 it != finish_vertices.end(); 00303 it++) 00304 { 00305 boost::add_edge(sink_descriptor, *it, MeshFaces::FaceEdgePointers(0, 0, 0, 0.0), graph); 00306 } 00307 00308 /* Now we have the graph we want. Lets find the minimal distance to each 00309 * vertex from the sink node. 00310 */ 00311 std::vector<MeshFaces::VertexGraph::vertex_descriptor> predecessors(boost::num_vertices(graph)); 00312 std::vector<btScalar> distances(boost::num_vertices(graph)); 00313 boost::dijkstra_shortest_paths(graph, sink_descriptor, 00314 boost::weight_map(get(&MeshFaces::FaceEdgePointers::length, graph)). 00315 predecessor_map(&predecessors[0]).distance_map(&distances[0]) 00316 ); 00317 // The length of the lap is the shortest distance from end to finish, 00318 // without the 100m length of the connections to the source node. 00319 m_lap_length = distances[source_descriptor] - 100.0; 00320 /* Now we want to put the distances back into the mesh. 00321 * We use the u coordinate for face vertices. 00322 * The same vertex will appear on multiple faces. Normally each vertex has 00323 * only one value, but the vertices in start_vertices get 0 for the faces 00324 * infront of the start plane and distances[sink_descriptor] behind it. 00325 */ 00326 // For each edge, set the right distances on each end. 00327 std::pair<MeshFaces::VertexGraph::edge_iterator, 00328 MeshFaces::VertexGraph::edge_iterator> edge_its; 00329 btScalar end_cut_off = m_lap_length / 2.0; 00330 for (edge_its = boost::edges(graph); edge_its.first != edge_its.second; edge_its.first++) 00331 { 00332 MeshFaces::VertexGraph::edge_descriptor edge = *(edge_its.first); 00333 MeshFaces::FaceEdgePointers & fep = graph[edge]; 00334 // Each face vertex is set twice due to the edges both sides of it. 00335 if (fep.source) 00336 { 00337 if (( boost::source(edge, graph) > sink_descriptor 00338 || boost::target(edge, graph) > sink_descriptor) 00339 && distances[fep.source->vertex_index] > end_cut_off) 00340 { 00341 // Must be a copy of a starting vertex placed on the end. 00342 // This edge connects to the end of the course. 00343 fep.source->texture_coord_u = m_lap_length; 00344 } 00345 else 00346 { 00347 fep.source->texture_coord_u = m_lap_length - distances[fep.source->vertex_index]; 00348 } 00349 } 00350 if (fep.target) 00351 { 00352 if (( boost::target(edge, graph) > sink_descriptor 00353 || boost::source(edge, graph) > sink_descriptor) 00354 && distances[fep.target->vertex_index] > end_cut_off) 00355 { 00356 // Must be a copy of a starting vertex placed on the end. 00357 // This edge connects to the end of the course. 00358 fep.target->texture_coord_u = m_lap_length; 00359 } 00360 else 00361 { 00362 fep.target->texture_coord_u = m_lap_length - distances[fep.target->vertex_index]; 00363 } 00364 } 00365 } 00366 DEBUG_MESSAGE("Track is " << m_lap_length << "m long."); 00367 } 00368 00369 const MeshFaces::Graph & Track::get_ai_graph() const 00370 { 00371 return m_ai_graph; 00372 } 00373 00374 btScalar Track::get_lap_length() const 00375 { 00376 return m_lap_length; 00377 } 00378 00379 void Track::set_filename(std::string filename_in) 00380 { 00381 filename = filename_in; 00382 } 00383 00384 std::string Track::get_filename() const 00385 { 00386 return filename; 00387 } 00388 00389 void Track::scan_theme() 00390 { 00391 if (!editor) return; 00392 std::size_t range = theme.get_number_of_segments(); 00393 for (std::size_t index = 0; index < range; index++) 00394 { 00400 const_cast<DrawableMesh&>(theme.get_segment(index).get_graphics_mesh().get_faces()).set_render_mode(DrawableMesh::RM_WIREFRAME); 00401 } 00402 } 00403 00404 const Lighting & Track::get_lighting() const 00405 { 00406 return m_lighting; 00407 } 00408 00409 void Track::set_lighting(const Lighting & lighting) 00410 { 00411 m_lighting = lighting; 00412 } 00413 00414 };
Generated at Mon Sep 6 00:41:12 2010 by Doxygen version 1.4.7 for Racer version svn335.