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