summaryrefslogtreecommitdiffstats
path: root/src/mesa/main/querymatrix.c
blob: ccd5c5e990470e1ed8207fa9e4ac59fbe0bf9523 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**************************************************************************
 *
 * 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 < 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])) {
      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;
}