⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t_vp_build.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
	    if (count == nr_lights) {
	       if (separate) {
		  mask0 = WRITEMASK_XYZ;
		  mask1 = WRITEMASK_XYZ;
		  res0 = register_output( p, VERT_RESULT_COL0 );
		  res1 = register_output( p, VERT_RESULT_COL1 );
	       }
	       else {
		  mask0 = 0;
		  mask1 = WRITEMASK_XYZ;
		  res0 = _col0;
		  res1 = register_output( p, VERT_RESULT_COL0 );
	       }
	    } else {
	       mask0 = 0;
	       mask1 = 0;
	       res0 = _col0;
	       res1 = _col1;
	    }

	    emit_op3(p, VP_OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0);
	    emit_op3(p, VP_OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0);
	    emit_op3(p, VP_OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1);
      
	    release_temp(p, ambient);
	    release_temp(p, diffuse);
	    release_temp(p, specular);
	 }

	 /* Back face lighting:
	  */
	 if (twoside) {
	    struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT);
	    struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE);
	    struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR);
	    struct ureg res0, res1;
	    GLuint mask0, mask1;
	       
	    emit_op1(p, VP_OPCODE_LIT, lit, 0, negate(swizzle(dots,X,Y,W,Z)));

	    if (!is_undef(att)) 
	       emit_op2(p, VP_OPCODE_MUL, lit, 0, lit, att);

	    if (count == nr_lights) {
	       if (separate) {
		  mask0 = WRITEMASK_XYZ;
		  mask1 = WRITEMASK_XYZ;
		  res0 = register_output( p, VERT_RESULT_BFC0 );
		  res1 = register_output( p, VERT_RESULT_BFC1 );
	       }
	       else {
		  mask0 = 0;
		  mask1 = WRITEMASK_XYZ;
		  res0 = _bfc0;
		  res1 = register_output( p, VERT_RESULT_BFC0 );
	       }
	    } else {
	       res0 = _bfc0;
	       res1 = _bfc1;
	       mask0 = 0;
	       mask1 = 0;
	    }

	    emit_op3(p, VP_OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0);
	    emit_op3(p, VP_OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0);
	    emit_op3(p, VP_OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1);

	    release_temp(p, ambient);
	    release_temp(p, diffuse);
	    release_temp(p, specular);
	 }

	 release_temp(p, half);
	 release_temp(p, VPpli);
	 release_temp(p, att);
      }
   }

   release_temps( p );
}


static void build_fog( struct tnl_program *p )
{
   struct ureg fog = register_output(p, VERT_RESULT_FOGC);
   struct ureg input;
   
   if (p->state->fog_source_is_depth) {
      input = swizzle1(get_eye_position(p), Z);
   }
   else {
      input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X);
   }

   if (p->state->tnl_do_vertex_fog) {
      struct ureg params = register_param1(p, STATE_FOG_PARAMS);
      struct ureg tmp = get_temp(p);

      switch (p->state->fog_mode) {
      case FOG_LINEAR: {
	 struct ureg id = get_identity_param(p);
	 emit_op2(p, VP_OPCODE_SUB, tmp, 0, swizzle1(params,Z), input); 
	 emit_op2(p, VP_OPCODE_MUL, tmp, 0, tmp, swizzle1(params,W)); 
	 emit_op2(p, VP_OPCODE_MAX, tmp, 0, tmp, swizzle1(id,X)); /* saturate */
	 emit_op2(p, VP_OPCODE_MIN, fog, WRITEMASK_X, tmp, swizzle1(id,W));
	 break;
      }
      case FOG_EXP:
	 emit_op1(p, VP_OPCODE_ABS, tmp, 0, input); 
	 emit_op2(p, VP_OPCODE_MUL, tmp, 0, tmp, swizzle1(params,X)); 
	 emit_op2(p, VP_OPCODE_POW, fog, WRITEMASK_X, 
		  register_const1f(p, M_E), negate(tmp)); 
	 break;
      case FOG_EXP2:
	 emit_op2(p, VP_OPCODE_MUL, tmp, 0, input, swizzle1(params,X)); 
	 emit_op2(p, VP_OPCODE_MUL, tmp, 0, tmp, tmp); 
	 emit_op2(p, VP_OPCODE_POW, fog, WRITEMASK_X, 
		  register_const1f(p, M_E), negate(tmp)); 
	 break;
      }
      
      release_temp(p, tmp);
   }
   else {
      /* results = incoming fog coords (compute fog per-fragment later) 
       *
       * KW:  Is it really necessary to do anything in this case?
       */
      emit_op1(p, VP_OPCODE_MOV, fog, WRITEMASK_X, input);
   }
}
 
