querymatrix.c revision af69d88d
1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 **************************************************************************/
7
8
9/**
10 * Code to implement GL_OES_query_matrix.  See the spec at:
11 * http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt
12 */
13
14
15#include <stdlib.h>
16#include <math.h>
17#include "glheader.h"
18#include "querymatrix.h"
19#include "main/get.h"
20
21
22/**
23 * This is from the GL_OES_query_matrix extension specification:
24 *
25 *  GLbitfield glQueryMatrixxOES( GLfixed mantissa[16],
26 *                                GLint   exponent[16] )
27 *  mantissa[16] contains the contents of the current matrix in GLfixed
28 *  format.  exponent[16] contains the unbiased exponents applied to the
29 *  matrix components, so that the internal representation of component i
30 *  is close to mantissa[i] * 2^exponent[i].  The function returns a status
31 *  word which is zero if all the components are valid. If
32 *  status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf).
33 *  The implementations are not required to keep track of overflows.  In
34 *  that case, the invalid bits are never set.
35 */
36
37#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16))
38#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0))
39
40#if defined(_MSC_VER)
41#if _MSC_VER < 1800  /* Not required on VS2013 and above. */
42/* Oddly, the fpclassify() function doesn't exist in such a form
43 * on MSVC.  This is an implementation using slightly different
44 * lower-level Windows functions.
45 */
46#include <float.h>
47
48enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
49fpclassify(double x)
50{
51    switch(_fpclass(x)) {
52        case _FPCLASS_SNAN: /* signaling NaN */
53        case _FPCLASS_QNAN: /* quiet NaN */
54            return FP_NAN;
55        case _FPCLASS_NINF: /* negative infinity */
56        case _FPCLASS_PINF: /* positive infinity */
57            return FP_INFINITE;
58        case _FPCLASS_NN:   /* negative normal */
59        case _FPCLASS_PN:   /* positive normal */
60            return FP_NORMAL;
61        case _FPCLASS_ND:   /* negative denormalized */
62        case _FPCLASS_PD:   /* positive denormalized */
63            return FP_SUBNORMAL;
64        case _FPCLASS_NZ:   /* negative zero */
65        case _FPCLASS_PZ:   /* positive zero */
66            return FP_ZERO;
67        default:
68            /* Should never get here; but if we do, this will guarantee
69             * that the pattern is not treated like a number.
70             */
71            return FP_NAN;
72    }
73}
74#endif  /* _MSC_VER < 1800 */
75
76#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
77     defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
78     (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \
79     (defined(__sun) && defined(__GNUC__)) || defined(ANDROID) || defined(__HAIKU__)
80
81/* fpclassify is available. */
82
83#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
84
85enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
86fpclassify(double x)
87{
88   /* XXX do something better someday */
89   return FP_NORMAL;
90}
91
92#endif
93
94GLbitfield GLAPIENTRY _mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16])
95{
96    GLfloat matrix[16];
97    GLint tmp;
98    GLenum currentMode = GL_FALSE;
99    GLenum desiredMatrix = GL_FALSE;
100    /* The bitfield returns 1 for each component that is invalid (i.e.
101     * NaN or Inf).  In case of error, everything is invalid.
102     */
103    GLbitfield rv;
104    register unsigned int i;
105    unsigned int bit;
106
107    /* This data structure defines the mapping between the current matrix
108     * mode and the desired matrix identifier.
109     */
110    static struct {
111        GLenum currentMode;
112        GLenum desiredMatrix;
113    } modes[] = {
114        {GL_MODELVIEW, GL_MODELVIEW_MATRIX},
115        {GL_PROJECTION, GL_PROJECTION_MATRIX},
116        {GL_TEXTURE, GL_TEXTURE_MATRIX},
117    };
118
119    /* Call Mesa to get the current matrix in floating-point form.  First,
120     * we have to figure out what the current matrix mode is.
121     */
122    _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp);
123    currentMode = (GLenum) tmp;
124
125    /* The mode is either GL_FALSE, if for some reason we failed to query
126     * the mode, or a given mode from the above table.  Search for the
127     * returned mode to get the desired matrix; if we don't find it,
128     * we can return immediately, as _mesa_GetInteger() will have
129     * logged the necessary error already.
130     */
131    for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) {
132        if (modes[i].currentMode == currentMode) {
133            desiredMatrix = modes[i].desiredMatrix;
134            break;
135        }
136    }
137    if (desiredMatrix == GL_FALSE) {
138        /* Early error means all values are invalid. */
139        return 0xffff;
140    }
141
142    /* Now pull the matrix itself. */
143    _mesa_GetFloatv(desiredMatrix, matrix);
144
145    rv = 0;
146    for (i = 0, bit = 1; i < 16; i++, bit<<=1) {
147        float normalizedFraction;
148        int exp;
149
150        switch (fpclassify(matrix[i])) {
151            /* A "subnormal" or denormalized number is too small to be
152             * represented in normal format; but despite that it's a
153             * valid floating point number.  FP_ZERO and FP_NORMAL
154             * are both valid as well.  We should be fine treating
155             * these three cases as legitimate floating-point numbers.
156             */
157            case FP_SUBNORMAL:
158            case FP_NORMAL:
159            case FP_ZERO:
160                normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
161                mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
162                exponent[i] = (GLint) exp;
163                break;
164
165            /* If the entry is not-a-number or an infinity, then the
166             * matrix component is invalid.  The invalid flag for
167             * the component is already set; might as well set the
168             * other return values to known values.  We'll set
169             * distinct values so that a savvy end user could determine
170             * whether the matrix component was a NaN or an infinity,
171             * but this is more useful for debugging than anything else
172             * since the standard doesn't specify any such magic
173             * values to return.
174             */
175            case FP_NAN:
176                mantissa[i] = INT_TO_FIXED(0);
177                exponent[i] = (GLint) 0;
178                rv |= bit;
179                break;
180
181            case FP_INFINITE:
182                /* Return +/- 1 based on whether it's a positive or
183                 * negative infinity.
184                 */
185                if (matrix[i] > 0) {
186                    mantissa[i] = INT_TO_FIXED(1);
187                }
188                else {
189                    mantissa[i] = -INT_TO_FIXED(1);
190                }
191                exponent[i] = (GLint) 0;
192                rv |= bit;
193                break;
194
195            /* We should never get here; but here's a catching case
196             * in case fpclassify() is returnings something unexpected.
197             */
198            default:
199                mantissa[i] = INT_TO_FIXED(2);
200                exponent[i] = (GLint) 0;
201                rv |= bit;
202                break;
203        }
204
205    } /* for each component */
206
207    /* All done */
208    return rv;
209}
210