querymatrix.c revision 3464ebd5
13464ebd5Sriastradh/**************************************************************************
23464ebd5Sriastradh *
33464ebd5Sriastradh * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
43464ebd5Sriastradh * All Rights Reserved.
53464ebd5Sriastradh *
63464ebd5Sriastradh **************************************************************************/
73464ebd5Sriastradh
83464ebd5Sriastradh
93464ebd5Sriastradh/**
103464ebd5Sriastradh * Code to implement GL_OES_query_matrix.  See the spec at:
113464ebd5Sriastradh * http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt
123464ebd5Sriastradh */
133464ebd5Sriastradh
143464ebd5Sriastradh
153464ebd5Sriastradh#include <stdlib.h>
163464ebd5Sriastradh#include <math.h>
173464ebd5Sriastradh#include "GLES/gl.h"
183464ebd5Sriastradh#include "GLES/glext.h"
193464ebd5Sriastradh
203464ebd5Sriastradh
213464ebd5Sriastradh/**
223464ebd5Sriastradh * This is from the GL_OES_query_matrix extension specification:
233464ebd5Sriastradh *
243464ebd5Sriastradh *  GLbitfield glQueryMatrixxOES( GLfixed mantissa[16],
253464ebd5Sriastradh *                                GLint   exponent[16] )
263464ebd5Sriastradh *  mantissa[16] contains the contents of the current matrix in GLfixed
273464ebd5Sriastradh *  format.  exponent[16] contains the unbiased exponents applied to the
283464ebd5Sriastradh *  matrix components, so that the internal representation of component i
293464ebd5Sriastradh *  is close to mantissa[i] * 2^exponent[i].  The function returns a status
303464ebd5Sriastradh *  word which is zero if all the components are valid. If
313464ebd5Sriastradh *  status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf).
323464ebd5Sriastradh *  The implementations are not required to keep track of overflows.  In
333464ebd5Sriastradh *  that case, the invalid bits are never set.
343464ebd5Sriastradh */
353464ebd5Sriastradh
363464ebd5Sriastradh#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16))
373464ebd5Sriastradh#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0))
383464ebd5Sriastradh
393464ebd5Sriastradh#if defined(_MSC_VER)
403464ebd5Sriastradh/* Oddly, the fpclassify() function doesn't exist in such a form
413464ebd5Sriastradh * on MSVC.  This is an implementation using slightly different
423464ebd5Sriastradh * lower-level Windows functions.
433464ebd5Sriastradh */
443464ebd5Sriastradh#include <float.h>
453464ebd5Sriastradh
463464ebd5Sriastradhenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
473464ebd5Sriastradhfpclassify(double x)
483464ebd5Sriastradh{
493464ebd5Sriastradh    switch(_fpclass(x)) {
503464ebd5Sriastradh        case _FPCLASS_SNAN: /* signaling NaN */
513464ebd5Sriastradh        case _FPCLASS_QNAN: /* quiet NaN */
523464ebd5Sriastradh            return FP_NAN;
533464ebd5Sriastradh        case _FPCLASS_NINF: /* negative infinity */
543464ebd5Sriastradh        case _FPCLASS_PINF: /* positive infinity */
553464ebd5Sriastradh            return FP_INFINITE;
563464ebd5Sriastradh        case _FPCLASS_NN:   /* negative normal */
573464ebd5Sriastradh        case _FPCLASS_PN:   /* positive normal */
583464ebd5Sriastradh            return FP_NORMAL;
593464ebd5Sriastradh        case _FPCLASS_ND:   /* negative denormalized */
603464ebd5Sriastradh        case _FPCLASS_PD:   /* positive denormalized */
613464ebd5Sriastradh            return FP_SUBNORMAL;
623464ebd5Sriastradh        case _FPCLASS_NZ:   /* negative zero */
633464ebd5Sriastradh        case _FPCLASS_PZ:   /* positive zero */
643464ebd5Sriastradh            return FP_ZERO;
653464ebd5Sriastradh        default:
663464ebd5Sriastradh            /* Should never get here; but if we do, this will guarantee
673464ebd5Sriastradh             * that the pattern is not treated like a number.
683464ebd5Sriastradh             */
693464ebd5Sriastradh            return FP_NAN;
703464ebd5Sriastradh    }
713464ebd5Sriastradh}
723464ebd5Sriastradh
733464ebd5Sriastradh#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
743464ebd5Sriastradh     defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
753464ebd5Sriastradh     (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \
763464ebd5Sriastradh     (defined(__sun) && defined(__GNUC__))
773464ebd5Sriastradh
783464ebd5Sriastradh/* fpclassify is available. */
793464ebd5Sriastradh
803464ebd5Sriastradh#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
813464ebd5Sriastradh
823464ebd5Sriastradhenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
833464ebd5Sriastradhfpclassify(double x)
843464ebd5Sriastradh{
853464ebd5Sriastradh   /* XXX do something better someday */
863464ebd5Sriastradh   return FP_NORMAL;
873464ebd5Sriastradh}
883464ebd5Sriastradh
893464ebd5Sriastradh#endif
903464ebd5Sriastradh
913464ebd5Sriastradhextern GLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]);
923464ebd5Sriastradh
933464ebd5Sriastradh/* The Mesa functions we'll need */
943464ebd5Sriastradhextern void GL_APIENTRY _mesa_GetIntegerv(GLenum pname, GLint *params);
953464ebd5Sriastradhextern void GL_APIENTRY _mesa_GetFloatv(GLenum pname, GLfloat *params);
963464ebd5Sriastradh
973464ebd5SriastradhGLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16])
983464ebd5Sriastradh{
993464ebd5Sriastradh    GLfloat matrix[16];
1003464ebd5Sriastradh    GLint tmp;
1013464ebd5Sriastradh    GLenum currentMode = GL_FALSE;
1023464ebd5Sriastradh    GLenum desiredMatrix = GL_FALSE;
1033464ebd5Sriastradh    /* The bitfield returns 1 for each component that is invalid (i.e.
1043464ebd5Sriastradh     * NaN or Inf).  In case of error, everything is invalid.
1053464ebd5Sriastradh     */
1063464ebd5Sriastradh    GLbitfield rv;
1073464ebd5Sriastradh    register unsigned int i;
1083464ebd5Sriastradh    unsigned int bit;
1093464ebd5Sriastradh
1103464ebd5Sriastradh    /* This data structure defines the mapping between the current matrix
1113464ebd5Sriastradh     * mode and the desired matrix identifier.
1123464ebd5Sriastradh     */
1133464ebd5Sriastradh    static struct {
1143464ebd5Sriastradh        GLenum currentMode;
1153464ebd5Sriastradh        GLenum desiredMatrix;
1163464ebd5Sriastradh    } modes[] = {
1173464ebd5Sriastradh        {GL_MODELVIEW, GL_MODELVIEW_MATRIX},
1183464ebd5Sriastradh        {GL_PROJECTION, GL_PROJECTION_MATRIX},
1193464ebd5Sriastradh        {GL_TEXTURE, GL_TEXTURE_MATRIX},
1203464ebd5Sriastradh    };
1213464ebd5Sriastradh
1223464ebd5Sriastradh    /* Call Mesa to get the current matrix in floating-point form.  First,
1233464ebd5Sriastradh     * we have to figure out what the current matrix mode is.
1243464ebd5Sriastradh     */
1253464ebd5Sriastradh    _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp);
1263464ebd5Sriastradh    currentMode = (GLenum) tmp;
1273464ebd5Sriastradh
1283464ebd5Sriastradh    /* The mode is either GL_FALSE, if for some reason we failed to query
1293464ebd5Sriastradh     * the mode, or a given mode from the above table.  Search for the
1303464ebd5Sriastradh     * returned mode to get the desired matrix; if we don't find it,
1313464ebd5Sriastradh     * we can return immediately, as _mesa_GetInteger() will have
1323464ebd5Sriastradh     * logged the necessary error already.
1333464ebd5Sriastradh     */
1343464ebd5Sriastradh    for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) {
1353464ebd5Sriastradh        if (modes[i].currentMode == currentMode) {
1363464ebd5Sriastradh            desiredMatrix = modes[i].desiredMatrix;
1373464ebd5Sriastradh            break;
1383464ebd5Sriastradh        }
1393464ebd5Sriastradh    }
1403464ebd5Sriastradh    if (desiredMatrix == GL_FALSE) {
1413464ebd5Sriastradh        /* Early error means all values are invalid. */
1423464ebd5Sriastradh        return 0xffff;
1433464ebd5Sriastradh    }
1443464ebd5Sriastradh
1453464ebd5Sriastradh    /* Now pull the matrix itself. */
1463464ebd5Sriastradh    _mesa_GetFloatv(desiredMatrix, matrix);
1473464ebd5Sriastradh
1483464ebd5Sriastradh    rv = 0;
1493464ebd5Sriastradh    for (i = 0, bit = 1; i < 16; i++, bit<<=1) {
1503464ebd5Sriastradh        float normalizedFraction;
1513464ebd5Sriastradh        int exp;
1523464ebd5Sriastradh
1533464ebd5Sriastradh        switch (fpclassify(matrix[i])) {
1543464ebd5Sriastradh            /* A "subnormal" or denormalized number is too small to be
1553464ebd5Sriastradh             * represented in normal format; but despite that it's a
1563464ebd5Sriastradh             * valid floating point number.  FP_ZERO and FP_NORMAL
1573464ebd5Sriastradh             * are both valid as well.  We should be fine treating
1583464ebd5Sriastradh             * these three cases as legitimate floating-point numbers.
1593464ebd5Sriastradh             */
1603464ebd5Sriastradh            case FP_SUBNORMAL:
1613464ebd5Sriastradh            case FP_NORMAL:
1623464ebd5Sriastradh            case FP_ZERO:
1633464ebd5Sriastradh                normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
1643464ebd5Sriastradh                mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
1653464ebd5Sriastradh                exponent[i] = (GLint) exp;
1663464ebd5Sriastradh                break;
1673464ebd5Sriastradh
1683464ebd5Sriastradh            /* If the entry is not-a-number or an infinity, then the
1693464ebd5Sriastradh             * matrix component is invalid.  The invalid flag for
1703464ebd5Sriastradh             * the component is already set; might as well set the
1713464ebd5Sriastradh             * other return values to known values.  We'll set
1723464ebd5Sriastradh             * distinct values so that a savvy end user could determine
1733464ebd5Sriastradh             * whether the matrix component was a NaN or an infinity,
1743464ebd5Sriastradh             * but this is more useful for debugging than anything else
1753464ebd5Sriastradh             * since the standard doesn't specify any such magic
1763464ebd5Sriastradh             * values to return.
1773464ebd5Sriastradh             */
1783464ebd5Sriastradh            case FP_NAN:
1793464ebd5Sriastradh                mantissa[i] = INT_TO_FIXED(0);
1803464ebd5Sriastradh                exponent[i] = (GLint) 0;
1813464ebd5Sriastradh                rv |= bit;
1823464ebd5Sriastradh                break;
1833464ebd5Sriastradh
1843464ebd5Sriastradh            case FP_INFINITE:
1853464ebd5Sriastradh                /* Return +/- 1 based on whether it's a positive or
1863464ebd5Sriastradh                 * negative infinity.
1873464ebd5Sriastradh                 */
1883464ebd5Sriastradh                if (matrix[i] > 0) {
1893464ebd5Sriastradh                    mantissa[i] = INT_TO_FIXED(1);
1903464ebd5Sriastradh                }
1913464ebd5Sriastradh                else {
1923464ebd5Sriastradh                    mantissa[i] = -INT_TO_FIXED(1);
1933464ebd5Sriastradh                }
1943464ebd5Sriastradh                exponent[i] = (GLint) 0;
1953464ebd5Sriastradh                rv |= bit;
1963464ebd5Sriastradh                break;
1973464ebd5Sriastradh
1983464ebd5Sriastradh            /* We should never get here; but here's a catching case
1993464ebd5Sriastradh             * in case fpclassify() is returnings something unexpected.
2003464ebd5Sriastradh             */
2013464ebd5Sriastradh            default:
2023464ebd5Sriastradh                mantissa[i] = INT_TO_FIXED(2);
2033464ebd5Sriastradh                exponent[i] = (GLint) 0;
2043464ebd5Sriastradh                rv |= bit;
2053464ebd5Sriastradh                break;
2063464ebd5Sriastradh        }
2073464ebd5Sriastradh
2083464ebd5Sriastradh    } /* for each component */
2093464ebd5Sriastradh
2103464ebd5Sriastradh    /* All done */
2113464ebd5Sriastradh    return rv;
2123464ebd5Sriastradh}
213