13464ebd5Sriastradh/************************************************************************** 23464ebd5Sriastradh * 3af69d88dSmrg * Copyright 2008 VMware, Inc. 43464ebd5Sriastradh * All Rights Reserved. 53464ebd5Sriastradh * 63464ebd5Sriastradh **************************************************************************/ 73464ebd5Sriastradh 83464ebd5Sriastradh 93464ebd5Sriastradh/** 103464ebd5Sriastradh * Code to implement GL_OES_query_matrix. See the spec at: 113464ebd5Sriastradh * http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt 123464ebd5Sriastradh */ 133464ebd5Sriastradh 143464ebd5Sriastradh 153464ebd5Sriastradh#include <stdlib.h> 1601e04c3fSmrg#include "c99_math.h" 17af69d88dSmrg#include "glheader.h" 18af69d88dSmrg#include "querymatrix.h" 19af69d88dSmrg#include "main/get.h" 2001e04c3fSmrg#include "util/macros.h" 213464ebd5Sriastradh 223464ebd5Sriastradh 233464ebd5Sriastradh/** 243464ebd5Sriastradh * This is from the GL_OES_query_matrix extension specification: 253464ebd5Sriastradh * 263464ebd5Sriastradh * GLbitfield glQueryMatrixxOES( GLfixed mantissa[16], 273464ebd5Sriastradh * GLint exponent[16] ) 283464ebd5Sriastradh * mantissa[16] contains the contents of the current matrix in GLfixed 293464ebd5Sriastradh * format. exponent[16] contains the unbiased exponents applied to the 303464ebd5Sriastradh * matrix components, so that the internal representation of component i 313464ebd5Sriastradh * is close to mantissa[i] * 2^exponent[i]. The function returns a status 323464ebd5Sriastradh * word which is zero if all the components are valid. If 333464ebd5Sriastradh * status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf). 343464ebd5Sriastradh * The implementations are not required to keep track of overflows. In 353464ebd5Sriastradh * that case, the invalid bits are never set. 363464ebd5Sriastradh */ 373464ebd5Sriastradh 383464ebd5Sriastradh#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16)) 393464ebd5Sriastradh#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0)) 403464ebd5Sriastradh 413464ebd5Sriastradh 4201e04c3fSmrgGLbitfield GLAPIENTRY 4301e04c3fSmrg_mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) 443464ebd5Sriastradh{ 4501e04c3fSmrg GLfloat matrix[16]; 4601e04c3fSmrg GLint tmp; 4701e04c3fSmrg GLenum currentMode = GL_FALSE; 4801e04c3fSmrg GLenum desiredMatrix = GL_FALSE; 4901e04c3fSmrg /* The bitfield returns 1 for each component that is invalid (i.e. 5001e04c3fSmrg * NaN or Inf). In case of error, everything is invalid. 5101e04c3fSmrg */ 5201e04c3fSmrg GLbitfield rv; 5301e04c3fSmrg unsigned i, bit; 5401e04c3fSmrg 5501e04c3fSmrg /* This data structure defines the mapping between the current matrix 5601e04c3fSmrg * mode and the desired matrix identifier. 5701e04c3fSmrg */ 5801e04c3fSmrg static const struct { 5901e04c3fSmrg GLenum currentMode; 6001e04c3fSmrg GLenum desiredMatrix; 6101e04c3fSmrg } modes[] = { 6201e04c3fSmrg {GL_MODELVIEW, GL_MODELVIEW_MATRIX}, 6301e04c3fSmrg {GL_PROJECTION, GL_PROJECTION_MATRIX}, 6401e04c3fSmrg {GL_TEXTURE, GL_TEXTURE_MATRIX}, 6501e04c3fSmrg }; 6601e04c3fSmrg 6701e04c3fSmrg /* Call Mesa to get the current matrix in floating-point form. First, 6801e04c3fSmrg * we have to figure out what the current matrix mode is. 6901e04c3fSmrg */ 7001e04c3fSmrg _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp); 7101e04c3fSmrg currentMode = (GLenum) tmp; 7201e04c3fSmrg 7301e04c3fSmrg /* The mode is either GL_FALSE, if for some reason we failed to query 7401e04c3fSmrg * the mode, or a given mode from the above table. Search for the 7501e04c3fSmrg * returned mode to get the desired matrix; if we don't find it, 7601e04c3fSmrg * we can return immediately, as _mesa_GetInteger() will have 7701e04c3fSmrg * logged the necessary error already. 7801e04c3fSmrg */ 7901e04c3fSmrg for (i = 0; i < ARRAY_SIZE(modes); i++) { 8001e04c3fSmrg if (modes[i].currentMode == currentMode) { 8101e04c3fSmrg desiredMatrix = modes[i].desiredMatrix; 8201e04c3fSmrg break; 8301e04c3fSmrg } 8401e04c3fSmrg } 8501e04c3fSmrg if (desiredMatrix == GL_FALSE) { 8601e04c3fSmrg /* Early error means all values are invalid. */ 8701e04c3fSmrg return 0xffff; 8801e04c3fSmrg } 8901e04c3fSmrg 9001e04c3fSmrg /* Now pull the matrix itself. */ 9101e04c3fSmrg _mesa_GetFloatv(desiredMatrix, matrix); 9201e04c3fSmrg 9301e04c3fSmrg rv = 0; 9401e04c3fSmrg for (i = 0, bit = 1; i < 16; i++, bit<<=1) { 9501e04c3fSmrg float normalizedFraction; 9601e04c3fSmrg int exp; 9701e04c3fSmrg 9801e04c3fSmrg switch (fpclassify(matrix[i])) { 9901e04c3fSmrg case FP_SUBNORMAL: 10001e04c3fSmrg case FP_NORMAL: 10101e04c3fSmrg case FP_ZERO: 10201e04c3fSmrg /* A "subnormal" or denormalized number is too small to be 10301e04c3fSmrg * represented in normal format; but despite that it's a 10401e04c3fSmrg * valid floating point number. FP_ZERO and FP_NORMAL 10501e04c3fSmrg * are both valid as well. We should be fine treating 10601e04c3fSmrg * these three cases as legitimate floating-point numbers. 10701e04c3fSmrg */ 10801e04c3fSmrg normalizedFraction = (GLfloat)frexp(matrix[i], &exp); 10901e04c3fSmrg mantissa[i] = FLOAT_TO_FIXED(normalizedFraction); 11001e04c3fSmrg exponent[i] = (GLint) exp; 11101e04c3fSmrg break; 11201e04c3fSmrg 11301e04c3fSmrg case FP_NAN: 11401e04c3fSmrg /* If the entry is not-a-number or an infinity, then the 11501e04c3fSmrg * matrix component is invalid. The invalid flag for 11601e04c3fSmrg * the component is already set; might as well set the 11701e04c3fSmrg * other return values to known values. We'll set 11801e04c3fSmrg * distinct values so that a savvy end user could determine 11901e04c3fSmrg * whether the matrix component was a NaN or an infinity, 12001e04c3fSmrg * but this is more useful for debugging than anything else 12101e04c3fSmrg * since the standard doesn't specify any such magic 12201e04c3fSmrg * values to return. 12301e04c3fSmrg */ 12401e04c3fSmrg mantissa[i] = INT_TO_FIXED(0); 12501e04c3fSmrg exponent[i] = (GLint) 0; 12601e04c3fSmrg rv |= bit; 12701e04c3fSmrg break; 12801e04c3fSmrg 12901e04c3fSmrg case FP_INFINITE: 13001e04c3fSmrg /* Return +/- 1 based on whether it's a positive or 13101e04c3fSmrg * negative infinity. 13201e04c3fSmrg */ 13301e04c3fSmrg if (matrix[i] > 0) { 13401e04c3fSmrg mantissa[i] = INT_TO_FIXED(1); 13501e04c3fSmrg } 13601e04c3fSmrg else { 13701e04c3fSmrg mantissa[i] = -INT_TO_FIXED(1); 13801e04c3fSmrg } 13901e04c3fSmrg exponent[i] = (GLint) 0; 14001e04c3fSmrg rv |= bit; 14101e04c3fSmrg break; 14201e04c3fSmrg 14301e04c3fSmrg default: 14401e04c3fSmrg /* We should never get here; but here's a catching case 14501e04c3fSmrg * in case fpclassify() is returnings something unexpected. 14601e04c3fSmrg */ 14701e04c3fSmrg mantissa[i] = INT_TO_FIXED(2); 14801e04c3fSmrg exponent[i] = (GLint) 0; 14901e04c3fSmrg rv |= bit; 15001e04c3fSmrg break; 15101e04c3fSmrg } 15201e04c3fSmrg 15301e04c3fSmrg } /* for each component */ 15401e04c3fSmrg 15501e04c3fSmrg /* All done */ 15601e04c3fSmrg return rv; 1573464ebd5Sriastradh} 158