diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-09-08 01:36:52 (GMT) |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-09-08 01:36:52 (GMT) |
commit | 7b7e776d9042fa34a17db3189af99efb7494d070 (patch) | |
tree | 6363b7373ac918ac70a68b981e6ccca23087d0c8 /src | |
parent | 4bb098ed9449bd3b2798000bc5394bda98c9165f (diff) | |
download | Qt-7b7e776d9042fa34a17db3189af99efb7494d070.zip Qt-7b7e776d9042fa34a17db3189af99efb7494d070.tar.gz Qt-7b7e776d9042fa34a17db3189af99efb7494d070.tar.bz2 |
Make the matrix and viewport logic in renderText() a bit better
The original renderText() was using the highly unportable (to OpenGL/ES)
glGetDoublev() and glGetIntegerv() functions.
Reviewed-by: Sarah Smith
Diffstat (limited to 'src')
-rw-r--r-- | src/opengl/qgl.cpp | 187 |
1 files changed, 137 insertions, 50 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 9e0c5f8..49dc8a2 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -63,6 +63,7 @@ #include "qpixmap.h" #include "qimage.h" +#include "qmatrix4x4.h" #include "qgl_p.h" #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) @@ -251,46 +252,24 @@ QGLSignalProxy *QGLSignalProxy::instance() \sa QGLContext, QGLWidget */ -static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4]) +static inline void qgluProject + (qreal objx, qreal objy, qreal objz, + const QMatrix4x4& model, const QMatrix4x4& proj, const GLint viewport[4], + GLfloat *winx, GLfloat *winy, GLfloat* winz) { -#define M(row,col) m[col*4+row] - out[0] = - M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3]; - out[1] = - M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3]; - out[2] = - M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3]; - out[3] = - M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3]; -#undef M -} - -static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz, - const GLdouble model[16], const GLdouble proj[16], - const GLint viewport[4], - GLdouble * winx, GLdouble * winy, GLdouble * winz) -{ - GLdouble in[4], out[4]; - - in[0] = objx; - in[1] = objy; - in[2] = objz; - in[3] = 1.0; - transform_point(out, model, in); - transform_point(in, proj, out); + QVector4D transformed = proj.map(model.map(QVector4D(objx, objy, objz, 1))); - if (in[3] == 0.0) - return GL_FALSE; + qreal w = transformed.w(); + if (w == 0.0f) + w = 1.0f; // Just in case! - in[0] /= in[3]; - in[1] /= in[3]; - in[2] /= in[3]; + qreal x = transformed.x() / w; + qreal y = transformed.y() / w; - *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2; - *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2; + *winx = viewport[0] + (1 + x) * viewport[2] / 2; + *winy = viewport[1] + (1 + y) * viewport[3] / 2; - *winz = (1 + in[2]) / 2; - return GL_TRUE; + *winz = (1 + transformed.z() / w) / 2; } /*! @@ -4113,6 +4092,30 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str, p->setFont(old_font); } +#if defined(GL_OES_VERSION_1_0) && !defined(GL_OES_VERSION_1_1) + +// OpenGL/ES 1.0 cannot fetch viewports from the GL server. +// We therefore create a default viewport to simulate the fetch. + +static void qt_gl_get_viewport(GLint *view, int deviceWidth, int deviceHeight) +{ + view[0] = 0; + view[1] = 0; + view[2] = deviceWidth; + view[3] = deviceHeight; +} + +#else + +static void qt_gl_get_viewport(GLint *view, int deviceWidth, int deviceHeight) +{ + Q_UNUSED(deviceWidth); + Q_UNUSED(deviceHeight); + glGetIntegerv(GL_VIEWPORT, view); +} + +#endif + /*! Renders the string \a str into the GL context of this widget. @@ -4138,13 +4141,19 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, GLint view[4]; #ifndef QT_OPENGL_ES bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST); - if (!use_scissor_testing) - glGetIntegerv(GL_VIEWPORT, &view[0]); #else bool use_scissor_testing = false; #endif int width = d->glcx->device()->width(); int height = d->glcx->device()->height(); + if (!use_scissor_testing) { + qt_gl_get_viewport(&view[0], width, height); + } else { + view[0] = 0; + view[1] = 0; + view[2] = width; + view[3] = height; + } bool auto_swap = autoBufferSwap(); QPaintEngine *engine = paintEngine(); @@ -4216,12 +4225,95 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, #endif } +#if defined(QT_OPENGL_ES_2) || \ + (defined(GL_OES_VERSION_1_0) && !defined(GL_OES_VERSION_1_1)) + +// OpenGL/ES 1.0 cannot fetch matrices from the GL server. +// OpenGL/ES 2.0 does not use fixed-function matrices at all. +// We therefore create some default matrices to simulate the fetch. + +static QMatrix4x4 qt_gl_projection_matrix(int deviceWidth, int deviceHeight) +{ + QMatrix4x4 m; + m.ortho(0, deviceWidth, deviceHeight, 0, -1, 1); + return m; +} + +static QMatrix4x4 qt_gl_modelview_matrix(void) +{ + return QMatrix4x4(); +} + +#else // !QT_OPENGL_ES_2 + +static QMatrix4x4 qt_gl_fetch_matrix(GLenum type) +{ + QMatrix4x4 matrix; +#if defined(QT_OPENGL_ES_1_CL) + GLfixed mat[16]; + glGetFixedv(type, mat); + qreal *m = matrix.data(); + for (int index = 0; index < 16; ++index) + m[index] = vt2f(mat[index]); +#else + if (sizeof(qreal) == sizeof(GLfloat)) { + glGetFloatv(type, reinterpret_cast<GLfloat *>(matrix.data())); +#if !defined(QT_OPENGL_ES) + } else if (sizeof(qreal) == sizeof(GLdouble)) { + glGetDoublev(type, reinterpret_cast<GLdouble *>(matrix.data())); +#endif + } else { + GLfloat mat[16]; + glGetFloatv(type, mat); + qreal *m = matrix.data(); + for (int index = 0; index < 16; ++index) + m[index] = mat[index]; + } +#endif + matrix.inferSpecialType(); + return matrix; +} + +static QMatrix4x4 qt_gl_projection_matrix(int deviceWidth, int deviceHeight) +{ + Q_UNUSED(deviceWidth); + Q_UNUSED(deviceHeight); + return qt_gl_fetch_matrix(GL_PROJECTION_MATRIX); +} + +static QMatrix4x4 qt_gl_modelview_matrix(void) +{ + return qt_gl_fetch_matrix(GL_MODELVIEW_MATRIX); +} + +#endif // !QT_OPENGL_ES_2 + /*! \overload \a x, \a y and \a z are specified in scene or object coordinates relative to the currently set projection and model matrices. This can be useful if you want to annotate models with text labels and have the labels move with the model as it is rotated etc. + + This function fetches the modelview matrix, projection matrix, and + current viewport from the GL server to map (\a x, \a y, \a z) + into window co-ordinates. This entails several round-trips to the GL + server which will probably impact performance. + + Fetching the modelview and projection matrices is not supported + under OpenGL/ES 1.0 and OpenGL/ES 2.0 so a default orthographic + projection will be used to map the co-ordinates on those platforms. + This probably will not give results that are consistent with desktop + and OpenGL/ES 1.1 systems. Fetching the viewport is not supported + under OpenGL/ES 1.0, so the full device will be used as the viewport. + + This function is deprecated because it is non-portable. It is + recommended that the application map the co-ordinates itself using + application-provided matrix data that reflects the desired + transformation. Then use QPainter::drawText() to draw \a str at + the mapped position. + + \sa QMatrix4x4 */ void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int) { @@ -4233,16 +4325,15 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con int width = d->glcx->device()->width(); int height = d->glcx->device()->height(); - GLdouble model[4][4], proj[4][4]; + + QMatrix4x4 model = qt_gl_modelview_matrix(); + QMatrix4x4 proj = qt_gl_projection_matrix(width, height); GLint view[4]; -#ifndef QT_OPENGL_ES - glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]); - glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]); - glGetIntegerv(GL_VIEWPORT, &view[0]); -#endif - GLdouble win_x = 0, win_y = 0, win_z = 0; - qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0], - &win_x, &win_y, &win_z); + qt_gl_get_viewport(view, width, height); + + GLfloat win_x = 0, win_y = 0, win_z = 0; + qgluProject(qreal(x), qreal(y), qreal(z), + model, proj, &view[0], &win_x, &win_y, &win_z); win_y = height - win_y; // y is inverted QPaintEngine *engine = paintEngine(); @@ -4295,11 +4386,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con glEnable(GL_ALPHA_TEST); if (use_depth_testing) glEnable(GL_DEPTH_TEST); -#ifndef QT_OPENGL_ES - glTranslated(0, 0, -win_z); -#else glTranslatef(0, 0, -win_z); -#endif #endif // !defined(QT_OPENGL_ES_2) qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font); |