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  */
45 static struct gl_texgen *
get_texgen(struct gl_context * ctx,GLuint texunitIndex,GLenum coord,const char * caller)46 get_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 */
77 static void
texgenfv(GLuint texunitIndex,GLenum coord,GLenum pname,const GLfloat * params,const char * caller)78 texgenfv( 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 */
185 static void
gettexgendv(GLuint texunitIndex,GLenum coord,GLenum pname,GLdouble * params,const char * caller)186 gettexgendv( 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 */
218 static void
gettexgenfv(GLenum texunitIndex,GLenum coord,GLenum pname,GLfloat * params,const char * caller)219 gettexgenfv( 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 */
259 static void
gettexgeniv(GLenum texunitIndex,GLenum coord,GLenum pname,GLint * params,const char * caller)260 gettexgeniv( 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 
305 void GLAPIENTRY
_mesa_TexGenfv(GLenum coord,GLenum pname,const GLfloat * params)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 
313 void GLAPIENTRY
_mesa_MultiTexGenfvEXT(GLenum texunit,GLenum coord,GLenum pname,const GLfloat * params)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 
320 void GLAPIENTRY
_mesa_TexGeniv(GLenum coord,GLenum pname,const GLint * params)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 
337 void GLAPIENTRY
_mesa_MultiTexGenivEXT(GLenum texunit,GLenum coord,GLenum pname,const GLint * params)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 
354 void GLAPIENTRY
_mesa_TexGend(GLenum coord,GLenum pname,GLdouble param)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 
365 void GLAPIENTRY
_mesa_MultiTexGendEXT(GLenum texunit,GLenum coord,GLenum pname,GLdouble param)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 
374 void GLAPIENTRY
_es_GetTexGenfv(GLenum coord,GLenum pname,GLfloat * params)375 _es_GetTexGenfv(GLenum coord, GLenum pname, GLfloat *params)
376 {
377    _mesa_GetTexGenfv(GL_S, pname, params);
378 }
379 
380 
381 void GLAPIENTRY
_es_TexGenf(GLenum coord,GLenum pname,GLfloat param)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 
396 void GLAPIENTRY
_es_TexGenfv(GLenum coord,GLenum pname,const GLfloat * params)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 
411 void GLAPIENTRY
_mesa_TexGendv(GLenum coord,GLenum pname,const GLdouble * params)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 
429 void GLAPIENTRY
_mesa_MultiTexGendvEXT(GLenum texunit,GLenum coord,GLenum pname,const GLdouble * params)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 
446 void GLAPIENTRY
_mesa_TexGenf(GLenum coord,GLenum pname,GLfloat param)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 
457 void GLAPIENTRY
_mesa_MultiTexGenfEXT(GLenum texunit,GLenum coord,GLenum pname,GLfloat param)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 
467 void GLAPIENTRY
_mesa_TexGeni(GLenum coord,GLenum pname,GLint param)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 
477 void GLAPIENTRY
_mesa_MultiTexGeniEXT(GLenum texunit,GLenum coord,GLenum pname,GLint param)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 
487 void GLAPIENTRY
_mesa_GetTexGendv(GLenum coord,GLenum pname,GLdouble * params)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 
495 void GLAPIENTRY
_mesa_GetMultiTexGendvEXT(GLenum texunit,GLenum coord,GLenum pname,GLdouble * params)496 _mesa_GetMultiTexGendvEXT( GLenum texunit, GLenum coord, GLenum pname, GLdouble *params )
497 {
498    gettexgendv(texunit - GL_TEXTURE0, coord, pname, params, "glGetMultiTexGendvEXT");
499 }
500 
501 
502 void GLAPIENTRY
_mesa_GetTexGenfv(GLenum coord,GLenum pname,GLfloat * params)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 
510 void GLAPIENTRY
_mesa_GetMultiTexGenfvEXT(GLenum texunit,GLenum coord,GLenum pname,GLfloat * params)511 _mesa_GetMultiTexGenfvEXT( GLenum texunit, GLenum coord, GLenum pname, GLfloat *params )
512 {
513    gettexgenfv(texunit - GL_TEXTURE0, coord, pname, params, "glGetMultiTexGenfvEXT");
514 }
515 
516 
517 void GLAPIENTRY
_mesa_GetTexGeniv(GLenum coord,GLenum pname,GLint * params)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 
525 void GLAPIENTRY
_mesa_GetMultiTexGenivEXT(GLenum texunit,GLenum coord,GLenum pname,GLint * params)526 _mesa_GetMultiTexGenivEXT( GLenum texunit, GLenum coord, GLenum pname, GLint *params )
527 {
528    gettexgeniv(texunit - GL_TEXTURE0, coord, pname, params, "glGetTexGenivEXT");
529 }
530