+#include "main/texstate.h"
+
+
+#define TE_ERROR(errCode, msg, value) \
+ _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
+
+
+/** Set texture env mode */
+static void
+set_env_mode(struct gl_context *ctx,
+ struct gl_texture_unit *texUnit,
+ GLenum mode)
+{
+ GLboolean legal;
+
+ if (texUnit->EnvMode == mode)
+ return;
+
+ switch (mode) {
+ case GL_MODULATE:
+ case GL_BLEND:
+ case GL_DECAL:
+ case GL_REPLACE:
+ legal = GL_TRUE;
+ break;
+ case GL_REPLACE_EXT:
+ mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
+ legal = GL_TRUE;
+ break;
+ case GL_ADD:
+ legal = ctx->Extensions.EXT_texture_env_add;
+ break;
+ case GL_COMBINE:
+ legal = (ctx->Extensions.EXT_texture_env_combine ||
+ ctx->Extensions.ARB_texture_env_combine);
+ break;
+ case GL_COMBINE4_NV:
+ legal = ctx->Extensions.NV_texture_env_combine4;
+ break;
+ default:
+ legal = GL_FALSE;
+ }
+
+ if (legal) {
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->EnvMode = mode;
+ }
+ else {
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
+ }
+}
+
+
+static void
+set_env_color(struct gl_context *ctx,
+ struct gl_texture_unit *texUnit,
+ const GLfloat *color)
+{
+ if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped))
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ COPY_4FV(texUnit->EnvColorUnclamped, color);
+ texUnit->EnvColor[0] = CLAMP(color[0], 0.0F, 1.0F);
+ texUnit->EnvColor[1] = CLAMP(color[1], 0.0F, 1.0F);
+ texUnit->EnvColor[2] = CLAMP(color[2], 0.0F, 1.0F);
+ texUnit->EnvColor[3] = CLAMP(color[3], 0.0F, 1.0F);
+}
+
+
+/** Set an RGB or A combiner mode/function */
+static void
+set_combiner_mode(struct gl_context *ctx,
+ struct gl_texture_unit *texUnit,
+ GLenum pname, GLenum mode)
+{
+ GLboolean legal;
+
+ if (!ctx->Extensions.EXT_texture_env_combine &&
+ !ctx->Extensions.ARB_texture_env_combine) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+ return;
+ }
+
+ switch (mode) {
+ case GL_REPLACE:
+ case GL_MODULATE:
+ case GL_ADD:
+ case GL_ADD_SIGNED:
+ case GL_INTERPOLATE:
+ legal = GL_TRUE;
+ break;
+ case GL_SUBTRACT:
+ legal = ctx->Extensions.ARB_texture_env_combine;
+ break;
+ case GL_DOT3_RGB_EXT:
+ case GL_DOT3_RGBA_EXT:
+ legal = (ctx->Extensions.EXT_texture_env_dot3 &&
+ pname == GL_COMBINE_RGB);
+ break;
+ case GL_DOT3_RGB:
+ case GL_DOT3_RGBA:
+ legal = (ctx->Extensions.ARB_texture_env_dot3 &&
+ pname == GL_COMBINE_RGB);
+ break;
+ case GL_MODULATE_ADD_ATI:
+ case GL_MODULATE_SIGNED_ADD_ATI:
+ case GL_MODULATE_SUBTRACT_ATI:
+ legal = ctx->Extensions.ATI_texture_env_combine3;
+ break;
+ case GL_BUMP_ENVMAP_ATI:
+ legal = (ctx->Extensions.ATI_envmap_bumpmap &&
+ pname == GL_COMBINE_RGB);
+ break;
+ default:
+ legal = GL_FALSE;
+ }
+
+ if (!legal) {
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
+ return;
+ }
+
+ switch (pname) {
+ case GL_COMBINE_RGB:
+ if (texUnit->Combine.ModeRGB == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->Combine.ModeRGB = mode;
+ break;
+
+ case GL_COMBINE_ALPHA:
+ if (texUnit->Combine.ModeA == mode)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->Combine.ModeA = mode;
+ break;
+ default:
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+ }
+}
+
+
+
+/** Set an RGB or A combiner source term */
+static void
+set_combiner_source(struct gl_context *ctx,
+ struct gl_texture_unit *texUnit,
+ GLenum pname, GLenum param)
+{
+ GLuint term;
+ GLboolean alpha, legal;
+
+ if (!ctx->Extensions.EXT_texture_env_combine &&
+ !ctx->Extensions.ARB_texture_env_combine) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+ return;
+ }
+
+ /*
+ * Translate pname to (term, alpha).
+ *
+ * The enums were given sequential values for a reason.
+ */
+ switch (pname) {
+ case GL_SOURCE0_RGB:
+ case GL_SOURCE1_RGB:
+ case GL_SOURCE2_RGB:
+ case GL_SOURCE3_RGB_NV:
+ term = pname - GL_SOURCE0_RGB;
+ alpha = GL_FALSE;
+ break;
+ case GL_SOURCE0_ALPHA:
+ case GL_SOURCE1_ALPHA:
+ case GL_SOURCE2_ALPHA:
+ case GL_SOURCE3_ALPHA_NV:
+ term = pname - GL_SOURCE0_ALPHA;
+ alpha = GL_TRUE;
+ break;
+ default:
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+ return;
+ }
+
+ if ((term == 3) && !ctx->Extensions.NV_texture_env_combine4) {
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+ return;
+ }
+
+ assert(term < MAX_COMBINER_TERMS);
+
+ /*
+ * Error-check param (the source term)
+ */
+ switch (param) {
+ case GL_TEXTURE:
+ case GL_CONSTANT:
+ case GL_PRIMARY_COLOR:
+ case GL_PREVIOUS:
+ legal = GL_TRUE;
+ break;
+ case GL_TEXTURE0:
+ case GL_TEXTURE1:
+ case GL_TEXTURE2:
+ case GL_TEXTURE3:
+ case GL_TEXTURE4:
+ case GL_TEXTURE5:
+ case GL_TEXTURE6:
+ case GL_TEXTURE7:
+ legal = (ctx->Extensions.ARB_texture_env_crossbar &&
+ param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
+ break;
+ case GL_ZERO:
+ legal = (ctx->Extensions.ATI_texture_env_combine3 ||
+ ctx->Extensions.NV_texture_env_combine4);
+ break;
+ case GL_ONE:
+ legal = ctx->Extensions.ATI_texture_env_combine3;
+ break;
+ default:
+ legal = GL_FALSE;
+ }
+
+ if (!legal) {
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+ if (alpha)
+ texUnit->Combine.SourceA[term] = param;
+ else
+ texUnit->Combine.SourceRGB[term] = param;
+}
+
+
+/** Set an RGB or A combiner operand term */
+static void
+set_combiner_operand(struct gl_context *ctx,
+ struct gl_texture_unit *texUnit,
+ GLenum pname, GLenum param)
+{
+ GLuint term;
+ GLboolean alpha, legal;
+
+ if (!ctx->Extensions.EXT_texture_env_combine &&
+ !ctx->Extensions.ARB_texture_env_combine) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+ return;
+ }
+
+ /* The enums were given sequential values for a reason.
+ */
+ switch (pname) {
+ case GL_OPERAND0_RGB:
+ case GL_OPERAND1_RGB:
+ case GL_OPERAND2_RGB:
+ case GL_OPERAND3_RGB_NV:
+ term = pname - GL_OPERAND0_RGB;
+ alpha = GL_FALSE;
+ break;
+ case GL_OPERAND0_ALPHA:
+ case GL_OPERAND1_ALPHA:
+ case GL_OPERAND2_ALPHA:
+ case GL_OPERAND3_ALPHA_NV:
+ term = pname - GL_OPERAND0_ALPHA;
+ alpha = GL_TRUE;
+ break;
+ default:
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+ return;
+ }
+
+ if ((term == 3) && !ctx->Extensions.NV_texture_env_combine4) {
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+ return;
+ }
+
+ assert(term < MAX_COMBINER_TERMS);
+
+ /*
+ * Error-check param (the source operand)
+ */
+ switch (param) {
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
+ * version. In the ARB and NV versions they can be used for any RGB
+ * operand.
+ */
+ legal = !alpha
+ && ((term < 2) || ctx->Extensions.ARB_texture_env_combine
+ || ctx->Extensions.NV_texture_env_combine4);
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ /* GL_ONE_MINUS_SRC_ALPHA can only be used with
+ * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version. In the ARB and NV
+ * versions it can be used for any operand.
+ */
+ legal = (term < 2) || ctx->Extensions.ARB_texture_env_combine
+ || ctx->Extensions.NV_texture_env_combine4;
+ break;
+ case GL_SRC_ALPHA:
+ legal = GL_TRUE;
+ break;
+ default:
+ legal = GL_FALSE;
+ }
+
+ if (!legal) {
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+ if (alpha)
+ texUnit->Combine.OperandA[term] = param;
+ else
+ texUnit->Combine.OperandRGB[term] = param;
+}
+
+
+static void
+set_combiner_scale(struct gl_context *ctx,
+ struct gl_texture_unit *texUnit,
+ GLenum pname, GLfloat scale)
+{
+ GLuint shift;
+
+ if (!ctx->Extensions.EXT_texture_env_combine &&
+ !ctx->Extensions.ARB_texture_env_combine) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+ return;
+ }
+
+ if (scale == 1.0F) {
+ shift = 0;
+ }
+ else if (scale == 2.0F) {
+ shift = 1;
+ }
+ else if (scale == 4.0F) {
+ shift = 2;
+ }
+ else {
+ _mesa_error( ctx, GL_INVALID_VALUE,
+ "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
+ return;
+ }
+
+ switch (pname) {
+ case GL_RGB_SCALE:
+ if (texUnit->Combine.ScaleShiftRGB == shift)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->Combine.ScaleShiftRGB = shift;
+ break;
+ case GL_ALPHA_SCALE:
+ if (texUnit->Combine.ScaleShiftA == shift)
+ return;
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ texUnit->Combine.ScaleShiftA = shift;
+ break;
+ default:
+ TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+ }
+}