Esempio n. 1
0
int DrawTriangleToBuffer( char* buff )//returns 0, if no output triangles
{
    const int vertex_size= sizeof(int)*3 + ( (color_mode==COLOR_PER_VERTEX)? 4 : 0 ) +
                           ( (texture_mode==TEXTURE_NONE)? 0 : 2*sizeof(int) ) +
						   ( (lighting_mode==LIGHTING_FROM_LIGHTMAP)? 2*sizeof(int) : 0 ) +
                           ( (lighting_mode==LIGHTING_PER_VERTEX)? sizeof(int) : 0 ) +
						   ( (lighting_mode==LIGHTING_PER_VERTEX_COLORED) ? 4 : 0 );


   // if( triangle_in_vertex_xy[1] == triangle_in_vertex_xy[3] && triangle_in_vertex_xy[1] == triangle_in_vertex_xy[5] )
    //    return 0;//nothing to draw, triangle is flat, works for far small triangles

    int vertex_indeces_from_upper[3]= { 0, 1, 2 };
    int vertex_y_from_upper[3]= { triangle_in_vertex_xy[1], triangle_in_vertex_xy[3], triangle_in_vertex_xy[5] };

    fixed16_t triangle_in_vertex_inv_z[]=
    {
        Fixed16Invert(triangle_in_vertex_z[0] ),
        Fixed16Invert(triangle_in_vertex_z[1] ),
        Fixed16Invert(triangle_in_vertex_z[2] )
    };

    //sort vertices from upper to lower, using bubble-sorting
	register int tmp;
    if( vertex_y_from_upper[0] < vertex_y_from_upper[1] )
    {
        tmp= vertex_y_from_upper[0];
        vertex_y_from_upper[0]= vertex_y_from_upper[1];
        vertex_y_from_upper[1]= tmp;
        tmp= vertex_indeces_from_upper[0];
        vertex_indeces_from_upper[0]= vertex_indeces_from_upper[1];
        vertex_indeces_from_upper[1]= tmp;
    }
    if( vertex_y_from_upper[0] < vertex_y_from_upper[2] )
    {
        tmp= vertex_y_from_upper[0];
        vertex_y_from_upper[0]= vertex_y_from_upper[2];
        vertex_y_from_upper[2]= tmp;
        tmp= vertex_indeces_from_upper[0];
        vertex_indeces_from_upper[0]= vertex_indeces_from_upper[2];
        vertex_indeces_from_upper[2]= tmp;
    }
    if( vertex_y_from_upper[1] < vertex_y_from_upper[2] )
    {
        tmp= vertex_y_from_upper[2];
        vertex_y_from_upper[2]= vertex_y_from_upper[1];
        vertex_y_from_upper[1]= tmp;
        tmp= vertex_indeces_from_upper[2];
        vertex_indeces_from_upper[2]= vertex_indeces_from_upper[1];
        vertex_indeces_from_upper[1]= tmp;
    }
    //end of sorting


	fixed16_t div= triangle_in_vertex_xy[ vertex_indeces_from_upper[0]*2 + 1 ] - triangle_in_vertex_xy[ vertex_indeces_from_upper[2]*2 + 1 ];
	if( div < 4 ) return 0;//triangle is so small
	fixed16_t k0= Fixed16Div( triangle_in_vertex_xy[ vertex_indeces_from_upper[0]*2 + 1 ] - triangle_in_vertex_xy[ vertex_indeces_from_upper[1]*2 + 1 ], div );
    fixed16_t k1= (1<<16) - k0;
	fixed16_t up_down_line_x=
		Fixed16Mul( triangle_in_vertex_xy[ vertex_indeces_from_upper[0]<<1 ], k1 ) +
		Fixed16Mul( triangle_in_vertex_xy[ vertex_indeces_from_upper[2]<<1 ], k0 );

    char* v= buff;
    //write lower vertex attributes
    ((int*)v)[0]= triangle_in_vertex_xy[ vertex_indeces_from_upper[2]<<1 ];
    ((int*)v)[1]= triangle_in_vertex_xy[ (vertex_indeces_from_upper[2]<<1)+1 ];
    ((int*)v)[2]= triangle_in_vertex_z[ vertex_indeces_from_upper[2] ];
    v+= 3 * sizeof(int);
    if( color_mode == COLOR_PER_VERTEX || lighting_mode == LIGHTING_PER_VERTEX_COLORED )
    {
        Byte4Copy( v, triangle_in_color + (vertex_indeces_from_upper[2]<<2) );
        v+=4;
    }
    if( texture_mode != TEXTURE_NONE )
    {
        ((int*)v)[0]= triangle_in_tex_coord[ vertex_indeces_from_upper[2]<<1 ];
        ((int*)v)[1]= triangle_in_tex_coord[ (vertex_indeces_from_upper[2]<<1)+1 ];
        v+=sizeof(fixed16_t)*2;
    }
    if( lighting_mode == LIGHTING_PER_VERTEX )
    {
        ((int*)v)[0]= triangle_in_light[ vertex_indeces_from_upper[2] ];
        v+= sizeof(fixed16_t);
    }
    if( lighting_mode == LIGHTING_FROM_LIGHTMAP )
    {
        ((int*)v)[0]= triangle_in_lightmap_tex_coord[ vertex_indeces_from_upper[2]<<1 ];
        ((int*)v)[1]= triangle_in_lightmap_tex_coord[ (vertex_indeces_from_upper[2]<<1)+1 ];
        v+=sizeof(fixed16_t)*2;
    }

  //write middle vertices
    bool invert_vertex_order= triangle_in_vertex_xy[ vertex_indeces_from_upper[1]<<1 ] <= up_down_line_x;
    if( invert_vertex_order )
        v+= vertex_size;

    //write interpolated vertex
    fixed16_t final_z;
    ((int*)v)[0]= up_down_line_x;
    ((int*)v)[1]= triangle_in_vertex_xy[ (vertex_indeces_from_upper[1]<<1)+1 ];//y - from middle vertex
    ((int*)v)[2]= Fixed16Invert
                  ( Fixed16Mul( triangle_in_vertex_inv_z[ vertex_indeces_from_upper[0] ], k1 ) +
                    Fixed16Mul( triangle_in_vertex_inv_z[ vertex_indeces_from_upper[2] ], k0 ) );//interpolate inv_z

    final_z= ((int*)v)[2];
    v+= 3 * sizeof(int);
    if( color_mode == COLOR_PER_VERTEX || lighting_mode == LIGHTING_PER_VERTEX_COLORED )
    {
		fixed16_t inv_z0= triangle_in_vertex_inv_z[ vertex_indeces_from_upper[0] ];
        fixed16_t inv_z2= triangle_in_vertex_inv_z[ vertex_indeces_from_upper[2] ];
        for( int i= 0; i< 4; i++ )
        {
            //convert in color to fixed16_t format and divede by z
            fixed16_t div_c0= triangle_in_color[ i + (vertex_indeces_from_upper[0]<<2) ] * inv_z0;
            fixed16_t div_c2= triangle_in_color[ i + (vertex_indeces_from_upper[2]<<2) ] * inv_z2;
            ((unsigned char*)v)[i]= Fixed16MulResultToInt( ( Fixed16Mul( div_c0, k1 ) + Fixed16Mul( div_c2, k0 ) ), final_z );//make interpolation and write result
        }
        v+=4;
    }
    if( texture_mode != TEXTURE_NONE )
    {

        fixed16_t inv_z0= triangle_in_vertex_inv_z[ vertex_indeces_from_upper[0] ];
        fixed16_t inv_z2= triangle_in_vertex_inv_z[ vertex_indeces_from_upper[2] ];
        fixed16_t div_tc0= Fixed16Mul( triangle_in_tex_coord[ (vertex_indeces_from_upper[0]<<1) ], inv_z0 );
        fixed16_t div_tc2= Fixed16Mul( triangle_in_tex_coord[ (vertex_indeces_from_upper[2]<<1) ], inv_z2 );
        ((int*)v)[0]= Fixed16Mul( Fixed16Mul( div_tc0, k1 ) + Fixed16Mul( div_tc2, k0 ), final_z );
        div_tc0= Fixed16Mul( triangle_in_tex_coord[ 1+(vertex_indeces_from_upper[0]<<1) ], inv_z0 );
        div_tc2= Fixed16Mul( triangle_in_tex_coord[ 1+(vertex_indeces_from_upper[2]<<1) ], inv_z2 );
        ((int*)v)[1]= Fixed16Mul( Fixed16Mul( div_tc0, k1 ) + Fixed16Mul( div_tc2, k0 ), final_z );
        v+=2*sizeof(int);
    }
    if( lighting_mode == LIGHTING_PER_VERTEX )
    {
        fixed16_t div_l0= triangle_in_light[ vertex_indeces_from_upper[0] ] * triangle_in_vertex_inv_z[ vertex_indeces_from_upper[0] ];
        fixed16_t div_l2= triangle_in_light[ vertex_indeces_from_upper[2] ] * triangle_in_vertex_inv_z[ vertex_indeces_from_upper[2] ];
        ((int*)v)[0]= Fixed16MulResultToInt( Fixed16Mul( div_l0, k1 ) + Fixed16Mul( div_l2, k0 ), final_z );
        v+=sizeof(int);
    }
    if( lighting_mode == LIGHTING_FROM_LIGHTMAP )
    {
        fixed16_t inv_z0= triangle_in_vertex_inv_z[ vertex_indeces_from_upper[0] ];
        fixed16_t inv_z2= triangle_in_vertex_inv_z[ vertex_indeces_from_upper[2] ];
        fixed16_t div_tc0= Fixed16Mul( triangle_in_lightmap_tex_coord[ (vertex_indeces_from_upper[0]<<1) ], inv_z0 );
        fixed16_t div_tc2= Fixed16Mul( triangle_in_lightmap_tex_coord[ (vertex_indeces_from_upper[2]<<1) ], inv_z2 );
        ((int*)v)[0]= Fixed16Mul( Fixed16Mul( div_tc0, k1 ) + Fixed16Mul( div_tc2, k0 ), final_z );
        div_tc0= Fixed16Mul( triangle_in_lightmap_tex_coord[ 1+(vertex_indeces_from_upper[0]<<1) ], inv_z0 );
        div_tc2= Fixed16Mul( triangle_in_lightmap_tex_coord[ 1+(vertex_indeces_from_upper[2]<<1) ], inv_z2 );
        ((int*)v)[1]= Fixed16Mul( Fixed16Mul( div_tc0, k1 ) + Fixed16Mul( div_tc2, k0 ), final_z );
        v+=2*sizeof(int);
    }

    if( invert_vertex_order )
        v-= 2*vertex_size;

    //write middle vertex
    ((int*)v)[0]= triangle_in_vertex_xy[ vertex_indeces_from_upper[1]<<1 ];
    ((int*)v)[1]= triangle_in_vertex_xy[ (vertex_indeces_from_upper[1]<<1)+1 ];
    ((int*)v)[2]= triangle_in_vertex_z[ vertex_indeces_from_upper[1] ];
    v+= 3 * sizeof(int);
    if( color_mode == COLOR_PER_VERTEX || lighting_mode == LIGHTING_PER_VERTEX_COLORED )
    {
        Byte4Copy( v, triangle_in_color + (vertex_indeces_from_upper[1]<<2) );
        v+=4;
    }
    if( texture_mode != TEXTURE_NONE )
    {
        ((int*)v)[0]= triangle_in_tex_coord[ vertex_indeces_from_upper[1]<<1 ];
        ((int*)v)[1]= triangle_in_tex_coord[ (vertex_indeces_from_upper[1]<<1)+1 ];
        v+=sizeof(fixed16_t)*2;
    }
    if( lighting_mode == LIGHTING_PER_VERTEX )
    {
        ((int*)v)[0]= triangle_in_light[ vertex_indeces_from_upper[1] ];
        v+= sizeof(fixed16_t);
    }
    if( lighting_mode == LIGHTING_FROM_LIGHTMAP )
    {
        ((int*)v)[0]= triangle_in_lightmap_tex_coord[ vertex_indeces_from_upper[1]<<1 ];
        ((int*)v)[1]= triangle_in_lightmap_tex_coord[ (vertex_indeces_from_upper[1]<<1)+1  ];
        v+=sizeof(fixed16_t)*2;
    }
    if( invert_vertex_order )
        v+= vertex_size;


    //write upper vertex attributes
    ((int*)v)[0]= triangle_in_vertex_xy[ vertex_indeces_from_upper[0]<<1 ];
    ((int*)v)[1]= triangle_in_vertex_xy[ (vertex_indeces_from_upper[0]<<1)+1 ];
    ((int*)v)[2]= triangle_in_vertex_z[ vertex_indeces_from_upper[0] ];
    v+= 3 * sizeof(int);
    if( color_mode == COLOR_PER_VERTEX || lighting_mode == LIGHTING_PER_VERTEX_COLORED )
    {
        Byte4Copy( v, triangle_in_color + (vertex_indeces_from_upper[0]<<2) );
        v+=4;
    }
    if( texture_mode != TEXTURE_NONE )
    {
        ((int*)v)[0]= triangle_in_tex_coord[ vertex_indeces_from_upper[0]<<1 ];
        ((int*)v)[1]= triangle_in_tex_coord[ (vertex_indeces_from_upper[0]<<1)+1 ];
        v+=sizeof(fixed16_t)*2;
    }
    if( lighting_mode == LIGHTING_PER_VERTEX )
    {
        ((int*)v)[0]= triangle_in_light[ vertex_indeces_from_upper[0] ];
        v+= sizeof(fixed16_t);
    }
    if( lighting_mode == LIGHTING_FROM_LIGHTMAP )
    {
        ((int*)v)[0]= triangle_in_lightmap_tex_coord[ vertex_indeces_from_upper[0]<<1 ];
        ((int*)v)[1]= triangle_in_lightmap_tex_coord[ (vertex_indeces_from_upper[0]<<1)+1  ];
        v+=sizeof(fixed16_t)*2;
    }

	return 4;
}
Esempio n. 2
0
/*
===============
UI_DrawPlayer
===============
*/
void UI_DrawPlayer( float x, float y, float w, float h, uiPlayerInfo_t *pi, int time ) {
	refdef_t		refdef;
	refEntity_t		legs = {0};
	refEntity_t		torso = {0};
	refEntity_t		head = {0};
	refEntity_t		gun = {0};
	refEntity_t		barrel = {0};
	refEntity_t		flash = {0};
	vec3_t			origin;
	int				renderfx;
	vec3_t			mins = {-16, -16, -24};
	vec3_t			maxs = {16, 16, 32};
	float			len;
	float			xx;
	float			xscale;
	float			yscale;

	if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
		return;
	}

	// this allows the ui to cache the player model on the main menu
	if (w == 0 || h == 0) {
		return;
	}

	dp_realtime = time;

	if ( pi->pendingWeapon != WP_NUM_WEAPONS && dp_realtime > pi->weaponTimer ) {
		pi->weapon = pi->pendingWeapon;
		pi->lastWeapon = pi->pendingWeapon;
		pi->pendingWeapon = WP_NUM_WEAPONS;
		pi->weaponTimer = 0;
		if( pi->currentWeapon != pi->weapon ) {
			trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
		}
	}

	CG_AdjustFrom640( &x, &y, &w, &h );

	y -= jumpHeight;

	memset( &refdef, 0, sizeof( refdef ) );
	memset( &legs, 0, sizeof(legs) );
	memset( &torso, 0, sizeof(torso) );
	memset( &head, 0, sizeof(head) );

	refdef.rdflags = RDF_NOWORLDMODEL;

	AxisClear( refdef.viewaxis );

	refdef.x = x;
	refdef.y = y;
	refdef.width = w;
	refdef.height = h;

	if ( ui_stretch.integer ) {
		xscale = cgs.screenXScaleStretch;
		yscale = cgs.screenYScaleStretch;
	} else {
		xscale = cgs.screenXScale;
		yscale = cgs.screenYScale;
	}

	refdef.fov_x = (int)((float)refdef.width / xscale / 640.0f * 90.0f);
	xx = refdef.width / xscale / tan( refdef.fov_x / 360 * M_PI );
	refdef.fov_y = atan2( refdef.height / yscale, xx );
	refdef.fov_y *= ( 360 / (float)M_PI );

	// calculate distance so the player nearly fills the box
	len = 0.7 * ( maxs[2] - mins[2] );
	origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
	origin[1] = 0.5 * ( mins[1] + maxs[1] );
	origin[2] = -0.5 * ( mins[2] + maxs[2] );

	refdef.time = dp_realtime;

	trap_R_ClearScene();

	// get the rotation information
	UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
	
	// get the animation state (after rotation, to allow feet shuffle)
	UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
		 &torso.oldframe, &torso.frame, &torso.backlerp );

	renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;

	//
	// add the legs
	//
	legs.hModel = pi->legsModel;
	legs.customSkin = CG_AddSkinToFrame( &pi->modelSkin );

	VectorCopy( origin, legs.origin );

	VectorCopy( origin, legs.lightingOrigin );
	legs.renderfx = renderfx;
	VectorCopy (legs.origin, legs.oldorigin);

	Byte4Copy( pi->c1RGBA, legs.shaderRGBA );

	CG_AddRefEntityWithMinLight( &legs );

	if (!legs.hModel) {
		return;
	}

	//
	// add the torso
	//
	torso.hModel = pi->torsoModel;
	if (!torso.hModel) {
		return;
	}

	torso.customSkin = legs.customSkin;

	VectorCopy( origin, torso.lightingOrigin );

	UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");

	torso.renderfx = renderfx;

	Byte4Copy( pi->c1RGBA, torso.shaderRGBA );

	CG_AddRefEntityWithMinLight( &torso );

	//
	// add the head
	//
	head.hModel = pi->headModel;
	if (!head.hModel) {
		return;
	}
	head.customSkin = legs.customSkin;

	VectorCopy( origin, head.lightingOrigin );

	UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");

	head.renderfx = renderfx;

	Byte4Copy( pi->c1RGBA, head.shaderRGBA );

	CG_AddRefEntityWithMinLight( &head );

	//
	// add the gun
	//
	if ( pi->currentWeapon != WP_NONE ) {
		memset( &gun, 0, sizeof(gun) );
		gun.hModel = pi->weaponModel;
		Byte4Copy( pi->c1RGBA, gun.shaderRGBA );
		VectorCopy( origin, gun.lightingOrigin );
		UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
		gun.renderfx = renderfx;
		CG_AddRefEntityWithMinLight( &gun );
	}

	//
	// add the spinning barrel
	//
	if ( pi->barrelModel ) {
		vec3_t	angles;

		memset( &barrel, 0, sizeof(barrel) );
		VectorCopy( origin, barrel.lightingOrigin );
		barrel.renderfx = renderfx;

		barrel.hModel = pi->barrelModel;
		angles[YAW] = 0;
		angles[PITCH] = 0;
		angles[ROLL] = UI_MachinegunSpinAngle( pi );
		AnglesToAxis( angles, barrel.axis );

		UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");

		CG_AddRefEntityWithMinLight( &barrel );
	}

	//
	// add muzzle flash
	//
	if ( dp_realtime <= pi->muzzleFlashTime ) {
		if ( pi->flashModel ) {
			memset( &flash, 0, sizeof(flash) );
			flash.hModel = pi->flashModel;
			Byte4Copy( pi->c1RGBA, flash.shaderRGBA );
			VectorCopy( origin, flash.lightingOrigin );
			UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
			flash.renderfx = renderfx;
			CG_AddRefEntityWithMinLight( &flash );
		}

		// make a dlight for the flash
		if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
			trap_R_AddJuniorLightToScene( flash.origin, 200 + (rand()&31), 1.0f, pi->flashDlightColor[0],
				pi->flashDlightColor[1], pi->flashDlightColor[2] );
		}
	}

	//
	// add the chat icon
	//
	if ( pi->chat ) {
		UI_PlayerFloatSprite( pi, torso.origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
	}

	//
	// add an accent light
	//
	origin[0] -= 100;	// + = behind, - = in front
	origin[1] += 100;	// + = left, - = right
	origin[2] += 100;	// + = above, - = below
	trap_R_AddJuniorLightToScene( origin, 500, 1.0, 1.0, 1.0, 1.0 );

	origin[0] -= 100;
	origin[1] -= 100;
	origin[2] -= 100;
	trap_R_AddJuniorLightToScene( origin, 500, 1.0, 1.0, 0.0, 0.0 );

	trap_R_RenderScene( &refdef );
}
Esempio n. 3
0
/*
===============
UI_DrawPlayer
===============
*/
void UI_DrawPlayer( float x, float y, float w, float h, uiPlayerInfo_t *pi, int time ) {
	refdef_t		refdef;
	refEntity_t		legs = {0};
	refEntity_t		torso = {0};
	refEntity_t		head = {0};
#ifdef TA_WEAPSYS
	refEntity_t		gun[MAX_HANDS] = {{0}};
#else
	refEntity_t		gun = {0};
#endif
	refEntity_t		barrel = {0};
	refEntity_t		flash = {0};
	vec3_t			origin;
	int				renderfx;
	vec3_t			mins = {-16, -16, -24};
	vec3_t			maxs = {16, 16, 32};
	float			len;
	float			xx;
	float			xscale;
	float			yscale;
#ifdef TA_WEAPSYS
	int				i;
	vec3_t			angles;
#ifdef TURTLEARENA // PLAYERS
	char *newTagNames[3] = { "tag_hand_primary", "tag_hand_secondary", NULL };
#endif
	char *originalTagNames[3] = { "tag_weapon", "tag_flag", NULL };
#endif

	if ( !pi->legsModel || !pi->torsoModel || !pi->headModel
#ifdef TA_PLAYERSYS
	|| !pi->playercfg.animations[0].numFrames ) {
#else
	|| !pi->animations[0].numFrames ) {
#endif
		return;
	}

	dp_realtime = time;

	if ( pi->pendingWeapon != WP_NUM_WEAPONS && dp_realtime > pi->weaponTimer ) {
		pi->weapon = pi->pendingWeapon;
		pi->lastWeapon = pi->pendingWeapon;
		pi->pendingWeapon = WP_NUM_WEAPONS;
		pi->weaponTimer = 0;
#ifndef TA_WEAPSYS_EX
		if( pi->currentWeapon != pi->weapon ) {
			trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
		}
#endif
	}

	CG_AdjustFrom640( &x, &y, &w, &h );

	y -= jumpHeight;

	memset( &refdef, 0, sizeof( refdef ) );
	memset( &legs, 0, sizeof(legs) );
	memset( &torso, 0, sizeof(torso) );
	memset( &head, 0, sizeof(head) );

	refdef.rdflags = RDF_NOWORLDMODEL;

	AxisClear( refdef.viewaxis );

	refdef.x = x;
	refdef.y = y;
	refdef.width = w;
	refdef.height = h;

	if ( ui_stretch.integer ) {
		xscale = cgs.screenXScaleStretch;
		yscale = cgs.screenYScaleStretch;
	} else {
		xscale = cgs.screenXScale;
		yscale = cgs.screenYScale;
	}

	refdef.fov_x = (int)((float)refdef.width / xscale / 640.0f * 90.0f);
	xx = refdef.width / xscale / tan( refdef.fov_x / 360 * M_PI );
	refdef.fov_y = atan2( refdef.height / yscale, xx );
	refdef.fov_y *= ( 360 / M_PI );

	// calculate distance so the player nearly fills the box
	len = 0.7 * ( maxs[2] - mins[2] );		
	origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
	origin[1] = 0.5 * ( mins[1] + maxs[1] );
	origin[2] = -0.5 * ( mins[2] + maxs[2] );

	refdef.time = dp_realtime;

	trap_R_ClearScene();

	// get the rotation information
	UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
	
	// get the animation state (after rotation, to allow feet shuffle)
	UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
		 &torso.oldframe, &torso.frame, &torso.backlerp );

	renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;

	//
	// add the legs
	//
	legs.hModel = pi->legsModel;
	legs.customSkin = CG_AddSkinToFrame( &pi->modelSkin );

	VectorCopy( origin, legs.origin );

	VectorCopy( origin, legs.lightingOrigin );
	legs.renderfx = renderfx;
	VectorCopy (legs.origin, legs.oldorigin);

	Byte4Copy( pi->c1RGBA, legs.shaderRGBA );

	CG_AddRefEntityWithMinLight( &legs );

	if (!legs.hModel) {
		return;
	}

	//
	// add the torso
	//
	torso.hModel = pi->torsoModel;
	if (!torso.hModel) {
		return;
	}

	torso.customSkin = legs.customSkin;

	VectorCopy( origin, torso.lightingOrigin );

	UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, NULL, "tag_torso");

	torso.renderfx = renderfx;

	Byte4Copy( pi->c1RGBA, torso.shaderRGBA );

	CG_AddRefEntityWithMinLight( &torso );

	//
	// add the head
	//
	head.hModel = pi->headModel;
	if (!head.hModel) {
		return;
	}
	head.customSkin = legs.customSkin;

	VectorCopy( origin, head.lightingOrigin );

	UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, NULL, "tag_head");

	head.renderfx = renderfx;

	Byte4Copy( pi->c1RGBA, head.shaderRGBA );

	CG_AddRefEntityWithMinLight( &head );

	//
	// add the gun
	//
	if ( pi->currentWeapon != WP_NONE ) {
#ifdef TA_WEAPSYS
		// get hands from cent
		for (i = 0; i < MAX_HANDS; i++)
		{
			memset( &gun[i], 0, sizeof(gun[i]) );
			gun[i].hModel = pi->weaponModel[i];
			VectorCopy( origin, gun[i].lightingOrigin );
			gun[i].renderfx = renderfx;
			Byte4Copy( pi->c1RGBA, gun[i].shaderRGBA );

			if (!originalTagNames[i]
#ifdef TURTLEARENA // PLAYERS
				|| !newTagNames[i]
#endif
				)
			{
				break;
			}

			if (!gun[i].hModel) {
				continue;
			}

			if (
#ifdef TURTLEARENA // PLAYERS
				!UI_PositionEntityOnTag( &gun[i], &torso, pi->torsoModel, NULL, newTagNames[i]) &&
#endif
				!UI_PositionEntityOnTag( &gun[i], &torso, pi->torsoModel, NULL, originalTagNames[i]))
			{
				// Failed to find tag
				continue;
			}

			CG_AddRefEntityWithMinLight( &gun[i] );
		}
#else
		memset( &gun, 0, sizeof(gun) );
		gun.hModel = pi->weaponModel;
		Byte4Copy( pi->c1RGBA, gun.shaderRGBA );
		VectorCopy( origin, gun.lightingOrigin );
		UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, NULL, "tag_weapon");
		gun.renderfx = renderfx;
		CG_AddRefEntityWithMinLight( &gun );
