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