void i810UpdateTextureState( struct gl_context *ctx )
{
   static const unsigned color_pass[3] = {
      GFX_OP_MAP_COLOR_STAGES | MC_STAGE_0 | MC_UPDATE_DEST | MC_DEST_CURRENT
	| MC_UPDATE_ARG1 | (MC_ARG_ITERATED_COLOR << MC_ARG1_SHIFT)
	| MC_UPDATE_ARG2 | (MC_ARG_ONE            << MC_ARG2_SHIFT)
	| MC_UPDATE_OP   | MC_OP_ARG1,
      GFX_OP_MAP_COLOR_STAGES | MC_STAGE_1 | MC_UPDATE_DEST | MC_DEST_CURRENT
	| MC_UPDATE_ARG1 | (MC_ARG_CURRENT_COLOR  << MC_ARG1_SHIFT)
	| MC_UPDATE_ARG2 | (MC_ARG_ONE            << MC_ARG2_SHIFT)
	| MC_UPDATE_OP   | MC_OP_ARG1,
      GFX_OP_MAP_COLOR_STAGES | MC_STAGE_2 | MC_UPDATE_DEST | MC_DEST_CURRENT
	| MC_UPDATE_ARG1 | (MC_ARG_CURRENT_COLOR  << MC_ARG1_SHIFT)
	| MC_UPDATE_ARG2 | (MC_ARG_ONE            << MC_ARG2_SHIFT)
	| MC_UPDATE_OP   | MC_OP_ARG1
   };
   static const unsigned alpha_pass[3] = {
      GFX_OP_MAP_ALPHA_STAGES | MA_STAGE_0
	| MA_UPDATE_ARG1 | (MA_ARG_ITERATED_ALPHA << MA_ARG1_SHIFT)
	| MA_UPDATE_ARG2 | (MA_ARG_ITERATED_ALPHA << MA_ARG2_SHIFT)
	| MA_UPDATE_OP   | MA_OP_ARG1,
      GFX_OP_MAP_ALPHA_STAGES | MA_STAGE_1
	| MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA  << MA_ARG1_SHIFT)
	| MA_UPDATE_ARG2 | (MA_ARG_CURRENT_ALPHA  << MA_ARG2_SHIFT)
	| MA_UPDATE_OP   | MA_OP_ARG1,
      GFX_OP_MAP_ALPHA_STAGES | MA_STAGE_2
	| MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA  << MA_ARG1_SHIFT)
	| MA_UPDATE_ARG2 | (MA_ARG_CURRENT_ALPHA  << MA_ARG2_SHIFT)
	| MA_UPDATE_OP   | MA_OP_ARG1
   };
   i810ContextPtr imesa = I810_CONTEXT(ctx);
   int next_color_stage = 0;
   int next_alpha_stage = 0;


   /*  fprintf(stderr, "%s\n", __FUNCTION__); */
   FALLBACK( imesa, I810_FALLBACK_TEXTURE, GL_FALSE );

   i810UpdateTexUnit( ctx, 0, & next_color_stage, & next_alpha_stage );
   i810UpdateTexUnit( ctx, 1, & next_color_stage, & next_alpha_stage );

   /* There needs to be at least one combine stage emitted that just moves
    * the incoming primary color to the current color register.  In addition,
    * there number be the same number of color and alpha stages emitted.
    * Finally, if there are less than 3 combine stages, a MC_OP_DISABLE stage
    * must be emitted.
    */

   while ( (next_color_stage == 0) ||
	   (next_color_stage < next_alpha_stage) ) {
      set_color_stage( color_pass[ next_color_stage ], next_color_stage,
		       imesa );
      next_color_stage++;
   }

   assert( next_color_stage <= 3 );

   while ( next_alpha_stage < next_color_stage ) {
      set_alpha_stage( alpha_pass[ next_alpha_stage ], next_alpha_stage,
		       imesa );
      next_alpha_stage++;
   }

   assert( next_alpha_stage <= 3 );
   assert( next_color_stage == next_alpha_stage );

   if ( next_color_stage < 3 ) {
      const unsigned color = GFX_OP_MAP_COLOR_STAGES
	| (next_color_stage << MC_STAGE_SHIFT)
	| MC_UPDATE_DEST | MC_DEST_CURRENT
	| MC_UPDATE_ARG1 | (MC_ARG_ONE << MC_ARG1_SHIFT)
	| MC_UPDATE_ARG2 | (MC_ARG_ONE << MC_ARG2_SHIFT)
	| MC_UPDATE_OP   | (MC_OP_DISABLE);

      const unsigned alpha = GFX_OP_MAP_ALPHA_STAGES
	| (next_color_stage << MC_STAGE_SHIFT)
	| MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA << MA_ARG1_SHIFT)
	| MA_UPDATE_ARG2 | (MA_ARG_CURRENT_ALPHA << MA_ARG2_SHIFT)
	| MA_UPDATE_OP   | (MA_OP_ARG1);

      set_color_stage( color, next_color_stage, imesa );
      set_alpha_stage( alpha, next_alpha_stage, imesa );
   }
}
Example #2
0
// meaning of *pass* is in [zz_material.h]
bool zz_material_terrain::set (int pass)
{
	zz_texture * firstmap, * secondmap, * lightmap;

	int shader_format = get_shader_format();

	if (shader_format == SHADER_FORMAT_DEFAULT) return false;

	firstmap = (shader_format & SHADER_FORMAT_FIRSTMAP) ? textures[0] : 0;
	secondmap = (shader_format & SHADER_FORMAT_SECONDMAP) ? textures[1] : 0;
	lightmap = (shader_format & SHADER_FORMAT_LIGHTMAP) ? textures[2] : 0;

	bool l_use_shadow = (shader_format & SHADER_FORMAT_SHADOWMAP) > 0;

	// texture binding
	int texture_stage = 0;

	if (firstmap) firstmap->set(texture_stage++);
	if (secondmap) secondmap->set(texture_stage++);
	if (lightmap) lightmap->set(texture_stage++);
	if (l_use_shadow) s_renderer->set_texture_shadowmap(texture_stage++);

#ifdef _DEBUG
	static bool debug_flags_multi [] = {true, true, true, true, true, true, true};
	static bool debug_flags_single [] = {true, true, true, true, true, true, true};
#endif

	// set texture stage
	if (s_renderstate->use_multipass) {
		if (firstmap) {
			if (secondmap) {
				TEST_FLAGS_MULTI(0);
				set_first_second();
			}
			else if (lightmap) {
				TEST_FLAGS_MULTI(1);
				set_first_light();
			}
			else if (l_use_shadow) {
				TEST_FLAGS_MULTI(2);
				set_first_shadow();
			}
			else {
				TEST_FLAGS_MULTI(3);
				set_first();
			}
		}
		else if (lightmap) {
			if (l_use_shadow) {
				TEST_FLAGS_MULTI(4);
				set_light_shadow();
			}
			else {
				TEST_FLAGS_MULTI(5);
				set_light();
			}
		}
		else if (l_use_shadow) {
			TEST_FLAGS_MULTI(6);
			set_shadow();
		}
		else {
			return false;
		}
	}
	else {
		if (firstmap) {
			if (secondmap) {
				if (lightmap) {
					if (l_use_shadow) {
						TEST_FLAGS_SINGLE(0);
						set_first_second_light_shadow();
					}
					else {
						TEST_FLAGS_SINGLE(1);
						set_first_second_light();
					}
				}
				else {
					if (l_use_shadow) {
						TEST_FLAGS_SINGLE(2);
						set_first_second_shadow();
					}
					else {
						TEST_FLAGS_SINGLE(3);
						set_first_second();
					}
				}
			}
			else {
				if (lightmap) {
					if (l_use_shadow) {
						TEST_FLAGS_SINGLE(4);
						set_first_light_shadow();
					}
					else {
						TEST_FLAGS_SINGLE(5);
						set_first_light();
					}
				}
				else {
					TEST_FLAGS_SINGLE(6);
					set_first();
				}
			}
		}
		else {
			return false;
		}
	}
	set_alpha_stage(pass, lightmap ? true : false, l_use_shadow);
	return true;
}
/**
 * Configure the hardware bits for the specified texture environment.
 *
 * Configures the hardware bits for the texture environment state for the
 * specified texture unit.  As combine stages are added, the values pointed
 * to by \c color_stage and \c alpha_stage are incremented.
 *
 * \param ctx          GL context pointer.
 * \param unit         Texture unit to be added.
 * \param color_stage  Next available hardware color combine stage.
 * \param alpha_stage  Next available hardware alpha combine stage.
 *
 * \returns
 * If the combine mode for the specified texture unit could be added without
 * requiring a software fallback, \c GL_TRUE is returned.  Otherwise,
 * \c GL_FALSE is returned.
 *
 * \todo
 * If the mode is (GL_REPLACE, GL_PREVIOUS), treat it as though the texture
 * stage is disabled.  That is, don't emit any combine stages.
 *
 * \todo
 * Add support for ATI_texture_env_combine3 modes.  This will require using
 * two combine stages.
 *
 * \todo
 * Add support for the missing \c GL_INTERPOLATE modes.  This will require
 * using all three combine stages.  There is a comment in the function
 * describing how this might work.
 *
 * \todo
 * If, after all the combine stages have been emitted, a texture is never
 * actually used, disable the texture unit.  That should save texture some
 * memory bandwidth.  This won't happen in this function, but this seems like
 * a reasonable place to make note of it.
 */
