00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "scenegraph/simulation.hpp"
00035 #include "scenegraph/freeview.hpp"
00036 #include "scenegraph/event.hpp"
00037 #include "scenegraph/utils.hpp"
00038
00039 #include "data/exception.hpp"
00040 #include "data/broker.hpp"
00041 #include "math/time.hpp"
00042 #include "math/vector.hpp"
00043 #include "math/transform.hpp"
00044 #include "physics/vehicle.hpp"
00045
00046 #include "platform/budget.hpp"
00047 #include "platform/lowlevel.hpp"
00048
00049 #include <cmath>
00050
00051 #ifdef WIN32
00052 #include <ctime>
00053 #else
00054 #include <sys/time.h>
00055 #endif
00056
00057 namespace gsgl
00058 {
00059
00060 using namespace data;
00061 using namespace io;
00062 using namespace math;
00063 using namespace platform;
00064
00065 namespace scenegraph
00066 {
00067
00068 static config_variable<int> NUM_FRAME_DELTAS(L"scenegraph/simulation/num_frame_deltas", 10);
00069
00070
00071
00072
00073 simulation::simulation(const config_record & sim_config,
00074 display *console, context *sim_context, node *scenery)
00075 : scenegraph_object(), running(true),
00076 console(console), sim_context(sim_context), scenery(scenery),
00077 start_time(0), time_scale(1), info_font(0), frame_deltas(NUM_FRAME_DELTAS)
00078 {
00079 assert(console);
00080 assert(sim_context);
00081 assert(scenery);
00082
00083 if (sim_config.get_name() != L"simulation")
00084 throw runtime_exception(L"Invalid simulation configuration file %ls", sim_config.get_file().get_full_path().w_string());
00085
00086
00087 double time = 0;
00088
00089 for (list<config_record>::const_iterator param = sim_config.get_children().iter(); param.is_valid(); ++param)
00090 {
00091 if (param->get_name() == L"start_time")
00092 {
00093 time = param->get_text().to_double();
00094 }
00095 else if (param->get_name() == L"viewpoint")
00096 {
00097 broker *b = broker::global_instance();
00098 assert(b);
00099
00100
00101 view = dynamic_cast<freeview *>(b->create_object(L"gsgl::scenegraph::freeview", *param));
00102 view->get_name() = L"Default View";
00103 non_scenery_nodes.append(view);
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 }
00126 else if (param->get_name() == L"vehicle")
00127 {
00128 throw runtime_exception(L"Loading vehicles is not yet implemented.");
00129 }
00130 else
00131 {
00132 throw runtime_exception(L"Unknown simulation parameter %ls in %ls.", param->get_name().w_string(), sim_config.get_file().get_full_path().w_string());
00133 }
00134 }
00135
00136 if (time != 0)
00137 {
00138 julian_day jd(time);
00139 start_time = jd.to_time_t();
00140 }
00141 else
00142 {
00143 throw runtime_exception(L"No time specified for simulation!");
00144 }
00145
00146
00147 if (scenery->connect(view))
00148 view->reset();
00149 else
00150 throw runtime_exception(L"Unable to add viewpoint to simulation.");
00151
00152
00153 color info_color(1, 0, 0);
00154
00155 info_font = new platform::font(L"Sans", 18, info_color);
00156
00157
00158 for (int i = 0; i < NUM_FRAME_DELTAS; ++i)
00159 frame_deltas[i] = 1.0f / 60.0f;
00160 }
00161
00162
00163 simulation::~simulation()
00164 {
00165 for (list<node *>::iterator i = non_scenery_nodes.iter(); i.is_valid(); ++i)
00166 {
00167 (*i)->detach();
00168 delete *i;
00169 }
00170 non_scenery_nodes.clear();
00171
00172 delete info_font;
00173 }
00174
00175
00176 void simulation::init_context()
00177 {
00178 sim_context->sim = this;
00179 sim_context->console = console;
00180 sim_context->scenery = scenery;
00181
00182 sim_context->screen = console;
00183 sim_context->view = view;
00184 sim_context->cam = view->get_camera();
00185
00186
00187 sim_context->time_scale = time_scale;
00188
00189 sim_context->frame = 0;
00190
00191 sim_context->start_t_time = start_time;
00192 sim_context->cur_t_time = sim_context->start_t_time;
00193
00194 sim_context->start_tick = SDL_GetTicks();
00195 sim_context->cur_tick = sim_context->start_tick;
00196 sim_context->delta_tick = 0;
00197
00198 sim_context->start_time = static_cast<double>(sim_context->start_t_time);
00199 sim_context->cur_time = static_cast<double>(sim_context->cur_t_time);
00200 sim_context->delta_time = 0;
00201
00202 math::julian_day jdn(sim_context->start_t_time);
00203 sim_context->julian_start = jdn.get_jdn();
00204 sim_context->julian_cur = sim_context->julian_start;
00205 sim_context->julian_dt = 0;
00206
00207
00208 sim_context->render_flags |= context::RENDER_ANISOTROPIC;
00209 }
00210
00211
00212 void simulation::update_context()
00213 {
00214 sim_context->sim = this;
00215 sim_context->console = console;
00216 sim_context->scenery = scenery;
00217
00218 sim_context->screen = console;
00219 sim_context->view = view;
00220 sim_context->cam = view->get_camera();
00221
00222
00223
00224 sim_context->time_scale = time_scale;
00225
00226 ++sim_context->frame;
00227
00228 unsigned int prev_tick = sim_context->cur_tick;
00229 sim_context->cur_tick = SDL_GetTicks();
00230 sim_context->delta_tick = sim_context->cur_tick - prev_tick;
00231
00232 sim_context->delta_time = time_scale * static_cast<double>(sim_context->delta_tick) / 1000.0;
00233 sim_context->cur_time += sim_context->delta_time;
00234
00235 sim_context->cur_t_time = static_cast<time_t>(sim_context->cur_time);
00236
00237 sim_context->julian_dt = sim_context->delta_time / math::julian_day::JDAY;
00238 sim_context->julian_cur += sim_context->julian_dt;
00239 }
00240
00241
00242 void simulation::cleanup_context()
00243 {
00244 }
00245
00246
00247 void simulation::init()
00248 {
00249 init_context();
00250
00251
00252 if (scenery)
00253 init_node(scenery);
00254 }
00255
00256
00257 void simulation::pre_draw()
00258 {
00259 budget_record br(L"prerender");
00260 node::pre_draw_scene(sim_context, pre_rec);
00261 }
00262
00263
00264 void simulation::draw()
00265 {
00266
00267
00268
00269 sim_context->screen = console;
00270 sim_context->view = view;
00271 sim_context->cam = view->get_camera();
00272
00273
00274 node::draw_scene(sim_context, pre_rec);
00275
00276 {
00277 budget_record br(L"sim info");
00278
00279
00280 gsgl::real_t avg_delta = 0.0f;
00281 for (int i = 0; i < NUM_FRAME_DELTAS; ++i)
00282 avg_delta += frame_deltas[i];
00283 avg_delta /= NUM_FRAME_DELTAS;
00284
00285
00286 int fps = static_cast<int>(::ceil(1.0f / avg_delta));
00287 float height = info_font->calc_height(L"Wtj");
00288
00289 console->draw_text_start();
00290
00291 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERRORS();
00292 glLoadIdentity(); CHECK_GL_ERRORS();
00293 glTranslatef(1.0f, console->get_height() - height, 0.0f); CHECK_GL_ERRORS();
00294 info_font->draw(L"Periapsis Spaceflight Simulation");
00295
00296 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERRORS();
00297 glLoadIdentity(); CHECK_GL_ERRORS();
00298 glTranslatef(1.0f, console->get_height() - 2*height, 0.0f); CHECK_GL_ERRORS();
00299 string rel = string::format(L"View Mode: %ls", view->is_relative() ? L"RELATIVE" : L"ABSOLUTE");
00300 info_font->draw(rel);
00301
00302 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERRORS();
00303 glLoadIdentity(); CHECK_GL_ERRORS();
00304 glTranslatef(1.0f, console->get_height() - 3*height, 0.0f); CHECK_GL_ERRORS();
00305 struct tm *gmt = ::gmtime(&sim_context->cur_t_time);
00306 string utc(::asctime(gmt));
00307 string date = string::format(L"%ls UTC", utc.trim().w_string());
00308 info_font->draw(date);
00309
00310 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERRORS();
00311 glLoadIdentity(); CHECK_GL_ERRORS();
00312 glTranslatef(1.0f, console->get_height() - 4*height, 0.0f); CHECK_GL_ERRORS();
00313 string info = string::format(L"Time: %dx FPS: %d", static_cast<int>(time_scale), fps);
00314 info_font->draw(info);
00315
00316 console->draw_text_stop();
00317 }
00318 }
00319
00320
00321 void simulation::update()
00322 {
00323 update_context();
00324
00325 frame_deltas[sim_context->frame % NUM_FRAME_DELTAS] = static_cast<gsgl::real_t>(sim_context->delta_tick) / 1000.0f;
00326
00327
00328 if (time_scale != 0.0f && scenery)
00329 update_node(scenery);
00330 }
00331
00332
00333 void simulation::cleanup()
00334 {
00335 cleanup_context();
00336
00337
00338 if (scenery)
00339 cleanup_node(scenery);
00340 }
00341
00342
00343 static config_variable<gsgl::real_t> MAX_TIME_SCALE(L"scenegraph/simulation/max_time_scale", 1000000000.0f);
00344
00345
00346 bool simulation::handle_event(sg_event & e)
00347 {
00348 switch (e.get_code())
00349 {
00350 case sg_event::SIM_QUIT:
00351 running = false;
00352 return true;
00353
00354 case sg_event::TIME_INC_SCALE:
00355 time_scale *= 10.0f;
00356
00357 if (time_scale > MAX_TIME_SCALE)
00358 time_scale = MAX_TIME_SCALE;
00359
00360 return true;
00361
00362 case sg_event::TIME_DEC_SCALE:
00363 time_scale /= 10.0f;
00364
00365 if (time_scale < 1.0f)
00366 time_scale = 1.0f;
00367
00368 return true;
00369
00370 case sg_event::TIME_RESET_SCALE:
00371 time_scale = 1.0f;
00372 return true;
00373
00374 case sg_event::TIME_PAUSE:
00375 time_scale = 0.0f;
00376 return true;
00377
00378 case sg_event::RENDER_TOGGLE_LABELS:
00379 sim_context->render_flags ^= context::RENDER_LABELS;
00380 return true;
00381
00382 case sg_event::RENDER_TOGGLE_COORD_SYSTEMS:
00383 sim_context->render_flags ^= context::RENDER_COORD_SYSTEMS;
00384 return true;
00385
00386 default:
00387 break;
00388 }
00389
00390
00391 if (scenery)
00392 return handle_event(e, scenery);
00393 else
00394 return false;
00395 }
00396
00397
00398 void simulation::init_node(node *n)
00399 {
00400 assert(n);
00401
00402 n->init(sim_context);
00403
00404
00405 for (simple_array<node *>::iterator i = n->get_children().iter(); i.is_valid(); ++i)
00406 init_node(*i);
00407 }
00408
00409
00410 static const string PHYSICS_CATEGORY = L"physics: ";
00411
00412 void simulation::update_node(node *n)
00413 {
00414 assert(n);
00415
00416 {
00417 platform::budget_record br(PHYSICS_CATEGORY + n->get_type_name());
00418 n->update(sim_context);
00419 }
00420
00421
00422 for (simple_array<node *>::iterator i = n->get_children().iter(); i.is_valid(); ++i)
00423 update_node(*i);
00424 }
00425
00426
00427 void simulation::cleanup_node(node *n)
00428 {
00429 assert(n);
00430
00431 n->cleanup(sim_context);
00432
00433 for (simple_array<node *>::iterator i = n->get_children().iter(); i.is_valid(); ++i)
00434 cleanup_node(*i);
00435 }
00436
00437
00438 bool simulation::handle_event(sg_event & e, node *n)
00439 {
00440 assert(n);
00441
00442 if (n->handle_event(sim_context, e))
00443 return true;
00444
00445 for (simple_array<node *>::iterator i = n->get_children().iter(); i.is_valid(); ++i)
00446 {
00447 if (handle_event(e, *i))
00448 return true;
00449 }
00450
00451 return false;
00452 }
00453
00454
00455 }
00456
00457 }