214 lines
7.2 KiB
C
214 lines
7.2 KiB
C
/**************************************************************************
|
|
*
|
|
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
|
|
* 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 <math.h>
|
|
#include "GLES/gl.h"
|
|
#include "GLES/glext.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))
|
|
|
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
|
/* Oddly, the fpclassify() function doesn't exist in such a form
|
|
* on Windows. This is an implementation using slightly different
|
|
* lower-level Windows functions.
|
|
*/
|
|
#include <float.h>
|
|
|
|
enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
|
|
fpclassify(double x)
|
|
{
|
|
switch(_fpclass(x)) {
|
|
case _FPCLASS_SNAN: /* signaling NaN */
|
|
case _FPCLASS_QNAN: /* quiet NaN */
|
|
return FP_NAN;
|
|
case _FPCLASS_NINF: /* negative infinity */
|
|
case _FPCLASS_PINF: /* positive infinity */
|
|
return FP_INFINITE;
|
|
case _FPCLASS_NN: /* negative normal */
|
|
case _FPCLASS_PN: /* positive normal */
|
|
return FP_NORMAL;
|
|
case _FPCLASS_ND: /* negative denormalized */
|
|
case _FPCLASS_PD: /* positive denormalized */
|
|
return FP_SUBNORMAL;
|
|
case _FPCLASS_NZ: /* negative zero */
|
|
case _FPCLASS_PZ: /* positive zero */
|
|
return FP_ZERO;
|
|
default:
|
|
/* Should never get here; but if we do, this will guarantee
|
|
* that the pattern is not treated like a number.
|
|
*/
|
|
return FP_NAN;
|
|
}
|
|
}
|
|
|
|
#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__)
|
|
|
|
/* fpclassify is available. */
|
|
|
|
#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
|
|
|
|
enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
|
|
fpclassify(double x)
|
|
{
|
|
/* XXX do something better someday */
|
|
return FP_NORMAL;
|
|
}
|
|
|
|
#endif
|
|
|
|
extern GLbitfield GL_APIENTRY _es_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]);
|
|
|
|
/* The Mesa functions we'll need */
|
|
extern void GL_APIENTRY _mesa_GetIntegerv(GLenum pname, GLint *params);
|
|
extern void GL_APIENTRY _mesa_GetFloatv(GLenum pname, GLfloat *params);
|
|
|
|
GLbitfield GL_APIENTRY _es_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;
|
|
register unsigned int i;
|
|
unsigned int bit;
|
|
|
|
/* This data structure defines the mapping between the current matrix
|
|
* mode and the desired matrix identifier.
|
|
*/
|
|
static struct {
|
|
GLenum currentMode;
|
|
GLenum desiredMatrix;
|
|
} modes[] = {
|
|
{GL_MODELVIEW, GL_MODELVIEW_MATRIX},
|
|
{GL_PROJECTION, GL_PROJECTION_MATRIX},
|
|
{GL_TEXTURE, GL_TEXTURE_MATRIX},
|
|
#if 0
|
|
/* this doesn't exist in GLES */
|
|
{GL_COLOR, GL_COLOR_MATRIX},
|
|
#endif
|
|
};
|
|
|
|
/* 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 < sizeof(modes)/sizeof(modes[0]); 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])) {
|
|
/* 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.
|
|
*/
|
|
case FP_SUBNORMAL:
|
|
case FP_NORMAL:
|
|
case FP_ZERO:
|
|
normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
|
|
mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
|
|
exponent[i] = (GLint) exp;
|
|
break;
|
|
|
|
/* 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.
|
|
*/
|
|
case FP_NAN:
|
|
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;
|
|
|
|
/* We should never get here; but here's a catching case
|
|
* in case fpclassify() is returnings something unexpected.
|
|
*/
|
|
default:
|
|
mantissa[i] = INT_TO_FIXED(2);
|
|
exponent[i] = (GLint) 0;
|
|
rv |= bit;
|
|
break;
|
|
}
|
|
|
|
} /* for each component */
|
|
|
|
/* All done */
|
|
return rv;
|
|
}
|