static void build_reflect_texgen( struct tnl_program *p,
				  struct ureg dest,
				  GLuint writemask )
{
   struct ureg normal = get_eye_normal(p);
   struct ureg eye_hat = get_eye_position_normalized(p);
   struct ureg tmp = get_temp(p);

   /* n.u */
   emit_op2(p, VP_OPCODE_DP3, tmp, 0, normal, eye_hat); 
   /* 2n.u */
   emit_op2(p, VP_OPCODE_ADD, tmp, 0, tmp, tmp); 
   /* (-2n.u)n + u */
   emit_op3(p, VP_OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat);
}

static void build_sphere_texgen( struct tnl_program *p,
				 struct ureg dest,
				 GLuint writemask )
{
   struct ureg normal = get_eye_normal(p);
   struct ureg eye_hat = get_eye_position_normalized(p);
   struct ureg tmp = get_temp(p);
   struct ureg half = register_scalar_const(p, .5);
   struct ureg r = get_temp(p);
   struct ureg inv_m = get_temp(p);
   struct ureg id = get_identity_param(p);

   /* Could share the above calculations, but it would be
    * a fairly odd state for someone to set (both sphere and
    * reflection active for different texture coordinate
    * components.  Of course - if two texture units enable
    * reflect and/or sphere, things start to tilt in favour
    * of seperating this out:
    */

   /* n.u */
   emit_op2(p, VP_OPCODE_DP3, tmp, 0, normal, eye_hat); 
   /* 2n.u */
   emit_op2(p, VP_OPCODE_ADD, tmp, 0, tmp, tmp); 
   /* (-2n.u)n + u */
   emit_op3(p, VP_OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat); 
   /* r + 0,0,1 */
   emit_op2(p, VP_OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z)); 
   /* rx^2 + ry^2 + (rz+1)^2 */
   emit_op2(p, VP_OPCODE_DP3, tmp, 0, tmp, tmp); 
   /* 2/m */
   emit_op1(p, VP_OPCODE_RSQ, tmp, 0, tmp); 
   /* 1/m */
   emit_op2(p, VP_OPCODE_MUL, inv_m, 0, tmp, half); 
   /* r/m + 1/2 */
   emit_op3(p, VP_OPCODE_MAD, dest, writemask, r, inv_m, half); 
	       
   release_temp(p, tmp);
   release_temp(p, r);
   release_temp(p, inv_m);
}


