1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 **************************************************************************/
7
8
9/**
10 * Code to implement GL_OES_query_matrix.  See the spec at:
11 * http://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt
12 */
13
14
15#include <stdlib.h>
16#include "c99_math.h"
17#include "glheader.h"
18#include "querymatrix.h"
19#include "main/get.h"
20#include "util/macros.h"
21
22
23/**
24 * This is from the GL_OES_query_matrix extension specification:
25 *
26 *  GLbitfield glQueryMatrixxOES( GLfixed mantissa[16],
27 *                                GLint   exponent[16] )
28 *  mantissa[16] contains the contents of the current matrix in GLfixed
29 *  format.  exponent[16] contains the unbiased exponents applied to the
30 *  matrix components, so that the internal representation of component i
31 *  is close to mantissa[i] * 2^exponent[i].  The function returns a status
32 *  word which is zero if all the components are valid. If
33 *  status & (1<<i) != 0, the component i is invalid (e.g., NaN, Inf).
34 *  The implementations are not required to keep track of overflows.  In
35 *  that case, the invalid bits are never set.
36 */
37
38#define INT_TO_FIXED(x) ((GLfixed) ((x) << 16))
39#define FLOAT_TO_FIXED(x) ((GLfixed) ((x) * 65536.0))
40
41
42GLbitfield GLAPIENTRY
43_mesa_QueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16])
44{
45   GLfloat matrix[16];
46   GLint tmp;
47   GLenum currentMode = GL_FALSE;
48   GLenum desiredMatrix = GL_FALSE;
49   /* The bitfield returns 1 for each component that is invalid (i.e.
50    * NaN or Inf).  In case of error, everything is invalid.
51    */
52   GLbitfield rv;
53   unsigned i, bit;
54
55   /* This data structure defines the mapping between the current matrix
56    * mode and the desired matrix identifier.
57    */
58   static const struct {
59      GLenum currentMode;
60      GLenum desiredMatrix;
61   } modes[] = {
62      {GL_MODELVIEW, GL_MODELVIEW_MATRIX},
63      {GL_PROJECTION, GL_PROJECTION_MATRIX},
64      {GL_TEXTURE, GL_TEXTURE_MATRIX},
65   };
66
67   /* Call Mesa to get the current matrix in floating-point form.  First,
68    * we have to figure out what the current matrix mode is.
69    */
70   _mesa_GetIntegerv(GL_MATRIX_MODE, &tmp);
71   currentMode = (GLenum) tmp;
72
73   /* The mode is either GL_FALSE, if for some reason we failed to query
74    * the mode, or a given mode from the above table.  Search for the
75    * returned mode to get the desired matrix; if we don't find it,
76    * we can return immediately, as _mesa_GetInteger() will have
77    * logged the necessary error already.
78    */
79   for (i = 0; i < ARRAY_SIZE(modes); i++) {
80      if (modes[i].currentMode == currentMode) {
81         desiredMatrix = modes[i].desiredMatrix;
82         break;
83      }
84   }
85   if (desiredMatrix == GL_FALSE) {
86      /* Early error means all values are invalid. */
87      return 0xffff;
88   }
89
90   /* Now pull the matrix itself. */
91   _mesa_GetFloatv(desiredMatrix, matrix);
92
93   rv = 0;
94   for (i = 0, bit = 1; i < 16; i++, bit<<=1) {
95      float normalizedFraction;
96      int exp;
97
98      switch (fpclassify(matrix[i])) {
99      case FP_SUBNORMAL:
100      case FP_NORMAL:
101      case FP_ZERO:
102         /* A "subnormal" or denormalized number is too small to be
103          * represented in normal format; but despite that it's a
104          * valid floating point number.  FP_ZERO and FP_NORMAL
105          * are both valid as well.  We should be fine treating
106          * these three cases as legitimate floating-point numbers.
107          */
108         normalizedFraction = (GLfloat)frexp(matrix[i], &exp);
109         mantissa[i] = FLOAT_TO_FIXED(normalizedFraction);
110         exponent[i] = (GLint) exp;
111         break;
112
113      case FP_NAN:
114         /* If the entry is not-a-number or an infinity, then the
115          * matrix component is invalid.  The invalid flag for
116          * the component is already set; might as well set the
117          * other return values to known values.  We'll set
118          * distinct values so that a savvy end user could determine
119          * whether the matrix component was a NaN or an infinity,
120          * but this is more useful for debugging than anything else
121          * since the standard doesn't specify any such magic
122          * values to return.
123          */
124         mantissa[i] = INT_TO_FIXED(0);
125         exponent[i] = (GLint) 0;
126         rv |= bit;
127         break;
128
129      case FP_INFINITE:
130         /* Return +/- 1 based on whether it's a positive or
131          * negative infinity.
132          */
133         if (matrix[i] > 0) {
134            mantissa[i] = INT_TO_FIXED(1);
135         }
136         else {
137            mantissa[i] = -INT_TO_FIXED(1);
138         }
139         exponent[i] = (GLint) 0;
140         rv |= bit;
141         break;
142
143      default:
144         /* We should never get here; but here's a catching case
145          * in case fpclassify() is returnings something unexpected.
146          */
147         mantissa[i] = INT_TO_FIXED(2);
148         exponent[i] = (GLint) 0;
149         rv |= bit;
150         break;
151      }
152
153   } /* for each component */
154
155   /* All done */
156   return rv;
157}
158