1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.5
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR 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/mfeatures.h"
38 #include "main/texgen.h"
39 #include "main/texstate.h"
40 #include "math/m_matrix.h"
41 #include "main/dispatch.h"
42 
43 
44 #if FEATURE_texgen
45 
46 
47 /**
48  * Return texgen state for given coordinate
49  */
50 static struct gl_texgen *
get_texgen(struct gl_context * ctx,struct gl_texture_unit * texUnit,GLenum coord)51 get_texgen(struct gl_context *ctx, struct gl_texture_unit *texUnit,
52            GLenum coord)
53 {
54    if (ctx->API == API_OPENGLES) {
55       return (coord == GL_TEXTURE_GEN_STR_OES)
56          ? &texUnit->GenS : NULL;
57    }
58 
59    switch (coord) {
60    case GL_S:
61       return &texUnit->GenS;
62    case GL_T:
63       return &texUnit->GenT;
64    case GL_R:
65       return &texUnit->GenR;
66    case GL_Q:
67       return &texUnit->GenQ;
68    default:
69       return NULL;
70    }
71 }
72 
73 
74 void GLAPIENTRY
_mesa_TexGenfv(GLenum coord,GLenum pname,const GLfloat * params)75 _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
76 {
77    struct gl_texture_unit *texUnit;
78    struct gl_texgen *texgen;
79    GET_CURRENT_CONTEXT(ctx);
80    ASSERT_OUTSIDE_BEGIN_END(ctx);
81 
82    if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
83       _mesa_debug(ctx, "glTexGen %s %s %.1f(%s)...\n",
84                   _mesa_lookup_enum_by_nr(coord),
85                   _mesa_lookup_enum_by_nr(pname),
86                   *params,
87 		  _mesa_lookup_enum_by_nr((GLenum) (GLint) *params));
88 
89    if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
90       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexGen(current unit)");
91       return;
92    }
93 
94    texUnit = _mesa_get_current_tex_unit(ctx);
95 
96    texgen = get_texgen(ctx, texUnit, coord);
97    if (!texgen) {
98       _mesa_error(ctx, GL_INVALID_ENUM, "glTexGen(coord)");
99       return;
100    }
101 
102    switch (pname) {
103    case GL_TEXTURE_GEN_MODE:
104       {
105          GLenum mode = (GLenum) (GLint) params[0];
106          GLbitfield bit = 0x0;
107          if (texgen->Mode == mode)
108             return;
109          switch (mode) {
110          case GL_OBJECT_LINEAR:
111             bit = TEXGEN_OBJ_LINEAR;
112             break;
113          case GL_EYE_LINEAR:
114             bit = TEXGEN_EYE_LINEAR;
115             break;
116          case GL_SPHERE_MAP:
117             if (coord == GL_S || coord == GL_T)
118                bit = TEXGEN_SPHERE_MAP;
119             break;
120          case GL_REFLECTION_MAP_NV:
121             if (coord != GL_Q)
122                bit = TEXGEN_REFLECTION_MAP_NV;
123             break;
124          case GL_NORMAL_MAP_NV:
125             if (coord != GL_Q)
126                bit = TEXGEN_NORMAL_MAP_NV;
127             break;
128          default:
129             ; /* nop */
130          }
131          if (!bit) {
132             _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
133             return;
134          }
135          if (ctx->API != API_OPENGL
136              && (bit & (TEXGEN_REFLECTION_MAP_NV | TEXGEN_NORMAL_MAP_NV)) == 0) {
137             _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
138             return;
139          }
140 
141          FLUSH_VERTICES(ctx, _NEW_TEXTURE);
142          texgen->Mode = mode;
143          texgen->_ModeBit = bit;
144       }
145       break;
146 
147    case GL_OBJECT_PLANE:
148       {
149          if (ctx->API != API_OPENGL) {
150             _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
151             return;
152          }
153          if (TEST_EQ_4V(texgen->ObjectPlane, params))
154             return;
155          FLUSH_VERTICES(ctx, _NEW_TEXTURE);
156          COPY_4FV(texgen->ObjectPlane, params);
157       }
158       break;
159 
160    case GL_EYE_PLANE:
161       {
162          GLfloat tmp[4];
163 
164          if (ctx->API != API_OPENGL) {
165             _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
166             return;
167          }
168 
169          /* Transform plane equation by the inverse modelview matrix */
170          if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) {
171             _math_matrix_analyse(ctx->ModelviewMatrixStack.Top);
172          }
173          _mesa_transform_vector(tmp, params,
174                                 ctx->ModelviewMatrixStack.Top->inv);
175          if (TEST_EQ_4V(texgen->EyePlane, tmp))
176             return;
177          FLUSH_VERTICES(ctx, _NEW_TEXTURE);
178          COPY_4FV(texgen->EyePlane, tmp);
179       }
180       break;
181 
182    default:
183       _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
184       return;
185    }
186 
187    if (ctx->Driver.TexGen)
188       ctx->Driver.TexGen( ctx, coord, pname, params );
189 }
190 
191 
192 static void GLAPIENTRY
_mesa_TexGeniv(GLenum coord,GLenum pname,const GLint * params)193 _mesa_TexGeniv(GLenum coord, GLenum pname, const GLint *params )
194 {
195    GLfloat p[4];
196    p[0] = (GLfloat) params[0];
197    if (pname == GL_TEXTURE_GEN_MODE) {
198       p[1] = p[2] = p[3] = 0.0F;
199    }
200    else {
201       p[1] = (GLfloat) params[1];
202       p[2] = (GLfloat) params[2];
203       p[3] = (GLfloat) params[3];
204    }
205    _mesa_TexGenfv(coord, pname, p);
206 }
207 
208 
209 static void GLAPIENTRY
_mesa_TexGend(GLenum coord,GLenum pname,GLdouble param)210 _mesa_TexGend(GLenum coord, GLenum pname, GLdouble param )
211 {
212    GLfloat p[4];
213    p[0] = (GLfloat) param;
214    p[1] = p[2] = p[3] = 0.0F;
215    _mesa_TexGenfv( coord, pname, p );
216 }
217 
218 #if FEATURE_ES1
219 
220 void GLAPIENTRY
_es_GetTexGenfv(GLenum coord,GLenum pname,GLfloat * params)221 _es_GetTexGenfv(GLenum coord, GLenum pname, GLfloat *params)
222 {
223    _mesa_GetTexGenfv(GL_S, pname, params);
224 }
225 
226 
227 void GLAPIENTRY
_es_TexGenf(GLenum coord,GLenum pname,GLfloat param)228 _es_TexGenf(GLenum coord, GLenum pname, GLfloat param)
229 {
230    if (coord != GL_TEXTURE_GEN_STR_OES) {
231       GET_CURRENT_CONTEXT(ctx);
232       _mesa_error( ctx, GL_INVALID_ENUM, "glTexGen[fx](pname)" );
233       return;
234    }
235    /* set S, T, and R at the same time */
236    _mesa_TexGenf(GL_S, pname, param);
237    _mesa_TexGenf(GL_T, pname, param);
238    _mesa_TexGenf(GL_R, pname, param);
239 }
240 
241 
242 void GLAPIENTRY
_es_TexGenfv(GLenum coord,GLenum pname,const GLfloat * params)243 _es_TexGenfv(GLenum coord, GLenum pname, const GLfloat *params)
244 {
245    if (coord != GL_TEXTURE_GEN_STR_OES) {
246       GET_CURRENT_CONTEXT(ctx);
247       _mesa_error( ctx, GL_INVALID_ENUM, "glTexGen[fx]v(pname)" );
248       return;
249    }
250    /* set S, T, and R at the same time */
251    _mesa_TexGenfv(GL_S, pname, params);
252    _mesa_TexGenfv(GL_T, pname, params);
253    _mesa_TexGenfv(GL_R, pname, params);
254 }
255 
256 #endif
257 
258 static void GLAPIENTRY
_mesa_TexGendv(GLenum coord,GLenum pname,const GLdouble * params)259 _mesa_TexGendv(GLenum coord, GLenum pname, const GLdouble *params )
260 {
261    GLfloat p[4];
262    p[0] = (GLfloat) params[0];
263    if (pname == GL_TEXTURE_GEN_MODE) {
264       p[1] = p[2] = p[3] = 0.0F;
265    }
266    else {
267       p[1] = (GLfloat) params[1];
268       p[2] = (GLfloat) params[2];
269       p[3] = (GLfloat) params[3];
270    }
271    _mesa_TexGenfv( coord, pname, p );
272 }
273 
274 
275 void GLAPIENTRY
_mesa_TexGenf(GLenum coord,GLenum pname,GLfloat param)276 _mesa_TexGenf( GLenum coord, GLenum pname, GLfloat param )
277 {
278    GLfloat p[4];
279    p[0] = param;
280    p[1] = p[2] = p[3] = 0.0F;
281    _mesa_TexGenfv(coord, pname, p);
282 }
283 
284 
285 void GLAPIENTRY
_mesa_TexGeni(GLenum coord,GLenum pname,GLint param)286 _mesa_TexGeni( GLenum coord, GLenum pname, GLint param )
287 {
288    GLint p[4];
289    p[0] = param;
290    p[1] = p[2] = p[3] = 0;
291    _mesa_TexGeniv( coord, pname, p );
292 }
293 
294 
295 
296 static void GLAPIENTRY
_mesa_GetTexGendv(GLenum coord,GLenum pname,GLdouble * params)297 _mesa_GetTexGendv( GLenum coord, GLenum pname, GLdouble *params )
298 {
299    struct gl_texture_unit *texUnit;
300    struct gl_texgen *texgen;
301    GET_CURRENT_CONTEXT(ctx);
302    ASSERT_OUTSIDE_BEGIN_END(ctx);
303 
304    if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
305       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexGendv(current unit)");
306       return;
307    }
308 
309    texUnit = _mesa_get_current_tex_unit(ctx);
310 
311    texgen = get_texgen(ctx, texUnit, coord);
312    if (!texgen) {
313       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexGendv(coord)");
314       return;
315    }
316 
317    switch (pname) {
318    case GL_TEXTURE_GEN_MODE:
319       params[0] = ENUM_TO_DOUBLE(texgen->Mode);
320       break;
321    case GL_OBJECT_PLANE:
322       COPY_4V(params, texgen->ObjectPlane);
323       break;
324    case GL_EYE_PLANE:
325       COPY_4V(params, texgen->EyePlane);
326       break;
327    default:
328       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGendv(pname)" );
329    }
330 }
331 
332 
333 
334 void GLAPIENTRY
_mesa_GetTexGenfv(GLenum coord,GLenum pname,GLfloat * params)335 _mesa_GetTexGenfv( GLenum coord, GLenum pname, GLfloat *params )
336 {
337    struct gl_texture_unit *texUnit;
338    struct gl_texgen *texgen;
339    GET_CURRENT_CONTEXT(ctx);
340    ASSERT_OUTSIDE_BEGIN_END(ctx);
341 
342    if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
343       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexGenfv(current unit)");
344       return;
345    }
346 
347    texUnit = _mesa_get_current_tex_unit(ctx);
348 
349    texgen = get_texgen(ctx, texUnit, coord);
350    if (!texgen) {
351       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexGenfv(coord)");
352       return;
353    }
354 
355    switch (pname) {
356    case GL_TEXTURE_GEN_MODE:
357       params[0] = ENUM_TO_FLOAT(texgen->Mode);
358       break;
359    case GL_OBJECT_PLANE:
360       if (ctx->API != API_OPENGL) {
361          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGenfv(param)" );
362          return;
363       }
364       COPY_4V(params, texgen->ObjectPlane);
365       break;
366    case GL_EYE_PLANE:
367       if (ctx->API != API_OPENGL) {
368          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGenfv(param)" );
369          return;
370       }
371       COPY_4V(params, texgen->EyePlane);
372       break;
373    default:
374       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGenfv(pname)" );
375    }
376 }
377 
378 
379 
380 void GLAPIENTRY
_mesa_GetTexGeniv(GLenum coord,GLenum pname,GLint * params)381 _mesa_GetTexGeniv( GLenum coord, GLenum pname, GLint *params )
382 {
383    struct gl_texture_unit *texUnit;
384    struct gl_texgen *texgen;
385    GET_CURRENT_CONTEXT(ctx);
386    ASSERT_OUTSIDE_BEGIN_END(ctx);
387 
388    if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
389       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexGeniv(current unit)");
390       return;
391    }
392 
393    texUnit = _mesa_get_current_tex_unit(ctx);
394 
395    texgen = get_texgen(ctx, texUnit, coord);
396    if (!texgen) {
397       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexGeniv(coord)");
398       return;
399    }
400 
401    switch (pname) {
402    case GL_TEXTURE_GEN_MODE:
403       params[0] = texgen->Mode;
404       break;
405    case GL_OBJECT_PLANE:
406       if (ctx->API != API_OPENGL) {
407          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGeniv(param)" );
408          return;
409       }
410       params[0] = (GLint) texgen->ObjectPlane[0];
411       params[1] = (GLint) texgen->ObjectPlane[1];
412       params[2] = (GLint) texgen->ObjectPlane[2];
413       params[3] = (GLint) texgen->ObjectPlane[3];
414       break;
415    case GL_EYE_PLANE:
416       if (ctx->API != API_OPENGL) {
417          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGeniv(param)" );
418          return;
419       }
420       params[0] = (GLint) texgen->EyePlane[0];
421       params[1] = (GLint) texgen->EyePlane[1];
422       params[2] = (GLint) texgen->EyePlane[2];
423       params[3] = (GLint) texgen->EyePlane[3];
424       break;
425    default:
426       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexGeniv(pname)" );
427    }
428 }
429 
430 
431 void
_mesa_init_texgen_dispatch(struct _glapi_table * disp)432 _mesa_init_texgen_dispatch(struct _glapi_table *disp)
433 {
434    SET_GetTexGendv(disp, _mesa_GetTexGendv);
435    SET_GetTexGenfv(disp, _mesa_GetTexGenfv);
436    SET_GetTexGeniv(disp, _mesa_GetTexGeniv);
437    SET_TexGend(disp, _mesa_TexGend);
438    SET_TexGendv(disp, _mesa_TexGendv);
439    SET_TexGenf(disp, _mesa_TexGenf);
440    SET_TexGenfv(disp, _mesa_TexGenfv);
441    SET_TexGeni(disp, _mesa_TexGeni);
442    SET_TexGeniv(disp, _mesa_TexGeniv);
443 }
444 
445 
446 #endif /* FEATURE_texgen */
447