static GLboolean
i810UpdateTexEnvCombine( struct gl_context *ctx, GLuint unit, 
			 int * color_stage, int * alpha_stage )
{
   i810ContextPtr imesa = I810_CONTEXT(ctx);
   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
   GLuint color_arg[3] = {
      MC_ARG_ONE,            MC_ARG_ONE,            MC_ARG_ONE
   };
   GLuint alpha_arg[3] = {
      MA_ARG_ITERATED_ALPHA, MA_ARG_ITERATED_ALPHA, MA_ARG_ITERATED_ALPHA
   };
   GLuint i;
   GLuint color_combine, alpha_combine;
   const GLuint numColorArgs = texUnit->_CurrentCombine->_NumArgsRGB;
   const GLuint numAlphaArgs = texUnit->_CurrentCombine->_NumArgsA;
   GLuint RGBshift = texUnit->_CurrentCombine->ScaleShiftRGB;
   GLuint Ashift = texUnit->_CurrentCombine->ScaleShiftA;


   if ( !texUnit->_ReallyEnabled ) {
      return GL_TRUE;
   }

      
   if ((*color_stage >= 3) || (*alpha_stage >= 3)) {
      return GL_FALSE;
   }


   /* Step 1:
    * Extract the color and alpha combine function arguments.
    */

   for ( i = 0 ; i < numColorArgs ; i++ ) {
      unsigned op = texUnit->_CurrentCombine->OperandRGB[i] - GL_SRC_COLOR;
      assert(op >= 0);
      assert(op <= 3);
      switch ( texUnit->_CurrentCombine->SourceRGB[i] ) {
      case GL_TEXTURE0:
	 color_arg[i] = MC_ARG_TEX0_COLOR;
	 break;
      case GL_TEXTURE1:
	 color_arg[i] = MC_ARG_TEX1_COLOR;
	 break;
      case GL_TEXTURE:
	 color_arg[i] = (unit == 0) 
	   ? MC_ARG_TEX0_COLOR : MC_ARG_TEX1_COLOR;
	 break;
      case GL_CONSTANT:
	 color_arg[i] = MC_ARG_COLOR_FACTOR;
	 break;
      case GL_PRIMARY_COLOR:
	 color_arg[i] = MC_ARG_ITERATED_COLOR;
	 break;
      case GL_PREVIOUS:
	 color_arg[i] = (unit == 0)
	   ? MC_ARG_ITERATED_COLOR : MC_ARG_CURRENT_COLOR;
	 break;
      case GL_ZERO:
	 /* Toggle the low bit of the op value.  The is the 'invert' bit,
	  * and it acts to convert GL_ZERO+op to the equivalent GL_ONE+op.
	  */
	 op ^= 1;

	 /*FALLTHROUGH*/

      case GL_ONE:
	 color_arg[i] = MC_ARG_ONE;
	 break;
      default:
	 return GL_FALSE;
      }

      color_arg[i] |= operand_modifiers[op];
   }


   for ( i = 0 ; i < numAlphaArgs ; i++ ) {
      unsigned op = texUnit->_CurrentCombine->OperandA[i] - GL_SRC_ALPHA;
      assert(op >= 0);
      assert(op <= 1);
      switch ( texUnit->_CurrentCombine->SourceA[i] ) {
      case GL_TEXTURE0:
	 alpha_arg[i] = MA_ARG_TEX0_ALPHA;
	 break;
      case GL_TEXTURE1:
	 alpha_arg[i] = MA_ARG_TEX1_ALPHA;
	 break;
      case GL_TEXTURE:
	 alpha_arg[i] = (unit == 0)
	   ? MA_ARG_TEX0_ALPHA : MA_ARG_TEX1_ALPHA;
	 break;
      case GL_CONSTANT:
	 alpha_arg[i] = MA_ARG_ALPHA_FACTOR;
	 break;
      case GL_PRIMARY_COLOR:
	 alpha_arg[i] = MA_ARG_ITERATED_ALPHA;
	 break;
      case GL_PREVIOUS:
	 alpha_arg[i] = (unit == 0)
	   ? MA_ARG_ITERATED_ALPHA : MA_ARG_CURRENT_ALPHA;
	 break;
      case GL_ZERO:
	 /* Toggle the low bit of the op value.  The is the 'invert' bit,
	  * and it acts to convert GL_ZERO+op to the equivalent GL_ONE+op.
	  */
	 op ^= 1;

	 /*FALLTHROUGH*/

      case GL_ONE:
	 if (i != 2) {
	    return GL_FALSE;
	 }

	 alpha_arg[i] = MA_ARG_ONE;
	 break;
      default:
	 return GL_FALSE;
      }

      alpha_arg[i] |= operand_modifiers[op];
   }


   /* Step 2:
    * Build up the color and alpha combine functions.
    */
   switch ( texUnit->_CurrentCombine->ModeRGB ) {
   case GL_REPLACE:
      color_combine = MC_OP_ARG1;
      break;
   case GL_MODULATE:
      color_combine = MC_OP_MODULATE + RGBshift;
      RGBshift = 0;
      break;
   case GL_ADD:
      color_combine = MC_OP_ADD;
      break;
   case GL_ADD_SIGNED:
      color_combine = MC_OP_ADD_SIGNED;
      break;
   case GL_SUBTRACT:
      color_combine = MC_OP_SUBTRACT;
      break;
   case GL_INTERPOLATE:
      /* For interpolation, the i810 hardware has some limitations.  It
       * can't handle using the secondary or diffuse color (diffuse alpha
       * is okay) for the third argument.
       *
       * It is possible to emulate the missing modes by using multiple
       * combine stages.  Unfortunately it requires all three stages to
       * emulate a single interpolate stage.  The (arg0*arg2) portion is
       * done in stage zero and writes to MC_DEST_ACCUMULATOR.  The
       * (arg1*(1-arg2)) portion is done in stage 1, and the final stage is
       * (MC_ARG1_ACCUMULATOR | MC_ARG2_CURRENT_COLOR | MC_OP_ADD).
       * 
       * It can also be done without using the accumulator by rearranging
       * the equation as (arg1 + (arg2 * (arg0 - arg1))).  Too bad the i810
       * doesn't support the MODULATE_AND_ADD mode that the i830 supports.
       * If it did, the interpolate could be done in only two stages.
       */
	 
      if ( (color_arg[2] & MC_ARG_INVERT) != 0 ) {
	 unsigned temp = color_arg[0];

	 color_arg[0] = color_arg[1];
	 color_arg[1] = temp;
	 color_arg[2] &= ~MC_ARG_INVERT;
      }

      switch (color_arg[2]) {
      case (MC_ARG_ONE):
      case (MC_ARG_ONE | MC_ARG_REPLICATE_ALPHA):
	 color_combine = MC_OP_ARG1;
	 color_arg[1] = MC_ARG_ONE;
	 break;

      case (MC_ARG_COLOR_FACTOR):
	 return GL_FALSE;

      case (MC_ARG_COLOR_FACTOR | MC_ARG_REPLICATE_ALPHA):
	 color_combine = MC_OP_LIN_BLEND_ALPHA_FACTOR;
	 break;

      case (MC_ARG_ITERATED_COLOR):
	 return GL_FALSE;

      case (MC_ARG_ITERATED_COLOR | MC_ARG_REPLICATE_ALPHA):
	 color_combine = MC_OP_LIN_BLEND_ITER_ALPHA;
	 break;

      case (MC_ARG_SPECULAR_COLOR):
      case (MC_ARG_SPECULAR_COLOR | MC_ARG_REPLICATE_ALPHA):
	 return GL_FALSE;

      case (MC_ARG_TEX0_COLOR):
	 color_combine = MC_OP_LIN_BLEND_TEX0_COLOR;
	 break;

      case (MC_ARG_TEX0_COLOR | MC_ARG_REPLICATE_ALPHA):
	 color_combine = MC_OP_LIN_BLEND_TEX0_ALPHA;
	 break;

      case (MC_ARG_TEX1_COLOR):
	 color_combine = MC_OP_LIN_BLEND_TEX1_COLOR;
	 break;

      case (MC_ARG_TEX1_COLOR | MC_ARG_REPLICATE_ALPHA):
	 color_combine = MC_OP_LIN_BLEND_TEX1_ALPHA;
	 break;

      default:
	 return GL_FALSE;
      }
      break;

   default:
      return GL_FALSE;
   }

   
   switch ( texUnit->_CurrentCombine->ModeA ) {
   case GL_REPLACE:
      alpha_combine = MA_OP_ARG1;
      break;
   case GL_MODULATE:
      alpha_combine = MA_OP_MODULATE + Ashift;
      Ashift = 0;
      break;
   case GL_ADD:
      alpha_combine = MA_OP_ADD;
      break;
   case GL_ADD_SIGNED:
      alpha_combine = MA_OP_ADD_SIGNED;
      break;
   case GL_SUBTRACT:
      alpha_combine = MA_OP_SUBTRACT;
      break;
   case GL_INTERPOLATE:
      if ( (alpha_arg[2] & MA_ARG_INVERT) != 0 ) {
	 unsigned temp = alpha_arg[0];

	 alpha_arg[0] = alpha_arg[1];
	 alpha_arg[1] = temp;
	 alpha_arg[2] &= ~MA_ARG_INVERT;
      }

      switch (alpha_arg[2]) {
      case MA_ARG_ONE:
	 alpha_combine = MA_OP_ARG1;
	 alpha_arg[1] = MA_ARG_ITERATED_ALPHA;
	 break;

      case MA_ARG_ALPHA_FACTOR:
	 alpha_combine = MA_OP_LIN_BLEND_ALPHA_FACTOR;
	 break;

      case MA_ARG_ITERATED_ALPHA:
	 alpha_combine = MA_OP_LIN_BLEND_ITER_ALPHA;
	 break;

      case MA_ARG_TEX0_ALPHA:
	 alpha_combine = MA_OP_LIN_BLEND_TEX0_ALPHA;
	 break;

      case MA_ARG_TEX1_ALPHA:
	 alpha_combine = MA_OP_LIN_BLEND_TEX1_ALPHA;
	 break;

      default:
	 return GL_FALSE;
      }
      break;

   default:
      return GL_FALSE;
   }


   color_combine |= GFX_OP_MAP_COLOR_STAGES | (*color_stage << MC_STAGE_SHIFT)
     | MC_UPDATE_DEST | MC_DEST_CURRENT
     | MC_UPDATE_ARG1 | (color_arg[0] << MC_ARG1_SHIFT)
     | MC_UPDATE_ARG2 | (color_arg[1] << MC_ARG2_SHIFT)
     | MC_UPDATE_OP;

   alpha_combine |= GFX_OP_MAP_ALPHA_STAGES | (*alpha_stage << MA_STAGE_SHIFT)
     | MA_UPDATE_ARG1 | (alpha_arg[0] << MA_ARG1_SHIFT)
     | MA_UPDATE_ARG2 | (alpha_arg[1] << MA_ARG2_SHIFT)
     | MA_UPDATE_OP;

   set_color_stage( color_combine, *color_stage, imesa );
   set_alpha_stage( alpha_combine, *alpha_stage, imesa );
   (*color_stage)++;
   (*alpha_stage)++;


   /* Step 3:
    * Apply the scale factor.
    */
   /* The only operation where the i810 directly supports adding a post-
    * scale factor is modulate.  For all the other modes the post-scale is
    * emulated by inserting and extra modulate stage.  For the modulate
    * case, the scaling is handled above when color_combine / alpha_combine
    * are initially set.
    */

   if ( RGBshift != 0 ) {
      const unsigned color_scale = GFX_OP_MAP_COLOR_STAGES
	| (*color_stage << MC_STAGE_SHIFT)
	| MC_UPDATE_DEST | MC_DEST_CURRENT
	| MC_UPDATE_ARG1 | (MC_ARG_CURRENT_COLOR << MC_ARG1_SHIFT)
	| MC_UPDATE_ARG2 | (MC_ARG_ONE           << MC_ARG2_SHIFT)
	| MC_UPDATE_OP   | (MC_OP_MODULATE + RGBshift);

      if ( *color_stage >= 3 ) {
	 return GL_FALSE;
      }

      set_color_stage( color_scale, *color_stage, imesa );
      (*color_stage)++;
   }

   
   if ( Ashift != 0 ) {
      const unsigned alpha_scale = GFX_OP_MAP_ALPHA_STAGES
	| (*alpha_stage << MA_STAGE_SHIFT)
	| MA_UPDATE_ARG1 | (MA_ARG_CURRENT_ALPHA << MA_ARG1_SHIFT)
	| MA_UPDATE_ARG2 | (MA_ARG_ONE           << MA_ARG2_SHIFT)
	| MA_UPDATE_OP   | (MA_OP_MODULATE + Ashift);

      if ( *alpha_stage >= 3 ) {
	 return GL_FALSE;
      }

      set_alpha_stage( alpha_scale, *alpha_stage, imesa );
      (*alpha_stage)++;
   }

   return GL_TRUE;
}