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