querymatrix.c revision d2fa95a4c08ba32237cff1d5b5d28b35f7d3d753
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(WIN32) || defined(_WIN32_WCE) 40/* Oddly, the fpclassify() function doesn't exist in such a form 41 * on Windows. 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(__DragonFly__) || (defined(__sun) && defined(__C99FEATURES__)) 75 76/* fpclassify is available. */ 77 78#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600 79 80enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} 81fpclassify(double x) 82{ 83 /* XXX do something better someday */ 84 return FP_NORMAL; 85} 86 87#endif 88 89extern GLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]); 90 91/* The Mesa functions we'll need */ 92extern void GL_APIENTRY _mesa_GetIntegerv(GLenum pname, GLint *params); 93extern void GL_APIENTRY _mesa_GetFloatv(GLenum pname, GLfloat *params); 94 95GLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) 96{ 97 GLfloat matrix[16]; 98 GLint tmp; 99 GLenum currentMode = GL_FALSE; 100 GLenum desiredMatrix = GL_FALSE; 101 /* The bitfield returns 1 for each component that is invalid (i.e. 102 * NaN or Inf). In case of error, everything is invalid. 103 */ 104 GLbitfield rv; 105 register unsigned int i; 106 unsigned int bit; 107 108 /* This data structure defines the mapping between the current matrix 109 * mode and the desired matrix identifier. 110 */ 111 static struct { 112 GLenum currentMode; 113 GLenum desiredMatrix; 114 } modes[] = { 115 {GL_MODELVIEW, GL_MODELVIEW_MATRIX}, 116 {GL_PROJECTION, GL_PROJECTION_MATRIX}, 117 {GL_TEXTURE, GL_TEXTURE_MATRIX}, 118#if 0 119 /* this doesn't exist in GLES */ 120 {GL_COLOR, GL_COLOR_MATRIX}, 121#endif 122 }; 123 124 /* Call Mesa to get the current matrix in floating-point form. First, 125 * we have to figure out what the current matrix mode is. 126 */ 127 _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp); 128 currentMode = (GLenum) tmp; 129 130 /* The mode is either GL_FALSE, if for some reason we failed to query 131 * the mode, or a given mode from the above table. Search for the 132 * returned mode to get the desired matrix; if we don't find it, 133 * we can return immediately, as _mesa_GetInteger() will have 134 * logged the necessary error already. 135 */ 136 for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) { 137 if (modes[i].currentMode == currentMode) { 138 desiredMatrix = modes[i].desiredMatrix; 139 break; 140 } 141 } 142 if (desiredMatrix == GL_FALSE) { 143 /* Early error means all values are invalid. */ 144 return 0xffff; 145 } 146 147 /* Now pull the matrix itself. */ 148 _mesa_GetFloatv(desiredMatrix, matrix); 149 150 rv = 0; 151 for (i = 0, bit = 1; i < 16; i++, bit<<=1) { 152 float normalizedFraction; 153 int exp; 154 155 switch (fpclassify(matrix[i])) { 156 /* A "subnormal" or denormalized number is too small to be 157 * represented in normal format; but despite that it's a 158 * valid floating point number. FP_ZERO and FP_NORMAL 159 * are both valid as well. We should be fine treating 160 * these three cases as legitimate floating-point numbers. 161 */ 162 case FP_SUBNORMAL: 163 case FP_NORMAL: 164 case FP_ZERO: 165 normalizedFraction = (GLfloat)frexp(matrix[i], &exp); 166 mantissa[i] = FLOAT_TO_FIXED(normalizedFraction); 167 exponent[i] = (GLint) exp; 168 break; 169 170 /* If the entry is not-a-number or an infinity, then the 171 * matrix component is invalid. The invalid flag for 172 * the component is already set; might as well set the 173 * other return values to known values. We'll set 174 * distinct values so that a savvy end user could determine 175 * whether the matrix component was a NaN or an infinity, 176 * but this is more useful for debugging than anything else 177 * since the standard doesn't specify any such magic 178 * values to return. 179 */ 180 case FP_NAN: 181 mantissa[i] = INT_TO_FIXED(0); 182 exponent[i] = (GLint) 0; 183 rv |= bit; 184 break; 185 186 case FP_INFINITE: 187 /* Return +/- 1 based on whether it's a positive or 188 * negative infinity. 189 */ 190 if (matrix[i] > 0) { 191 mantissa[i] = INT_TO_FIXED(1); 192 } 193 else { 194 mantissa[i] = -INT_TO_FIXED(1); 195 } 196 exponent[i] = (GLint) 0; 197 rv |= bit; 198 break; 199 200 /* We should never get here; but here's a catching case 201 * in case fpclassify() is returnings something unexpected. 202 */ 203 default: 204 mantissa[i] = INT_TO_FIXED(2); 205 exponent[i] = (GLint) 0; 206 rv |= bit; 207 break; 208 } 209 210 } /* for each component */ 211 212 /* All done */ 213 return rv; 214} 215