00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <iostream>
00012 #include <fstream>
00013
00014 #include "glut-demo/glut-demo.h"
00015 #include "opengl-effects/opengl-effects.h"
00016 #include "perf/perf.h"
00017 #include "wave-glut/frustum.h"
00018 #include "wave-glut/texture.h"
00019
00020
00021
00022 static const float s_bounds = 20.0;
00023
00024 static const int s_nRings = 7;
00025
00026
00027
00028
00029
00030
00031
00032
00033 static float
00034 randomX
00035 (
00036 IN float x
00037 )
00038 {
00039 return (x * rand()) / RAND_MAX;
00040 }
00041
00042
00043
00044 static void
00045 jitter
00046 (
00047 IO point3d_t& p,
00048 IN float dx
00049 )
00050 throw()
00051 {
00052 p.x += randomX(dx) - 0.5 * dx;
00053 p.y += randomX(dx) - 0.5 * dx;
00054 p.z += randomX(dx) - 0.5 * dx;
00055 }
00056
00057
00058
00059 static void
00060 checkLimit
00061 (
00062 IN float& x,
00063 IN float& v
00064 )
00065 throw()
00066 {
00067 if (x < -s_bounds) {
00068 x = -s_bounds;
00069 if (v < 0) {
00070 v = -v;
00071 }
00072 } else if (x > s_bounds) {
00073 x = s_bounds;
00074 if (v > 0) {
00075 v = -v;
00076 }
00077 }
00078 }
00079
00080
00081
00082 struct ring_t {
00083 ring_t(void) throw() {
00084 gamma = 1.01 + randomX(0.06);
00085
00086 axis.x = -1.0 + randomX(2.0);
00087 axis.y = -1.0 + randomX(2.0);
00088 axis.z = -1.0 + randomX(2.0);
00089 normalize(axis);
00090
00091 phi = randomX(2.0 * M_PI);
00092 dPhi = 5 + randomX(10);
00093 }
00094
00095 void tick(void) throw() {
00096 phi += dPhi;
00097 }
00098
00099
00100 float gamma;
00101 point3d_t axis;
00102 float phi;
00103 float dPhi;
00104 };
00105
00106
00107 static void
00108 drawLightningRing
00109 (
00110 IN const point3d_t& center,
00111 IN float radius,
00112 IN const point3d_t& axis,
00113 IN float phi,
00114 IN const glut_color_t& color
00115 )
00116 throw()
00117 {
00118 ASSERT(radius > 0, "bad radius: %f", radius);
00119 int nPoints = 16;
00120 ASSERT(nPoints > 1, "need at least 2!");
00121
00122
00123 glMatrixMode(GL_MODELVIEW);
00124 glPushMatrix();
00125 glTranslatef(center.x, center.y, center.z);
00126 glRotatef(phi, axis.x, axis.y, axis.z);
00127
00128 float theta = 0;
00129 float dTheta = 2.0 * M_PI / (nPoints - 1);
00130
00131 const float dJitter = 0.4;
00132
00133 glDisable(GL_LIGHTING);
00134 glColor4fv(&color.red);
00135 glBegin(GL_LINE_LOOP);
00136 for (int i = 0; i < nPoints; ++i) {
00137 float mu = theta + randomX(dJitter) - 0.5 * dJitter;
00138 float nu = randomX(dJitter) - 0.5 * dJitter;
00139 point3d_t p(cos(mu) * cos(nu), sin(nu), sin(mu) * cos(nu));
00140 p *= radius;
00141 glVertex3fv(&p.x);
00142 theta += dTheta;
00143 }
00144 glEnd();
00145 glEnable(GL_LIGHTING);
00146
00147 glPopMatrix();
00148 }
00149
00150
00151
00152 struct cool_sphere_t {
00153 cool_sphere_t(void) throw() {
00154 radius = 0.5 + randomX(0.5);
00155
00156 position.x = -10 + randomX(20);
00157 position.y = -10 + randomX(20);
00158 position.z = -10 + randomX(20);
00159
00160 const float vMax = 0.2;
00161 velocity.x = -vMax + randomX(2.0 * vMax);
00162 velocity.y = -vMax + randomX(2.0 * vMax);
00163 velocity.z = -vMax + randomX(2.0 * vMax);
00164
00165 phi = randomX(2.0 * M_PI);
00166 dPhi = -5 + randomX(10);
00167
00168 img_color_t c;
00169 c.red = (byte_t) (20 + randomX(235));
00170 c.green = (byte_t) (20 + randomX(235));
00171 c.blue = (byte_t) (20 + randomX(235));
00172 c.alpha = 128;
00173
00174
00175
00176
00177
00178
00179
00180 media::image_t img;
00181 glut::createSphericalDensityMap(40, c, img);
00182
00183
00184 textureId = glut::createTextureFromImage(img);
00185 DPRINTF("Texture ID: %d", textureId);
00186 }
00187
00188 ~cool_sphere_t(void) throw() {
00189 if (textureId) {
00190 glDeleteTextures(1, &textureId);
00191 }
00192 }
00193
00194 bool isValid(void) const throw() {
00195 return (radius > 0 && textureId);
00196 }
00197
00198 void reset(void) throw() {
00199 position.clear();
00200 velocity.clear();
00201 }
00202
00203 void tick(void) throw() {
00204
00205 position += velocity;
00206 phi += dPhi;
00207
00208
00209 checkLimit(position.x, velocity.x);
00210 checkLimit(position.y, velocity.y);
00211 checkLimit(position.z, velocity.z);
00212
00213
00214 for (int i = 0; i < s_nRings; ++i) {
00215 rings[i].tick();
00216 }
00217 }
00218
00219
00220 float radius;
00221 float phi;
00222 float dPhi;
00223 point3d_t position;
00224 point3d_t velocity;
00225 ring_t rings[s_nRings];
00226 GLuint textureId;
00227 };
00228
00229
00230
00231 struct sort_entry_t {
00232 cool_sphere_t * sphere;
00233 float d2;
00234 };
00235
00236
00237
00238 static int
00239 compareSpheres
00240 (
00241 IN const void * p1,
00242 IN const void * p2
00243 )
00244 throw()
00245 {
00246 const sort_entry_t * se1 = (const sort_entry_t *) p1;
00247 const sort_entry_t * se2 = (const sort_entry_t *) p2;
00248 ASSERT(se1 && se2, "null");
00249
00250 if (se1->d2 < se2->d2)
00251 return -1;
00252 if (se1->d2 > se2->d2)
00253 return +1;
00254 return 0;
00255 }
00256
00257
00258
00259 static void
00260 drawCoolSphere
00261 (
00262 IN const cool_sphere_t& sphere,
00263 IN const glut::render_context_t& rc,
00264 IN glut::RenderQueue * rq
00265 )
00266 throw()
00267 {
00268 ASSERT(sphere.isValid(), "sphere is invalid?");
00269 ASSERT(rq, "null");
00270
00271
00272 glMatrixMode(GL_MODELVIEW);
00273 glPushMatrix();
00274 glTranslatef(sphere.position.x, sphere.position.y, sphere.position.z);
00275 glRotatef(sphere.phi, 0, 1, 0);
00276 glutSolidSphere(sphere.radius, 16, 16);
00277 glPopMatrix();
00278
00279
00280 for (int i = 0; i < s_nRings; ++i) {
00281 const ring_t& r = sphere.rings[i];
00282 drawLightningRing(sphere.position, r.gamma * sphere.radius,
00283 r.axis, r.phi, glut_color_t(1, 1, 1, 1));
00284 }
00285
00286
00287 point3d_t to = sphere.position - rc.viewer.getPosition();
00288 float z2 = dotProduct(to, to);
00289 if (z2 < 1.0e-4)
00290 return;
00291 float z = sqrt(z2);
00292 to = (1.0 / z) * to;
00293
00294
00295 point3d_t up = rc.viewer.getUp();
00296 point3d_t right = crossProduct(to, up);
00297 normalize(right);
00298
00299
00300 point3d_t realUp = -crossProduct(to, right);
00301 normalize(realUp);
00302
00303
00304 glut::poly_request_t * pr = rq->grabRequestSlot();
00305 if (!pr) {
00306 DPRINTF("No available request slots?");
00307 return;
00308 }
00309
00310 matrix4_t T;
00311 glut::getModelViewMatrix(T);
00312
00313
00314
00315
00316
00317
00318
00319 float beta = 1.25;
00320 float gamma = 1.1;
00321 float alpha = beta * (z - gamma * sphere.radius) / z;
00322
00323
00324
00325 float scale = alpha * sphere.radius;
00326 point3d_t mid = sphere.position - gamma * sphere.radius * to;
00327
00328
00329 pr->nVertices = 4;
00330 pr->textureId = sphere.textureId;
00331 pr->normal = -to;
00332
00333 pr->vertex[0] = T * (mid + scale * (-up + right));
00334 pr->u[0] = 0;
00335 pr->v[0] = 0;
00336
00337 pr->vertex[1] = T * (mid + scale * ( up + right));
00338 pr->u[1] = 0;
00339 pr->v[1] = 1;
00340
00341 pr->vertex[2] = T * (mid + scale * ( up - right));
00342 pr->u[2] = 1;
00343 pr->v[2] = 1;
00344
00345 pr->vertex[3] = T * (mid + scale * (-up - right));
00346 pr->u[3] = 1;
00347 pr->v[3] = 0;
00348 }
00349
00350
00351
00352 class Drawer : public glut::DemoHost {
00353 public:
00354 Drawer(IN int nSpheres) throw() : m_nSpheres(nSpheres) { }
00355 ~Drawer(void) throw() { }
00356
00357
00358 void onInit(void) {
00359 m_spheres.reserve(m_nSpheres);
00360 m_sorting.reserve(m_nSpheres);
00361 for (int i = 0; i < m_nSpheres; ++i) {
00362 smart_ptr<cool_sphere_t> sphere =
00363 new cool_sphere_t;
00364 ASSERT(sphere, "out of memory");
00365
00366
00367 m_spheres.push_back(sphere);
00368
00369
00370 sort_entry_t se;
00371 m_sorting.push_back(se);
00372 }
00373 }
00374
00375 void display3D(IN const glut::render_context_t& rc,
00376 IN glut::RenderQueue * rq) {
00377 ASSERT(rq, "null");
00378
00379 ASSERT(m_nSpheres == (int) m_spheres.size(),
00380 "size mismatch!");
00381 ASSERT(m_nSpheres == (int) m_sorting.size(),
00382 "size mismatch!");
00383
00384
00385 frustum_t f;
00386 glut::getViewFrustum(rc.camera, rc.viewer, f);
00387
00388
00389 int nVisible = 0;
00390 const point3d_t& viewPosition = rc.viewer.getPosition();
00391 for (int i = 0; i < m_nSpheres; ++i) {
00392 cool_sphere_t * sphere = m_spheres[i];
00393 ASSERT(sphere, "null sphere in array");
00394 sphere->tick();
00395
00396 rect3d_t r;
00397 r.getBoundingRectForSphere(sphere->position,
00398 sphere->radius);
00399 if (!(eContains_HitMask & f.containsRect(r))) {
00400
00401
00402 continue;
00403 }
00404
00405 sort_entry_t& se = m_sorting[nVisible];
00406 point3d_t diff = sphere->position - viewPosition;
00407 se.sphere = sphere;
00408 se.d2 = dotProduct(diff, diff);
00409 nVisible++;
00410 }
00411 ASSERT(nVisible <= m_nSpheres, "mismatch");
00412
00413
00414 qsort(&m_sorting[0], nVisible,
00415 sizeof(sort_entry_t), compareSpheres);
00416
00417
00418 for (int i = 0; i < nVisible; ++i) {
00419 sort_entry_t& se = m_sorting[i];
00420 ASSERT(se.sphere, "null");
00421
00422 drawCoolSphere(*se.sphere, rc, rq);
00423 }
00424 }
00425
00426 private:
00427
00428 typedef std::vector<smart_ptr<cool_sphere_t> > vec_sphere_t;
00429 typedef std::vector<sort_entry_t> vec_sort_t;
00430
00431
00432 int m_nSpheres;
00433 vec_sphere_t m_spheres;
00434 vec_sort_t m_sorting;
00435 };
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 int
00446 main
00447 (
00448 IN int argc,
00449 IN const char * argv[]
00450 )
00451 {
00452 ASSERT(2 == argc, "Usage: opengl-effects-sphere <nSpheres>\n");
00453 int nSpheres = atoi(argv[1]);
00454 ASSERT(nSpheres > 0, "Bad sphere count: %d", nSpheres);
00455
00456 try {
00457
00458 std::string title = "OpenGL Effects Test -- Spheres";
00459
00460
00461 smart_ptr<glut::DemoHost> host = new Drawer(nSpheres);
00462 ASSERT(host, "out of memory");
00463 glut::startDemo(argc, argv, title.c_str(), host);
00464
00465 } catch (std::exception& e) {
00466 DPRINTF("Exception: %s", e.what());
00467 }
00468
00469
00470 return -1;
00471 }
00472