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/node.hpp"
00035 #include "scenegraph/camera.hpp"
00036 #include "scenegraph/light.hpp"
00037 #include "scenegraph/utils.hpp"
00038
00039 #include "data/pqueue.hpp"
00040 #include "math/units.hpp"
00041
00042 #include "platform/budget.hpp"
00043 #include "platform/lowlevel.hpp"
00044
00045 #include <cmath>
00046 #include <cfloat>
00047
00048 namespace gsgl
00049 {
00050
00051 using namespace data;
00052 using namespace math;
00053
00054 namespace scenegraph
00055 {
00056
00057 node_relative_path::node_relative_path(node *reference, node *cur)
00058 : relative_transform(transform::IDENTITY)
00059 {
00060 initialize(reference, cur);
00061 }
00062
00063
00064 static void get_parent_list(node *n, simple_array<node *> & a)
00065 {
00066 if (n->get_parent())
00067 get_parent_list(n->get_parent(), a);
00068 a.append(n);
00069 }
00070
00071
00072 void node_relative_path::initialize(node *reference, node *cur)
00073 {
00074 simple_array<node *> list_from;
00075 simple_array<node *> list_to;
00076
00077 get_parent_list(cur, list_from);
00078 get_parent_list(reference, list_to);
00079
00080 int i, num = gsgl::min_val(list_from.size(), list_to.size());
00081 for (i = 0; i < num; ++i)
00082 {
00083 if (list_from[i] != list_to[i])
00084 break;
00085 }
00086
00087 to_cur.clear();
00088 for (int j = i; j < list_from.size(); ++j)
00089 to_cur.append(list_from[j]);
00090
00091 from_ref.clear();
00092 for (int j = i; j < list_to.size(); ++j)
00093 from_ref.append(list_to[j]);
00094 }
00095
00096
00097 const math::transform & node_relative_path::calc_relative_transform(bool include_translation)
00098 {
00099 relative_transform = transform::IDENTITY;
00100
00101 int i, len = from_ref.size();
00102 for (i = 0; i < len; ++i)
00103 {
00104 relative_transform = relative_transform * from_ref[i]->get_orientation().transpose();
00105 if (include_translation)
00106 relative_transform = relative_transform * transform::translation_transform(-from_ref[i]->get_translation() * from_ref[i]->get_scale());
00107 }
00108
00109 len = to_cur.size();
00110 for (i = 0; i < len; ++i)
00111 {
00112 if (include_translation)
00113 relative_transform = relative_transform * transform::translation_transform(to_cur[i]->get_translation() * from_ref[i]->get_scale());
00114 relative_transform = relative_transform * to_cur[i]->get_orientation();
00115 }
00116
00117 return relative_transform;
00118 }
00119
00120
00121
00122 node::node(const string & name, node *parent)
00123 : scenegraph_object(),
00124 parent(parent), name(name), scale(1),
00125 translation(vector::ZERO), orientation(transform::IDENTITY),
00126 modelview(transform::IDENTITY),
00127 draw_flags(0), draw_results(0)
00128 {
00129 if (parent)
00130 parent->add_child(this);
00131 }
00132
00133
00134 node::node(const data::config_record & conf)
00135 : scenegraph_object(),
00136 parent(0), scale(1),
00137 translation(vector::ZERO), orientation(transform::IDENTITY),
00138 modelview(transform::IDENTITY),
00139 draw_flags(0), draw_results(0)
00140 {
00141 name = conf[L"name"];
00142 parent_name = conf[L"parent"];
00143
00144 if (!conf[L"scale"].is_empty())
00145 scale = math::units::parse(conf[L"scale"]);
00146 if (!conf[L"position"].is_empty())
00147 translation = vector::parse(conf[L"position"]);
00148 if (!conf[L"orientation"].is_empty())
00149 orientation = transform::parse(conf[L"orientation"]);
00150 }
00151
00152
00153 node::~node()
00154 {
00155 for (simple_array<node *>::iterator i = children.iter(); i.is_valid(); ++i)
00156 delete *i;
00157 }
00158
00159
00160
00161
00162 const node *node::get_parent() const
00163 {
00164 return parent;
00165 }
00166
00167
00168 node * & node::get_parent()
00169 {
00170 return parent;
00171 }
00172
00173
00174 data::simple_array<node *> & node::get_children()
00175 {
00176 return children;
00177 }
00178
00179
00180 static int num_unnamed_nodes = 0;
00181
00182 const string & node::get_name() const
00183 {
00184 string & name_ref = const_cast<string &>(name);
00185
00186 if (name_ref.is_empty())
00187 {
00188 name_ref = string::format(L"node_%d", num_unnamed_nodes++);
00189
00190 if (parent && !parent->get_name().is_empty())
00191 {
00192 int i, len = parent->get_children().size();
00193 for (i = 0; i < len; ++i)
00194 if (parent->get_children()[i] == this)
00195 break;
00196
00197 if (i < len)
00198 name_ref += string::format(L" (%ls child %d)", parent->get_name(), i);
00199 }
00200 }
00201
00202 return name;
00203 }
00204
00205 string & node::get_name()
00206 {
00207 return name;
00208 }
00209
00210 string & node::get_parent_name()
00211 {
00212 return parent_name;
00213 }
00214
00215 gsgl::real_t & node::get_scale()
00216 {
00217 return scale;
00218 }
00219
00220 math::vector & node::get_translation()
00221 {
00222 return translation;
00223 }
00224
00225 math::transform & node::get_orientation()
00226 {
00227 return orientation;
00228 }
00229
00230 math::transform & node::get_modelview()
00231 {
00232 return modelview;
00233 }
00234
00235
00236
00237 const gsgl::real_t node::NODE_DRAW_IGNORE = 0.000f;
00238 const gsgl::real_t node::NODE_DRAW_SOLID = 0.001f;
00239 const gsgl::real_t node::NODE_DRAW_TRANSLUCENT = 0.002f;
00240 const gsgl::real_t node::NODE_DRAW_FIRST = FLT_MAX;
00241
00242
00243 gsgl::real_t node::get_priority(context *)
00244 {
00245 return NODE_DRAW_IGNORE;
00246 }
00247
00248
00249 gsgl::real_t node::max_extent() const
00250 {
00251 return 0;
00252 }
00253
00254
00255 gsgl::real_t node::default_view_distance() const
00256 {
00257 return static_cast<gsgl::real_t>(32.0);
00258 }
00259
00260
00261 gsgl::real_t node::minimum_view_distance() const
00262 {
00263 return max_extent();
00264 }
00265
00266
00267 void node::add_child(node *child)
00268 {
00269 assert(child);
00270
00271 children.append(child);
00272 child->parent = this;
00273 }
00274
00275
00276 void node::detach()
00277 {
00278 if (parent)
00279 {
00280 simple_array<node *>::iterator child = parent->children.find_value(this);
00281 if (child.is_valid())
00282 parent->children.remove(child);
00283 }
00284
00285 parent = 0;
00286 }
00287
00288
00289 bool node::connect(node *branch)
00290 {
00291 if (name == branch->parent_name)
00292 {
00293 this->add_child(branch);
00294 return true;
00295 }
00296
00297 for (simple_array<node *>::iterator i = children.iter(); i.is_valid(); ++i)
00298 {
00299 if ((*i)->connect(branch))
00300 return true;
00301 }
00302
00303 return false;
00304 }
00305
00306
00307 void node::init(context *)
00308 {
00309 }
00310
00311 void node::draw(context *)
00312 {
00313 }
00314
00315 void node::update(context *)
00316 {
00317 }
00318
00319 void node::cleanup(context *)
00320 {
00321 }
00322
00323 bool node::handle_event(context *, sg_event &)
00324 {
00325 return false;
00326 }
00327
00328 data::config_record *node::save() const
00329 {
00330 return 0;
00331 }
00332
00333
00334
00335
00336 void node::build_draw_list(node *cur, node *prev, context *c, const transform & modelview, pre_draw_rec & rec)
00337 {
00338
00339 if (cur->parent && cur->parent != prev)
00340 {
00341 transform to_parent = cur->orientation.transpose() * transform::translation_transform(cur->translation * (-1 * cur->parent->scale));
00342 build_draw_list(cur->parent, cur, c, modelview * to_parent, rec);
00343 }
00344
00345
00346 cur->modelview = modelview;
00347
00348 light *l = dynamic_cast<light *>(cur);
00349 if (l)
00350 {
00351 rec.light_queue.push(l, utils::pos_in_eye_space(l).mag2());
00352 }
00353 else
00354 {
00355 gsgl::real_t pri = cur->get_priority(c);
00356
00357 if (pri == node::NODE_DRAW_SOLID)
00358 rec.solids.append(cur);
00359 else if (pri == node::NODE_DRAW_TRANSLUCENT)
00360 rec.translucents.append(cur);
00361 else if (pri > node::NODE_DRAW_TRANSLUCENT)
00362 rec.paint_queue.push(cur, pri);
00363 }
00364
00365
00366 int i, len = cur->children.size();
00367 for (i = 0; i < len; ++i)
00368 {
00369 node *child = cur->children[i];
00370
00371 if (child != prev && !(child->draw_flags & node::NODE_DUMMY_OBJECT))
00372 {
00373 transform from_parent = transform::translation_transform(child->translation * cur->scale) * child->orientation;
00374 build_draw_list(child, cur, c, modelview * from_parent, rec);
00375 }
00376 }
00377 }
00378
00379
00380 void node::pre_draw_scene(context *c, pre_draw_rec & rec)
00381 {
00382 rec.light_queue.clear();
00383 rec.paint_queue.clear();
00384 rec.solids.clear();
00385 rec.translucents.clear();
00386
00387 build_draw_list(c->cam, 0, c, transform::IDENTITY, rec);
00388 }
00389
00390
00391 static const string RENDER_CATEGORY = L"render: ";
00392
00393 static config_variable<platform::color> AMBIENT_LIGHT(L"scenegraph/draw/ambient_light", platform::color(0.15f, 0.15f, 0.15f, 1.0f));
00394 static config_variable<gsgl::real_t> LOCAL_CULL_DISTANCE(L"scenegraph/draw/local_cull_distance", 100000.0f);
00395
00396
00397 void node::draw_scene(context *c, pre_draw_rec & rec)
00398 {
00399 int i, len;
00400
00401
00402 glViewport(0, 0, c->screen->get_width(), c->screen->get_height()); CHECK_GL_ERRORS();
00403
00404 glPushAttrib(GL_ALL_ATTRIB_BITS); CHECK_GL_ERRORS();
00405 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); CHECK_GL_ERRORS();
00406
00407
00408 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, AMBIENT_LIGHT.get_value().get_val()); CHECK_GL_ERRORS();
00409
00410 int max_lights;
00411 glGetIntegerv(GL_MAX_LIGHTS, &max_lights); CHECK_GL_ERRORS();
00412
00413 for (i = 0; i < max_lights; ++i)
00414 glDisable(GL_LIGHT0 + i);
00415 c->num_lights = 0;
00416
00417 if (!(c->render_flags & context::RENDER_UNLIT))
00418 {
00419 len = rec.light_queue.size();
00420 for (i = 0; i < len && i < max_lights; ++i)
00421 {
00422 light *l = rec.light_queue[i];
00423
00424 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERRORS();
00425 glLoadMatrixf(l->get_modelview().ptr());
00426 l->bind(GL_LIGHT0 + i); CHECK_GL_ERRORS();
00427 }
00428
00429 c->num_lights = i;
00430 }
00431
00432
00433 len = rec.paint_queue.size();
00434 for (i = 0; i < len; ++i)
00435 {
00436 node *n = rec.paint_queue[i];
00437 n->draw_results = NODE_NO_DRAW_RESULTS;
00438
00439 platform::budget_record br(RENDER_CATEGORY + n->get_type_name());
00440
00441 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERRORS();
00442 glLoadMatrixf(n->get_modelview().ptr());
00443
00444 if (utils::is_on_screen(n, c->cam->get_field_of_view(), c->screen->get_aspect_ratio(), vector::ZERO, n->max_extent() * n->scale))
00445 n->draw(c);
00446 else
00447 n->draw_results |= NODE_OFF_SCREEN;
00448 }
00449
00450
00451 if (rec.solids.size() || rec.translucents.size())
00452 {
00453
00454 gsgl::real_t max_ext = 0;
00455 gsgl::real_t min_ext = FLT_MAX;
00456
00457 len = rec.solids.size();
00458 for (i = 0; i < len; ++i)
00459 {
00460 node *n = rec.solids[i];
00461 n->draw_results = NODE_NO_DRAW_RESULTS;
00462
00463 if (!utils::is_on_screen(n, c->cam->get_field_of_view(), c->screen->get_aspect_ratio(), vector::ZERO, n->max_extent()))
00464 {
00465 n->draw_results |= NODE_OFF_SCREEN;
00466 continue;
00467 }
00468
00469 gsgl::real_t e = utils::pos_in_eye_space(n).mag();
00470 if (e > LOCAL_CULL_DISTANCE)
00471 {
00472 n->draw_results |= NODE_DISTANCE_CULLED;
00473 continue;
00474 }
00475
00476 gsgl::real_t x = n->max_extent() * n->scale;
00477
00478 if ((e+x) > max_ext)
00479 max_ext = e+x;
00480
00481 gsgl::real_t m = max_val(e-x, 0.1f);
00482 if (m < min_ext)
00483 min_ext = m;
00484 }
00485
00486 len = rec.translucents.size();
00487 for (i = 0; i < len; ++i)
00488 {
00489 node *n = rec.translucents[i];
00490 n->draw_results = NODE_NO_DRAW_RESULTS;
00491
00492 if (!utils::is_on_screen(n, c->cam->get_field_of_view(), c->screen->get_aspect_ratio(), vector::ZERO, n->max_extent()))
00493 {
00494 n->draw_results |= NODE_OFF_SCREEN;
00495 continue;
00496 }
00497
00498 gsgl::real_t e = utils::pos_in_eye_space(n).mag();
00499 if (e > LOCAL_CULL_DISTANCE)
00500 {
00501 n->draw_results |= NODE_DISTANCE_CULLED;
00502 continue;
00503 }
00504
00505 gsgl::real_t x = n->max_extent() * n->scale;
00506
00507 if ((e+x) > max_ext)
00508 max_ext = e+x;
00509
00510 gsgl::real_t m = max_val(e-x, 0.1f);
00511 if (m < min_ext)
00512 min_ext = m;
00513 }
00514
00515 glClearDepth(1); CHECK_GL_ERRORS();
00516 glClear(GL_DEPTH_BUFFER_BIT); CHECK_GL_ERRORS();
00517 glEnable(GL_DEPTH_TEST); CHECK_GL_ERRORS();
00518
00519 float near_plane = min_ext * 0.9f;
00520 float far_plane = max_ext * 1.1f;
00521
00522 glMatrixMode(GL_PROJECTION); CHECK_GL_ERRORS();
00523 glLoadIdentity(); CHECK_GL_ERRORS();
00524 gluPerspective(c->cam->get_field_of_view(), c->screen->get_aspect_ratio(), near_plane, far_plane); CHECK_GL_ERRORS();
00525
00526
00527 len = rec.solids.size();
00528 for (i = 0; i < len; ++i)
00529 {
00530 node *n = rec.solids[i];
00531
00532 if (n->draw_results & (NODE_OFF_SCREEN | NODE_DISTANCE_CULLED))
00533 continue;
00534
00535 platform::budget_record br(RENDER_CATEGORY + n->get_type_name());
00536
00537 glMatrixMode(GL_MODELVIEW);
00538 glLoadMatrixf(n->get_modelview().ptr());
00539
00540 n->draw(c);
00541 }
00542
00543
00544 glEnable(GL_BLEND); CHECK_GL_ERRORS();
00545 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CHECK_GL_ERRORS();
00546
00547 len = rec.translucents.size();
00548 for (i = 0; i < len; ++i)
00549 {
00550 node *n = rec.translucents[i];
00551
00552 if (n->draw_results & (NODE_OFF_SCREEN | NODE_DISTANCE_CULLED))
00553 continue;
00554
00555 platform::budget_record br(RENDER_CATEGORY + n->get_type_name());
00556
00557 glMatrixMode(GL_MODELVIEW);
00558 glLoadMatrixf(n->get_modelview().ptr());
00559
00560 n->draw(c);
00561 }
00562 }
00563
00564
00565 glPopClientAttrib(); CHECK_GL_ERRORS();
00566 glPopAttrib(); CHECK_GL_ERRORS();
00567 }
00568
00569
00570 }
00571
00572 }