static void build_texture_transform( struct tnl_program *p )
{
   GLuint i, j;

   for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
      GLuint texmat_enabled = p->state->unit[i].texmat_enabled;

      if (p->state->unit[i].texgen_enabled || texmat_enabled) {
	 struct ureg out = register_output(p, VERT_RESULT_TEX0 + i);
	 struct ureg out_texgen = undef;

	 if (p->state->unit[i].texgen_enabled) {
	    GLuint copy_mask = 0;
	    GLuint sphere_mask = 0;
	    GLuint reflect_mask = 0;
	    GLuint normal_mask = 0;
	    GLuint modes[4];
	 
	    if (texmat_enabled) 
	       out_texgen = get_temp(p);
	    else
	       out_texgen = out;

	    modes[0] = p->state->unit[i].texgen_mode0;
	    modes[1] = p->state->unit[i].texgen_mode1;
	    modes[2] = p->state->unit[i].texgen_mode2;
	    modes[3] = p->state->unit[i].texgen_mode3;

	    for (j = 0; j < 4; j++) {
	       switch (modes[j]) {
	       case TXG_OBJ_LINEAR: {
		  struct ureg obj = register_input(p, VERT_ATTRIB_POS);
		  struct ureg plane = 
		     register_param3(p, STATE_TEXGEN, i,
				     STATE_TEXGEN_OBJECT_S + j);

		  emit_op2(p, VP_OPCODE_DP4, out_texgen, WRITEMASK_X << j, 
			   obj, plane );
		  break;
	       }
	       case TXG_EYE_LINEAR: {
		  struct ureg eye = get_eye_position(p);
		  struct ureg plane = 
		     register_param3(p, STATE_TEXGEN, i, 
				     STATE_TEXGEN_EYE_S + j);

		  emit_op2(p, VP_OPCODE_DP4, out_texgen, WRITEMASK_X << j, 
			   eye, plane );
		  break;
	       }
	       case TXG_SPHERE_MAP: 
		  sphere_mask |= WRITEMASK_X << j;
		  break;
	       case TXG_REFLECTION_MAP:
		  reflect_mask |= WRITEMASK_X << j;
		  break;
	       case TXG_NORMAL_MAP: 
		  normal_mask |= WRITEMASK_X << j;
		  break;
	       case TXG_NONE:
		  copy_mask |= WRITEMASK_X << j;
	       }

	    }

	 
	    if (sphere_mask) {
	       build_sphere_texgen(p, out_texgen, sphere_mask);
	    }

	    if (reflect_mask) {
	       build_reflect_texgen(p, out_texgen, reflect_mask);
	    }

	    if (normal_mask) {
	       struct ureg normal = get_eye_normal(p);
	       emit_op1(p, VP_OPCODE_MOV, out_texgen, normal_mask, normal );
	    }

	    if (copy_mask) {
	       struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i);
	       emit_op1(p, VP_OPCODE_MOV, out_texgen, copy_mask, in );
	    }
	 }

	 if (texmat_enabled) {
	    struct ureg texmat[4];
	    struct ureg in = (!is_undef(out_texgen) ? 
			      out_texgen : 
			      register_input(p, VERT_ATTRIB_TEX0+i));
	    if (PREFER_DP4) {
	       register_matrix_param6( p, STATE_MATRIX, STATE_TEXTURE, i, 
				       0, 3, STATE_MATRIX, texmat );
	       emit_matrix_transform_vec4( p, out, texmat, in );
	    }
	    else {
	       register_matrix_param6( p, STATE_MATRIX, STATE_TEXTURE, i, 
				       0, 3, STATE_MATRIX_TRANSPOSE, texmat );
	       emit_transpose_matrix_transform_vec4( p, out, texmat, in );
	    }
	 }

	 release_temps(p);
      } 
      else if (p->state->unit[i].texunit_really_enabled) {
	 /* KW: _ReallyEnabled isn't sufficient?  Need to know whether
	  * this texture unit is referenced by the fragment shader.  
	  */
	 emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i);
      }
   }
}


/* Seems like it could be tighter:
 */
static void build_pointsize( struct tnl_program *p )
{
   struct ureg eye = get_eye_position(p);
   struct ureg state_size = register_param1(p, STATE_POINT_SIZE);
   struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION);
   struct ureg out = register_output(p, VERT_RESULT_PSIZ);
   struct ureg ut = get_temp(p);

   /* 1, -Z, Z * Z, 1 */      
   emit_op1(p, VP_OPCODE_MOV, ut, 0, swizzle1(get_identity_param(p), W));
   emit_op2(p, VP_OPCODE_MUL, ut, WRITEMASK_YZ, ut, negate(swizzle1(eye, Z)));
   emit_op2(p, VP_OPCODE_MUL, ut, WRITEMASK_Z, ut, negate(swizzle1(eye, Z)));


   /* p1 +  p2 * dist + p3 * dist * dist, 0 */
   emit_op2(p, VP_OPCODE_DP3, ut, 0, ut, state_attenuation);

   /* 1 / factor */
   emit_op1(p, VP_OPCODE_RCP, ut, 0, ut ); 

   /* out = pointSize / factor */
   emit_op2(p, VP_OPCODE_MUL, out, WRITEMASK_X, ut, state_size); 

   release_temp(p, ut);
}

