1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5 * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26/**
27 * \file texgen.c
28 *
29 * glTexGen-related functions
30 */
31
32
33#include "main/glheader.h"
34#include "main/context.h"
35#include "main/enums.h"
36#include "main/macros.h"
37#include "main/texgen.h"
38#include "main/texstate.h"
39#include "math/m_matrix.h"
40
41
42/**
43 * Return texgen state for given coordinate
44 */
45static struct gl_texgen *
46get_texgen(struct gl_context *ctx, GLuint texunitIndex, GLenum coord, const char* caller)
47{
48   struct gl_fixedfunc_texture_unit* texUnit;
49   if (texunitIndex >= ctx->Const.MaxTextureCoordUnits) {
50      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unit=%d)", caller, texunitIndex);
51      return NULL;
52   }
53
54   texUnit = _mesa_get_fixedfunc_tex_unit(ctx, texunitIndex);
55
56   if (ctx->API == API_OPENGLES) {
57      return (coord == GL_TEXTURE_GEN_STR_OES)
58         ? &texUnit->GenS : NULL;
59   }
60
61   switch (coord) {
62   case GL_S:
63      return &texUnit->GenS;
64   case GL_T:
65      return &texUnit->GenT;
66   case GL_R:
67      return &texUnit->GenR;
68   case GL_Q:
69      return &texUnit->GenQ;
70   default:
71      return NULL;
72   }
73}
74
75
76/* Helper for glTexGenfv and glMultiTexGenfvEXT functions */
77static void
78texgenfv( GLuint texunitIndex, GLenum coord, GLenum pname,
79          const GLfloat *params, const char* caller )
80{
81   struct gl_texgen *texgen;
82   GET_CURRENT_CONTEXT(ctx);
83
84   texgen = get_texgen(ctx, texunitIndex, coord, caller);
85   if (!texgen) {
86      _mesa_error(ctx, GL_INVALID_ENUM, "%s(coord)", caller);
87      return;
88   }
89
90   struct gl_fixedfunc_texture_unit *unit = &ctx->Texture.FixedFuncUnit[texunitIndex];
91   int index = coord == GL_TEXTURE_GEN_STR_OES ? 0 : (coord - GL_S);
92
93   switch (pname) {
94   case GL_TEXTURE_GEN_MODE:
95      {
96         GLenum mode = (GLenum) (GLint) params[0];
97         GLbitfield bit = 0x0;
98         if (texgen->Mode == mode)
99            return;
100         switch (mode) {
101         case GL_OBJECT_LINEAR:
102            bit = TEXGEN_OBJ_LINEAR;
103            break;
104         case GL_EYE_LINEAR:
105            bit = TEXGEN_EYE_LINEAR;
106            break;
107         case GL_SPHERE_MAP:
108            if (coord == GL_S || coord == GL_T)
109               bit = TEXGEN_SPHERE_MAP;
110            break;
111         case GL_REFLECTION_MAP_NV:
112            if (coord != GL_Q)
113               bit = TEXGEN_REFLECTION_MAP_NV;
114            break;
115         case GL_NORMAL_MAP_NV:
116            if (coord != GL_Q)
117               bit = TEXGEN_NORMAL_MAP_NV;
118            break;
119         default:
120            ; /* nop */
121         }
122         if (!bit) {
123            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
124            return;
125         }
126         if (ctx->API != API_OPENGL_COMPAT
127             && (bit & (TEXGEN_REFLECTION_MAP_NV | TEXGEN_NORMAL_MAP_NV)) == 0) {
128            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
129            return;
130         }
131
132         FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE | _NEW_FF_VERT_PROGRAM,
133                        GL_TEXTURE_BIT);
134         texgen->Mode = mode;
135         texgen->_ModeBit = bit;
136      }
137      break;
138
139   case GL_OBJECT_PLANE:
140      {
141         if (ctx->API != API_OPENGL_COMPAT) {
142            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
143            return;
144         }
145         if (TEST_EQ_4V(unit->ObjectPlane[index], params))
146            return;
147         FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT);
148         COPY_4FV(unit->ObjectPlane[index], params);
149      }
150      break;
151
152   case GL_EYE_PLANE:
153      {
154         GLfloat tmp[4];
155
156         if (ctx->API != API_OPENGL_COMPAT) {
157            _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
158            return;
159         }
160
161         /* Transform plane equation by the inverse modelview matrix */
162         if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) {
163            _math_matrix_analyse(ctx->ModelviewMatrixStack.Top);
164         }
165         _mesa_transform_vector(tmp, params,
166                                ctx->ModelviewMatrixStack.Top->inv);
167         if (TEST_EQ_4V(unit->EyePlane[index], tmp))
168            return;
169         FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT);
170         COPY_4FV(unit->EyePlane[index], tmp);
171      }
172      break;
173
174   default:
175      _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
176      return;
177   }
178
179   if (ctx->Driver.TexGen)
180      ctx->Driver.TexGen( ctx, coord, pname, params );
181}
182
183
184/* Helper for glGetTexGendv / glGetMultiTexGendvEXT */
185static void
186gettexgendv( GLuint texunitIndex, GLenum coord, GLenum pname,
187             GLdouble *params, const char* caller)
188{
189   struct gl_texgen *texgen;
190   GET_CURRENT_CONTEXT(ctx);
191
192   texgen = get_texgen(ctx, texunitIndex, coord, caller);
193   if (!texgen) {
194      _mesa_error(ctx, GL_INVALID_ENUM, "%s(coord)", caller);
195      return;
196   }
197
198   struct gl_fixedfunc_texture_unit *unit = &ctx->Texture.FixedFuncUnit[texunitIndex];
199   int index = coord == GL_TEXTURE_GEN_STR_OES ? 0 : (coord - GL_S);
200
201   switch (pname) {
202   case GL_TEXTURE_GEN_MODE:
203      params[0] = ENUM_TO_DOUBLE(texgen->Mode);
204      break;
205   case GL_OBJECT_PLANE:
206      COPY_4V(params, unit->ObjectPlane[index]);
207      break;
208   case GL_EYE_PLANE:
209      COPY_4V(params, unit->EyePlane[index]);
210      break;
211   default:
212      _mesa_error( ctx, GL_INVALID_ENUM, "%s(pname)", caller );
213   }
214}
215
216
217/* Helper for glGetTexGenfv / glGetMultiTexGenfvEXT */
218static void
219gettexgenfv( GLenum texunitIndex, GLenum coord, GLenum pname,
220             GLfloat *params, const char* caller )
221{
222   struct gl_texgen *texgen;
223   GET_CURRENT_CONTEXT(ctx);
224
225   texgen = get_texgen(ctx, texunitIndex, coord, caller);
226   if (!texgen) {
227      _mesa_error(ctx, GL_INVALID_ENUM, "%s(coord)", caller);
228      return;
229   }
230
231   struct gl_fixedfunc_texture_unit *unit = &ctx->Texture.FixedFuncUnit[texunitIndex];
232   int index = coord == GL_TEXTURE_GEN_STR_OES ? 0 : (coord - GL_S);
233
234   switch (pname) {
235   case GL_TEXTURE_GEN_MODE:
236      params[0] = ENUM_TO_FLOAT(texgen->Mode);
237      break;
238   case GL_OBJECT_PLANE:
239      if (ctx->API != API_OPENGL_COMPAT) {
240         _mesa_error( ctx, GL_INVALID_ENUM, "%s(param)", caller );
241         return;
242      }
243      COPY_4V(params, unit->ObjectPlane[index]);
244      break;
245   case GL_EYE_PLANE:
246      if (ctx->API != API_OPENGL_COMPAT) {
247         _mesa_error( ctx, GL_INVALID_ENUM, "%s(param)", caller );
248         return;
249      }
250      COPY_4V(params, unit->EyePlane[index]);
251      break;
252   default:
253      _mesa_error( ctx, GL_INVALID_ENUM, "%s(pname)", caller );
254   }
255}
256
257
258/* Helper for glGetTexGeniv / glGetMultiTexGenivEXT */
259static void
260gettexgeniv( GLenum texunitIndex, GLenum coord, GLenum pname,
261             GLint *params, const char* caller)
262{
263   struct gl_texgen *texgen;
264   GET_CURRENT_CONTEXT(ctx);
265
266   texgen = get_texgen(ctx, texunitIndex, coord, caller);
267   if (!texgen) {
268      _mesa_error(ctx, GL_INVALID_ENUM, "%s(coord)", caller);
269      return;
270   }
271
272   struct gl_fixedfunc_texture_unit *unit = &ctx->Texture.FixedFuncUnit[texunitIndex];
273   int index = coord == GL_TEXTURE_GEN_STR_OES ? 0 : (coord - GL_S);
274
275   switch (pname) {
276   case GL_TEXTURE_GEN_MODE:
277      params[0] = texgen->Mode;
278      break;
279   case GL_OBJECT_PLANE:
280      if (ctx->API != API_OPENGL_COMPAT) {
281         _mesa_error( ctx, GL_INVALID_ENUM, "%s(param)" , caller);
282         return;
283      }
284      params[0] = (GLint) unit->ObjectPlane[index][0];
285      params[1] = (GLint) unit->ObjectPlane[index][1];
286      params[2] = (GLint) unit->ObjectPlane[index][2];
287      params[3] = (GLint) unit->ObjectPlane[index][3];
288      break;
289   case GL_EYE_PLANE:
290      if (ctx->API != API_OPENGL_COMPAT) {
291         _mesa_error( ctx, GL_INVALID_ENUM, "%s(param)" , caller);
292         return;
293      }
294      params[0] = (GLint) unit->EyePlane[index][0];
295      params[1] = (GLint) unit->EyePlane[index][1];
296      params[2] = (GLint) unit->EyePlane[index][2];
297      params[3] = (GLint) unit->EyePlane[index][3];
298      break;
299   default:
300      _mesa_error( ctx, GL_INVALID_ENUM, "%s(pname)" , caller);
301   }
302}
303
304
305void GLAPIENTRY
306_mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
307{
308   GET_CURRENT_CONTEXT(ctx);
309   texgenfv(ctx->Texture.CurrentUnit, coord, pname, params, "glTexGenfv");
310}
311
312
313void GLAPIENTRY
314_mesa_MultiTexGenfvEXT( GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params )
315{
316   texgenfv(texunit - GL_TEXTURE0, coord, pname, params, "glMultiTexGenfvEXT");
317}
318
319
320void GLAPIENTRY
321_mesa_TexGeniv(GLenum coord, GLenum pname, const GLint *params )
322{
323   GET_CURRENT_CONTEXT(ctx);
324   GLfloat p[4];
325   p[0] = (GLfloat) params[0];
326   if (pname == GL_TEXTURE_GEN_MODE) {
327      p[1] = p[2] = p[3] = 0.0F;
328   }
329   else {
330      p[1] = (GLfloat) params[1];
331      p[2] = (GLfloat) params[2];
332      p[3] = (GLfloat) params[3];
333   }
334   texgenfv(ctx->Texture.CurrentUnit, coord, pname, p, "glTexGeniv");
335}
336
337void GLAPIENTRY
338_mesa_MultiTexGenivEXT(GLenum texunit, GLenum coord, GLenum pname, const GLint *params )
339{
340   GLfloat p[4];
341   p[0] = (GLfloat) params[0];
342   if (pname == GL_TEXTURE_GEN_MODE) {
343      p[1] = p[2] = p[3] = 0.0F;
344   }
345   else {
346      p[1] = (GLfloat) params[1];
347      p[2] = (GLfloat) params[2];
348      p[3] = (GLfloat) params[3];
349   }
350   texgenfv(texunit - GL_TEXTURE0, coord, pname, p, "glMultiTexGenivEXT");
351}
352
353
354void GLAPIENTRY
355_mesa_TexGend(GLenum coord, GLenum pname, GLdouble param )
356{
357   GET_CURRENT_CONTEXT(ctx);
358   GLfloat p[4];
359   p[0] = (GLfloat) param;
360   p[1] = p[2] = p[3] = 0.0F;
361   texgenfv(ctx->Texture.CurrentUnit, coord, pname, p, "glTexGend");
362}
363
364
365void GLAPIENTRY
366_mesa_MultiTexGendEXT(GLenum texunit, GLenum coord, GLenum pname, GLdouble param )
367{
368   GLfloat p[4];
369   p[0] = (GLfloat) param;
370   p[1] = p[2] = p[3] = 0.0F;
371   texgenfv(texunit - GL_TEXTURE0, coord, pname, p, "glMultiTexGendEXT");
372}
373
374void GLAPIENTRY
375_es_GetTexGenfv(GLenum coord, GLenum pname, GLfloat *params)
376{
377   _mesa_GetTexGenfv(GL_S, pname, params);
378}
379
380
381void GLAPIENTRY
382_es_TexGenf(GLenum coord, GLenum pname, GLfloat param)
383{
384   if (coord != GL_TEXTURE_GEN_STR_OES) {
385      GET_CURRENT_CONTEXT(ctx);
386      _mesa_error( ctx, GL_INVALID_ENUM, "glTexGen[fx](pname)" );
387      return;
388   }
389   /* set S, T, and R at the same time */
390   _mesa_TexGenf(GL_S, pname, param);
391   _mesa_TexGenf(GL_T, pname, param);
392   _mesa_TexGenf(GL_R, pname, param);
393}
394
395
396void GLAPIENTRY
397_es_TexGenfv(GLenum coord, GLenum pname, const GLfloat *params)
398{
399   if (coord != GL_TEXTURE_GEN_STR_OES) {
400      GET_CURRENT_CONTEXT(ctx);
401      _mesa_error( ctx, GL_INVALID_ENUM, "glTexGen[fx]v(pname)" );
402      return;
403   }
404   /* set S, T, and R at the same time */
405   _mesa_TexGenfv(GL_S, pname, params);
406   _mesa_TexGenfv(GL_T, pname, params);
407   _mesa_TexGenfv(GL_R, pname, params);
408}
409
410
411void GLAPIENTRY
412_mesa_TexGendv(GLenum coord, GLenum pname, const GLdouble *params )
413{
414   GET_CURRENT_CONTEXT(ctx);
415   GLfloat p[4];
416   p[0] = (GLfloat) params[0];
417   if (pname == GL_TEXTURE_GEN_MODE) {
418      p[1] = p[2] = p[3] = 0.0F;
419   }
420   else {
421      p[1] = (GLfloat) params[1];
422      p[2] = (GLfloat) params[2];
423      p[3] = (GLfloat) params[3];
424   }
425   texgenfv(ctx->Texture.CurrentUnit, coord, pname, p, "glTexGendv");
426}
427
428
429void GLAPIENTRY
430_mesa_MultiTexGendvEXT(GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params )
431{
432   GLfloat p[4];
433   p[0] = (GLfloat) params[0];
434   if (pname == GL_TEXTURE_GEN_MODE) {
435      p[1] = p[2] = p[3] = 0.0F;
436   }
437   else {
438      p[1] = (GLfloat) params[1];
439      p[2] = (GLfloat) params[2];
440      p[3] = (GLfloat) params[3];
441   }
442   texgenfv(texunit - GL_TEXTURE0, coord, pname, p, "glMultiTexGendvEXT");
443}
444
445
446void GLAPIENTRY
447_mesa_TexGenf( GLenum coord, GLenum pname, GLfloat param )
448{
449   GET_CURRENT_CONTEXT(ctx);
450   GLfloat p[4];
451   p[0] = param;
452   p[1] = p[2] = p[3] = 0.0F;
453   texgenfv(ctx->Texture.CurrentUnit, coord, pname, p, "glTexGenf");
454}
455
456
457void GLAPIENTRY
458_mesa_MultiTexGenfEXT( GLenum texunit, GLenum coord, GLenum pname, GLfloat param )
459{
460   GLfloat p[4];
461   p[0] = param;
462   p[1] = p[2] = p[3] = 0.0F;
463   texgenfv(texunit - GL_TEXTURE0, coord, pname, p, "glMultiTexGenfEXT");
464}
465
466
467void GLAPIENTRY
468_mesa_TexGeni( GLenum coord, GLenum pname, GLint param )
469{
470   GLint p[4];
471   p[0] = param;
472   p[1] = p[2] = p[3] = 0;
473   _mesa_TexGeniv( coord, pname, p );
474}
475
476
477void GLAPIENTRY
478_mesa_MultiTexGeniEXT( GLenum texunit, GLenum coord, GLenum pname, GLint param )
479{
480   GLint p[4];
481   p[0] = param;
482   p[1] = p[2] = p[3] = 0;
483   _mesa_MultiTexGenivEXT( texunit, coord, pname, p );
484}
485
486
487void GLAPIENTRY
488_mesa_GetTexGendv( GLenum coord, GLenum pname, GLdouble *params )
489{
490   GET_CURRENT_CONTEXT(ctx);
491   gettexgendv(ctx->Texture.CurrentUnit, coord, pname, params, "glGetTexGendv");
492}
493
494
495void GLAPIENTRY
496_mesa_GetMultiTexGendvEXT( GLenum texunit, GLenum coord, GLenum pname, GLdouble *params )
497{
498   gettexgendv(texunit - GL_TEXTURE0, coord, pname, params, "glGetMultiTexGendvEXT");
499}
500
501
502void GLAPIENTRY
503_mesa_GetTexGenfv( GLenum coord, GLenum pname, GLfloat *params )
504{
505   GET_CURRENT_CONTEXT(ctx);
506   gettexgenfv(ctx->Texture.CurrentUnit, coord, pname, params, "glGetTexGenfv");
507}
508
509
510void GLAPIENTRY
511_mesa_GetMultiTexGenfvEXT( GLenum texunit, GLenum coord, GLenum pname, GLfloat *params )
512{
513   gettexgenfv(texunit - GL_TEXTURE0, coord, pname, params, "glGetMultiTexGenfvEXT");
514}
515
516
517void GLAPIENTRY
518_mesa_GetTexGeniv( GLenum coord, GLenum pname, GLint *params )
519{
520   GET_CURRENT_CONTEXT(ctx);
521   gettexgeniv(ctx->Texture.CurrentUnit, coord, pname, params, "glGetTexGeniv");
522}
523
524
525void GLAPIENTRY
526_mesa_GetMultiTexGenivEXT( GLenum texunit, GLenum coord, GLenum pname, GLint *params )
527{
528   gettexgeniv(texunit - GL_TEXTURE0, coord, pname, params, "glGetTexGenivEXT");
529}
530