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