querymatrix.c revision 848b8605
1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2008 VMware, Inc. 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg **************************************************************************/ 7848b8605Smrg 8848b8605Smrg 9848b8605Smrg/** 10848b8605Smrg * Code to implement GL_OES_query_matrix. See the spec at: 11848b8605Smrg * http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt 12848b8605Smrg */ 13848b8605Smrg 14848b8605Smrg 15848b8605Smrg#include <stdlib.h> 16848b8605Smrg#include <math.h> 17848b8605Smrg#include "glheader.h" 18848b8605Smrg#include "querymatrix.h" 19848b8605Smrg#include "main/get.h" 20848b8605Smrg 21848b8605Smrg 22848b8605Smrg/** 23848b8605Smrg * This is from the GL_OES_query_matrix extension specification: 24848b8605Smrg * 25848b8605Smrg * GLbitfield glQueryMatrixxOES( GLfixed mantissa[16], 26848b8605Smrg * GLint exponent[16] ) 27848b8605Smrg * mantissa[16] contains the contents of the current matrix in GLfixed 28848b8605Smrg * format. exponent[16] contains the unbiased exponents applied to the 29848b8605Smrg * matrix components, so that the internal representation of component i 30848b8605Smrg * is close to mantissa[i] * 2^exponent[i]. The function returns a status 31848b8605Smrg * word which is zero if all the components are valid. If 32848b8605Smrg * status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf). 33848b8605Smrg * The implementations are not required to keep track of overflows. In 34848b8605Smrg * that case, the invalid bits are never set. 35848b8605Smrg */ 36848b8605Smrg 37848b8605Smrg#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16)) 38848b8605Smrg#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0)) 39848b8605Smrg 40848b8605Smrg#if defined(_MSC_VER) 41848b8605Smrg#if _MSC_VER < 1800 /* Not required on VS2013 and above. */ 42848b8605Smrg/* Oddly, the fpclassify() function doesn't exist in such a form 43848b8605Smrg * on MSVC. This is an implementation using slightly different 44848b8605Smrg * lower-level Windows functions. 45848b8605Smrg */ 46848b8605Smrg#include <float.h> 47848b8605Smrg 48848b8605Smrgenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} 49848b8605Smrgfpclassify(double x) 50848b8605Smrg{ 51848b8605Smrg switch(_fpclass(x)) { 52848b8605Smrg case _FPCLASS_SNAN: /* signaling NaN */ 53848b8605Smrg case _FPCLASS_QNAN: /* quiet NaN */ 54848b8605Smrg return FP_NAN; 55848b8605Smrg case _FPCLASS_NINF: /* negative infinity */ 56848b8605Smrg case _FPCLASS_PINF: /* positive infinity */ 57848b8605Smrg return FP_INFINITE; 58848b8605Smrg case _FPCLASS_NN: /* negative normal */ 59848b8605Smrg case _FPCLASS_PN: /* positive normal */ 60848b8605Smrg return FP_NORMAL; 61848b8605Smrg case _FPCLASS_ND: /* negative denormalized */ 62848b8605Smrg case _FPCLASS_PD: /* positive denormalized */ 63848b8605Smrg return FP_SUBNORMAL; 64848b8605Smrg case _FPCLASS_NZ: /* negative zero */ 65848b8605Smrg case _FPCLASS_PZ: /* positive zero */ 66848b8605Smrg return FP_ZERO; 67848b8605Smrg default: 68848b8605Smrg /* Should never get here; but if we do, this will guarantee 69848b8605Smrg * that the pattern is not treated like a number. 70848b8605Smrg */ 71848b8605Smrg return FP_NAN; 72848b8605Smrg } 73848b8605Smrg} 74848b8605Smrg#endif /* _MSC_VER < 1800 */ 75848b8605Smrg 76848b8605Smrg#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ 77848b8605Smrg defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ 78848b8605Smrg (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \ 79848b8605Smrg (defined(__sun) && defined(__GNUC__)) || defined(ANDROID) || defined(__HAIKU__) 80848b8605Smrg 81848b8605Smrg/* fpclassify is available. */ 82848b8605Smrg 83848b8605Smrg#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600 84848b8605Smrg 85848b8605Smrgenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} 86848b8605Smrgfpclassify(double x) 87848b8605Smrg{ 88848b8605Smrg /* XXX do something better someday */ 89848b8605Smrg return FP_NORMAL; 90848b8605Smrg} 91848b8605Smrg 92848b8605Smrg#endif 93848b8605Smrg 94848b8605SmrgGLbitfield GLAPIENTRY _mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) 95848b8605Smrg{ 96848b8605Smrg GLfloat matrix[16]; 97848b8605Smrg GLint tmp; 98848b8605Smrg GLenum currentMode = GL_FALSE; 99848b8605Smrg GLenum desiredMatrix = GL_FALSE; 100848b8605Smrg /* The bitfield returns 1 for each component that is invalid (i.e. 101848b8605Smrg * NaN or Inf). In case of error, everything is invalid. 102848b8605Smrg */ 103848b8605Smrg GLbitfield rv; 104848b8605Smrg register unsigned int i; 105848b8605Smrg unsigned int bit; 106848b8605Smrg 107848b8605Smrg /* This data structure defines the mapping between the current matrix 108848b8605Smrg * mode and the desired matrix identifier. 109848b8605Smrg */ 110848b8605Smrg static struct { 111848b8605Smrg GLenum currentMode; 112848b8605Smrg GLenum desiredMatrix; 113848b8605Smrg } modes[] = { 114848b8605Smrg {GL_MODELVIEW, GL_MODELVIEW_MATRIX}, 115848b8605Smrg {GL_PROJECTION, GL_PROJECTION_MATRIX}, 116848b8605Smrg {GL_TEXTURE, GL_TEXTURE_MATRIX}, 117848b8605Smrg }; 118848b8605Smrg 119848b8605Smrg /* Call Mesa to get the current matrix in floating-point form. First, 120848b8605Smrg * we have to figure out what the current matrix mode is. 121848b8605Smrg */ 122848b8605Smrg _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp); 123848b8605Smrg currentMode = (GLenum) tmp; 124848b8605Smrg 125848b8605Smrg /* The mode is either GL_FALSE, if for some reason we failed to query 126848b8605Smrg * the mode, or a given mode from the above table. Search for the 127848b8605Smrg * returned mode to get the desired matrix; if we don't find it, 128848b8605Smrg * we can return immediately, as _mesa_GetInteger() will have 129848b8605Smrg * logged the necessary error already. 130848b8605Smrg */ 131848b8605Smrg for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) { 132848b8605Smrg if (modes[i].currentMode == currentMode) { 133848b8605Smrg desiredMatrix = modes[i].desiredMatrix; 134848b8605Smrg break; 135848b8605Smrg } 136848b8605Smrg } 137848b8605Smrg if (desiredMatrix == GL_FALSE) { 138848b8605Smrg /* Early error means all values are invalid. */ 139848b8605Smrg return 0xffff; 140848b8605Smrg } 141848b8605Smrg 142848b8605Smrg /* Now pull the matrix itself. */ 143848b8605Smrg _mesa_GetFloatv(desiredMatrix, matrix); 144848b8605Smrg 145848b8605Smrg rv = 0; 146848b8605Smrg for (i = 0, bit = 1; i < 16; i++, bit<<=1) { 147848b8605Smrg float normalizedFraction; 148848b8605Smrg int exp; 149848b8605Smrg 150848b8605Smrg switch (fpclassify(matrix[i])) { 151848b8605Smrg /* A "subnormal" or denormalized number is too small to be 152848b8605Smrg * represented in normal format; but despite that it's a 153848b8605Smrg * valid floating point number. FP_ZERO and FP_NORMAL 154848b8605Smrg * are both valid as well. We should be fine treating 155848b8605Smrg * these three cases as legitimate floating-point numbers. 156848b8605Smrg */ 157848b8605Smrg case FP_SUBNORMAL: 158848b8605Smrg case FP_NORMAL: 159848b8605Smrg case FP_ZERO: 160848b8605Smrg normalizedFraction = (GLfloat)frexp(matrix[i], &exp); 161848b8605Smrg mantissa[i] = FLOAT_TO_FIXED(normalizedFraction); 162848b8605Smrg exponent[i] = (GLint) exp; 163848b8605Smrg break; 164848b8605Smrg 165848b8605Smrg /* If the entry is not-a-number or an infinity, then the 166848b8605Smrg * matrix component is invalid. The invalid flag for 167848b8605Smrg * the component is already set; might as well set the 168848b8605Smrg * other return values to known values. We'll set 169848b8605Smrg * distinct values so that a savvy end user could determine 170848b8605Smrg * whether the matrix component was a NaN or an infinity, 171848b8605Smrg * but this is more useful for debugging than anything else 172848b8605Smrg * since the standard doesn't specify any such magic 173848b8605Smrg * values to return. 174848b8605Smrg */ 175848b8605Smrg case FP_NAN: 176848b8605Smrg mantissa[i] = INT_TO_FIXED(0); 177848b8605Smrg exponent[i] = (GLint) 0; 178848b8605Smrg rv |= bit; 179848b8605Smrg break; 180848b8605Smrg 181848b8605Smrg case FP_INFINITE: 182848b8605Smrg /* Return +/- 1 based on whether it's a positive or 183848b8605Smrg * negative infinity. 184848b8605Smrg */ 185848b8605Smrg if (matrix[i] > 0) { 186848b8605Smrg mantissa[i] = INT_TO_FIXED(1); 187848b8605Smrg } 188848b8605Smrg else { 189848b8605Smrg mantissa[i] = -INT_TO_FIXED(1); 190848b8605Smrg } 191848b8605Smrg exponent[i] = (GLint) 0; 192848b8605Smrg rv |= bit; 193848b8605Smrg break; 194848b8605Smrg 195848b8605Smrg /* We should never get here; but here's a catching case 196848b8605Smrg * in case fpclassify() is returnings something unexpected. 197848b8605Smrg */ 198848b8605Smrg default: 199848b8605Smrg mantissa[i] = INT_TO_FIXED(2); 200848b8605Smrg exponent[i] = (GLint) 0; 201848b8605Smrg rv |= bit; 202848b8605Smrg break; 203848b8605Smrg } 204848b8605Smrg 205848b8605Smrg } /* for each component */ 206848b8605Smrg 207848b8605Smrg /* All done */ 208848b8605Smrg return rv; 209848b8605Smrg} 210