095817cf5b95023b9c326e4b26ff9a021a08686e
[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 "c99_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
41 GLbitfield GLAPIENTRY _mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16])
42 {
43 GLfloat matrix[16];
44 GLint tmp;
45 GLenum currentMode = GL_FALSE;
46 GLenum desiredMatrix = GL_FALSE;
47 /* The bitfield returns 1 for each component that is invalid (i.e.
48 * NaN or Inf). In case of error, everything is invalid.
49 */
50 GLbitfield rv;
51 register unsigned int i;
52 unsigned int bit;
53
54 /* This data structure defines the mapping between the current matrix
55 * mode and the desired matrix identifier.
56 */
57 static struct {
58 GLenum currentMode;
59 GLenum desiredMatrix;
60 } modes[] = {
61 {GL_MODELVIEW, GL_MODELVIEW_MATRIX},
62 {GL_PROJECTION, GL_PROJECTION_MATRIX},
63 {GL_TEXTURE, GL_TEXTURE_MATRIX},
64 };
65
66 /* Call Mesa to get the current matrix in floating-point form. First,
67 * we have to figure out what the current matrix mode is.
68 */
69 _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp);
70 currentMode = (GLenum) tmp;
71
72 /* The mode is either GL_FALSE, if for some reason we failed to query
73 * the mode, or a given mode from the above table. Search for the
74 * returned mode to get the desired matrix; if we don't find it,
75 * we can return immediately, as _mesa_GetInteger() will have
76 * logged the necessary error already.
77 */
78 for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) {
79 if (modes[i].currentMode == currentMode) {
80 desiredMatrix = modes[i].desiredMatrix;
81 break;
82 }
83 }
84 if (desiredMatrix == GL_FALSE) {
85 /* Early error means all values are invalid. */
86 return 0xffff;
87 }
88
89 /* Now pull the matrix itself. */
90 _mesa_GetFloatv(desiredMatrix, matrix);
91
92 rv = 0;
93 for (i = 0, bit = 1; i < 16; i++, bit<<=1) {
94 float normalizedFraction;
95 int exp;
96
97 switch (fpclassify(matrix[i])) {
98 /* A "subnormal" or denormalized number is too small to be
99 * represented in normal format; but despite that it's a
100 * valid floating point number. FP_ZERO and FP_NORMAL
101 * are both valid as well. We should be fine treating
102 * these three cases as legitimate floating-point numbers.
103 */
104 case FP_SUBNORMAL:
105 case FP_NORMAL:
106 case FP_ZERO:
107 normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
108 mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
109 exponent[i] = (GLint) exp;
110 break;
111
112 /* If the entry is not-a-number or an infinity, then the
113 * matrix component is invalid. The invalid flag for
114 * the component is already set; might as well set the
115 * other return values to known values. We'll set
116 * distinct values so that a savvy end user could determine
117 * whether the matrix component was a NaN or an infinity,
118 * but this is more useful for debugging than anything else
119 * since the standard doesn't specify any such magic
120 * values to return.
121 */
122 case FP_NAN:
123 mantissa[i] = INT_TO_FIXED(0);
124 exponent[i] = (GLint) 0;
125 rv |= bit;
126 break;
127
128 case FP_INFINITE:
129 /* Return +/- 1 based on whether it's a positive or
130 * negative infinity.
131 */
132 if (matrix[i] > 0) {
133 mantissa[i] = INT_TO_FIXED(1);
134 }
135 else {
136 mantissa[i] = -INT_TO_FIXED(1);
137 }
138 exponent[i] = (GLint) 0;
139 rv |= bit;
140 break;
141
142 /* We should never get here; but here's a catching case
143 * in case fpclassify() is returnings something unexpected.
144 */
145 default:
146 mantissa[i] = INT_TO_FIXED(2);
147 exponent[i] = (GLint) 0;
148 rv |= bit;
149 break;
150 }
151
152 } /* for each component */
153
154 /* All done */
155 return rv;
156 }