#endif
	}

	//
	// add the spinning barrel
	//
#ifdef TA_WEAPSYS
	for (i = 0; i < MAX_HANDS; i++)
#else
	if ( pi->barrelModel )
#endif
	{
#ifdef TA_WEAPSYS
		if (!pi->barrelModel[i])
			continue;
#else
		vec3_t	angles;
#endif

		memset( &barrel, 0, sizeof(barrel) );
		VectorCopy( origin, barrel.lightingOrigin );
		barrel.renderfx = renderfx;

#ifdef TA_WEAPSYS
		barrel.hModel = pi->barrelModel[i];
		VectorClear(angles);
		if (bg_weapongroupinfo[pi->realWeapon].weapon[i]->barrelSpin != BS_NONE)
		{
			if (i & 1)
				angles[bg_weapongroupinfo[pi->realWeapon].weapon[i]->barrelSpin]
						= 360-UI_MachinegunSpinAngle( pi );
			else
				angles[bg_weapongroupinfo[pi->realWeapon].weapon[i]->barrelSpin]
						= UI_MachinegunSpinAngle( pi );
		}
#else
		barrel.hModel = pi->barrelModel;
		angles[YAW] = 0;
		angles[PITCH] = 0;
		angles[ROLL] = UI_MachinegunSpinAngle( pi );
#endif
		AnglesToAxis( angles, barrel.axis );

#ifdef TA_WEAPSYS
		UI_PositionRotatedEntityOnTag( &barrel, &gun[i], pi->weaponModel[i], NULL, "tag_barrel");
#else
		UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, NULL, "tag_barrel");
