Commit 09259380 authored by Jan Möbius's avatar Jan Möbius

Added picking cache.

Set always a perspective projection matrix Stereo mode.
Setting a orthogonal matrix in the state and rendering with the perspective stereo matrix breaks the project/unprojoce calls.



git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@6802 383ad7c9-94d9-4d36-a494-682f7c89f535
parent b30f871b
......@@ -142,6 +142,9 @@ glViewer::glViewer( QGraphicsScene* _scene,
glWidget_(_glWidget),
cursorPainter_(0),
cursorPositionValid_(false),
pickCache_(0),
updatePickCache_(true),
pickCacheSupported_(true),
clickEvent_(QEvent::MouseButtonPress, QPoint (), Qt::NoButton, Qt::NoButton, Qt::NoModifier),
properties_(_properties),
glstate_(0),
......@@ -339,30 +342,24 @@ void glViewer::updateProjectionMatrix()
glstate_->reset_projection();
switch (projectionMode_)
// In scereo mode we have to use a perspective matrix
if (stereo_ || projectionMode_ == PERSPECTIVE_PROJECTION)
{
case ORTHOGRAPHIC_PROJECTION:
{
double aspect;
if (isVisible())
aspect = (double) glWidth() / (double) glHeight();
else
aspect = 1.0;
glstate_->perspective(fovy_, (GLdouble) glWidth() / (GLdouble) glHeight(),
near_, far_);
}
else
{
double aspect;
glstate_->ortho( -orthoWidth_, orthoWidth_,
-orthoWidth_/aspect, orthoWidth_/aspect,
near_, far_ );
break;
}
if (isVisible())
aspect = (double) glWidth() / (double) glHeight();
else
aspect = 1.0;
case PERSPECTIVE_PROJECTION:
{
glstate_->perspective(fovy_,
(GLdouble) glWidth() / (GLdouble) glHeight(),
near_, far_);
break;
}
glstate_->ortho( -orthoWidth_, orthoWidth_,
-orthoWidth_/aspect, orthoWidth_/aspect,
near_, far_ );
}
}
......@@ -452,6 +449,7 @@ void glViewer::updateGL()
{
if (!properties_.updateLocked() && isVisible() )
{
updatePickCache_ = true;
update();
emit viewUpdated();
......@@ -1905,26 +1903,19 @@ void glViewer::viewWheelEvent( QWheelEvent* _event)
if (_event->modifiers() == Qt::ShiftModifier)
factor = properties_.wheelZoomFactorShift();
switch (projectionMode())
if (projectionMode() == PERSPECTIVE_PROJECTION || stereo_)
{
case PERSPECTIVE_PROJECTION:
{
double d = -(double)_event->delta() / 120.0 * 0.2 * factor * trackball_radius_/3;
translate( ACG::Vec3d(0.0, 0.0, d) );
updateGL();
break;
}
case ORTHOGRAPHIC_PROJECTION:
{
double d = (double)_event->delta() / 120.0 * 0.2 * factor * orthoWidth_;
orthoWidth_ += d;
updateProjectionMatrix();
updateGL();
break;
}
double d = -(double)_event->delta() / 120.0 * 0.2 * factor * trackball_radius_/3;
translate( ACG::Vec3d(0.0, 0.0, d) );
updateGL();
}
else
{
double d = (double)_event->delta() / 120.0 * 0.2 * factor * orthoWidth_;
orthoWidth_ += d;
updateProjectionMatrix();
updateGL();
}
}
......
......@@ -94,6 +94,7 @@ class QSplitter;
class QTimer;
class QImage;
class QSocketNotifier;
class QGLFramebufferObject;
//== NAMESPACES ===============================================================
......@@ -785,6 +786,24 @@ private:
unsigned int& _targetIdx,
ACG::Vec3d* _hitPointPtr=0 );
/// pick from cache
int pickFromCache( ACG::SceneGraph::PickTarget _pickTarget,
const QPoint& _mousePos,
unsigned int& _nodeIdx,
unsigned int& _targetIdx,
ACG::Vec3d* _hitPointPtr=0 );
private:
/// Framebuffer object that holds the pick cache
QGLFramebufferObject *pickCache_;
/// Should the pick cache be updated
bool updatePickCache_;
/// Is pick caching supported
bool pickCacheSupported_;
/** @} */
//===========================================================================
......
......@@ -56,6 +56,8 @@
#include "QtGLGraphicsScene.hh"
#include "QtGLGraphicsView.hh"
#include <QGLFramebufferObject>
//== NAMESPACES ===============================================================
//== IMPLEMENTATION ==========================================================
......@@ -77,7 +79,11 @@ bool glViewer::pick( ACG::SceneGraph::PickTarget _pickTarget,
// unsigned int node, target;
// QTime time;
// time.start ();
int rv = pickColor (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
int rv = pickFromCache (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
// cache will return -1 if a update is needed or caching is not supported
if (rv < 0)
rv = pickColor (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
// printf ("ColorPicking took %d msec\n",time.restart ());
// rv = -1;
......@@ -109,12 +115,51 @@ int glViewer::pickColor( ACG::SceneGraph::PickTarget _pickTarget,
l = scenePos().x(),
b = scene()->height () - scenePos().y() - h,
x = _mousePos.x(),
y = scene()->height () - _mousePos.y();
y = scene()->height () - _mousePos.y(),
pW = 1,
pH = 1;
GLubyte pixels[9][4];
GLfloat depths[9];
int hit = -1;
// traversing order (center, top, bottom, ...)
unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 };
if (pickCacheSupported_)
{
// delete pick cache if the size changed
if (pickCache_ && pickCache_->size () != QSize (glWidth (), glHeight ()))
{
delete pickCache_;
pickCache_ = NULL;
}
// create a new pick cache frambuffer object
if (!pickCache_)
{
pickCache_ = new QGLFramebufferObject (glWidth (), glHeight (), QGLFramebufferObject::Depth);
if (!pickCache_->isValid ())
{
pickCacheSupported_ = false;
delete pickCache_;
pickCache_ = NULL;
}
}
if (pickCache_)
{
// the viewport for the framebuffer object
l = 0;
b = 0;
x = _mousePos.x() - scenePos().x();
y = glHeight() - (_mousePos.y() - scenePos().y());
// we can only pick inside of our window
if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
return 0;
pickCache_->bind ();
}
}
const ACG::GLMatrixd& modelview = properties_.glState().modelview();
const ACG::GLMatrixd& projection = properties_.glState().projection();
......@@ -151,14 +196,167 @@ int glViewer::pickColor( ACG::SceneGraph::PickTarget _pickTarget,
properties_.glState().set_clear_color (clear_color);
if (properties_.glState().pick_error ())
{
if (pickCache_ && pickCache_->isBound ())
pickCache_->release ();
return -1;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadPixels (x - 1, y - 1, 3, 3, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glReadPixels (x - 1, y - 1, 3, 3, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
// we can only read inside our viewport
if (x + 1 < w)
pW++;
if (y + 1 < h)
pH++;
if (x > 0)
{
x--;
pW++;
}
if (y > 0)
{
y--;
pH++;
}
if (pH != 3 || pW != 3)
{
// initialize unused values with 0
for (int i = 0; i < 9; i++)
{
pixels[i][0] = 0;
pixels[i][1] = 0;
pixels[i][2] = 0;
pixels[i][3] = 0;
depths[i] = 0.0;
}
}
// read from framebuffer
glReadPixels (x, y, pW, pH, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glReadPixels (x, y, pW, pH, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
// unbind pick cache
if (pickCache_ && pickCache_->isBound ())
{
pickCache_->release ();
updatePickCache_ = false;
}
// get first found pixel
for (int i = 0; i < 9; i++)
{
if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0 || pixels[order[i]][3] != 0))
{
hit = order[i];
break;
}
}
if (hit < 0)
return 0;
ACG::Vec4uc rgba;
rgba[0] = pixels[hit][0];
rgba[1] = pixels[hit][1];
rgba[2] = pixels[hit][2];
rgba[3] = pixels[hit][3];
std::vector<unsigned int> rv = properties_.glState().pick_color_to_stack (rgba);
// something wrong with the color stack ?
if (rv.size () < 2)
return -1;
_nodeIdx = rv[1];
_targetIdx = rv[0];
if (_hitPointPtr)
{
*_hitPointPtr = properties_.glState().unproject (
ACG::Vec3d(_mousePos.x(), scene()->height () - _mousePos.y(),depths[hit]));
}
return 1;
}
//-----------------------------------------------------------------------------
int glViewer::pickFromCache( ACG::SceneGraph::PickTarget _pickTarget,
const QPoint& _mousePos,
unsigned int& _nodeIdx,
unsigned int& _targetIdx,
ACG::Vec3d* _hitPointPtr )
{
// do we need an update?
if (!pickCacheSupported_ || updatePickCache_ || !pickCache_)
return -1;
GLint x = _mousePos.x() - scenePos().x(),
y = glHeight() - (_mousePos.y() - scenePos().y()),
pW = 1,
pH = 1;
GLubyte pixels[9][4];
GLfloat depths[9];
int hit = -1;
// traversing order (center, top, bottom, ...)
unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 };
// can't pick outside
if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
return 0;
// bind cache framebuffer object
pickCache_->bind ();
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// we can only read inside our viewport
if (x + 1 < (int)glWidth ())
pW++;
if (y + 1 < (int)glHeight ())
pH++;
if (x > 0)
{
x--;
pW++;
}
if (y > 0)
{
y--;
pH++;
}
if (pH != 3 || pW != 3)
{
// initialize unused values with 0
for (int i = 0; i < 9; i++)
{
pixels[i][0] = 0;
pixels[i][1] = 0;
pixels[i][2] = 0;
pixels[i][3] = 0;
depths[i] = 0.0;
}
}
// read from framebuffer
glReadPixels (x, y, pW, pH, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glReadPixels (x, y, pW, pH, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
// unbind
pickCache_->release ();
// get first found pixel
for (int i = 0; i < 9; i++)
{
if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0 || pixels[order[i]][3] != 0))
......@@ -189,7 +387,8 @@ int glViewer::pickColor( ACG::SceneGraph::PickTarget _pickTarget,
if (_hitPointPtr)
{
*_hitPointPtr = properties_.glState().unproject(ACG::Vec3d(x,y,depths[hit]));
*_hitPointPtr = properties_.glState().unproject(
ACG::Vec3d(_mousePos.x(), scene()->height () - _mousePos.y(),depths[hit]));
}
return 1;
......
......@@ -92,6 +92,8 @@ glViewer::setStereoMode(bool _b)
glDrawBuffer(GL_BACK);
}
updateProjectionMatrix ();
updateGL();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment