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