querymatrix.c revision 3464ebd5
13464ebd5Sriastradh/************************************************************************** 23464ebd5Sriastradh * 33464ebd5Sriastradh * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 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> 163464ebd5Sriastradh#include <math.h> 173464ebd5Sriastradh#include "GLES/gl.h" 183464ebd5Sriastradh#include "GLES/glext.h" 193464ebd5Sriastradh 203464ebd5Sriastradh 213464ebd5Sriastradh/** 223464ebd5Sriastradh * This is from the GL_OES_query_matrix extension specification: 233464ebd5Sriastradh * 243464ebd5Sriastradh * GLbitfield glQueryMatrixxOES( GLfixed mantissa[16], 253464ebd5Sriastradh * GLint exponent[16] ) 263464ebd5Sriastradh * mantissa[16] contains the contents of the current matrix in GLfixed 273464ebd5Sriastradh * format. exponent[16] contains the unbiased exponents applied to the 283464ebd5Sriastradh * matrix components, so that the internal representation of component i 293464ebd5Sriastradh * is close to mantissa[i] * 2^exponent[i]. The function returns a status 303464ebd5Sriastradh * word which is zero if all the components are valid. If 313464ebd5Sriastradh * status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf). 323464ebd5Sriastradh * The implementations are not required to keep track of overflows. In 333464ebd5Sriastradh * that case, the invalid bits are never set. 343464ebd5Sriastradh */ 353464ebd5Sriastradh 363464ebd5Sriastradh#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16)) 373464ebd5Sriastradh#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0)) 383464ebd5Sriastradh 393464ebd5Sriastradh#if defined(_MSC_VER) 403464ebd5Sriastradh/* Oddly, the fpclassify() function doesn't exist in such a form 413464ebd5Sriastradh * on MSVC. This is an implementation using slightly different 423464ebd5Sriastradh * lower-level Windows functions. 433464ebd5Sriastradh */ 443464ebd5Sriastradh#include <float.h> 453464ebd5Sriastradh 463464ebd5Sriastradhenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} 473464ebd5Sriastradhfpclassify(double x) 483464ebd5Sriastradh{ 493464ebd5Sriastradh switch(_fpclass(x)) { 503464ebd5Sriastradh case _FPCLASS_SNAN: /* signaling NaN */ 513464ebd5Sriastradh case _FPCLASS_QNAN: /* quiet NaN */ 523464ebd5Sriastradh return FP_NAN; 533464ebd5Sriastradh case _FPCLASS_NINF: /* negative infinity */ 543464ebd5Sriastradh case _FPCLASS_PINF: /* positive infinity */ 553464ebd5Sriastradh return FP_INFINITE; 563464ebd5Sriastradh case _FPCLASS_NN: /* negative normal */ 573464ebd5Sriastradh case _FPCLASS_PN: /* positive normal */ 583464ebd5Sriastradh return FP_NORMAL; 593464ebd5Sriastradh case _FPCLASS_ND: /* negative denormalized */ 603464ebd5Sriastradh case _FPCLASS_PD: /* positive denormalized */ 613464ebd5Sriastradh return FP_SUBNORMAL; 623464ebd5Sriastradh case _FPCLASS_NZ: /* negative zero */ 633464ebd5Sriastradh case _FPCLASS_PZ: /* positive zero */ 643464ebd5Sriastradh return FP_ZERO; 653464ebd5Sriastradh default: 663464ebd5Sriastradh /* Should never get here; but if we do, this will guarantee 673464ebd5Sriastradh * that the pattern is not treated like a number. 683464ebd5Sriastradh */ 693464ebd5Sriastradh return FP_NAN; 703464ebd5Sriastradh } 713464ebd5Sriastradh} 723464ebd5Sriastradh 733464ebd5Sriastradh#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ 743464ebd5Sriastradh defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ 753464ebd5Sriastradh (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \ 763464ebd5Sriastradh (defined(__sun) && defined(__GNUC__)) 773464ebd5Sriastradh 783464ebd5Sriastradh/* fpclassify is available. */ 793464ebd5Sriastradh 803464ebd5Sriastradh#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600 813464ebd5Sriastradh 823464ebd5Sriastradhenum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} 833464ebd5Sriastradhfpclassify(double x) 843464ebd5Sriastradh{ 853464ebd5Sriastradh /* XXX do something better someday */ 863464ebd5Sriastradh return FP_NORMAL; 873464ebd5Sriastradh} 883464ebd5Sriastradh 893464ebd5Sriastradh#endif 903464ebd5Sriastradh 913464ebd5Sriastradhextern GLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]); 923464ebd5Sriastradh 933464ebd5Sriastradh/* The Mesa functions we'll need */ 943464ebd5Sriastradhextern void GL_APIENTRY _mesa_GetIntegerv(GLenum pname, GLint *params); 953464ebd5Sriastradhextern void GL_APIENTRY _mesa_GetFloatv(GLenum pname, GLfloat *params); 963464ebd5Sriastradh 973464ebd5SriastradhGLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) 983464ebd5Sriastradh{ 993464ebd5Sriastradh GLfloat matrix[16]; 1003464ebd5Sriastradh GLint tmp; 1013464ebd5Sriastradh GLenum currentMode = GL_FALSE; 1023464ebd5Sriastradh GLenum desiredMatrix = GL_FALSE; 1033464ebd5Sriastradh /* The bitfield returns 1 for each component that is invalid (i.e. 1043464ebd5Sriastradh * NaN or Inf). In case of error, everything is invalid. 1053464ebd5Sriastradh */ 1063464ebd5Sriastradh GLbitfield rv; 1073464ebd5Sriastradh register unsigned int i; 1083464ebd5Sriastradh unsigned int bit; 1093464ebd5Sriastradh 1103464ebd5Sriastradh /* This data structure defines the mapping between the current matrix 1113464ebd5Sriastradh * mode and the desired matrix identifier. 1123464ebd5Sriastradh */ 1133464ebd5Sriastradh static struct { 1143464ebd5Sriastradh GLenum currentMode; 1153464ebd5Sriastradh GLenum desiredMatrix; 1163464ebd5Sriastradh } modes[] = { 1173464ebd5Sriastradh {GL_MODELVIEW, GL_MODELVIEW_MATRIX}, 1183464ebd5Sriastradh {GL_PROJECTION, GL_PROJECTION_MATRIX}, 1193464ebd5Sriastradh {GL_TEXTURE, GL_TEXTURE_MATRIX}, 1203464ebd5Sriastradh }; 1213464ebd5Sriastradh 1223464ebd5Sriastradh /* Call Mesa to get the current matrix in floating-point form. First, 1233464ebd5Sriastradh * we have to figure out what the current matrix mode is. 1243464ebd5Sriastradh */ 1253464ebd5Sriastradh _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp); 1263464ebd5Sriastradh currentMode = (GLenum) tmp; 1273464ebd5Sriastradh 1283464ebd5Sriastradh /* The mode is either GL_FALSE, if for some reason we failed to query 1293464ebd5Sriastradh * the mode, or a given mode from the above table. Search for the 1303464ebd5Sriastradh * returned mode to get the desired matrix; if we don't find it, 1313464ebd5Sriastradh * we can return immediately, as _mesa_GetInteger() will have 1323464ebd5Sriastradh * logged the necessary error already. 1333464ebd5Sriastradh */ 1343464ebd5Sriastradh for (i = 0; i < sizeof(modes)/sizeof(modes[0]); i++) { 1353464ebd5Sriastradh if (modes[i].currentMode == currentMode) { 1363464ebd5Sriastradh desiredMatrix = modes[i].desiredMatrix; 1373464ebd5Sriastradh break; 1383464ebd5Sriastradh } 1393464ebd5Sriastradh } 1403464ebd5Sriastradh if (desiredMatrix == GL_FALSE) { 1413464ebd5Sriastradh /* Early error means all values are invalid. */ 1423464ebd5Sriastradh return 0xffff; 1433464ebd5Sriastradh } 1443464ebd5Sriastradh 1453464ebd5Sriastradh /* Now pull the matrix itself. */ 1463464ebd5Sriastradh _mesa_GetFloatv(desiredMatrix, matrix); 1473464ebd5Sriastradh 1483464ebd5Sriastradh rv = 0; 1493464ebd5Sriastradh for (i = 0, bit = 1; i < 16; i++, bit<<=1) { 1503464ebd5Sriastradh float normalizedFraction; 1513464ebd5Sriastradh int exp; 1523464ebd5Sriastradh 1533464ebd5Sriastradh switch (fpclassify(matrix[i])) { 1543464ebd5Sriastradh /* A "subnormal" or denormalized number is too small to be 1553464ebd5Sriastradh * represented in normal format; but despite that it's a 1563464ebd5Sriastradh * valid floating point number. FP_ZERO and FP_NORMAL 1573464ebd5Sriastradh * are both valid as well. We should be fine treating 1583464ebd5Sriastradh * these three cases as legitimate floating-point numbers. 1593464ebd5Sriastradh */ 1603464ebd5Sriastradh case FP_SUBNORMAL: 1613464ebd5Sriastradh case FP_NORMAL: 1623464ebd5Sriastradh case FP_ZERO: 1633464ebd5Sriastradh normalizedFraction = (GLfloat)frexp(matrix[i], &exp); 1643464ebd5Sriastradh mantissa[i] = FLOAT_TO_FIXED(normalizedFraction); 1653464ebd5Sriastradh exponent[i] = (GLint) exp; 1663464ebd5Sriastradh break; 1673464ebd5Sriastradh 1683464ebd5Sriastradh /* If the entry is not-a-number or an infinity, then the 1693464ebd5Sriastradh * matrix component is invalid. The invalid flag for 1703464ebd5Sriastradh * the component is already set; might as well set the 1713464ebd5Sriastradh * other return values to known values. We'll set 1723464ebd5Sriastradh * distinct values so that a savvy end user could determine 1733464ebd5Sriastradh * whether the matrix component was a NaN or an infinity, 1743464ebd5Sriastradh * but this is more useful for debugging than anything else 1753464ebd5Sriastradh * since the standard doesn't specify any such magic 1763464ebd5Sriastradh * values to return. 1773464ebd5Sriastradh */ 1783464ebd5Sriastradh case FP_NAN: 1793464ebd5Sriastradh mantissa[i] = INT_TO_FIXED(0); 1803464ebd5Sriastradh exponent[i] = (GLint) 0; 1813464ebd5Sriastradh rv |= bit; 1823464ebd5Sriastradh break; 1833464ebd5Sriastradh 1843464ebd5Sriastradh case FP_INFINITE: 1853464ebd5Sriastradh /* Return +/- 1 based on whether it's a positive or 1863464ebd5Sriastradh * negative infinity. 1873464ebd5Sriastradh */ 1883464ebd5Sriastradh if (matrix[i] > 0) { 1893464ebd5Sriastradh mantissa[i] = INT_TO_FIXED(1); 1903464ebd5Sriastradh } 1913464ebd5Sriastradh else { 1923464ebd5Sriastradh mantissa[i] = -INT_TO_FIXED(1); 1933464ebd5Sriastradh } 1943464ebd5Sriastradh exponent[i] = (GLint) 0; 1953464ebd5Sriastradh rv |= bit; 1963464ebd5Sriastradh break; 1973464ebd5Sriastradh 1983464ebd5Sriastradh /* We should never get here; but here's a catching case 1993464ebd5Sriastradh * in case fpclassify() is returnings something unexpected. 2003464ebd5Sriastradh */ 2013464ebd5Sriastradh default: 2023464ebd5Sriastradh mantissa[i] = INT_TO_FIXED(2); 2033464ebd5Sriastradh exponent[i] = (GLint) 0; 2043464ebd5Sriastradh rv |= bit; 2053464ebd5Sriastradh break; 2063464ebd5Sriastradh } 2073464ebd5Sriastradh 2083464ebd5Sriastradh } /* for each component */ 2093464ebd5Sriastradh 2103464ebd5Sriastradh /* All done */ 2113464ebd5Sriastradh return rv; 2123464ebd5Sriastradh} 213