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