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 "space/spherical_clipmap.hpp"
00035
00036 #include "math/quaternion.hpp"
00037 #include "platform/vbuffer.hpp"
00038 #include "platform/lowlevel.hpp"
00039
00040 #include <cmath>
00041
00042 using namespace gsgl;
00043 using namespace gsgl::data;
00044 using namespace gsgl::math;
00045 using namespace gsgl::platform;
00046 using namespace gsgl::scenegraph;
00047
00048
00049 namespace periapsis
00050 {
00051
00052 namespace space
00053 {
00054
00055 class clipmap_ring
00056 {
00057 public:
00058 spherical_clipmap *parent;
00059 clipmap_ring *prev, *next;
00060
00061 int level;
00062 double start_phi;
00063 double end_phi;
00064
00065 data::array<gsgl::real_t> geographical_lon_and_lat;
00066 data::array<gsgl::real_t> geographical_x_and_y;
00067
00068 vertex_buffer vertices;
00069 vertex_buffer normals;
00070 index_buffer indices;
00071
00072 clipmap_ring(spherical_clipmap *parent, int level);
00073 clipmap_ring(spherical_clipmap *parent, double start_phi, double end_phi);
00074 ~clipmap_ring();
00075
00076 void init();
00077 void draw();
00078 };
00079
00080
00081 clipmap_ring::clipmap_ring(spherical_clipmap *parent, int level)
00082 : parent(parent), prev(0), next(0), start_phi(0), end_phi(0), vertices(vbuffer::STATIC), indices(vbuffer::STATIC)
00083 {
00084 assert(level > 0);
00085
00086 start_phi = ::pow(2.0, -level) * math::PI;
00087 end_phi = ::pow(2.0, -level-1) * math::PI;
00088
00089 init();
00090 }
00091
00092
00093 clipmap_ring::clipmap_ring(spherical_clipmap *parent, double start_phi, double end_phi)
00094 : parent(parent), prev(0), next(0), level(0), start_phi(start_phi), end_phi(end_phi), vertices(vbuffer::DYNAMIC), indices(vbuffer::DYNAMIC)
00095 {
00096
00097 }
00098
00099
00100 clipmap_ring::~clipmap_ring()
00101 {
00102 }
00103
00104
00105 static const int PHI_STEPS = 8;
00106 static const int THETA_STEPS = 32;
00107
00108 void clipmap_ring::init()
00109 {
00110
00111 geographical_lon_and_lat.clear();
00112
00113 for (int lat = 0; lat <= PHI_STEPS; ++lat)
00114 {
00115 double phi = 0;
00116
00117 if (level)
00118 {
00119 double exp = static_cast<double>(-lat) / static_cast<double>(PHI_STEPS);
00120 phi = start_phi * ::pow(2.0, exp);
00121 }
00122 else
00123 {
00124 double delta_phi = (start_phi - end_phi) / static_cast<double>(PHI_STEPS);
00125 phi = start_phi - delta_phi * lat;
00126 }
00127
00128 for (int lon = 0; lon <= THETA_STEPS; ++lon)
00129 {
00130 double theta = (static_cast<double>(lon) / static_cast<double>(THETA_STEPS)) * math::PI_TIMES_2;
00131
00132
00133 geographical_lon_and_lat.append(static_cast<gsgl::real_t>(theta));
00134 geographical_lon_and_lat.append(static_cast<gsgl::real_t>(phi));
00135
00136
00137
00138 }
00139 }
00140
00141
00142 if (indices.size() == 0)
00143 {
00144 unsigned int stride = THETA_STEPS+1;
00145 for (unsigned int j = 0; j < PHI_STEPS; ++j)
00146 {
00147 for (unsigned int i = 0; i <= THETA_STEPS; ++i)
00148 {
00149 indices.append((j+1)*stride + i);
00150 indices.append(j*stride + i);
00151 }
00152 }
00153 }
00154 }
00155
00156
00157 void clipmap_ring::draw()
00158 {
00159 vertices.bind();
00160 glVertexPointer(2, GL_FLOAT, 0, 0); CHECK_GL_ERRORS();
00161
00162 indices.bind();
00163
00164 int index_stride = (THETA_STEPS+1)*2;
00165 for (int i = 0; i < PHI_STEPS; ++i)
00166 {
00167 glDrawElements(GL_TRIANGLE_STRIP, index_stride, GL_UNSIGNED_INT, vbuffer::VBO_OFFSET(i*index_stride*sizeof(unsigned int))); CHECK_GL_ERRORS();
00168 }
00169 }
00170
00171
00172 void clipmap_ring::update()
00173 {
00174 }
00175
00176
00177
00178
00179 spherical_clipmap::spherical_clipmap(gsgl::real_t polar_radius, gsgl::real_t equatorial_radius)
00180 : polar_radius(polar_radius), equatorial_radius(equatorial_radius), first_ring(0), last_ring(0), clipmap_cap(0)
00181 {
00182 clipmap_cap = new clipmap_ring(this, 0, 0);
00183 }
00184
00185
00186 spherical_clipmap::~spherical_clipmap()
00187 {
00188 for (int i = 0; i < clipmap_rings.size(); ++i)
00189 {
00190 delete clipmap_rings[i];
00191 }
00192
00193 delete clipmap_cap;
00194 }
00195
00196
00197 void spherical_clipmap::init(context *)
00198 {
00199 }
00200
00201
00202 void spherical_clipmap::update(const transform & modelview, gsgl::real_t field_of_view, int screen_height)
00203 {
00204
00205 double radius = gsgl::min_val(polar_radius, equatorial_radius);
00206
00207 vector pt_in_eye_space = modelview * vector::ZERO;
00208 double altitude = pt_in_eye_space.mag() - radius;
00209 if (altitude < 1)
00210 altitude = 1;
00211
00212 double max_phi = ::acos(radius / (radius + altitude));
00213 double min_phi = 100.0 * altitude * ::tan(field_of_view * math::DEG2RAD / static_cast<double>(screen_height)) / radius;
00214
00215
00216 first_ring = 0;
00217 while (true)
00218 {
00219 while (first_ring >= clipmap_rings.size())
00220 clipmap_rings.append(new clipmap_ring(this, clipmap_rings.size()+1));
00221
00222 clipmap_ring *cur_ring = clipmap_rings[first_ring];
00223 if (cur_ring->start_phi > max_phi && cur_ring->end_phi < max_phi)
00224 break;
00225 else
00226 ++first_ring;
00227 }
00228
00229
00230 last_ring = 0;
00231 while (true)
00232 {
00233 while (last_ring >= clipmap_rings.size())
00234 clipmap_rings.append(new clipmap_ring(this, clipmap_rings.size()+1));
00235
00236 clipmap_ring *cur_ring = clipmap_rings[last_ring];
00237 if (cur_ring->end_phi < min_phi)
00238 break;
00239 else
00240 ++last_ring;
00241 }
00242
00243
00244 if (clipmap_cap->start_phi != clipmap_rings[last_ring]->end_phi)
00245 {
00246 clipmap_cap->start_phi = clipmap_rings[last_ring]->end_phi;
00247 clipmap_cap->init();
00248 }
00249
00250
00251 for (int i = 0; i < clipmap_rings.size(); ++i)
00252 {
00253 clipmap_rings[i]->prev = (i > 0) ? clipmap_rings[i-1] : 0;
00254 clipmap_rings[i]->next = (i < clipmap_rings.size()-1) ? clipmap_rings[i+1] : 0;
00255 }
00256
00257 clipmap_cap->prev = clipmap_rings[last_ring];
00258 clipmap_cap->prev->next = clipmap_cap;
00259 }
00260
00261
00262 static const color GRAY(0.6f, 0.6f, 0.6f);
00263
00264
00265 void spherical_clipmap::draw(context *c)
00266 {
00267
00268 if (clipmap_rings.size())
00269 {
00270 glPushAttrib(GL_ALL_ATTRIB_BITS);
00271 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
00272
00273 glEnableClientState(GL_VERTEX_ARRAY);
00274 glEnableClientState(GL_INDEX_ARRAY);
00275
00276 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
00277
00278 color::WHITE.set();
00279
00280 for (int i = 0; i <= last_ring; ++i)
00281 {
00282 if (i >= first_ring)
00283 clipmap_rings[i]->draw();
00284
00285 if (c->render_flags & context::RENDER_WIREFRAME)
00286 {
00287 if (i % 2)
00288 color::WHITE.set();
00289 else
00290 GRAY.set();
00291 }
00292 }
00293
00294 clipmap_cap->draw();
00295
00296
00297 glPopClientAttrib();
00298 glPopAttrib();
00299 }
00300 }
00301
00302
00303 }
00304
00305 }
00306
00307
00308
00309
00310
00311
00312 #if 0
00313
00314 static const int PHI_STEPS = 8;
00315 static const int THETA_STEPS = 128;
00316
00317
00318 class clipmap_ring
00319 {
00320 public:
00321 spherical_clipmap *parent;
00322 clipmap_ring *prev, *next;
00323
00324 heightmap *hmap;
00325 double map_offset;
00326
00327 int level;
00328 double start_phi, end_phi;
00329
00330 double old_view_phi, old_view_theta;
00331
00332 quaternion roty, roty_conj;
00333 quaternion rotz, rotz_conj;
00334
00335 int vbuf_id, ibuf_id;
00336 array<double> cbuf;
00337 array<float> vbuf;
00338 array<unsigned int> ibuf;
00339
00340 clipmap_ring(spherical_clipmap *parent, int level, heightmap *hmap, double map_offset);
00341 clipmap_ring(spherical_clipmap *parent, double start_phi, double end_phi, heightmap *hmap, double map_offset);
00342 ~clipmap_ring();
00343
00344 void update(const vector & eye_dir);
00345 void draw();
00346
00347 void generate_vertices();
00348 void generate_indices();
00349 void repair_quad(unsigned int *indices);
00350
00351 vector get_vertex(int i, int j);
00352 void generate_normals();
00353 };
00354
00355
00356 clipmap_ring::clipmap_ring(spherical_clipmap *parent, int level, heightmap *hmap, double map_offset)
00357 : parent(parent), prev(0), next(0), hmap(hmap), map_offset(map_offset), start_phi(0), end_phi(0), old_view_phi(12345), old_view_theta(12345), vbuf_id(0), ibuf_id(0)
00358 {
00359 assert(level > 0);
00360
00361 start_phi = ::pow(2.0, -level) * math::PI;
00362 end_phi = ::pow(2.0, -level-1) * math::PI;
00363 }
00364
00365 clipmap_ring::clipmap_ring(spherical_clipmap *parent, double start_phi, double end_phi, heightmap *hmap, double map_offset)
00366 : parent(parent), prev(0), next(0), hmap(hmap), map_offset(map_offset), level(0), start_phi(start_phi), end_phi(end_phi), old_view_phi(12345), old_view_theta(12345), vbuf_id(0), ibuf_id(0)
00367 {
00368 }
00369
00370
00371 clipmap_ring::~clipmap_ring()
00372 {
00373 if (vbuf_id)
00374 glDeleteBuffers(1, (GLuint *) &vbuf_id);
00375 if (ibuf_id)
00376 glDeleteBuffers(1, (GLuint *) &ibuf_id);
00377 }
00378
00379
00380 void clipmap_ring::generate_vertices()
00381 {
00382
00383 cbuf.clear();
00384 vbuf.clear();
00385
00386 double delta_theta = 2.0 * math::PI / static_cast<double>(THETA_STEPS);
00387
00388 for (int j = 0; j <= PHI_STEPS; ++j)
00389 {
00390 double eye_phi = 0;
00391
00392 if (level)
00393 {
00394 double exp = static_cast<double>(-j) / static_cast<double>(PHI_STEPS);
00395 eye_phi = start_phi * ::pow(2.0, exp);
00396 }
00397 else
00398 {
00399 double delta_phi = (start_phi - end_phi) / static_cast<double>(PHI_STEPS);
00400 eye_phi = start_phi - delta_phi * static_cast<double>(j);
00401 }
00402
00403
00404 for (int i = 0; i <= THETA_STEPS; ++i)
00405 {
00406 double eye_theta = delta_theta * static_cast<double>(i);
00407
00408 double eye_x = ::cos(eye_theta) * ::sin(eye_phi);
00409 double eye_y = ::sin(eye_theta) * ::sin(eye_phi);
00410 double eye_z = ::cos(eye_phi);
00411
00412 quaternion eye_point(0, eye_x, eye_y, eye_z);
00413 quaternion yrot_point = (roty * eye_point) * roty_conj;
00414 quaternion obj_point = (rotz * yrot_point) * rotz_conj;
00415
00416 double obj_x = obj_point.x;
00417 double obj_y = obj_point.y;
00418 double obj_z = obj_point.z;
00419
00420 double obj_phi = ::acos(obj_z);
00421 double obj_theta = ::atan2(obj_y, obj_x) + (map_offset * math::PI_TIMES_2);
00422 if (obj_theta < 0.0)
00423 obj_theta += math::PI_TIMES_2;
00424
00425 cbuf.append(obj_phi);
00426 cbuf.append(obj_theta);
00427
00428 float s = static_cast<float>(obj_theta / math::PI_TIMES_2);
00429 float t = 1.0f - static_cast<float>(obj_phi / math::PI);
00430
00431 float nx = static_cast<float>(obj_x);
00432 float ny = static_cast<float>(obj_y);
00433 float nz = static_cast<float>(obj_z);
00434
00435 float x = parent->get_equatorial_radius() * nx;
00436 float y = parent->get_equatorial_radius() * ny;
00437 float z = parent->get_polar_radius() * nz;
00438
00439 if (hmap)
00440 {
00441 double hval, alpha;
00442 hmap->get_data(s, t, hval, alpha);
00443
00444 vector old_vertex(x, y, z);
00445 vector normal(nx, ny, nz);
00446
00447 gsgl::real_t alt = static_cast<gsgl::real_t>(hval * hmap->get_altitude());
00448
00449 vector new_vertex = old_vertex + normal*alt;
00450
00451 x = new_vertex[0];
00452 y = new_vertex[1];
00453 z = new_vertex[2];
00454 }
00455
00456 vbuf.append(s);
00457 vbuf.append(t);
00458 vbuf.append(nx);
00459 vbuf.append(ny);
00460 vbuf.append(nz);
00461 vbuf.append(x);
00462 vbuf.append(y);
00463 vbuf.append(z);
00464 }
00465 }
00466 }
00467
00468
00469 vector clipmap_ring::get_vertex(int i, int j)
00470 {
00471 clipmap_ring *rp = this;
00472
00473 if (j < 0)
00474 {
00475 if (prev)
00476 {
00477 rp = prev;
00478 j = PHI_STEPS + j;
00479 }
00480 else
00481 {
00482 j = 0;
00483 }
00484 }
00485 else if (j > PHI_STEPS)
00486 {
00487 if (next)
00488 {
00489 rp = next;
00490 j = j - PHI_STEPS;
00491 }
00492 else if (rp->level == 0)
00493 {
00494 j = PHI_STEPS-1;
00495 i += THETA_STEPS;
00496 }
00497 else
00498 {
00499 j = PHI_STEPS;
00500 }
00501 }
00502
00503 if (i < 0)
00504 i = i + THETA_STEPS;
00505 else if (i > THETA_STEPS)
00506 i = i - THETA_STEPS;
00507
00508
00509 int index = i + j*(THETA_STEPS+1);
00510
00511 float x = rp->vbuf[index*8 + 5];
00512 float y = rp->vbuf[index*8 + 6];
00513 float z = rp->vbuf[index*8 + 7];
00514
00515 return vector(x, y, z);
00516 }
00517
00518
00519 void clipmap_ring::generate_normals()
00520 {
00521 for (int j = 0; j <= PHI_STEPS; ++j)
00522 {
00523 for (int i = 0; i <= THETA_STEPS; ++i)
00524 {
00525 int index = i + j*(THETA_STEPS+1);
00526
00527 vector x0 = get_vertex(i-1, j);
00528 vector x1 = get_vertex(i, j);
00529 vector x2 = get_vertex(i+1, j);
00530
00531 vector xx = x2 - x0;
00532
00533 vector y0 = get_vertex(i, j-1);
00534 vector y1 = get_vertex(i, j);
00535 vector y2 = get_vertex(i, j+1);
00536
00537 vector yy = y2 - y0;
00538
00539 vector nn = xx.cross(yy);
00540 nn.normalize();
00541
00542 vbuf[index*8 + 2] = nn[0];
00543 vbuf[index*8 + 3] = nn[1];
00544 vbuf[index*8 + 4] = nn[2];
00545 }
00546 }
00547 }
00548
00549
00550 void clipmap_ring::generate_indices()
00551 {
00552 unsigned int indices[4];
00553
00554 ibuf.clear();
00555
00556 for (int j = 0; j < PHI_STEPS; ++j)
00557 {
00558 for (int i = 0; i < THETA_STEPS; ++i)
00559 {
00560 indices[0] = static_cast<unsigned int>( (j+0) * (THETA_STEPS+1) + (i+0) );
00561 indices[1] = static_cast<unsigned int>( (j+0) * (THETA_STEPS+1) + (i+1) );
00562 indices[2] = static_cast<unsigned int>( (j+1) * (THETA_STEPS+1) + (i+1) );
00563 indices[3] = static_cast<unsigned int>( (j+1) * (THETA_STEPS+1) + (i+0) );
00564
00565 repair_quad(indices);
00566
00567 ibuf.append(indices[0]);
00568 ibuf.append(indices[1]);
00569 ibuf.append(indices[3]);
00570
00571 ibuf.append(indices[2]);
00572 ibuf.append(indices[3]);
00573 ibuf.append(indices[1]);
00574 }
00575 }
00576 }
00577
00578
00579 void clipmap_ring::repair_quad(unsigned int *indices)
00580 {
00581 int quadrant_one = 0;
00582 int quadrant_four = 0;
00583
00584 for (int i = 0; i < 4; ++i)
00585 {
00586 double theta = cbuf[ indices[i]*2 + 1 ];
00587 if (theta < math::PI_TIMES_2 && theta > math::PI * 0.75)
00588 quadrant_four++;
00589 else if (theta < math::PI_OVER_2)
00590 quadrant_one++;
00591 }
00592
00593
00594 if (quadrant_one && quadrant_four)
00595 {
00596 for (int i = 0; i < 4; ++i)
00597 {
00598 double phi = cbuf[ indices[i]*2 + 0 ];
00599 double theta = cbuf[ indices[i]*2 + 1 ];
00600 if (theta > math::PI * 0.75)
00601 theta -= math::PI_TIMES_2;
00602
00603 unsigned int orig_index = indices[i];
00604 unsigned int new_index = vbuf.size() / 8;
00605 indices[i] = new_index;
00606
00607 float s = static_cast<float>(theta / math::PI_TIMES_2);
00608 float t = 1.0f - static_cast<float>(phi / math::PI);
00609
00610 vbuf.append(s);
00611 vbuf.append(t);
00612 vbuf.append( vbuf[orig_index*8 + 2] );
00613 vbuf.append( vbuf[orig_index*8 + 3] );
00614 vbuf.append( vbuf[orig_index*8 + 4] );
00615 vbuf.append( vbuf[orig_index*8 + 5] );
00616 vbuf.append( vbuf[orig_index*8 + 6] );
00617 vbuf.append( vbuf[orig_index*8 + 7] );
00618 }
00619 }
00620 }
00621
00622
00623 static const double VIEW_EPSILON = 0.005;
00624
00625
00626 void clipmap_ring::update(const vector & eye_dir_in_object_space)
00627 {
00628
00629 double view_phi = ::acos(eye_dir_in_object_space[2]);
00630 double view_theta = ::atan2(eye_dir_in_object_space[1], eye_dir_in_object_space[0]);
00631
00632 if ( level && !( (::fabs(view_phi - old_view_phi) > VIEW_EPSILON) || (::fabs(view_theta - old_view_theta) > VIEW_EPSILON) ) )
00633 {
00634 return;
00635 }
00636
00637 old_view_phi = view_phi;
00638 old_view_theta = view_theta;
00639
00640 roty = quaternion(vector::Y_AXIS, view_phi);
00641 roty_conj = roty.conjugate();
00642
00643 rotz = quaternion(vector::Z_AXIS, view_theta);
00644 rotz_conj = rotz.conjugate();
00645
00646
00647 generate_vertices();
00648 generate_indices();
00649
00650
00651 if (!vbuf_id)
00652 {
00653 glGenBuffers(1, (GLuint *) &vbuf_id);
00654 if (!vbuf_id)
00655 throw opengl_exception(__FILE__, __LINE__, L"clipmap_ring unable to generate buffer id: ");
00656 }
00657
00658 if (!ibuf_id)
00659 {
00660 glGenBuffers(1, (GLuint *) &ibuf_id);
00661 if (!ibuf_id)
00662 throw opengl_exception(__FILE__, __LINE__, L"clipmap_ring unable to generate buffer id");
00663 }
00664
00665
00666 glBindBuffer(GL_ARRAY_BUFFER, vbuf_id);
00667 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vbuf.size(), vbuf.ptr(), GL_STREAM_DRAW);
00668
00669 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf_id);
00670 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * ibuf.size(), ibuf.ptr(), GL_STREAM_DRAW);
00671 }
00672
00673
00674 void clipmap_ring::draw()
00675 {
00676 glBindBuffer(GL_ARRAY_BUFFER, vbuf_id);
00677 glInterleavedArrays(GL_T2F_N3F_V3F, 0, 0);
00678
00679 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf_id);
00680 glDrawElements(GL_TRIANGLES, ibuf.size(), GL_UNSIGNED_INT, 0);
00681 }
00682 #endif
00683