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/utils.hpp"
00035 #include "scenegraph/node.hpp"
00036 #include "scenegraph/camera.hpp"
00037 #include "scenegraph/freeview.hpp"
00038 
00039 #include "platform/vbuffer.hpp"
00040 #include "platform/lowlevel.hpp"
00041 
00042 #include <cmath>
00043 
00044 
00045 namespace gsgl
00046 {
00047 
00048     using namespace data;
00049     using namespace math;
00050     using namespace platform;
00051 
00052     namespace scenegraph
00053     {
00054 
00055         namespace utils
00056         {
00057 
00058 
00059             
00060 
00061             coord_system::coord_system(node *parent, const gsgl::real_t radius, const gsgl::real_t degree_step, const color & draw_color)
00062                 : parent(parent), radius(radius), degree_step(degree_step), draw_color(draw_color), display_list_id(0)
00063             {
00064             } 
00065 
00066 
00067             coord_system::~coord_system()
00068             {
00069                 if (display_list_id)
00070                 {
00071                     glDeleteLists(display_list_id, 1);                                                              CHECK_GL_ERRORS();
00072                 }
00073             } 
00074 
00075 
00076             void coord_system::init(context *c)
00077             {
00078             } 
00079 
00080 
00081             void coord_system::draw(context *c)
00082             {
00083                 glPushAttrib(GL_ALL_ATTRIB_BITS);                                                                   CHECK_GL_ERRORS();
00084                 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);                                                      CHECK_GL_ERRORS();
00085 
00086                 
00087                 vector ep = pos_in_eye_space(parent);
00088                 gsgl::real_t far_plane = (-ep.get_z() + radius) * 1.1f; 
00089 
00090                 gsgl::real_t near_plane = far_plane * static_cast<gsgl::real_t>(::cos(c->cam->get_field_of_view() * math::DEG2RAD));
00091                 if (near_plane < 0)
00092                     near_plane = 1;
00093 
00094                 glMatrixMode(GL_PROJECTION);                                                                        CHECK_GL_ERRORS();
00095                 glLoadIdentity();                                                                                   CHECK_GL_ERRORS();
00096                 gluPerspective(c->cam->get_field_of_view(), c->screen->get_aspect_ratio(), near_plane, far_plane);  CHECK_GL_ERRORS();
00097 
00098                 
00099                 glEnable(GL_BLEND);                                                                                 CHECK_GL_ERRORS();
00100                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);                                                  CHECK_GL_ERRORS();
00101 
00102                 glEnable(GL_LINE_SMOOTH);
00103                 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00104 
00105                 draw_color.set();
00106 
00107                 if (display_list_id)
00108                 {
00109                     glCallList(display_list_id);                                                                    CHECK_GL_ERRORS();
00110                 }
00111                 else
00112                 {
00113                     if ((display_list_id = glGenLists(1)))
00114                     {
00115                         glNewList(display_list_id, GL_COMPILE_AND_EXECUTE);                                         CHECK_GL_ERRORS();
00116 
00117                         gsgl::real_t x, y, z;
00118 
00119                         
00120                         for (gsgl::real_t theta = 0.0f; theta < 360.0f; theta += degree_step)
00121                         {
00122                             if (theta == 0.0f)
00123                                 glLineWidth(4.0f);
00124                             else
00125                                 glLineWidth(2.0f);
00126 
00127                             glBegin(GL_LINE_STRIP);                                                                 
00128 
00129                             for (gsgl::real_t phi = 0.0f; phi <= 180.0f; phi += 1.0f)
00130                             {
00131                                 x = static_cast<gsgl::real_t>(radius * ::cos(theta * math::DEG2RAD) * ::sin(phi * math::DEG2RAD));
00132                                 y = static_cast<gsgl::real_t>(radius * ::sin(theta * math::DEG2RAD) * ::sin(phi * math::DEG2RAD));
00133                                 z = static_cast<gsgl::real_t>(radius * ::cos(phi * math::DEG2RAD));
00134 
00135                                 glVertex3f(x, y, z);
00136                             }
00137 
00138                             glEnd();                                                                                CHECK_GL_ERRORS();
00139                         }
00140 
00141                         
00142                         for (gsgl::real_t phi = degree_step; phi < 180.0f; phi += degree_step)
00143                         {
00144                             if (phi == 90.0f)
00145                                 glLineWidth(4.0f);
00146                             else
00147                                 glLineWidth(2.0f);
00148 
00149                             glBegin(GL_LINE_STRIP);                                                                 
00150 
00151                             for (gsgl::real_t theta = 0.0f; theta <= 360.0f; theta += 1.0f)
00152                             {
00153                                 x = static_cast<gsgl::real_t>(radius * ::cos(theta * math::DEG2RAD) * ::sin(phi * math::DEG2RAD));
00154                                 y = static_cast<gsgl::real_t>(radius * ::sin(theta * math::DEG2RAD) * ::sin(phi * math::DEG2RAD));
00155                                 z = static_cast<gsgl::real_t>(radius * ::cos(phi * math::DEG2RAD));
00156 
00157                                 glVertex3f(x, y, z);
00158                             }
00159 
00160                             glEnd();                                                                                CHECK_GL_ERRORS();
00161                         }
00162 
00163                         glEndList();                                                                                CHECK_GL_ERRORS();
00164                     }
00165                 }
00166 
00167                 glPopClientAttrib();                                                                                CHECK_GL_ERRORS();
00168                 glPopAttrib();                                                                                      CHECK_GL_ERRORS();
00169             } 
00170 
00171 
00172 
00173 
00174             simple_sphere::simple_sphere(node *parent, const int num_steps, 
00175                                          const gsgl::real_t equatorial_radius, const gsgl::real_t polar_radius,
00176                                          texture *tex, const gsgl::real_t tex_offset_x, const gsgl::real_t tex_offset_y)
00177                 : parent(parent), num_steps(num_steps),
00178                   equatorial_radius(equatorial_radius), polar_radius(polar_radius), 
00179                   vertices(vbuffer::STATIC), indices(vbuffer::STATIC),
00180                   tex(tex), tex_offset_x(tex_offset_x), tex_offset_y(tex_offset_y)
00181             {
00182                 double b_over_a = polar_radius / equatorial_radius;
00183                 double altitude = 0;
00184 
00185                 
00186                 
00187                 for (int lat = 0; lat <= num_steps; ++lat)
00188                 {
00189                     
00190                     double pct_lat = static_cast<double>(lat) / static_cast<double>(num_steps);
00191                     double spherical_phi = pct_lat * math::PI;
00192                     double geographic_phi = math::PI_OVER_2 - spherical_phi;
00193 
00194                     double nz = ::cos(spherical_phi);
00195                     double nr = ::sin(spherical_phi);
00196                     double geocentric_phi = ::atan2(b_over_a * b_over_a * nz, nr);  
00197                     double geocentric_spherical_phi = math::PI_OVER_2 - geocentric_phi;
00198 
00199                     for (int lon = 0; lon <= num_steps*2; ++lon)
00200                     {
00201                         double pct_lon = static_cast<double>(lon) / static_cast<double>(num_steps*2);
00202                         double theta = pct_lon * math::PI_TIMES_2;
00203 
00204                         double s = pct_lon + tex_offset_x;
00205                         double t = (1.0 - pct_lat) + tex_offset_y;
00206 
00207                         double nx = ::cos(theta) * ::sin(spherical_phi);
00208                         double ny = ::sin(theta) * ::sin(spherical_phi);
00209 
00210                         double x = equatorial_radius * ::cos(theta) * ::sin(geocentric_spherical_phi);
00211                         double y = equatorial_radius * ::sin(theta) * ::sin(geocentric_spherical_phi);
00212                         double z = polar_radius * ::cos(geocentric_spherical_phi);
00213 
00214                         vertices.append(static_cast<float>(s));
00215                         vertices.append(static_cast<float>(t));
00216                         vertices.append(static_cast<float>(nx));
00217                         vertices.append(static_cast<float>(ny));
00218                         vertices.append(static_cast<float>(nz));
00219                         vertices.append(static_cast<float>(x));
00220                         vertices.append(static_cast<float>(y));
00221                         vertices.append(static_cast<float>(z));
00222                     }
00223                 }
00224 
00225                 
00226                 int stride = num_steps*2+1;
00227 
00228                 for (int j = 0; j < num_steps; ++j)
00229                 {
00230                     for (int i = 0; i <= num_steps*2; ++i)
00231                     {
00232                         indices.append( j*stride + i ); 
00233                         indices.append( (j+1)*stride + i ); 
00234                     }
00235                 }
00236             } 
00237 
00238 
00239             simple_sphere::~simple_sphere()
00240             {
00241             } 
00242 
00243             
00244             void simple_sphere::init(context *c)
00245             {
00246             } 
00247 
00248 
00249             void simple_sphere::draw(context *c)
00250             {
00251                 glPushAttrib(GL_ALL_ATTRIB_BITS);                                                                   CHECK_GL_ERRORS();
00252                 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);                                                      CHECK_GL_ERRORS();
00253 
00254                 glEnableClientState(GL_VERTEX_ARRAY);                                                               CHECK_GL_ERRORS();
00255                 glEnableClientState(GL_COLOR_ARRAY);
00256                 glEnableClientState(GL_NORMAL_ARRAY);
00257                 glEnableClientState(GL_INDEX_ARRAY);                                                                CHECK_GL_ERRORS();
00258 
00259                 if (tex && !(c->render_flags & context::RENDER_UNTEXTURED))
00260                 {
00261                     glEnable(GL_TEXTURE_2D);
00262                     tex->bind((c->render_flags & context::RENDER_ANISOTROPIC) ? TEXTURE_RENDER_ANISOTROPIC : TEXTURE_NO_FLAGS);
00263                 }
00264 
00265                 vertices.bind();
00266                 glInterleavedArrays(GL_T2F_N3F_V3F, 0, 0);                                                          CHECK_GL_ERRORS();
00267 
00268                 indices.bind();
00269 
00270                 int index_stride = (num_steps*2+1)*2;
00271                 int vertex_stride = 8;
00272 
00273                 
00274                 
00275                 
00276                 
00277                 
00278                 
00279                 
00280                 
00281 
00282                 
00283                 
00284                 
00285                 
00286                 
00287                 
00288 
00289                 for (int i = 0; i < num_steps; ++i)
00290                 {
00291                     glDrawElements(GL_TRIANGLE_STRIP, index_stride, GL_UNSIGNED_INT, vbuffer::VBO_OFFSET<vbuffer::index_t>(i*index_stride));
00292                 }
00293 
00294                 if (tex)
00295                     tex->unbind();
00296 
00297                 glPopClientAttrib();                                                                                CHECK_GL_ERRORS();
00298                 glPopAttrib();                                                                                      CHECK_GL_ERRORS();
00299             } 
00300 
00301 
00302 
00303 
00304             vector pos_in_eye_space(node *frame, const vector & p)
00305             {
00306                 return frame->get_modelview() * p;
00307             } 
00308 
00309 
00310             gsgl::real_t dot_in_eye_space(node *frame, const vector & pos)
00311             {
00312                 vector eye_dir = frame->get_modelview() * pos;
00313                 eye_dir.normalize();
00314 
00315                 return eye_dir.dot(vector::NEG_Z_AXIS);
00316             } 
00317 
00318 
00319             bool is_on_screen(node *frame, 
00320                               const gsgl::real_t field_of_view, const gsgl::real_t aspect_ratio,
00321                               const vector & pos, const gsgl::real_t radius)
00322             {
00323                 if (frame->get_draw_flags() & node::NODE_NO_FRUSTUM_CHECK)
00324                     return true;
00325 
00326                 vector eye_dir = frame->get_modelview() * pos;
00327                 double dist = eye_dir.mag();
00328 
00329                 eye_dir.normalize();
00330                 double cos_angle = vector::NEG_Z_AXIS.dot(eye_dir);
00331 
00332                 double node_angle = ::acos(cos_angle);
00333                 double radius_angle = ::atan(radius / dist);
00334 
00335                 double obj_angle = node_angle - radius_angle;
00336                 double view_angle = field_of_view * math::DEG2RAD * aspect_ratio;
00337 
00338                 return obj_angle < view_angle;
00339             } 
00340 
00341 
00342             gsgl::real_t pixel_size(const gsgl::real_t distance, const gsgl::real_t radius,
00343                                     const gsgl::real_t field_of_view, const int pixels_in_field_of_view)
00344             {
00345                 double half_angle = ::atan(radius / distance);
00346                 double pixel_size = (2.0 * half_angle / (field_of_view*math::DEG2RAD)) * static_cast<gsgl::real_t>(pixels_in_field_of_view);
00347                 return static_cast<gsgl::real_t>(pixel_size);
00348             } 
00349 
00350 
00351             void save_screen_info(int viewport[4], transform & modelview_projection)
00352             {
00353                 transform modelview, projection;
00354 
00355                 glGetIntegerv(GL_VIEWPORT, viewport);                                                         CHECK_GL_ERRORS();
00356                 glGetFloatv(GL_MODELVIEW_MATRIX, modelview.ptr());                                            CHECK_GL_ERRORS();
00357                 glGetFloatv(GL_PROJECTION_MATRIX, projection.ptr());                                          CHECK_GL_ERRORS();
00358                 modelview_projection = projection * modelview;
00359             } 
00360 
00361 
00362             vector pos_in_screen_space(const vector & point, const int viewport[4], const transform & modelview_projection)
00363             {
00364                 vector point_in_clip_space = modelview_projection * point;
00365                 return vector(viewport[0] + viewport[2]*(point_in_clip_space.get_x() + 1)/2,
00366                               viewport[1] + viewport[3]*(point_in_clip_space.get_y() + 1)/2,
00367                               (point_in_clip_space.get_z() + 1)/2);
00368             } 
00369 
00370 
00371             gsgl::real_t greatest_extent(const node *cn)
00372             {
00373                 node *n = const_cast<node *>(cn);
00374 
00375                 gsgl::real_t max_val = n->max_extent();
00376 
00377                 for (simple_array<node *>::iterator i = n->get_children().iter(); i.is_valid(); ++i)
00378                 {
00379                     
00380                     if (dynamic_cast<freeview *>(*i))
00381                         continue;
00382 
00383                     gsgl::real_t dist = n->get_scale() * (*i)->get_translation().mag();
00384                     gsgl::real_t m = dist + greatest_extent(*i);
00385 
00386                     if (m > max_val)
00387                         max_val = m;
00388                 }
00389 
00390                 return max_val;
00391             } 
00392 
00393 
00394             
00395 
00396             void draw_billboard(node *frame, const vector & pos, const gsgl::real_t radius)
00397             {
00398                 
00399                 vector eye_pos = frame->get_modelview() * pos;
00400                 
00401                 
00402                 vector front = eye_pos; 
00403                 front.normalize();
00404 
00405                 
00406                 const vector & eye_up = vector::Y_AXIS;
00407 
00408                 
00409                 vector right = front.cross(eye_up);
00410 
00411                 
00412                 vector up = right.cross(front);
00413 
00414                 
00415                 transform mvi = frame->get_modelview().rotation_part().transpose();
00416 
00417                 vector horiz = mvi * right;   horiz *= radius;
00418                 vector vert = mvi * up;       vert *= radius;
00419                 vector normal = mvi * -front;
00420 
00421                 
00422                 vector lower_left  = pos + -horiz + -vert;
00423                 vector lower_right = pos + horiz + -vert;
00424                 vector upper_right = pos + horiz + vert;
00425                 vector upper_left  = pos + -horiz + vert;
00426 
00427                 glBegin(GL_TRIANGLE_STRIP);
00428                 {
00429                     
00430                     glTexCoord2f(0, 1);
00431                     glNormal3fv(normal.ptr());
00432                     glVertex3fv(upper_left.ptr());
00433 
00434                     
00435                     glTexCoord2f(0, 0);
00436                     glNormal3fv(normal.ptr());
00437                     glVertex3fv(lower_left.ptr());
00438 
00439                     
00440                     glTexCoord2f(1, 1);
00441                     glNormal3fv(normal.ptr());
00442                     glVertex3fv(upper_right.ptr());
00443 
00444                     
00445                     glTexCoord2f(0, 1);
00446                     glNormal3fv(normal.ptr());
00447                     glVertex3fv(lower_right.ptr());
00448                 }
00449                 glEnd();                                                                                            CHECK_GL_ERRORS();
00450             } 
00451 
00452 
00453             
00454             
00455             checkered_box::checkered_box(const string & name, node *parent, gsgl::real_t radius)
00456                 : node(name, parent), radius(radius), normals(vbuffer::STATIC), vertices(vbuffer::STATIC)
00457             {
00458             } 
00459 
00460 
00461             checkered_box::~checkered_box()
00462             {
00463             } 
00464 
00465 
00466             static void add_vertex(vertex_buffer & vb, gsgl::real_t x, gsgl::real_t y, gsgl::real_t z,
00467                                    vertex_buffer & nb, gsgl::real_t nx, gsgl::real_t ny, gsgl::real_t nz, 
00468                                    gsgl::real_t radius)
00469             {
00470                 vb.append(x * radius);
00471                 vb.append(y * radius);
00472                 vb.append(z * radius);
00473 
00474                 vector nn(nx, ny, nz);
00475                 nn.normalize();
00476 
00477                 nb.append(nn.get_x());
00478                 nb.append(nn.get_y());
00479                 nb.append(nn.get_z());
00480             } 
00481 
00482 
00483             void checkered_box::init(gsgl::scenegraph::context *c)
00484             {
00485                 
00486                 add_vertex(vertices, -1, -1,  1,  normals,  0,  0,  1,  radius);
00487                 add_vertex(vertices, -1,  1,  1,  normals,  0,  0,  1,  radius);
00488                 add_vertex(vertices,  1,  1,  1,  normals,  0,  0,  1,  radius);
00489                 add_vertex(vertices,  1, -1,  1,  normals,  0,  0,  1,  radius);
00490 
00491                 
00492                 add_vertex(vertices, -1, -1,  1,  normals, -1,  0,  0,  radius);
00493                 add_vertex(vertices, -1, -1, -1,  normals, -1,  0,  0,  radius);
00494                 add_vertex(vertices, -1,  1, -1,  normals, -1,  0,  0,  radius);
00495                 add_vertex(vertices, -1,  1,  1,  normals, -1,  0,  0,  radius);
00496 
00497                 
00498                 add_vertex(vertices, -1,  1,  1,  normals,  0,  1,  0,  radius);
00499                 add_vertex(vertices, -1,  1, -1,  normals,  0,  1,  0,  radius);
00500                 add_vertex(vertices,  1,  1, -1,  normals,  0,  1,  0,  radius);
00501                 add_vertex(vertices,  1,  1,  1,  normals,  0,  1,  0,  radius);
00502 
00503                 
00504                 add_vertex(vertices,  1,  1,  1,  normals,  1,  0,  0,  radius);
00505                 add_vertex(vertices,  1,  1, -1,  normals,  1,  0,  0,  radius);
00506                 add_vertex(vertices,  1, -1, -1,  normals,  1,  0,  0,  radius);
00507                 add_vertex(vertices,  1, -1,  1,  normals,  1,  0,  0,  radius);
00508 
00509                 
00510                 add_vertex(vertices, -1, -1,  1,  normals,  0, -1,  0,  radius);
00511                 add_vertex(vertices,  1, -1,  1,  normals,  0, -1,  0,  radius);
00512                 add_vertex(vertices,  1, -1, -1,  normals,  0, -1,  0,  radius);
00513                 add_vertex(vertices, -1, -1, -1,  normals,  0, -1,  0,  radius);
00514 
00515                 
00516                 add_vertex(vertices, -1, -1, -1,  normals,  0,  0, -1,  radius);
00517                 add_vertex(vertices,  1, -1, -1,  normals,  0,  0, -1,  radius);
00518                 add_vertex(vertices,  1,  1, -1,  normals,  0,  0, -1,  radius);
00519                 add_vertex(vertices, -1,  1, -1,  normals,  0,  0, -1,  radius);
00520             } 
00521 
00522 
00523             void checkered_box::draw(gsgl::scenegraph::context *c)
00524             {
00525                 glPushAttrib(GL_ALL_ATTRIB_BITS);                                                                   CHECK_GL_ERRORS();
00526                 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);                                                      CHECK_GL_ERRORS();
00527 
00528                 glEnableClientState(GL_VERTEX_ARRAY);                                                               CHECK_GL_ERRORS();
00529                 glEnableClientState(GL_NORMAL_ARRAY);                                                               CHECK_GL_ERRORS();
00530 
00531                 platform::color cc(0.8f, 0.8f, 0.8f, 0.8f);
00532                 glColor4fv(cc.get_val());
00533 
00534                 glEnable(GL_LIGHTING);                                                                              CHECK_GL_ERRORS();
00535 
00536                 glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);                                                CHECK_GL_ERRORS();
00537                 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);                                                    CHECK_GL_ERRORS();
00538 
00539                 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cc.get_val());                                       CHECK_GL_ERRORS();
00540                 glMaterialfv(GL_FRONT, GL_SPECULAR, color::BLACK.get_val());                                        CHECK_GL_ERRORS();
00541                 glMaterialfv(GL_FRONT, GL_EMISSION, color::BLACK.get_val());                                        CHECK_GL_ERRORS();
00542                 glMaterialf(GL_FRONT, GL_SHININESS, 8);                                                             CHECK_GL_ERRORS();
00543 
00544                 normals.bind();
00545                 glNormalPointer(GL_FLOAT, 0, 0);                                                                    CHECK_GL_ERRORS();
00546 
00547                 vertices.bind();
00548                 glVertexPointer(3, GL_FLOAT, 0, 0);                                                                 CHECK_GL_ERRORS();
00549 
00550                 glDrawArrays(GL_QUADS, 0, vertices.size()/3);                                                       CHECK_GL_ERRORS();
00551 
00552                 glPopClientAttrib();                                                                                CHECK_GL_ERRORS();
00553                 glPopAttrib();                                                                                      CHECK_GL_ERRORS();
00554             } 
00555 
00556 
00557             void checkered_box::update(gsgl::scenegraph::context *c)
00558             {
00559                 node::update(c);
00560             } 
00561 
00562 
00563             void checkered_box::cleanup(gsgl::scenegraph::context *c)
00564             {
00565                 node::cleanup(c);
00566 
00567                 normals.unload();
00568                 vertices.unload();
00569             } 
00570 
00571 
00572             gsgl::real_t checkered_box::get_priority(gsgl::scenegraph::context *)
00573             {
00574                 return node::NODE_DRAW_TRANSLUCENT;
00575             } 
00576 
00577 
00578             gsgl::real_t checkered_box::max_extent() const
00579             {
00580                 return radius*2;
00581             } 
00582 
00583             gsgl::real_t checkered_box::default_view_distance() const
00584             {
00585                 return radius - 1.0f;
00586             }
00587 
00588             gsgl::real_t checkered_box::minimum_view_distance() const
00589             {
00590                 return 1.0f;
00591             }
00592 
00593         } 
00594 
00595     } 
00596 
00597 }