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