/**************************************************************************
*
* Copyright 2008 VMware, Inc.
* All Rights Reserved.
*
**************************************************************************/
/**
* Code to implement GL_OES_query_matrix. See the spec at:
* http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt
*/
#include <stdlib.h>
#include "c99_math.h"
#include "glheader.h"
#include "querymatrix.h"
#include "main/get.h"
/**
* This is from the GL_OES_query_matrix extension specification:
*
* GLbitfield glQueryMatrixxOES( GLfixed mantissa[16],
* GLint exponent[16] )
* mantissa[16] contains the contents of the current matrix in GLfixed
* format. exponent[16] contains the unbiased exponents applied to the
* matrix components, so that the internal representation of component i
* is close to mantissa[i] * 2^exponent[i]. The function returns a status
* word which is zero if all the components are valid. If
* status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf).
* The implementations are not required to keep track of overflows. In
* that case, the invalid bits are never set.
*/
#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16))
#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0))
GLbitfield GLAPIENTRY
_mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16])
{
GLfloat matrix[16];
GLint tmp;
GLenum currentMode = GL_FALSE;
GLenum desiredMatrix = GL_FALSE;
/* The bitfield returns 1 for each component that is invalid (i.e.
* NaN or Inf). In case of error, everything is invalid.
*/
GLbitfield rv;
unsigned i, bit;
/* This data structure defines the mapping between the current matrix
* mode and the desired matrix identifier.
*/
static const struct {
GLenum currentMode;
GLenum desiredMatrix;
} modes[] = {
{GL_MODELVIEW, GL_MODELVIEW_MATRIX},
{GL_PROJECTION, GL_PROJECTION_MATRIX},
{GL_TEXTURE, GL_TEXTURE_MATRIX},
};
/* Call Mesa to get the current matrix in floating-point form. First,
* we have to figure out what the current matrix mode is.
*/
_mesa_GetIntegerv(GL_MATRIX_MODE, &tmp);
currentMode = (GLenum) tmp;
/* The mode is either GL_FALSE, if for some reason we failed to query
* the mode, or a given mode from the above table. Search for the
* returned mode to get the desired matrix; if we don't find it,
* we can return immediately, as _mesa_GetInteger() will have
* logged the necessary error already.
*/
for (i = 0; i < ARRAY_SIZE(modes); i++) {
if (modes[i].currentMode == currentMode) {
desiredMatrix = modes[i].desiredMatrix;
break;
}
}
if (desiredMatrix == GL_FALSE) {
/* Early error means all values are invalid. */
return 0xffff;
}
/* Now pull the matrix itself. */
_mesa_GetFloatv(desiredMatrix, matrix);
rv = 0;
for (i = 0, bit = 1; i < 16; i++, bit<<=1) {
float normalizedFraction;
int exp;
switch (fpclassify(matrix[i])) {
case FP_SUBNORMAL:
case FP_NORMAL:
case FP_ZERO:
/* A "subnormal" or denormalized number is too small to be
* represented in normal format; but despite that it's a
* valid floating point number. FP_ZERO and FP_NORMAL
* are both valid as well. We should be fine treating
* these three cases as legitimate floating-point numbers.
*/
normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
exponent[i] = (GLint) exp;
break;
case FP_NAN:
/* If the entry is not-a-number or an infinity, then the
* matrix component is invalid. The invalid flag for
* the component is already set; might as well set the
* other return values to known values. We'll set
* distinct values so that a savvy end user could determine
* whether the matrix component was a NaN or an infinity,
* but this is more useful for debugging than anything else
* since the standard doesn't specify any such magic
* values to return.
*/
mantissa[i] = INT_TO_FIXED(0);
exponent[i] = (GLint) 0;
rv |= bit;
break;
case FP_INFINITE:
/* Return +/- 1 based on whether it's a positive or
* negative infinity.
*/
if (matrix[i] > 0) {
mantissa[i] = INT_TO_FIXED(1);
}
else {
mantissa[i] = -INT_TO_FIXED(1);
}
exponent[i] = (GLint) 0;
rv |= bit;
break;
default:
/* We should never get here; but here's a catching case
* in case fpclassify() is returnings something unexpected.
*/
mantissa[i] = INT_TO_FIXED(2);
exponent[i] = (GLint) 0;
rv |= bit;
break;
}
} /* for each component */
/* All done */
return rv;
}