2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
29 * glTexEnv-related functions
33 #include "main/glheader.h"
34 #include "main/context.h"
35 #include "main/blend.h"
36 #include "main/enums.h"
37 #include "main/macros.h"
38 #include "main/mtypes.h"
39 #include "main/state.h"
40 #include "main/texenv.h"
41 #include "main/texstate.h"
44 #define TE_ERROR(errCode, msg, value) \
45 _mesa_error(ctx, errCode, msg, _mesa_enum_to_string(value));
48 /** Set texture env mode */
50 set_env_mode(struct gl_context
*ctx
,
51 struct gl_texture_unit
*texUnit
,
56 if (texUnit
->EnvMode
== mode
)
69 mode
= GL_REPLACE
; /* GL_REPLACE_EXT != GL_REPLACE */
73 legal
= ctx
->Extensions
.NV_texture_env_combine4
;
80 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
81 texUnit
->EnvMode
= mode
;
84 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(param=%s)", mode
);
90 set_env_color(struct gl_context
*ctx
,
91 struct gl_texture_unit
*texUnit
,
94 if (TEST_EQ_4V(color
, texUnit
->EnvColorUnclamped
))
96 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
97 COPY_4FV(texUnit
->EnvColorUnclamped
, color
);
98 texUnit
->EnvColor
[0] = CLAMP(color
[0], 0.0F
, 1.0F
);
99 texUnit
->EnvColor
[1] = CLAMP(color
[1], 0.0F
, 1.0F
);
100 texUnit
->EnvColor
[2] = CLAMP(color
[2], 0.0F
, 1.0F
);
101 texUnit
->EnvColor
[3] = CLAMP(color
[3], 0.0F
, 1.0F
);
105 /** Set an RGB or A combiner mode/function */
107 set_combiner_mode(struct gl_context
*ctx
,
108 struct gl_texture_unit
*texUnit
,
109 GLenum pname
, GLenum mode
)
122 legal
= ctx
->Extensions
.ARB_texture_env_combine
;
124 case GL_DOT3_RGB_EXT
:
125 case GL_DOT3_RGBA_EXT
:
126 legal
= (ctx
->API
== API_OPENGL_COMPAT
&&
127 ctx
->Extensions
.EXT_texture_env_dot3
&&
128 pname
== GL_COMBINE_RGB
);
132 legal
= (ctx
->Extensions
.ARB_texture_env_dot3
&&
133 pname
== GL_COMBINE_RGB
);
135 case GL_MODULATE_ADD_ATI
:
136 case GL_MODULATE_SIGNED_ADD_ATI
:
137 case GL_MODULATE_SUBTRACT_ATI
:
138 legal
= (ctx
->API
== API_OPENGL_COMPAT
&&
139 ctx
->Extensions
.ATI_texture_env_combine3
);
146 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(param=%s)", mode
);
152 if (texUnit
->Combine
.ModeRGB
== mode
)
154 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
155 texUnit
->Combine
.ModeRGB
= mode
;
158 case GL_COMBINE_ALPHA
:
159 if (texUnit
->Combine
.ModeA
== mode
)
161 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
162 texUnit
->Combine
.ModeA
= mode
;
165 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
171 /** Set an RGB or A combiner source term */
173 set_combiner_source(struct gl_context
*ctx
,
174 struct gl_texture_unit
*texUnit
,
175 GLenum pname
, GLenum param
)
178 GLboolean alpha
, legal
;
181 * Translate pname to (term, alpha).
183 * The enums were given sequential values for a reason.
189 case GL_SOURCE3_RGB_NV
:
190 term
= pname
- GL_SOURCE0_RGB
;
193 case GL_SOURCE0_ALPHA
:
194 case GL_SOURCE1_ALPHA
:
195 case GL_SOURCE2_ALPHA
:
196 case GL_SOURCE3_ALPHA_NV
:
197 term
= pname
- GL_SOURCE0_ALPHA
;
201 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
205 if ((term
== 3) && (ctx
->API
!= API_OPENGL_COMPAT
206 || !ctx
->Extensions
.NV_texture_env_combine4
)) {
207 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
211 assert(term
< MAX_COMBINER_TERMS
);
214 * Error-check param (the source term)
219 case GL_PRIMARY_COLOR
:
231 legal
= (ctx
->Extensions
.ARB_texture_env_crossbar
&&
232 param
- GL_TEXTURE0
< ctx
->Const
.MaxTextureUnits
);
235 legal
= (ctx
->API
== API_OPENGL_COMPAT
&&
236 (ctx
->Extensions
.ATI_texture_env_combine3
||
237 ctx
->Extensions
.NV_texture_env_combine4
));
240 legal
= (ctx
->API
== API_OPENGL_COMPAT
&&
241 ctx
->Extensions
.ATI_texture_env_combine3
);
248 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(param=%s)", param
);
252 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
255 texUnit
->Combine
.SourceA
[term
] = param
;
257 texUnit
->Combine
.SourceRGB
[term
] = param
;
261 /** Set an RGB or A combiner operand term */
263 set_combiner_operand(struct gl_context
*ctx
,
264 struct gl_texture_unit
*texUnit
,
265 GLenum pname
, GLenum param
)
268 GLboolean alpha
, legal
;
270 /* The enums were given sequential values for a reason.
273 case GL_OPERAND0_RGB
:
274 case GL_OPERAND1_RGB
:
275 case GL_OPERAND2_RGB
:
276 case GL_OPERAND3_RGB_NV
:
277 term
= pname
- GL_OPERAND0_RGB
;
280 case GL_OPERAND0_ALPHA
:
281 case GL_OPERAND1_ALPHA
:
282 case GL_OPERAND2_ALPHA
:
283 case GL_OPERAND3_ALPHA_NV
:
284 term
= pname
- GL_OPERAND0_ALPHA
;
288 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
292 if ((term
== 3) && (ctx
->API
!= API_OPENGL_COMPAT
293 || !ctx
->Extensions
.NV_texture_env_combine4
)) {
294 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
298 assert(term
< MAX_COMBINER_TERMS
);
301 * Error-check param (the source operand)
305 case GL_ONE_MINUS_SRC_COLOR
:
306 /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
307 * version. In the ARB and NV versions and OpenGL ES 1.x they can be
308 * used for any RGB operand.
311 && ((term
< 2) || ctx
->Extensions
.ARB_texture_env_combine
312 || ctx
->Extensions
.NV_texture_env_combine4
);
314 case GL_ONE_MINUS_SRC_ALPHA
:
315 /* GL_ONE_MINUS_SRC_ALPHA can only be used with
316 * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version. In the ARB and NV
317 * versions and OpenGL ES 1.x it can be used for any operand.
319 legal
= (term
< 2) || ctx
->Extensions
.ARB_texture_env_combine
320 || ctx
->Extensions
.NV_texture_env_combine4
;
330 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(param=%s)", param
);
334 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
337 texUnit
->Combine
.OperandA
[term
] = param
;
339 texUnit
->Combine
.OperandRGB
[term
] = param
;
344 set_combiner_scale(struct gl_context
*ctx
,
345 struct gl_texture_unit
*texUnit
,
346 GLenum pname
, GLfloat scale
)
353 else if (scale
== 2.0F
) {
356 else if (scale
== 4.0F
) {
360 _mesa_error( ctx
, GL_INVALID_VALUE
,
361 "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
367 if (texUnit
->Combine
.ScaleShiftRGB
== shift
)
369 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
370 texUnit
->Combine
.ScaleShiftRGB
= shift
;
373 if (texUnit
->Combine
.ScaleShiftA
== shift
)
375 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
376 texUnit
->Combine
.ScaleShiftA
= shift
;
379 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
386 _mesa_TexEnvfv( GLenum target
, GLenum pname
, const GLfloat
*param
)
388 const GLint iparam0
= (GLint
) param
[0];
389 struct gl_texture_unit
*texUnit
;
391 GET_CURRENT_CONTEXT(ctx
);
393 maxUnit
= (target
== GL_POINT_SPRITE_NV
&& pname
== GL_COORD_REPLACE_NV
)
394 ? ctx
->Const
.MaxTextureCoordUnits
: ctx
->Const
.MaxCombinedTextureImageUnits
;
395 if (ctx
->Texture
.CurrentUnit
>= maxUnit
) {
396 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glTexEnvfv(current unit)");
400 texUnit
= _mesa_get_current_tex_unit(ctx
);
402 if (target
== GL_TEXTURE_ENV
) {
404 case GL_TEXTURE_ENV_MODE
:
405 set_env_mode(ctx
, texUnit
, (GLenum
) iparam0
);
407 case GL_TEXTURE_ENV_COLOR
:
408 set_env_color(ctx
, texUnit
, param
);
411 case GL_COMBINE_ALPHA
:
412 set_combiner_mode(ctx
, texUnit
, pname
, (GLenum
) iparam0
);
417 case GL_SOURCE3_RGB_NV
:
418 case GL_SOURCE0_ALPHA
:
419 case GL_SOURCE1_ALPHA
:
420 case GL_SOURCE2_ALPHA
:
421 case GL_SOURCE3_ALPHA_NV
:
422 set_combiner_source(ctx
, texUnit
, pname
, (GLenum
) iparam0
);
424 case GL_OPERAND0_RGB
:
425 case GL_OPERAND1_RGB
:
426 case GL_OPERAND2_RGB
:
427 case GL_OPERAND3_RGB_NV
:
428 case GL_OPERAND0_ALPHA
:
429 case GL_OPERAND1_ALPHA
:
430 case GL_OPERAND2_ALPHA
:
431 case GL_OPERAND3_ALPHA_NV
:
432 set_combiner_operand(ctx
, texUnit
, pname
, (GLenum
) iparam0
);
436 set_combiner_scale(ctx
, texUnit
, pname
, param
[0]);
439 _mesa_error( ctx
, GL_INVALID_ENUM
, "glTexEnv(pname)" );
443 else if (target
== GL_TEXTURE_FILTER_CONTROL_EXT
) {
444 if (pname
== GL_TEXTURE_LOD_BIAS_EXT
) {
445 if (texUnit
->LodBias
== param
[0])
447 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
448 texUnit
->LodBias
= param
[0];
451 TE_ERROR(GL_INVALID_ENUM
, "glTexEnv(pname=%s)", pname
);
455 else if (target
== GL_POINT_SPRITE_NV
) {
456 /* GL_ARB_point_sprite / GL_NV_point_sprite */
457 if (!ctx
->Extensions
.NV_point_sprite
458 && !ctx
->Extensions
.ARB_point_sprite
) {
459 _mesa_error( ctx
, GL_INVALID_ENUM
, "glTexEnv(target=0x%x)", target
);
462 if (pname
== GL_COORD_REPLACE_NV
) {
463 if (iparam0
== GL_TRUE
|| iparam0
== GL_FALSE
) {
464 /* It's kind of weird to set point state via glTexEnv,
465 * but that's what the spec calls for.
467 const GLboolean state
= (GLboolean
) iparam0
;
468 if (ctx
->Point
.CoordReplace
[ctx
->Texture
.CurrentUnit
] == state
)
470 FLUSH_VERTICES(ctx
, _NEW_POINT
);
471 ctx
->Point
.CoordReplace
[ctx
->Texture
.CurrentUnit
] = state
;
474 _mesa_error( ctx
, GL_INVALID_VALUE
, "glTexEnv(param=0x%x)", iparam0
);
479 _mesa_error( ctx
, GL_INVALID_ENUM
, "glTexEnv(pname=0x%x)", pname
);
484 _mesa_error(ctx
, GL_INVALID_ENUM
, "glTexEnv(target=%s)",
485 _mesa_enum_to_string(target
));
489 if (MESA_VERBOSE
&(VERBOSE_API
|VERBOSE_TEXTURE
))
490 _mesa_debug(ctx
, "glTexEnv %s %s %.1f(%s) ...\n",
491 _mesa_enum_to_string(target
),
492 _mesa_enum_to_string(pname
),
494 _mesa_enum_to_string((GLenum
) iparam0
));
496 /* Tell device driver about the new texture environment */
497 if (ctx
->Driver
.TexEnv
) {
498 ctx
->Driver
.TexEnv(ctx
, target
, pname
, param
);
504 _mesa_TexEnvf( GLenum target
, GLenum pname
, GLfloat param
)
508 p
[1] = p
[2] = p
[3] = 0.0;
509 _mesa_TexEnvfv( target
, pname
, p
);
515 _mesa_TexEnvi( GLenum target
, GLenum pname
, GLint param
)
518 p
[0] = (GLfloat
) param
;
519 p
[1] = p
[2] = p
[3] = 0.0;
520 _mesa_TexEnvfv( target
, pname
, p
);
525 _mesa_TexEnviv( GLenum target
, GLenum pname
, const GLint
*param
)
528 if (pname
== GL_TEXTURE_ENV_COLOR
) {
529 p
[0] = INT_TO_FLOAT( param
[0] );
530 p
[1] = INT_TO_FLOAT( param
[1] );
531 p
[2] = INT_TO_FLOAT( param
[2] );
532 p
[3] = INT_TO_FLOAT( param
[3] );
535 p
[0] = (GLfloat
) param
[0];
536 p
[1] = p
[2] = p
[3] = 0; /* init to zero, just to be safe */
538 _mesa_TexEnvfv( target
, pname
, p
);
544 * Helper for glGetTexEnvi/f()
545 * \return value of queried pname or -1 if error.
548 get_texenvi(struct gl_context
*ctx
, const struct gl_texture_unit
*texUnit
,
552 case GL_TEXTURE_ENV_MODE
:
553 return texUnit
->EnvMode
;
556 return texUnit
->Combine
.ModeRGB
;
557 case GL_COMBINE_ALPHA
:
558 return texUnit
->Combine
.ModeA
;
561 case GL_SOURCE2_RGB
: {
562 const unsigned rgb_idx
= pname
- GL_SOURCE0_RGB
;
563 return texUnit
->Combine
.SourceRGB
[rgb_idx
];
565 case GL_SOURCE3_RGB_NV
:
566 if (ctx
->API
== API_OPENGL_COMPAT
&& ctx
->Extensions
.NV_texture_env_combine4
) {
567 return texUnit
->Combine
.SourceRGB
[3];
570 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)");
573 case GL_SOURCE0_ALPHA
:
574 case GL_SOURCE1_ALPHA
:
575 case GL_SOURCE2_ALPHA
: {
576 const unsigned alpha_idx
= pname
- GL_SOURCE0_ALPHA
;
577 return texUnit
->Combine
.SourceA
[alpha_idx
];
579 case GL_SOURCE3_ALPHA_NV
:
580 if (ctx
->API
== API_OPENGL_COMPAT
&& ctx
->Extensions
.NV_texture_env_combine4
) {
581 return texUnit
->Combine
.SourceA
[3];
584 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)");
587 case GL_OPERAND0_RGB
:
588 case GL_OPERAND1_RGB
:
589 case GL_OPERAND2_RGB
: {
590 const unsigned op_rgb
= pname
- GL_OPERAND0_RGB
;
591 return texUnit
->Combine
.OperandRGB
[op_rgb
];
593 case GL_OPERAND3_RGB_NV
:
594 if (ctx
->API
== API_OPENGL_COMPAT
&& ctx
->Extensions
.NV_texture_env_combine4
) {
595 return texUnit
->Combine
.OperandRGB
[3];
598 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)");
601 case GL_OPERAND0_ALPHA
:
602 case GL_OPERAND1_ALPHA
:
603 case GL_OPERAND2_ALPHA
: {
604 const unsigned op_alpha
= pname
- GL_OPERAND0_ALPHA
;
605 return texUnit
->Combine
.OperandA
[op_alpha
];
607 case GL_OPERAND3_ALPHA_NV
:
608 if (ctx
->API
== API_OPENGL_COMPAT
&& ctx
->Extensions
.NV_texture_env_combine4
) {
609 return texUnit
->Combine
.OperandA
[3];
612 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)");
616 return 1 << texUnit
->Combine
.ScaleShiftRGB
;
618 return 1 << texUnit
->Combine
.ScaleShiftA
;
620 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)");
624 return -1; /* error */
630 _mesa_GetTexEnvfv( GLenum target
, GLenum pname
, GLfloat
*params
)
633 const struct gl_texture_unit
*texUnit
;
634 GET_CURRENT_CONTEXT(ctx
);
636 maxUnit
= (target
== GL_POINT_SPRITE_NV
&& pname
== GL_COORD_REPLACE_NV
)
637 ? ctx
->Const
.MaxTextureCoordUnits
: ctx
->Const
.MaxCombinedTextureImageUnits
;
638 if (ctx
->Texture
.CurrentUnit
>= maxUnit
) {
639 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexEnvfv(current unit)");
643 texUnit
= _mesa_get_current_tex_unit(ctx
);
645 if (target
== GL_TEXTURE_ENV
) {
646 if (pname
== GL_TEXTURE_ENV_COLOR
) {
647 if(ctx
->NewState
& (_NEW_BUFFERS
| _NEW_FRAG_CLAMP
))
648 _mesa_update_state(ctx
);
649 if (_mesa_get_clamp_fragment_color(ctx
, ctx
->DrawBuffer
))
650 COPY_4FV( params
, texUnit
->EnvColor
);
652 COPY_4FV( params
, texUnit
->EnvColorUnclamped
);
655 GLint val
= get_texenvi(ctx
, texUnit
, pname
);
657 *params
= (GLfloat
) val
;
661 else if (target
== GL_TEXTURE_FILTER_CONTROL_EXT
) {
662 if (pname
== GL_TEXTURE_LOD_BIAS_EXT
) {
663 *params
= texUnit
->LodBias
;
666 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)" );
670 else if (target
== GL_POINT_SPRITE_NV
) {
671 /* GL_ARB_point_sprite / GL_NV_point_sprite */
672 if (!ctx
->Extensions
.NV_point_sprite
673 && !ctx
->Extensions
.ARB_point_sprite
) {
674 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(target)" );
677 if (pname
== GL_COORD_REPLACE_NV
) {
678 *params
= (GLfloat
) ctx
->Point
.CoordReplace
[ctx
->Texture
.CurrentUnit
];
681 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(pname)" );
686 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnvfv(target)" );
693 _mesa_GetTexEnviv( GLenum target
, GLenum pname
, GLint
*params
)
696 const struct gl_texture_unit
*texUnit
;
697 GET_CURRENT_CONTEXT(ctx
);
699 maxUnit
= (target
== GL_POINT_SPRITE_NV
&& pname
== GL_COORD_REPLACE_NV
)
700 ? ctx
->Const
.MaxTextureCoordUnits
: ctx
->Const
.MaxCombinedTextureImageUnits
;
701 if (ctx
->Texture
.CurrentUnit
>= maxUnit
) {
702 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexEnviv(current unit)");
706 texUnit
= _mesa_get_current_tex_unit(ctx
);
708 if (target
== GL_TEXTURE_ENV
) {
709 if (pname
== GL_TEXTURE_ENV_COLOR
) {
710 params
[0] = FLOAT_TO_INT( texUnit
->EnvColor
[0] );
711 params
[1] = FLOAT_TO_INT( texUnit
->EnvColor
[1] );
712 params
[2] = FLOAT_TO_INT( texUnit
->EnvColor
[2] );
713 params
[3] = FLOAT_TO_INT( texUnit
->EnvColor
[3] );
716 GLint val
= get_texenvi(ctx
, texUnit
, pname
);
722 else if (target
== GL_TEXTURE_FILTER_CONTROL_EXT
) {
723 if (pname
== GL_TEXTURE_LOD_BIAS_EXT
) {
724 *params
= (GLint
) texUnit
->LodBias
;
727 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnviv(pname)" );
731 else if (target
== GL_POINT_SPRITE_NV
) {
732 /* GL_ARB_point_sprite / GL_NV_point_sprite */
733 if (!ctx
->Extensions
.NV_point_sprite
734 && !ctx
->Extensions
.ARB_point_sprite
) {
735 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnviv(target)" );
738 if (pname
== GL_COORD_REPLACE_NV
) {
739 *params
= (GLint
) ctx
->Point
.CoordReplace
[ctx
->Texture
.CurrentUnit
];
742 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnviv(pname)" );
747 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexEnviv(target)" );