#endif

		CG_AddRefEntityWithMinLight( &barrel );
	}

	//
	// add muzzle flash
	//
	if ( dp_realtime <= pi->muzzleFlashTime ) {
#ifdef TA_WEAPSYS
		vec3_t *flashDlightColor;

		for (i = 0; i < MAX_HANDS; i++)
		{
			memset( &flash, 0, sizeof(flash) );
			flash.hModel = pi->flashModel[i];
			flashDlightColor = &pi->flashDlightColor[i];
			Byte4Copy( pi->c1RGBA, flash.shaderRGBA );

			if (!flash.hModel)
				continue;

			VectorCopy( origin, flash.lightingOrigin );
			UI_PositionEntityOnTag( &flash, &gun[i], pi->weaponModel[i], NULL, "tag_flash");
			flash.renderfx = renderfx;
			trap_R_AddRefEntityToScene( &flash );

			// make a dlight for the flash
			if ( *flashDlightColor[0] || *flashDlightColor[1] || *flashDlightColor[2] ) {
				trap_R_AddJuniorLightToScene( flash.origin, 200 + (rand()&31), 1.0f, *flashDlightColor[0],
					*flashDlightColor[1], *flashDlightColor[2] );
			}
		}
#else
		if ( pi->flashModel ) {
			memset( &flash, 0, sizeof(flash) );
			flash.hModel = pi->flashModel;
			Byte4Copy( pi->c1RGBA, flash.shaderRGBA );
			VectorCopy( origin, flash.lightingOrigin );
			UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, NULL, "tag_flash");
			flash.renderfx = renderfx;
			CG_AddRefEntityWithMinLight( &flash );
		}

		// make a dlight for the flash
		if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
			trap_R_AddJuniorLightToScene( flash.origin, 200 + (rand()&31), 1.0f, pi->flashDlightColor[0],
				pi->flashDlightColor[1], pi->flashDlightColor[2] );
		}
#endif
	}

	//
	// add the chat icon
	//
	if ( pi->chat ) {
#ifdef TA_DATA // shaders
		UI_PlayerFloatSprite( pi, torso.origin, trap_R_RegisterShaderNoMip( "sprites/talkBalloon" ) );
#else
		UI_PlayerFloatSprite( pi, torso.origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
#endif
	}

	//
	// add an accent light
	//
	origin[0] -= 100;	// + = behind, - = in front
	origin[1] += 100;	// + = left, - = right
	origin[2] += 100;	// + = above, - = below
	trap_R_AddJuniorLightToScene( origin, 500, 1.0, 1.0, 1.0, 1.0 );

	origin[0] -= 100;
	origin[1] -= 100;
	origin[2] -= 100;
	trap_R_AddJuniorLightToScene( origin, 500, 1.0, 1.0, 0.0, 0.0 );

	trap_R_RenderScene( &refdef );
}

/*
==========================
UI_FileExists
==========================
*/
static qboolean	UI_FileExists(const char *filename) {
	int len;

	len = trap_FS_FOpenFile( filename, NULL, FS_READ );
	if (len>0) {
		return qtrue;
	}
	return qfalse;
}