00001
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
00033
00034 #ifndef GROOVX_GFX_GLCANVAS_CC_UTC20050626084024_DEFINED
00035 #define GROOVX_GFX_GLCANVAS_CC_UTC20050626084024_DEFINED
00036
00037 #include "glcanvas.h"
00038
00039 #include "geom/projection.h"
00040 #include "geom/rect.h"
00041 #include "geom/txform.h"
00042 #include "geom/vec2.h"
00043 #include "geom/vec3.h"
00044
00045 #include "gfx/glwindowinterface.h"
00046 #include "gfx/glxopts.h"
00047 #include "gfx/gxrasterfont.h"
00048 #include "gfx/gxvectorfont.h"
00049 #include "gfx/rgbacolor.h"
00050
00051 #include "media/bmapdata.h"
00052
00053 #include "rutz/error.h"
00054 #include "rutz/sfmt.h"
00055 #include "rutz/shared_ptr.h"
00056
00057 #include <vector>
00058
00059 #if defined(GVX_GL_PLATFORM_GLX)
00060 # include <GL/gl.h>
00061 # include <GL/glu.h>
00062 #elif defined(GVX_GL_PLATFORM_AGL)
00063 # include <AGL/gl.h>
00064 # include <AGL/glu.h>
00065 #endif
00066
00067 #include "rutz/trace.h"
00068 #include "rutz/debug.h"
00069 GVX_DBG_REGISTER
00070
00071 using geom::recti;
00072 using geom::rectd;
00073 using geom::txform;
00074 using geom::vec2i;
00075 using geom::vec2d;
00076 using geom::vec3i;
00077 using geom::vec3d;
00078
00079 using rutz::shared_ptr;
00080
00081 namespace
00082 {
00083 nub::soft_ref<GLCanvas> theCurrentCanvas;
00084
00085 GLint attribStackDepth()
00086 {
00087 GLint d = -1;
00088 glGetIntegerv(GL_ATTRIB_STACK_DEPTH, &d);
00089 return d;
00090 }
00091
00092 bool rasterPositionValid() throw()
00093 {
00094 GLboolean value = GL_FALSE;
00095 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &value);
00096 return (value == GL_TRUE);
00097 }
00098
00099 geom::span<double> rawGepthRange()
00100 {
00101 GVX_TRACE("<glcanvas.cc>::depthRange");
00102 GLdouble vals[2];
00103 glGetDoublev(GL_DEPTH_RANGE, &vals[0]);
00104 return geom::span<double>(vals[0], vals[1]);
00105 }
00106
00107 txform rawGetModelview()
00108 {
00109 GVX_TRACE("<glcanvas.cc>::rawGetModelview");
00110 GLdouble m[16];
00111 glGetDoublev(GL_MODELVIEW_MATRIX, &m[0]);
00112 return txform::copy_of(&m[0]);
00113 }
00114
00115 txform rawGetProjection()
00116 {
00117 GVX_TRACE("<glcanvas.cc>::rawGetProjection");
00118 GLdouble m[16];
00119 glGetDoublev(GL_PROJECTION_MATRIX, &m[0]);
00120 return txform::copy_of(&m[0]);
00121 }
00122
00123 vec3d unproject1(const txform& modelview,
00124 const txform& projection,
00125 const recti& viewport,
00126 const vec3d& screen)
00127 {
00128 GVX_TRACE("<glcanvas.cc>::unproject1");
00129
00130 const GLint v[4] = { viewport.left(), viewport.bottom(),
00131 viewport.width(), viewport.height() };
00132
00133 vec3d world_pos;
00134
00135 GLint status =
00136 gluUnProject(screen.x(), screen.y(), screen.z(),
00137 modelview.col_major_data(),
00138 projection.col_major_data(),
00139 &v[0],
00140 &world_pos.x(), &world_pos.y(), &world_pos.z());
00141
00142 dbg_eval_nl(3, status);
00143
00144 if (status == GL_FALSE)
00145 throw rutz::error("gluUnProject error", SRC_POS);
00146
00147 return world_pos;
00148 }
00149
00150 vec3d project1(const txform& modelview,
00151 const txform& projection,
00152 const recti& viewport,
00153 const vec3d& world_pos)
00154 {
00155 GVX_TRACE("<glcanvas.cc>::project1");
00156
00157 const GLint v[4] = { viewport.left(), viewport.bottom(),
00158 viewport.width(), viewport.height() };
00159
00160 vec3d screen_pos;
00161
00162 GLint status =
00163 gluProject(world_pos.x(), world_pos.y(), world_pos.z(),
00164 modelview.col_major_data(),
00165 projection.col_major_data(),
00166 &v[0],
00167 &screen_pos.x(), &screen_pos.y(), &screen_pos.z());
00168
00169 dbg_eval_nl(3, status);
00170
00171 if (status == GL_FALSE)
00172 throw rutz::error("GLCanvas::screenFromWorld3(): gluProject error",
00173 SRC_POS);
00174
00175 return screen_pos;
00176 }
00177 }
00178
00179 class GLCanvas::Impl
00180 {
00181 public:
00182 Impl(shared_ptr<GlxOpts> opts_, shared_ptr<GlWindowInterface> glx_) :
00183 opts(opts_),
00184 glx(glx_),
00185 modelviewCache(),
00186 projectionCache(),
00187 viewportCache(),
00188 depthrangeCache(0.0, 1.0)
00189 {
00190 modelviewCache.push_back(txform::identity());
00191 projectionCache.push_back(txform::identity());
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 #if 0
00202 glMatrixMode(GL_PROJECTION); glLoadIdentity();
00203 glMatrixMode(GL_MODELVIEW); glLoadIdentity();
00204 #endif
00205
00206 dbg_dump(4, modelviewCache.back());
00207 }
00208
00209 const txform& getModelview() const
00210 {
00211 GVX_TRACE("GLCanvas::getModelview");
00212 GVX_ASSERT(modelviewCache.size() > 0);
00213 if (GVX_DBG_LEVEL() >= 8)
00214 {
00215 const txform ref = rawGetModelview();
00216 const double sse = ref.debug_sse(modelviewCache.back());
00217 if (sse > 1e-10)
00218 {
00219 dbg_eval_nl(0, sse);
00220 dbg_dump(0, ref);
00221 dbg_dump(0, modelviewCache.back());
00222 GVX_PANIC("numerical error in modelview matrix cache");
00223 }
00224 }
00225 return modelviewCache.back();
00226 }
00227
00228 const txform& getProjection() const
00229 {
00230 GVX_TRACE("GLCanvas::getProjection");
00231 GVX_ASSERT(projectionCache.size() > 0);
00232 if (GVX_DBG_LEVEL() >= 8)
00233 {
00234 const txform ref = rawGetProjection();
00235 const double sse = ref.debug_sse(projectionCache.back());
00236 if (sse > 1e-10)
00237 {
00238 dbg_eval_nl(0, sse);
00239 dbg_dump(0, ref);
00240 dbg_dump(0, projectionCache.back());
00241 GVX_PANIC("numerical error in projection matrix cache");
00242 }
00243 }
00244 return projectionCache.back();
00245 }
00246
00247 shared_ptr<GlxOpts> opts;
00248 shared_ptr<GlWindowInterface> glx;
00249 std::vector<txform> modelviewCache;
00250 std::vector<txform> projectionCache;
00251 recti viewportCache;
00252 const geom::span<double> depthrangeCache;
00253 };
00254
00255 GLCanvas::GLCanvas(shared_ptr<GlxOpts> opts,
00256 shared_ptr<GlWindowInterface> glx) :
00257 rep(new Impl(opts, glx))
00258 {
00259 GVX_TRACE("GLCanvas::GLCanvas");
00260 }
00261
00262 GLCanvas* GLCanvas::make(shared_ptr<GlxOpts> opts,
00263 shared_ptr<GlWindowInterface> glx)
00264 {
00265 GVX_TRACE("GLCanvas::make");
00266 return new GLCanvas(opts, glx);
00267 }
00268
00269 GLCanvas::~GLCanvas() throw()
00270 {
00271 GVX_TRACE("GLCanvas::~GLCanvas");
00272 delete rep;
00273 rep = 0;
00274 }
00275
00276 void GLCanvas::makeCurrent()
00277 {
00278 GVX_TRACE("GLCanvas::makeCurrent");
00279 rep->glx->makeCurrent();
00280 if (!rep->opts->doubleFlag && this->isDoubleBuffered())
00281 {
00282
00283
00284
00285 this->drawBufferFront();
00286 }
00287 theCurrentCanvas = nub::soft_ref<GLCanvas>(this);
00288 }
00289
00290 nub::soft_ref<GLCanvas> GLCanvas::getCurrent()
00291 {
00292 GVX_TRACE("GLCanvas::getCurrent");
00293 return theCurrentCanvas;
00294 }
00295
00296 void GLCanvas::drawBufferFront() throw()
00297 {
00298 GVX_TRACE("GLCanvas::drawBufferFront");
00299 glDrawBuffer(GL_FRONT);
00300 }
00301
00302 void GLCanvas::drawBufferBack() throw()
00303 {
00304 GVX_TRACE("GLCanvas::drawBufferBack");
00305 glDrawBuffer(GL_BACK);
00306 }
00307
00308 vec3d GLCanvas::screenFromWorld3(const vec3d& world_pos) const
00309 {
00310 GVX_TRACE("GLCanvas::screenFromWorld3");
00311
00312 const txform m = rep->getModelview();
00313 const txform p = rep->getProjection();
00314 const recti v = this->getScreenViewport();
00315
00316 const vec3d screen_pos = geom::project(m, p, v, world_pos);
00317
00318 dbg_dump(3, world_pos);
00319 dbg_dump(3, screen_pos);
00320
00321 if (GVX_DBG_LEVEL() >= 8)
00322 {
00323 const vec3d screen_pos1 = project1(m, p, v, world_pos);
00324 const vec3d diff = screen_pos - screen_pos1;
00325
00326 if (diff.length() > 1e-10)
00327 {
00328 dbg_eval_nl(0, diff.length());
00329 dbg_dump(0, p);
00330 dbg_dump(0, m);
00331 dbg_dump(0, screen_pos1);
00332 dbg_dump(0, screen_pos);
00333 GVX_PANIC("numerical error during world->screen projection");
00334 }
00335 }
00336
00337 return screen_pos;
00338 }
00339
00340 vec3d GLCanvas::worldFromScreen3(const vec3d& screen_pos) const
00341 {
00342 GVX_TRACE("GLCanvas::worldFromScreen3");
00343
00344 dbg_dump(3, screen_pos);
00345
00346 const txform m = rep->getModelview();
00347 const txform p = rep->getProjection();
00348 const recti v = getScreenViewport();
00349
00350 dbg_dump(5, m);
00351 dbg_dump(5, p);
00352
00353 const vec3d world2 = geom::unproject(m, p, v, screen_pos);
00354
00355 if (GVX_DBG_LEVEL() >= 8)
00356 {
00357 const vec3d world1 = unproject1(m, p, v, screen_pos);
00358 const vec3d diff = world2 - world1;
00359
00360 if (diff.length() > 1e-10)
00361 {
00362 dbg_eval_nl(0, diff.length());
00363 dbg_dump(0, p);
00364 dbg_dump(0, m);
00365 dbg_dump(0, world1);
00366 dbg_dump(0, world2);
00367 GVX_PANIC("numerical error during screen->world reverse projection");
00368 }
00369 }
00370
00371 return world2;
00372 }
00373
00374
00375 recti GLCanvas::getScreenViewport() const
00376 {
00377 GVX_TRACE("GLCanvas::getScreenViewport");
00378
00379 return rep->viewportCache;
00380 }
00381
00382
00383 bool GLCanvas::isRgba() const
00384 {
00385 GVX_TRACE("GLCanvas::isRgba");
00386
00387 return rep->opts->rgbaFlag;
00388 }
00389
00390 bool GLCanvas::isColorIndex() const
00391 {
00392 GVX_TRACE("GLCanvas::isColorIndex");
00393
00394 return !(rep->opts->rgbaFlag);
00395 }
00396
00397 bool GLCanvas::isDoubleBuffered() const
00398 {
00399 GVX_TRACE("GLCanvas::isDoubleBuffered");
00400
00401 return rep->glx->isDoubleBuffered();
00402 }
00403
00404 unsigned int GLCanvas::bitsPerPixel() const
00405 {
00406 GVX_TRACE("GLCanvas::bitsPerPixel");
00407
00408 return rep->glx->bitsPerPixel();
00409 }
00410
00411 void GLCanvas::throwIfError(const char* where,
00412 const rutz::file_pos& pos) const
00413 {
00414 GVX_TRACE("GLCanvas::throwIfError");
00415 GLenum status = glGetError();
00416 if (status != GL_NO_ERROR)
00417 {
00418 const char* msg =
00419 reinterpret_cast<const char*>(gluErrorString(status));
00420 throw rutz::error(rutz::sfmt("GL error: %s %s", msg, where), pos);
00421 }
00422 }
00423
00424 void GLCanvas::pushAttribs(const char* )
00425 {
00426 GVX_TRACE("GLCanvas::pushAttribs");
00427 glPushAttrib(GL_ALL_ATTRIB_BITS);
00428 dbg_eval_nl(3, attribStackDepth());
00429 }
00430
00431 void GLCanvas::popAttribs()
00432 {
00433 GVX_TRACE("GLCanvas::popAttribs");
00434 glPopAttrib();
00435 dbg_eval_nl(3, attribStackDepth());
00436 }
00437
00438 void GLCanvas::drawOnFrontBuffer()
00439 {
00440 GVX_TRACE("GLCanvas::drawOnFrontBuffer");
00441 glDrawBuffer(GL_FRONT);
00442 }
00443
00444 void GLCanvas::drawOnBackBuffer()
00445 {
00446 GVX_TRACE("GLCanvas::drawOnBackBuffer");
00447 glDrawBuffer(GL_BACK);
00448 }
00449
00450 void GLCanvas::setColor(const Gfx::RgbaColor& rgba)
00451 {
00452 GVX_TRACE("GLCanvas::setColor");
00453 glColor4dv(rgba.data());
00454 }
00455
00456 void GLCanvas::setClearColor(const Gfx::RgbaColor& rgba)
00457 {
00458 GVX_TRACE("GLCanvas::setClearColor");
00459 glClearColor(rgba.r(), rgba.g(), rgba.b(), rgba.a());
00460 }
00461
00462 void GLCanvas::setColorIndex(unsigned int index)
00463 {
00464 GVX_TRACE("GLCanvas::setColorIndex");
00465 glIndexi(index);
00466 }
00467
00468 void GLCanvas::setClearColorIndex(unsigned int index)
00469 {
00470 GVX_TRACE("GLCanvas::setClearColorIndex");
00471 glClearIndex(index);
00472 }
00473
00474 void GLCanvas::swapForeBack()
00475 {
00476 GVX_TRACE("GLCanvas::swapForeBack");
00477 if ( this->isRgba() )
00478 {
00479 GLdouble foreground[4];
00480 GLdouble background[4];
00481 glGetDoublev(GL_CURRENT_COLOR, &foreground[0]);
00482 glGetDoublev(GL_COLOR_CLEAR_VALUE, &background[0]);
00483
00484 glColor4d(background[0],
00485 background[1],
00486 background[2],
00487 foreground[3]);
00488
00489 glClearColor(foreground[0],
00490 foreground[1],
00491 foreground[2],
00492 background[3]);
00493 }
00494 else
00495 {
00496 GLint foreground, background;
00497 glGetIntegerv(GL_CURRENT_INDEX, &foreground);
00498 glGetIntegerv(GL_INDEX_CLEAR_VALUE, &background);
00499 glIndexi(background);
00500 glClearIndex(foreground);
00501 }
00502 }
00503
00504 void GLCanvas::setPolygonFill(bool on)
00505 {
00506 GVX_TRACE("GLCanvas::setPolygonFill");
00507
00508 if (on)
00509 {
00510 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00511 }
00512 else
00513 {
00514 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00515 }
00516 }
00517
00518 void GLCanvas::setPointSize(double size)
00519 {
00520 GVX_TRACE("GLCanvas::setPointSize");
00521
00522 glPointSize(size);
00523 }
00524
00525 void GLCanvas::setLineWidth(double width)
00526 {
00527 GVX_TRACE("GLCanvas::setLineWidth");
00528 glLineWidth(width);
00529 }
00530
00531 void GLCanvas::setLineStipple(unsigned short bit_pattern)
00532 {
00533 GVX_TRACE("GLCanvas::setLineStipple");
00534 glEnable(GL_LINE_STIPPLE);
00535 glLineStipple(1, bit_pattern);
00536 }
00537
00538 void GLCanvas::enableAntialiasing()
00539 {
00540 GVX_TRACE("GLCanvas::enableAntialiasing");
00541
00542 if (isRgba())
00543 {
00544 glEnable(GL_BLEND);
00545
00546 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00547
00548
00549 glEnable(GL_LINE_SMOOTH);
00550 }
00551 }
00552
00553
00554
00555 void GLCanvas::viewport(int x, int y, int w, int h)
00556 {
00557 GVX_TRACE("GLCanvas::viewport");
00558
00559 glViewport(x, y, w, h);
00560 dbg_eval(2, x); dbg_eval(2, y); dbg_eval(2, w); dbg_eval_nl(2, h);
00561 if (GVX_DBG_LEVEL() >= 8)
00562 {
00563 GLint viewport[4];
00564 glGetIntegerv(GL_VIEWPORT, viewport);
00565 dbg_eval(2, viewport[0]);
00566 dbg_eval(2, viewport[1]);
00567 dbg_eval(2, viewport[2]);
00568 dbg_eval_nl(2, viewport[3]);
00569 }
00570
00571 rep->viewportCache = recti::lbwh(x, y, w, h);
00572 }
00573
00574 void GLCanvas::orthographic(const rectd& bounds,
00575 double zNear, double zFar)
00576 {
00577 GVX_TRACE("GLCanvas::orthographic");
00578
00579 dbg_eval(3, bounds.left()); dbg_eval_nl(3, bounds.right());
00580 dbg_eval(3, bounds.bottom()); dbg_eval_nl(3, bounds.top());
00581 dbg_eval(3, zNear); dbg_eval_nl(3, zFar);
00582
00583 glMatrixMode(GL_PROJECTION);
00584 glLoadIdentity();
00585 glOrtho(bounds.left(), bounds.right(),
00586 bounds.bottom(), bounds.top(),
00587 zNear, zFar);
00588 rep->projectionCache.back() = txform::orthographic(bounds, zNear, zFar);
00589 glMatrixMode(GL_MODELVIEW);
00590 }
00591
00592 void GLCanvas::perspective(double fovy, double aspect,
00593 double zNear, double zFar)
00594 {
00595 GVX_TRACE("GLCanvas::perspective");
00596
00597 glMatrixMode(GL_PROJECTION);
00598 glLoadIdentity();
00599 gluPerspective(fovy, aspect, zNear, zFar);
00600 rep->projectionCache.back() = rawGetProjection();
00601 glMatrixMode(GL_MODELVIEW);
00602 }
00603
00604 void GLCanvas::pushMatrix(const char* )
00605 {
00606 GVX_TRACE("GLCanvas::pushMatrix");
00607 glMatrixMode(GL_MODELVIEW);
00608 glPushMatrix();
00609 rep->modelviewCache.push_back(rep->modelviewCache.back());
00610 dbg_dump(4, rep->modelviewCache.back());
00611 }
00612
00613 void GLCanvas::popMatrix()
00614 {
00615 GVX_TRACE("GLCanvas::popMatrix");
00616 glMatrixMode(GL_MODELVIEW);
00617 glPopMatrix();
00618 GVX_ASSERT(rep->modelviewCache.size() > 0);
00619 rep->modelviewCache.pop_back();
00620 dbg_dump(4, rep->modelviewCache.back());
00621 }
00622
00623 void GLCanvas::translate(const vec3d& v)
00624 {
00625 GVX_TRACE("GLCanvas::translate");
00626 glTranslated(v.x(), v.y(), v.z());
00627 rep->modelviewCache.back().translate(v);
00628 dbg_dump(4, rep->modelviewCache.back());
00629 }
00630
00631 void GLCanvas::scale(const vec3d& v)
00632 {
00633 GVX_TRACE("GLCanvas::scale");
00634 if (v.x() == 0.0)
00635 {
00636 throw rutz::error("invalid x scaling factor", SRC_POS);
00637 }
00638 if (v.y() == 0.0)
00639 {
00640 throw rutz::error("invalid y scaling factor", SRC_POS);
00641 }
00642 if (v.z() == 0.0)
00643 {
00644 throw rutz::error("invalid z scaling factor", SRC_POS);
00645 }
00646 glScaled(v.x(), v.y(), v.z());
00647 rep->modelviewCache.back().scale(v);
00648 dbg_dump(4, rep->modelviewCache.back());
00649 }
00650
00651 void GLCanvas::rotate(const vec3d& v, double angle_in_degrees)
00652 {
00653 GVX_TRACE("GLCanvas::rotate");
00654 glRotated(angle_in_degrees, v.x(), v.y(), v.z());
00655 rep->modelviewCache.back().rotate(v, angle_in_degrees);
00656 dbg_dump(4, rep->modelviewCache.back());
00657 }
00658
00659 void GLCanvas::transform(const geom::txform& tx)
00660 {
00661 GVX_TRACE("GLCanvas::transform");
00662 glMultMatrixd(tx.col_major_data());
00663 rep->modelviewCache.back().transform(tx);
00664 dbg_dump(4, rep->modelviewCache.back());
00665 }
00666
00667 void GLCanvas::loadMatrix(const geom::txform& tx)
00668 {
00669 GVX_TRACE("GLCanvas::loadMatrix");
00670 glLoadMatrixd(tx.col_major_data());
00671 rep->modelviewCache.back() = tx;
00672 dbg_dump(4, rep->modelviewCache.back());
00673 }
00674
00675 void GLCanvas::rasterPos(const geom::vec3<double>& world_pos)
00676 {
00677 GVX_TRACE("GLCanvas::rasterPos");
00678
00679 const rectd viewport = rectd(getScreenViewport());
00680
00681 const geom::span<double> depth = rep->depthrangeCache;
00682
00683 const vec3d screen_pos = screenFromWorld3(world_pos);
00684
00685 dbg_dump(3, world_pos);
00686 dbg_dump(3, screen_pos);
00687
00688 if (viewport.contains(screen_pos.as_vec2()) &&
00689 depth.contains(screen_pos.z()))
00690 {
00691 GVX_TRACE("GLCanvas::rasterPos::branch-1");
00692 glRasterPos3d(world_pos.x(), world_pos.y(), world_pos.z());
00693 }
00694 else
00695 {
00696 GVX_TRACE("GLCanvas::rasterPos::branch-2");
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 const vec3d safe_screen = vec3d(viewport.center_x(),
00708 viewport.center_y(),
00709 depth.center());
00710 const vec3d safe_world = worldFromScreen3(safe_screen);
00711
00712 dbg_dump(3, safe_screen);
00713 dbg_dump(3, safe_world);
00714
00715 glRasterPos3d(safe_world.x(), safe_world.y(), safe_world.z());
00716
00717 glBitmap(0, 0, 0.0f, 0.0f,
00718 screen_pos.x()-safe_screen.x(),
00719 screen_pos.y()-safe_screen.y(),
00720 static_cast<const GLubyte*>(0));
00721 }
00722
00723 if (GVX_DBG_LEVEL() >= 8)
00724 {
00725
00726 GVX_POSTCONDITION(rasterPositionValid());
00727 }
00728 }
00729
00730 void GLCanvas::drawPixels(const media::bmap_data& data,
00731 const vec3d& world_pos,
00732 const vec2d& zoom)
00733 {
00734 GVX_TRACE("GLCanvas::drawPixels");
00735
00736 data.set_row_order(media::bmap_data::BOTTOM_FIRST);
00737
00738 rasterPos(world_pos);
00739
00740 glPixelZoom(zoom.x(), zoom.y());
00741
00742 glPixelStorei(GL_UNPACK_ALIGNMENT, data.byte_alignment());
00743
00744 if (data.bits_per_pixel() == 32)
00745 {
00746 GVX_TRACE("GLCanvas::drawPixels[32]");
00747 glDrawPixels(data.width(), data.height(), GL_RGBA, GL_UNSIGNED_BYTE,
00748 static_cast<GLvoid*>(data.bytes_ptr()));
00749 }
00750 else if (data.bits_per_pixel() == 24)
00751 {
00752 GVX_TRACE("GLCanvas::drawPixels[24]");
00753 glDrawPixels(data.width(), data.height(), GL_RGB, GL_UNSIGNED_BYTE,
00754 static_cast<GLvoid*>(data.bytes_ptr()));
00755 }
00756 else if (data.bits_per_pixel() == 8)
00757 {
00758 GVX_TRACE("GLCanvas::drawPixels[8]");
00759 if (isRgba())
00760 {
00761 glDrawPixels(data.width(), data.height(),
00762 GL_LUMINANCE, GL_UNSIGNED_BYTE,
00763 static_cast<GLvoid*>(data.bytes_ptr()));
00764 }
00765 else
00766 {
00767 glDrawPixels(data.width(), data.height(),
00768 GL_COLOR_INDEX, GL_UNSIGNED_BYTE,
00769 static_cast<GLvoid*>(data.bytes_ptr()));
00770 }
00771 }
00772 else if (data.bits_per_pixel() == 1)
00773 {
00774 GVX_TRACE("GLCanvas::drawPixels[1]");
00775
00776 #if 0
00777 if (isRgba())
00778 {
00779 GLfloat simplemap[] = {0.0, 1.0};
00780
00781 glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 2, simplemap);
00782 glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 2, simplemap);
00783 glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 2, simplemap);
00784 glPixelMapfv(GL_PIXEL_MAP_I_TO_A, 2, simplemap);
00785 }
00786
00787 glDrawPixels(data.width(), data.height(), GL_COLOR_INDEX,
00788 GL_BITMAP, static_cast<GLvoid*>(data.bytes_ptr()));
00789 #else
00790
00791
00792
00793
00794
00795 media::bmap_data unpacked(data.size(), 8, 1);
00796
00797 const unsigned char* sptr = data.bytes_ptr();
00798 const unsigned char* sstop = sptr + data.byte_count();
00799 unsigned char* dptr = unpacked.bytes_ptr();
00800 unsigned char* dstop = unpacked.bytes_ptr() + unpacked.byte_count();
00801
00802 while (sptr != sstop)
00803 {
00804 GVX_ASSERT((dptr+7) < dstop);
00805
00806 *dptr++ = ((*sptr) & (1 << 7)) ? 255 : 0;
00807 *dptr++ = ((*sptr) & (1 << 6)) ? 255 : 0;
00808 *dptr++ = ((*sptr) & (1 << 5)) ? 255 : 0;
00809 *dptr++ = ((*sptr) & (1 << 4)) ? 255 : 0;
00810 *dptr++ = ((*sptr) & (1 << 3)) ? 255 : 0;
00811 *dptr++ = ((*sptr) & (1 << 2)) ? 255 : 0;
00812 *dptr++ = ((*sptr) & (1 << 1)) ? 255 : 0;
00813 *dptr++ = ((*sptr) & (1 << 0)) ? 255 : 0;
00814
00815 ++sptr;
00816 }
00817
00818 glPixelStorei(GL_UNPACK_ALIGNMENT, unpacked.byte_alignment());
00819
00820 glDrawPixels(unpacked.width(), unpacked.height(),
00821 GL_LUMINANCE, GL_UNSIGNED_BYTE,
00822 static_cast<GLvoid*>(unpacked.bytes_ptr()));
00823 #endif
00824 }
00825 }
00826
00827 void GLCanvas::drawBitmap(const media::bmap_data& data,
00828 const vec3d& world_pos)
00829 {
00830 GVX_TRACE("GLCanvas::drawBitmap");
00831
00832 data.set_row_order(media::bmap_data::BOTTOM_FIRST);
00833
00834 rasterPos(world_pos);
00835
00836 glBitmap(data.width(), data.height(), 0.0, 0.0, 0.0, 0.0,
00837 static_cast<GLubyte*>(data.bytes_ptr()));
00838 }
00839
00840 void GLCanvas::grabPixels(const recti& bounds,
00841 media::bmap_data& data_out)
00842 {
00843 GVX_TRACE("GLCanvas::grabPixels");
00844
00845 const int pixel_alignment = 1;
00846
00847
00848
00849
00850
00851
00852 const int bmap_bits_per_pixel = isRgba() ? 24 : 8;
00853
00854 media::bmap_data new_data(bounds.size(),
00855 bmap_bits_per_pixel, pixel_alignment);
00856
00857 glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment);
00858
00859 glPushAttrib(GL_PIXEL_MODE_BIT);
00860 {
00861 glReadBuffer(GL_FRONT);
00862 glReadPixels(bounds.left(), bounds.bottom(),
00863 bounds.width(), bounds.height(),
00864 (isRgba() ? GL_RGB : GL_COLOR_INDEX),
00865 GL_UNSIGNED_BYTE, new_data.bytes_ptr());
00866 }
00867 glPopAttrib();
00868
00869 new_data.specify_row_order(media::bmap_data::BOTTOM_FIRST);
00870
00871 data_out.swap(new_data);
00872 }
00873
00874 void GLCanvas::clearColorBuffer()
00875 {
00876 GVX_TRACE("GLCanvas::clearColorBuffer");
00877 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00878 }
00879
00880 void GLCanvas::clearColorBuffer(const recti& screen_rect)
00881 {
00882 GVX_TRACE("GLCanvas::clearColorBuffer(geom::recti)");
00883
00884 glPushAttrib(GL_SCISSOR_BIT);
00885 {
00886 glEnable(GL_SCISSOR_TEST);
00887
00888 glScissor(screen_rect.left(), screen_rect.bottom(),
00889 screen_rect.width(), screen_rect.height());
00890
00891 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00892 glDisable(GL_SCISSOR_TEST);
00893 }
00894 glPopAttrib();
00895 }
00896
00897 void GLCanvas::drawRect(const rectd& rect)
00898 {
00899 GVX_TRACE("GLCanvas::drawRect");
00900
00901 glRectd(rect.left(),
00902 rect.bottom(),
00903 rect.right(),
00904 rect.top());
00905 }
00906
00907 void GLCanvas::drawCircle(double inner_radius, double outer_radius,
00908 bool fill,
00909 unsigned int slices, unsigned int loops)
00910 {
00911 GVX_TRACE("GLCanvas::drawCircle");
00912
00913 GLUquadricObj* qobj = gluNewQuadric();
00914
00915 if (qobj == 0)
00916 throw rutz::error("couldn't allocate GLUquadric object", SRC_POS);
00917
00918 gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_SILHOUETTE);
00919 gluDisk(qobj, inner_radius, outer_radius, slices, loops);
00920 gluDeleteQuadric(qobj);
00921 }
00922
00923 void GLCanvas::drawCylinder(double base_radius, double top_radius,
00924 double height, int slices, int stacks,
00925 bool fill)
00926 {
00927 GVX_TRACE("GLCanvas::drawCylinder");
00928
00929 GLUquadric* qobj = gluNewQuadric();
00930
00931 if (qobj == 0)
00932 throw rutz::error("couldn't allocate GLUquadric object", SRC_POS);
00933
00934 gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_LINE);
00935 gluCylinder(qobj, base_radius, top_radius, height, slices, stacks);
00936 gluDeleteQuadric(qobj);
00937 }
00938
00939 void GLCanvas::drawSphere(double radius, int slices, int stacks,
00940 bool fill)
00941 {
00942 GVX_TRACE("GLCanvas::drawSphere");
00943
00944 GLUquadric* qobj = gluNewQuadric();
00945
00946 if (qobj == 0)
00947 throw rutz::error("couldn't allocate GLUquadric object", SRC_POS);
00948
00949 gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_LINE);
00950 gluSphere(qobj, radius, slices, stacks);
00951 gluDeleteQuadric(qobj);
00952 }
00953
00954 void GLCanvas::drawBezier4(const vec3d& p1,
00955 const vec3d& p2,
00956 const vec3d& p3,
00957 const vec3d& p4,
00958 unsigned int subdivisions)
00959 {
00960 GVX_TRACE("GLCanvas::drawBezier4");
00961
00962 #if 1
00963
00964
00965 Canvas::drawBezier4(p1, p2, p3, p4, subdivisions);
00966
00967 #else
00968
00969 vec3d points[] =
00970 {
00971 p1, p2, p3, p4
00972 };
00973
00974 glEnable(GL_MAP1_VERTEX_3);
00975 glMap1d(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, points[0].data());
00976
00977 glMapGrid1d(subdivisions, 0.0, 1.0);
00978 glEvalMesh1(GL_LINE, 0, subdivisions);
00979 #endif
00980 }
00981
00982 void GLCanvas::drawBezierFill4(const vec3d& center,
00983 const vec3d& p1,
00984 const vec3d& p2,
00985 const vec3d& p3,
00986 const vec3d& p4,
00987 unsigned int subdivisions)
00988 {
00989 GVX_TRACE("GLCanvas::drawBezierFill4");
00990
00991
00992
00993
00994 #if 0
00995 Canvas::drawBezierFill4(center, p1, p2, p3, p4, subdivisions);
00996 #else
00997 vec3d points[] =
00998 {
00999 p1, p2, p3, p4
01000 };
01001
01002 glEnable(GL_MAP1_VERTEX_3);
01003 glMap1d(GL_MAP1_VERTEX_3,
01004 0.0,
01005 double(subdivisions),
01006 3,
01007 4,
01008 points[0].data());
01009
01010 glMapGrid1d(subdivisions, 0.0, 1.0);
01011
01012 glBegin(GL_TRIANGLE_FAN);
01013 vertex3(center);
01014 for (unsigned int d = 0; d <= subdivisions; ++d)
01015 {
01016 glEvalCoord1d(double(d));
01017 }
01018 glEnd();
01019 #endif
01020 }
01021
01022 void GLCanvas::beginPoints(const char* )
01023 { GVX_TRACE("GLCanvas::beginPoints"); glBegin(GL_POINTS); }
01024
01025 void GLCanvas::beginLines(const char* )
01026 { GVX_TRACE("GLCanvas::beginLines"); glBegin(GL_LINES); }
01027
01028 void GLCanvas::beginLineStrip(const char* )
01029 { GVX_TRACE("GLCanvas::beginLineStrip"); glBegin(GL_LINE_STRIP); }
01030
01031 void GLCanvas::beginLineLoop(const char* )
01032 { GVX_TRACE("GLCanvas::beginLineLoop"); glBegin(GL_LINE_LOOP); }
01033
01034 void GLCanvas::beginTriangles(const char* )
01035 { GVX_TRACE("GLCanvas::beginTriangles"); glBegin(GL_TRIANGLES); }
01036
01037 void GLCanvas::beginTriangleStrip(const char* )
01038 { GVX_TRACE("GLCanvas::beginTriangleStrip"); glBegin(GL_TRIANGLE_STRIP); }
01039
01040 void GLCanvas::beginTriangleFan(const char* )
01041 { GVX_TRACE("GLCanvas::beginTriangleFan"); glBegin(GL_TRIANGLE_FAN); }
01042
01043 void GLCanvas::beginQuads(const char* )
01044 { GVX_TRACE("GLCanvas::beginQuads"); glBegin(GL_QUADS); }
01045
01046 void GLCanvas::beginQuadStrip(const char* )
01047 { GVX_TRACE("GLCanvas::beginQuadStrip"); glBegin(GL_QUAD_STRIP); }
01048
01049 void GLCanvas::beginPolygon(const char* )
01050 { GVX_TRACE("GLCanvas::beginPolygon"); glBegin(GL_POLYGON); }
01051
01052 void GLCanvas::vertex2(const vec2d& v)
01053 {
01054 GVX_TRACE("GLCanvas::vertex2");
01055 glVertex2d(v.x(), v.y());
01056 }
01057
01058 void GLCanvas::vertex3(const vec3d& v)
01059 {
01060 GVX_TRACE("GLCanvas::vertex3");
01061 glVertex3d(v.x(), v.y(), v.z());
01062 }
01063
01064 void GLCanvas::end()
01065 {
01066 GVX_TRACE("GLCanvas::end");
01067 glEnd();
01068 }
01069
01070 void GLCanvas::drawRasterText(const rutz::fstring& text,
01071 const GxRasterFont& font)
01072 {
01073 GVX_TRACE("GLCanvas::drawRasterText");
01074
01075 glListBase( font.listBase() );
01076
01077 const char* p = text.c_str();
01078
01079 int line = 0;
01080
01081 while (1)
01082 {
01083 int len = 0;
01084 while (p[len] != '\0' && p[len] != '\n')
01085 ++len;
01086
01087 dbg_eval(3, len); dbg_eval_nl(3, p);
01088
01089 rasterPos( vec3d::zeros() );
01090 if (line > 0)
01091 {
01092
01093
01094 glBitmap(0, 0, 0.0f, 0.0f,
01095 0,
01096 -1 * font.rasterHeight() * line,
01097 static_cast<const GLubyte*>(0));
01098 }
01099
01100 glCallLists( len, GL_BYTE, p );
01101
01102 p += len;
01103
01104 if (*p == '\0')
01105 break;
01106
01107
01108 GVX_ASSERT(*p == '\n');
01109 ++p;
01110 ++line;
01111 }
01112 }
01113
01114 void GLCanvas::drawVectorText(const rutz::fstring& text,
01115 const GxVectorFont& font)
01116 {
01117 GVX_TRACE("GLCanvas::drawVectorText");
01118
01119 glListBase( font.listBase() );
01120
01121 const char* p = text.c_str();
01122
01123 glMatrixMode(GL_MODELVIEW);
01124
01125 int line = 0;
01126
01127 while (1)
01128 {
01129 int len = 0;
01130 while (p[len] != '\0' && p[len] != '\n')
01131 ++len;
01132
01133 dbg_eval(3, len); dbg_eval_nl(3, p);
01134
01135 glPushMatrix();
01136
01137 if (line > 0)
01138 glTranslated( 0.0,
01139 -1.0 * font.vectorHeight() * line,
01140 0.0 );
01141
01142 glCallLists( len, GL_BYTE, p );
01143 glPopMatrix();
01144
01145 p += len;
01146
01147 if (*p == '\0')
01148 break;
01149
01150
01151 GVX_ASSERT(*p == '\n');
01152 ++p;
01153 ++line;
01154 }
01155 }
01156
01157 void GLCanvas::flushOutput()
01158 {
01159 GVX_TRACE("GLCanvas::flushOutput");
01160
01161 if (rep->opts->doubleFlag)
01162 rep->glx->swapBuffers();
01163 else
01164 glFlush();
01165 }
01166
01167 void GLCanvas::finishDrawing()
01168 {
01169 GVX_TRACE("GLCanvas::finishDrawing");
01170 glFinish();
01171 }
01172
01173 int GLCanvas::genLists(int num)
01174 {
01175 GVX_TRACE("GLCanvas::genLists");
01176 const int i = glGenLists(num);
01177
01178 if (i == 0)
01179 throw rutz::error("Couldn't allocate GL display list", SRC_POS);
01180
01181 return i;
01182 }
01183
01184 void GLCanvas::deleteLists(int start, int num)
01185 {
01186 GVX_TRACE("GLCanvas::deleteLists");
01187 glDeleteLists(start, num);
01188 }
01189
01190 void GLCanvas::newList(int i, bool do_execute)
01191 {
01192 GVX_TRACE("GLCanvas::newList");
01193
01194 glNewList(i,
01195 do_execute
01196 ? GL_COMPILE_AND_EXECUTE
01197 : GL_COMPILE);
01198 }
01199
01200 void GLCanvas::endList()
01201 {
01202 GVX_TRACE("GLCanvas::endList");
01203 glEndList();
01204 }
01205
01206 bool GLCanvas::isList(int i)
01207 {
01208 GVX_TRACE("GLCanvas::isList");
01209 return i != 0 && glIsList(i) == GL_TRUE;
01210 }
01211
01212 void GLCanvas::callList(int i)
01213 {
01214 GVX_TRACE("GLCanvas::callList");
01215 glCallList(i);
01216 }
01217
01218 void GLCanvas::light(int lightnum,
01219 const Gfx::RgbaColor* spec,
01220 const Gfx::RgbaColor* diff,
01221 const Gfx::RgbaColor* ambi,
01222 const vec3d* posi,
01223 const vec3d* sdir,
01224 double attenuation,
01225 double spotExponent,
01226 double spotCutoff)
01227 {
01228 GVX_TRACE("GLCanvas::light");
01229
01230 glEnable(GL_LIGHTING);
01231 glEnable(GL_LIGHT0+lightnum);
01232 glEnable(GL_DEPTH_TEST);
01233
01234 if (spec != 0)
01235 {
01236 const GLfloat fspecular[] = { spec->r(), spec->g(), spec->b(), spec->a() };
01237 glLightfv(GL_LIGHT0+lightnum, GL_SPECULAR, fspecular);
01238 }
01239
01240 if (diff != 0)
01241 {
01242 const GLfloat fdiffuse[] = { diff->r(), diff->g(), diff->b(), diff->a() };
01243 glLightfv(GL_LIGHT0+lightnum, GL_DIFFUSE, fdiffuse);
01244 }
01245
01246 if (ambi != 0)
01247 {
01248 const GLfloat fambient[] = { ambi->r(), ambi->g(), ambi->b(), ambi->a() };
01249 glLightfv(GL_LIGHT0+lightnum, GL_AMBIENT, fambient);
01250 }
01251
01252 if (posi != 0)
01253 {
01254 const GLfloat w = (attenuation == 0.0) ? 0.0 : 1.0;
01255 const GLfloat m = (attenuation == 0.0) ? 1.0 : (1.0/attenuation);
01256
01257 const GLfloat fposition[] = { m*posi->x(), m*posi->y(), m*posi->z(), w };
01258 glLightfv(GL_LIGHT0+lightnum, GL_POSITION, fposition);
01259 }
01260
01261 if (sdir != 0)
01262 {
01263 const GLfloat fdirection[] = { sdir->x(), sdir->y(), sdir->z(), 0.0 };
01264
01265 glLightfv(GL_LIGHT0+lightnum, GL_SPOT_DIRECTION, fdirection);
01266 glLightf(GL_LIGHT0+lightnum, GL_SPOT_EXPONENT, spotExponent);
01267 glLightf(GL_LIGHT0+lightnum, GL_SPOT_CUTOFF, spotCutoff);
01268 }
01269 }
01270
01271 void GLCanvas::material(const Gfx::RgbaColor* spec,
01272 const Gfx::RgbaColor* diff,
01273 const Gfx::RgbaColor* ambi,
01274 const double* shininess)
01275 {
01276 glEnable(GL_DEPTH_TEST);
01277
01278 if (spec != 0)
01279 {
01280 const GLfloat specular[] = { spec->r(), spec->g(), spec->b(), spec->a() };
01281 glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
01282 }
01283
01284 if (diff != 0)
01285 {
01286 const GLfloat diffuse[] = { diff->r(), diff->g(), diff->b(), diff->a() };
01287 glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
01288 }
01289
01290 if (ambi != 0)
01291 {
01292 const GLfloat ambient[] = { ambi->r(), ambi->g(), ambi->b(), ambi->a() };
01293 glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
01294 }
01295
01296 if (shininess != 0)
01297 glMaterialf(GL_FRONT, GL_SHININESS, *shininess);
01298 }
01299
01300 static const char __attribute__((used)) vcid_groovx_gfx_glcanvas_cc_utc20050626084024[] = "$Id: glcanvas.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
01301 #endif // !GROOVX_GFX_GLCANVAS_CC_UTC20050626084024_DEFINED