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 }