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