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