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