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