querymatrix.c revision 848b8605
1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2008 VMware, Inc.
4848b8605Smrg * All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg **************************************************************************/
7848b8605Smrg
8848b8605Smrg
9848b8605Smrg/**
10848b8605Smrg * Code to implement GL_OES_query_matrix.  See the spec at:
11848b8605Smrg * http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt
12848b8605Smrg */
13848b8605Smrg
14848b8605Smrg
15848b8605Smrg#include <stdlib.h>
16848b8605Smrg#include <math.h>
17848b8605Smrg#include "glheader.h"
18848b8605Smrg#include "querymatrix.h"
19848b8605Smrg#include "main/get.h"
20848b8605Smrg
21848b8605Smrg
22848b8605Smrg/**
23848b8605Smrg * This is from the GL_OES_query_matrix extension specification:
24848b8605Smrg *
25848b8605Smrg *  GLbitfield glQueryMatrixxOES( GLfixed mantissa[16],
26848b8605Smrg *                                GLint   exponent[16] )
27848b8605Smrg *  mantissa[16] contains the contents of the current matrix in GLfixed
28848b8605Smrg *  format.  exponent[16] contains the unbiased exponents applied to the
29848b8605Smrg *  matrix components, so that the internal representation of component i
30848b8605Smrg *  is close to mantissa[i] * 2^exponent[i].  The function returns a status
31848b8605Smrg *  word which is zero if all the components are valid. If
32848b8605Smrg *  status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf).
33848b8605Smrg *  The implementations are not required to keep track of overflows.  In
34848b8605Smrg *  that case, the invalid bits are never set.
35848b8605Smrg */
36848b8605Smrg
37848b8605Smrg#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16))
38848b8605Smrg#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0))
39848b8605Smrg
40848b8605Smrg#if defined(_MSC_VER)
41848b8605Smrg#if _MSC_VER < 1800  /* Not required on VS2013 and above. */
42848b8605Smrg/* Oddly, the fpclassify() function doesn't exist in such a form
43848b8605Smrg * on MSVC.  This is an implementation using slightly different
44848b8605Smrg * lower-level Windows functions.
45848b8605Smrg */
46848b8605Smrg#include <float.h>
47848b8605Smrg
48848b8605Smrgenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
49848b8605Smrgfpclassify(double x)
50848b8605Smrg{
51848b8605Smrg    switch(_fpclass(x)) {
52848b8605Smrg        case _FPCLASS_SNAN: /* signaling NaN */
53848b8605Smrg        case _FPCLASS_QNAN: /* quiet NaN */
54848b8605Smrg            return FP_NAN;
55848b8605Smrg        case _FPCLASS_NINF: /* negative infinity */
56848b8605Smrg        case _FPCLASS_PINF: /* positive infinity */
57848b8605Smrg            return FP_INFINITE;
58848b8605Smrg        case _FPCLASS_NN:   /* negative normal */
59848b8605Smrg        case _FPCLASS_PN:   /* positive normal */
60848b8605Smrg            return FP_NORMAL;
61848b8605Smrg        case _FPCLASS_ND:   /* negative denormalized */
62848b8605Smrg        case _FPCLASS_PD:   /* positive denormalized */
63848b8605Smrg            return FP_SUBNORMAL;
64848b8605Smrg        case _FPCLASS_NZ:   /* negative zero */
65848b8605Smrg        case _FPCLASS_PZ:   /* positive zero */
66848b8605Smrg            return FP_ZERO;
67848b8605Smrg        default:
68848b8605Smrg            /* Should never get here; but if we do, this will guarantee
69848b8605Smrg             * that the pattern is not treated like a number.
70848b8605Smrg             */
71848b8605Smrg            return FP_NAN;
72848b8605Smrg    }
73848b8605Smrg}
74848b8605Smrg#endif  /* _MSC_VER < 1800 */
75848b8605Smrg
76848b8605Smrg#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
77848b8605Smrg     defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
78848b8605Smrg     (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \
79848b8605Smrg     (defined(__sun) && defined(__GNUC__)) || defined(ANDROID) || defined(__HAIKU__)
80848b8605Smrg
81848b8605Smrg/* fpclassify is available. */
82848b8605Smrg
83848b8605Smrg#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
84848b8605Smrg
85848b8605Smrgenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
86848b8605Smrgfpclassify(double x)
87848b8605Smrg{
88848b8605Smrg   /* XXX do something better someday */
89848b8605Smrg   return FP_NORMAL;
90848b8605Smrg}
91848b8605Smrg
92848b8605Smrg#endif
93848b8605Smrg
94848b8605SmrgGLbitfield GLAPIENTRY _mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16])
95848b8605Smrg{
96848b8605Smrg    GLfloat matrix[16];
97848b8605Smrg    GLint tmp;
98848b8605Smrg    GLenum currentMode = GL_FALSE;
99848b8605Smrg    GLenum desiredMatrix = GL_FALSE;
100848b8605Smrg    /* The bitfield returns 1 for each component that is invalid (i.e.
101848b8605Smrg     * NaN or Inf).  In case of error, everything is invalid.
102848b8605Smrg     */
103848b8605Smrg    GLbitfield rv;
104848b8605Smrg    register unsigned int i;
105848b8605Smrg    unsigned int bit;
106848b8605Smrg
107848b8605Smrg    /* This data structure defines the mapping between the current matrix
108848b8605Smrg     * mode and the desired matrix identifier.
109848b8605Smrg     */
110848b8605Smrg    static struct {
111848b8605Smrg        GLenum currentMode;
112848b8605Smrg        GLenum desiredMatrix;
113848b8605Smrg    } modes[] = {
114848b8605Smrg        {GL_MODELVIEW, GL_MODELVIEW_MATRIX},
115848b8605Smrg        {GL_PROJECTION, GL_PROJECTION_MATRIX},
116848b8605Smrg        {GL_TEXTURE, GL_TEXTURE_MATRIX},
117848b8605Smrg    };
118848b8605Smrg
119848b8605Smrg    /* Call Mesa to get the current matrix in floating-point form.  First,
120848b8605Smrg     * we have to figure out what the current matrix mode is.
121848b8605Smrg     */
122848b8605Smrg    _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp);
123848b8605Smrg    currentMode = (GLenum) tmp;
124848b8605Smrg
125848b8605Smrg    /* The mode is either GL_FALSE, if for some reason we failed to query
126848b8605Smrg     * the mode, or a given mode from the above table.  Search for the
127848b8605Smrg     * returned mode to get the desired matrix; if we don't find it,
128848b8605Smrg     * we can return immediately, as _mesa_GetInteger() will have
129848b8605Smrg     * logged the necessary error already.
130848b8605Smrg     */
131848b8605Smrg    for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) {
132848b8605Smrg        if (modes[i].currentMode == currentMode) {
133848b8605Smrg            desiredMatrix = modes[i].desiredMatrix;
134848b8605Smrg            break;
135848b8605Smrg        }
136848b8605Smrg    }
137848b8605Smrg    if (desiredMatrix == GL_FALSE) {
138848b8605Smrg        /* Early error means all values are invalid. */
139848b8605Smrg        return 0xffff;
140848b8605Smrg    }
141848b8605Smrg
142848b8605Smrg    /* Now pull the matrix itself. */
143848b8605Smrg    _mesa_GetFloatv(desiredMatrix, matrix);
144848b8605Smrg
145848b8605Smrg    rv = 0;
146848b8605Smrg    for (i = 0, bit = 1; i < 16; i++, bit<<=1) {
147848b8605Smrg        float normalizedFraction;
148848b8605Smrg        int exp;
149848b8605Smrg
150848b8605Smrg        switch (fpclassify(matrix[i])) {
151848b8605Smrg            /* A "subnormal" or denormalized number is too small to be
152848b8605Smrg             * represented in normal format; but despite that it's a
153848b8605Smrg             * valid floating point number.  FP_ZERO and FP_NORMAL
154848b8605Smrg             * are both valid as well.  We should be fine treating
155848b8605Smrg             * these three cases as legitimate floating-point numbers.
156848b8605Smrg             */
157848b8605Smrg            case FP_SUBNORMAL:
158848b8605Smrg            case FP_NORMAL:
159848b8605Smrg            case FP_ZERO:
160848b8605Smrg                normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
161848b8605Smrg                mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
162848b8605Smrg                exponent[i] = (GLint) exp;
163848b8605Smrg                break;
164848b8605Smrg
165848b8605Smrg            /* If the entry is not-a-number or an infinity, then the
166848b8605Smrg             * matrix component is invalid.  The invalid flag for
167848b8605Smrg             * the component is already set; might as well set the
168848b8605Smrg             * other return values to known values.  We'll set
169848b8605Smrg             * distinct values so that a savvy end user could determine
170848b8605Smrg             * whether the matrix component was a NaN or an infinity,
171848b8605Smrg             * but this is more useful for debugging than anything else
172848b8605Smrg             * since the standard doesn't specify any such magic
173848b8605Smrg             * values to return.
174848b8605Smrg             */
175848b8605Smrg            case FP_NAN:
176848b8605Smrg                mantissa[i] = INT_TO_FIXED(0);
177848b8605Smrg                exponent[i] = (GLint) 0;
178848b8605Smrg                rv |= bit;
179848b8605Smrg                break;
180848b8605Smrg
181848b8605Smrg            case FP_INFINITE:
182848b8605Smrg                /* Return +/- 1 based on whether it's a positive or
183848b8605Smrg                 * negative infinity.
184848b8605Smrg                 */
185848b8605Smrg                if (matrix[i] > 0) {
186848b8605Smrg                    mantissa[i] = INT_TO_FIXED(1);
187848b8605Smrg                }
188848b8605Smrg                else {
189848b8605Smrg                    mantissa[i] = -INT_TO_FIXED(1);
190848b8605Smrg                }
191848b8605Smrg                exponent[i] = (GLint) 0;
192848b8605Smrg                rv |= bit;
193848b8605Smrg                break;
194848b8605Smrg
195848b8605Smrg            /* We should never get here; but here's a catching case
196848b8605Smrg             * in case fpclassify() is returnings something unexpected.
197848b8605Smrg             */
198848b8605Smrg            default:
199848b8605Smrg                mantissa[i] = INT_TO_FIXED(2);
200848b8605Smrg                exponent[i] = (GLint) 0;
201848b8605Smrg                rv |= bit;
202848b8605Smrg                break;
203848b8605Smrg        }
204848b8605Smrg
205848b8605Smrg    } /* for each component */
206848b8605Smrg
207848b8605Smrg    /* All done */
208848b8605Smrg    return rv;
209848b8605Smrg}
210