static void build_tnl_program( struct tnl_program *p )
{   /* Emit the program, starting with modelviewproject:
    */
   build_hpos(p);

   /* Lighting calculations:
    */
   if (p->state->light_global_enabled)
      build_lighting(p);
   else
      emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0);

   if (p->state->fog_enabled)
      build_fog(p);

   if (p->state->texture_enabled_global)
      build_texture_transform(p);

   if (p->state->point_attenuated)
      build_pointsize(p);

   /* Finish up:
    */
   emit_op1(p, VP_OPCODE_END, undef, 0, undef);

   /* Disassemble:
    */
   if (DISASSEM) {
      _mesa_printf ("\n");
   }
}


static void
create_new_program( const struct state_key *key,
                    struct vertex_program *program,
                    GLuint max_temps)
{
   struct tnl_program p;

   _mesa_memset(&p, 0, sizeof(p));
   p.state = key;
   p.program = program;
   p.eye_position = undef;
   p.eye_position_normalized = undef;
   p.eye_normal = undef;
   p.identity = undef;
   p.temp_in_use = 0;
   
   if (max_temps >= sizeof(int) * 8)
      p.temp_reserved = 0;
   else
      p.temp_reserved = ~((1<<max_temps)-1);

   p.program->Instructions = MALLOC(sizeof(struct vp_instruction) * MAX_INSN);
   p.program->Base.String = 0;
   p.program->Base.NumInstructions =
   p.program->Base.NumTemporaries =
   p.program->Base.NumParameters =
   p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0;
   p.program->Parameters = _mesa_new_parameter_list();
   p.program->InputsRead = 0;
   p.program->OutputsWritten = 0;

   build_tnl_program( &p );
}

static void *search_cache( struct tnl_cache *cache,
			   GLuint hash,
			   const void *key,
			   GLuint keysize)
{
   struct tnl_cache *c;

   for (c = cache; c; c = c->next) {
      if (c->hash == hash && memcmp(c->key, key, keysize) == 0)
	 return c->data;
   }

   return NULL;
}

static void cache_item( struct tnl_cache **cache,
			GLuint hash,
			void *key,
			void *data )
{
   struct tnl_cache *c = MALLOC(sizeof(*c));
   c->hash = hash;
   c->key = key;
   c->data = data;
   c->next = *cache;
   *cache = c;
}

static GLuint hash_key( struct state_key *key )
{
   GLuint *ikey = (GLuint *)key;
   GLuint hash = 0, i;

   /* I'm sure this can be improved on, but speed is important:
    */
   for (i = 0; i < sizeof(*key)/sizeof(GLuint); i++)
      hash ^= ikey[i];

   return hash;
}

void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx )
{
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   struct state_key *key;
   GLuint hash;

   if (ctx->VertexProgram._Enabled)
      return;

   /* Grab all the relevent state and put it in a single structure:
    */
   key = make_state_key(ctx);
   hash = hash_key(key);

   /* Look for an already-prepared program for this state:
    */
   ctx->_TnlProgram = (struct vertex_program *)
      search_cache( tnl->vp_cache, hash, key, sizeof(*key) );
   
   /* OK, we'll have to build a new one:
    */
   if (!ctx->_TnlProgram) {
      if (0)
	 _mesa_printf("Build new TNL program\n");

      ctx->_TnlProgram = (struct vertex_program *)
	 ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); 

      create_new_program( key, ctx->_TnlProgram, 
			  ctx->Const.MaxVertexProgramTemps );

      cache_item(&tnl->vp_cache, hash, key, ctx->_TnlProgram );
   }
   else {
      FREE(key);
      if (0) 
	 _mesa_printf("Found existing TNL program for key %x\n", hash);
   }

   /* Need a BindProgram callback for the driver?
    */
}


void _tnl_ProgramCacheDestroy( GLcontext *ctx )
{
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   struct tnl_cache *a, *tmp;

   for (a = tnl->vp_cache ; a; a = tmp) {
      tmp = a->next;
      FREE(a->key);
      FREE(a->data);
      FREE(a);
   }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -