Esempio n. 1
0
/*
* CG_AddBlobShadow
* 
* Ok, to not use decals space we need these arrays to store the
* polygons info. We do not need the linked list nor registration
*/
static void CG_AddBlobShadow( vec3_t origin, vec3_t dir, float orient, float radius,
							 float r, float g, float b, float a, cgshadebox_t *shadeBox )
{
	int i, j, c, nverts;
	vec3_t axis[3];
	byte_vec4_t color;
	fragment_t *fr, fragments[MAX_BLOBSHADOW_FRAGMENTS];
	int numfragments;
	poly_t poly;
	vec4_t verts[MAX_BLOBSHADOW_VERTS];

	if( radius <= 0 || VectorCompare( dir, vec3_origin ) )
		return; // invalid

	// calculate orientation matrix
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orient );
	CrossProduct( axis[0], axis[2], axis[1] );

	numfragments = trap_R_GetClippedFragments( origin, radius, axis, // clip it
		MAX_BLOBSHADOW_VERTS, verts, MAX_BLOBSHADOW_FRAGMENTS, fragments );

	// no valid fragments
	if( !numfragments )
		return;

	// clamp and scale colors
	if( r < 0 ) r = 0;else if( r > 1 ) r = 255;else r *= 255;
	if( g < 0 ) g = 0;else if( g > 1 ) g = 255;else g *= 255;
	if( b < 0 ) b = 0;else if( b > 1 ) b = 255;else b *= 255;
	if( a < 0 ) a = 0;else if( a > 1 ) a = 255;else a *= 255;

	color[0] = ( qbyte )( r );
	color[1] = ( qbyte )( g );
	color[2] = ( qbyte )( b );
	color[3] = ( qbyte )( a );
	c = *( int * )color;

	radius = 0.5f / radius;
	VectorScale( axis[1], radius, axis[1] );
	VectorScale( axis[2], radius, axis[2] );

	memset( &poly, 0, sizeof( poly ) );

	for( i = 0, nverts = 0, fr = fragments; i < numfragments; i++, fr++ )
	{
		if( nverts+fr->numverts > MAX_BLOBSHADOW_VERTS )
			return;
		if( fr->numverts <= 0 )
			continue;

		poly.shader = shadeBox->shader;
		poly.verts = &shadeBox->verts[nverts];
		poly.normals = &shadeBox->norms[nverts];
		poly.stcoords = &shadeBox->stcoords[nverts];
		poly.colors = &shadeBox->colors[nverts];
		poly.numverts = fr->numverts;
		poly.fognum = fr->fognum;
		nverts += fr->numverts;

		for( j = 0; j < fr->numverts; j++ )
		{
			vec3_t v;

			Vector4Copy( verts[fr->firstvert+j], poly.verts[j] );
			VectorCopy( axis[0], poly.normals[j] ); poly.normals[j][3] = 0;
			VectorSubtract( poly.verts[j], origin, v );
			poly.stcoords[j][0] = DotProduct( v, axis[1] ) + 0.5f;
			poly.stcoords[j][1] = DotProduct( v, axis[2] ) + 0.5f;
			*( int * )poly.colors[j] = c;
		}

		trap_R_AddPolyToScene( &poly );
	}
}
/*
==================
CG_BuildableStatusDisplay
==================
*/
static void CG_BuildableStatusDisplay( centity_t *cent )
{
  entityState_t   *es = &cent->currentState;
  vec3_t          origin;
  float           healthScale;
  int             health;
  float           x, y;
  vec4_t          color;
  qboolean        powered, marked;
  trace_t         tr;
  float           d;
  buildStat_t     *bs;
  int             i, j;
  int             entNum;
  vec3_t          trOrigin;
  vec3_t          right;
  qboolean        visible = qfalse;
  vec3_t          mins, maxs;
  entityState_t   *hit;

  if( BG_FindTeamForBuildable( es->modelindex ) == BIT_ALIENS )
    bs = &cgs.alienBuildStat;
  else
    bs = &cgs.humanBuildStat;

  if( !bs->loaded )
    return;
  
  d = Distance( cent->lerpOrigin, cg.refdef.vieworg );
  if( d > STATUS_MAX_VIEW_DIST )
    return;
 
  Vector4Copy( bs->foreColor, color );

  // trace for center point 
  BG_FindBBoxForBuildable( es->modelindex, mins, maxs );

  VectorCopy( cent->lerpOrigin, origin );

  // center point
  origin[ 2 ] += mins[ 2 ];
  origin[ 2 ] += ( abs( mins[ 2 ] ) + abs( maxs[ 2 ] ) ) / 2;

  entNum = cg.predictedPlayerState.clientNum;

  // if first try fails, step left, step right
  for( j = 0; j < 3; j++ )
  {
    VectorCopy( cg.refdef.vieworg, trOrigin );
    switch( j )
    {
      case 1:
        // step right
        AngleVectors( cg.refdefViewAngles, NULL, right, NULL );
        VectorMA( trOrigin, STATUS_PEEK_DIST, right, trOrigin );
        break;
      case 2:
        // step left
        AngleVectors( cg.refdefViewAngles, NULL, right, NULL );
        VectorMA( trOrigin, -STATUS_PEEK_DIST, right, trOrigin );
        break;
      default:
        break;
    }
    // look through up to 3 players and/or transparent buildables
    for( i = 0; i < 3; i++ )
    {
      CG_Trace( &tr, trOrigin, NULL, NULL, origin, entNum, MASK_SHOT );
      if( tr.entityNum == cent->currentState.number )
      {
        visible = qtrue;
        break;
      }

      if( tr.entityNum == ENTITYNUM_WORLD )
        break;

      hit  = &cg_entities[ tr.entityNum ].currentState;

      if( tr.entityNum < MAX_CLIENTS || ( hit->eType == ET_BUILDABLE &&
          ( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ||
            BG_FindTransparentTestForBuildable( hit->modelindex ) ) ) )
      {
        entNum = tr.entityNum;
        VectorCopy( tr.endpos, trOrigin );
      }
      else
        break;
    }
  }
  // hack to make the kit obscure view
  if( cg_drawGun.integer && visible &&
      cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS &&
      CG_WorldToScreen( origin, &x, &y ) )
  {
    if( x > 450 && y > 290 )
      visible = qfalse;
  }

  if( !visible && cent->buildableStatus.visible )
  {
    cent->buildableStatus.visible   = qfalse;
    cent->buildableStatus.lastTime  = cg.time;
  }
  else if( visible && !cent->buildableStatus.visible )
  {
    cent->buildableStatus.visible   = qtrue;
    cent->buildableStatus.lastTime  = cg.time;
  }

  // Fade up
  if( cent->buildableStatus.visible )
  {
    if( cent->buildableStatus.lastTime + STATUS_FADE_TIME > cg.time )
      color[ 3 ] = (float)( cg.time - cent->buildableStatus.lastTime ) / STATUS_FADE_TIME;
  }

  // Fade down
  if( !cent->buildableStatus.visible )
  {
    if( cent->buildableStatus.lastTime + STATUS_FADE_TIME > cg.time )
      color[ 3 ] = 1.0f - (float)( cg.time - cent->buildableStatus.lastTime ) / STATUS_FADE_TIME;
    else
      return;
  }

  health = es->generic1 & B_HEALTH_MASK;
  healthScale = (float)health / B_HEALTH_MASK;

  if( health > 0 && healthScale < 0.01f )
    healthScale = 0.01f;
  else if( healthScale < 0.0f )
    healthScale = 0.0f;
  else if( healthScale > 1.0f )
    healthScale = 1.0f;

  if( CG_WorldToScreen( origin, &x, &y ) )
  {
    float  picH = bs->frameHeight;
    float  picW = bs->frameWidth;
    float  picX = x;
    float  picY = y;
    float  scale;
    float  subH, subY;
    vec4_t frameColor;

    // this is fudged to get the width/height in the cfg to be more realistic
    scale = ( picH / d ) * 3;

    powered = es->generic1 & B_POWERED_TOGGLEBIT;
    marked = es->generic1 & B_MARKED_TOGGLEBIT;

    picH *= scale;
    picW *= scale;
    picX -= ( picW * 0.5f );
    picY -= ( picH * 0.5f );

    // sub-elements such as icons and number
    subH = picH - ( picH * bs->verticalMargin );
    subY = picY + ( picH * 0.5f ) - ( subH * 0.5f );

    if( bs->frameShader )
    {
      Vector4Copy( bs->backColor, frameColor );
      frameColor[ 3 ] = color[ 3 ];
      trap_R_SetColor( frameColor );
      CG_DrawPic( picX, picY, picW, picH, bs->frameShader );
      trap_R_SetColor( NULL );
    }

    if( health > 0 )
    {
      float hX, hY, hW, hH;
      vec4_t healthColor;

      hX = picX + ( bs->healthPadding * scale );
      hY = picY + ( bs->healthPadding * scale );
      hH = picH - ( bs->healthPadding * 2.0f * scale );
      hW = picW * healthScale - ( bs->healthPadding * 2.0f * scale );

      if( healthScale == 1.0f )
        Vector4Copy( bs->healthLowColor, healthColor );
      else if( healthScale >= 0.75f )
        Vector4Copy( bs->healthGuardedColor, healthColor );
      else if( healthScale >= 0.50f )
        Vector4Copy( bs->healthElevatedColor, healthColor );
      else if( healthScale >= 0.25f )
        Vector4Copy( bs->healthHighColor, healthColor );
      else
        Vector4Copy( bs->healthSevereColor, healthColor );

      healthColor[ 3 ] = color[ 3 ];
      trap_R_SetColor( healthColor );
     
      CG_DrawPic( hX, hY, hW, hH, cgs.media.whiteShader );
      trap_R_SetColor( NULL );
    }

    if( bs->overlayShader )
    {
      float oW = bs->overlayWidth;
      float oH = bs->overlayHeight;
      float oX = x;
      float oY = y;

      oH *= scale;
      oW *= scale;
      oX -= ( oW * 0.5f );
      oY -= ( oH * 0.5f );
 
      trap_R_SetColor( frameColor );
      CG_DrawPic( oX, oY, oW, oH, bs->overlayShader );
      trap_R_SetColor( NULL );
    }

    trap_R_SetColor( color );
    if( !powered )
    {
      float pX;

      pX = picX + ( subH * bs->horizontalMargin );
      CG_DrawPic( pX, subY, subH, subH, bs->noPowerShader );
    }

    if( marked )
    {
      float mX;

      mX = picX + picW - ( subH * bs->horizontalMargin ) - subH;
      CG_DrawPic( mX, subY, subH, subH, bs->markedShader );
    }

    {
      float nX;
      int healthMax;
      int healthPoints;

      healthMax = BG_FindHealthForBuildable( es->modelindex );
      healthPoints = (int)( healthScale * healthMax );
      if( health > 0 && healthPoints < 1 )
        healthPoints = 1;
      nX = picX + ( picW * 0.5f ) - 2.0f - ( ( subH * 4 ) * 0.5f ); 
       
      if( healthPoints > 999 )
        nX -= 0.0f;
      else if( healthPoints > 99 )
        nX -= subH * 0.5f;
      else if( healthPoints > 9 )
        nX -= subH * 1.0f;
      else
        nX -= subH * 1.5f;
     
      CG_DrawField( nX, subY, 4, subH, subH, healthPoints );
    }
    trap_R_SetColor( NULL );
  }
}
Esempio n. 3
0
static void UI_SPLevelMenu_MenuDraw( void ) {
	int				n, i;
	int				x, y;
	vec4_t			color;
	int				level;
//	int				fraglimit;
	int				pad;
	char			buf[MAX_INFO_VALUE];
	char			string[64];

	if(	levelMenuInfo.reinit ) {
		UI_PopMenu();
		UI_SPLevelMenu();
		return;
	}

	// draw player name
	trap_Cvar_VariableStringBuffer( "name", string, 32 );
	Q_CleanStr( string );
	UI_DrawProportionalString( 320, PLAYER_Y, string, UI_CENTER|UI_SMALLFONT, color_orange );

	// check for model changes
	trap_Cvar_VariableStringBuffer( "model", buf, sizeof(buf) );
	if( Q_stricmp( buf, levelMenuInfo.playerModel ) != 0 ) {
		Q_strncpyz( levelMenuInfo.playerModel, buf, sizeof(levelMenuInfo.playerModel) );
		PlayerIcon( levelMenuInfo.playerModel, levelMenuInfo.playerPicName, sizeof(levelMenuInfo.playerPicName) );
		levelMenuInfo.item_player.shader = 0;
	}

	// standard menu drawing
	Menu_Draw( &levelMenuInfo.menu );

	// draw player award levels
	y = AWARDS_Y;
	i = 0;
	for( n = 0; n < 6; n++ ) {
		level = levelMenuInfo.awardLevels[n];
		if( level > 0 ) {
			if( i & 1 ) {
				x = 224 - (i - 1 ) / 2 * (48 + 16);
			}
			else {
				x = 368 + i / 2 * (48 + 16);
			}
			i++;

			if( level == 1 ) {
				continue;
			}

			if( level >= 1000000 ) {
				Com_sprintf( string, sizeof(string), "%im", level / 1000000 );
			}
			else if( level >= 1000 ) {
				Com_sprintf( string, sizeof(string), "%ik", level / 1000 );
			}
			else {
				Com_sprintf( string, sizeof(string), "%i", level );
			}

			UI_DrawString( x + 24, y + 48, string, UI_CENTER, color_yellow );
		}
	}

	UI_DrawProportionalString( 18, 38, va( "Tier %i", selectedArenaSet + 1 ), UI_LEFT|UI_SMALLFONT, color_orange );

	for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
		x = levelMenuInfo.item_maps[n].generic.x;
		y = levelMenuInfo.item_maps[n].generic.y;
		UI_FillRect( x, y + 96, 128, 18, color_black );
	}

	if ( selectedArenaSet > currentSet ) {
		UI_DrawProportionalString( 320, 216, "ACCESS DENIED", UI_CENTER|UI_BIGFONT, color_red );
		return;
	}

	// show levelshots for levels of current tier
	Vector4Copy( color_white, color );
	color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
	for ( n = 0; n < levelMenuInfo.numMaps; n++ ) {
		x = levelMenuInfo.item_maps[n].generic.x;
		y = levelMenuInfo.item_maps[n].generic.y;

		UI_DrawString( x + 64, y + 96, levelMenuInfo.levelNames[n], UI_CENTER|UI_SMALLFONT, color_orange );

		if( levelMenuInfo.levelScores[n] == 1 ) {
			UI_DrawHandlePic( x, y, 128, 96, levelMenuInfo.levelCompletePic[levelMenuInfo.levelScoresSkill[n] - 1] ); 
		}

		if ( n == selectedArena ) {
			if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
				trap_R_SetColor( color );
			}
			UI_DrawHandlePic( x-1, y-1, 130, 130 - 14, levelMenuInfo.levelSelectedPic ); 
			trap_R_SetColor( NULL );
		}
		else if( Menu_ItemAtCursor( &levelMenuInfo.menu ) == &levelMenuInfo.item_maps[n] ) {
			trap_R_SetColor( color );
			UI_DrawHandlePic( x-31, y-30, 256, 256-27, levelMenuInfo.levelFocusPic); 
			trap_R_SetColor( NULL );
		}
	}

	// show map name and long name of selected level
	y = 192;
	Q_strncpyz( buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "map" ), 20 );
	Q_strupr( buf );
	Com_sprintf( string, sizeof(string), "%s: %s", buf, Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "longname" ) );
	UI_DrawProportionalString( 320, y, string, UI_CENTER|UI_SMALLFONT, color_orange );

//	fraglimit = atoi( Info_ValueForKey( levelMenuInfo.selectedArenaInfo, "fraglimit" ) );
//	UI_DrawString( 18, 212, va("Frags %i", fraglimit) , UI_LEFT|UI_SMALLFONT, color_orange );

	// draw bot opponents
	y += 24;
	pad = (7 - levelMenuInfo.numBots) * (64 + 26) / 2;
	for( n = 0; n < levelMenuInfo.numBots; n++ ) {
		x = 18 + pad + (64 + 26) * n;
		if( levelMenuInfo.botPics[n] ) {
			UI_DrawHandlePic( x, y, 64, 64, levelMenuInfo.botPics[n]);
		}
		else {
			UI_FillRect( x, y, 64, 64, color_black );
			UI_DrawProportionalString( x+22, y+18, "?", UI_BIGFONT, color_orange );
		}
		UI_DrawString( x, y + 64, levelMenuInfo.botNames[n], UI_SMALLFONT|UI_LEFT, color_orange );
	}
}
Esempio n. 4
0
/*
@@@@@@@@@@@@@@@@@@@@@
RE_RenderScene

Draw a 3D view into a part of the window, then return
to 2D drawing.

Rendering a scene may require multiple views to be rendered
to handle mirrors,
@@@@@@@@@@@@@@@@@@@@@
*/
void RE_RenderScene( const refdef_t *fd )
{
	viewParms_t parms;
	int         startTime;

	if ( !tr.registered )
	{
		return;
	}

	GLimp_LogComment( "====== RE_RenderScene =====\n" );

	if ( r_norefresh->integer )
	{
		return;
	}

	startTime = ri.Milliseconds();

	if ( !tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) )
	{
		ri.Error(errorParm_t::ERR_DROP, "R_RenderScene: NULL worldmodel" );
	}

	tr.refdef.x = fd->x;
	tr.refdef.y = fd->y;
	tr.refdef.width = fd->width;
	tr.refdef.height = fd->height;
	tr.refdef.fov_x = fd->fov_x;
	tr.refdef.fov_y = fd->fov_y;

	VectorCopy( fd->vieworg, tr.refdef.vieworg );
	VectorCopy( fd->viewaxis[ 0 ], tr.refdef.viewaxis[ 0 ] );
	VectorCopy( fd->viewaxis[ 1 ], tr.refdef.viewaxis[ 1 ] );
	VectorCopy( fd->viewaxis[ 2 ], tr.refdef.viewaxis[ 2 ] );
	VectorCopy( fd->blurVec, tr.refdef.blurVec );

	tr.refdef.time = fd->time;
	tr.refdef.rdflags = fd->rdflags;

	// copy the areamask data over and note if it has changed, which
	// will force a reset of the visible leafs even if the view hasn't moved
	tr.refdef.areamaskModified = false;

	if ( !( tr.refdef.rdflags & RDF_NOWORLDMODEL ) && !( ( tr.refdef.rdflags & RDF_SKYBOXPORTAL ) && tr.world->numSkyNodes > 0 ) )
	{
		int areaDiff;
		int i;

		// compare the area bits
		areaDiff = 0;

		for ( i = 0; i < MAX_MAP_AREA_BYTES / 4; i++ )
		{
			areaDiff |= ( ( int * ) tr.refdef.areamask ) [ i ] ^ ( ( int * ) fd->areamask ) [ i ];
			( ( int * ) tr.refdef.areamask ) [ i ] = ( ( int * ) fd->areamask ) [ i ];
		}

		if ( areaDiff )
		{
			// a door just opened or something
			tr.refdef.areamaskModified = true;
		}
	}

	R_AddWorldLightsToScene();

	// derived info
	tr.refdef.floatTime = float(double(tr.refdef.time) * 0.001);

	tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
	tr.refdef.drawSurfs = backEndData[ tr.smpFrame ]->drawSurfs;

	tr.refdef.numInteractions = r_firstSceneInteraction;
	tr.refdef.interactions = backEndData[ tr.smpFrame ]->interactions;

	tr.refdef.numEntities = r_numEntities - r_firstSceneEntity;
	tr.refdef.entities = &backEndData[ tr.smpFrame ]->entities[ r_firstSceneEntity ];

	tr.refdef.numLights = r_numLights - r_firstSceneLight;
	tr.refdef.lights = &backEndData[ tr.smpFrame ]->lights[ r_firstSceneLight ];

	tr.refdef.numPolys = r_numPolys - r_firstScenePoly;
	tr.refdef.polys = &backEndData[ tr.smpFrame ]->polys[ r_firstScenePoly ];

	tr.refdef.numPolybuffers = r_numPolybuffers - r_firstScenePolybuffer;
	tr.refdef.polybuffers = &backEndData[ tr.smpFrame ]->polybuffers[ r_firstScenePolybuffer ];

	tr.refdef.numDecalProjectors = r_numDecalProjectors - r_firstSceneDecalProjector;
	tr.refdef.decalProjectors = &backEndData[ tr.smpFrame ]->decalProjectors[ r_firstSceneDecalProjector ];

	tr.refdef.numDecals = r_numDecals - r_firstSceneDecal;
	tr.refdef.decals = &backEndData[ tr.smpFrame ]->decals[ r_firstSceneDecal ];

	tr.refdef.numVisTests = r_numVisTests - r_firstSceneVisTest;
	tr.refdef.visTests = &backEndData[ tr.smpFrame ]->visTests[ r_firstSceneVisTest ];

	// a single frame may have multiple scenes draw inside it --
	// a 3D game view, 3D status bar renderings, 3D menus, etc.
	// They need to be distinguished by the light flare code, because
	// the visibility state for a given surface may be different in
	// each scene / view.
	tr.frameSceneNum++;
	tr.sceneCount++;

	// Tr3B: a scene can have multiple views caused by mirrors or portals
	// the number of views is restricted so we can use hardware occlusion queries
	// and put them into the BSP nodes for each view
	tr.viewCount = -1;

	// setup view parms for the initial view
	//
	// set up viewport
	// The refdef takes 0-at-the-top y coordinates, so
	// convert to GL's 0-at-the-bottom space
	//
	Com_Memset( &parms, 0, sizeof( parms ) );

	if ( tr.refdef.pixelTarget == nullptr )
	{
		parms.viewportX = tr.refdef.x;
		parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
	}
	else
	{
		//Driver bug, if we try and do pixel target work along the top edge of a window
		//we can end up capturing part of the status bar. (see screenshot corruption..)
		//Soooo.. use the middle.
		parms.viewportX = glConfig.vidWidth / 2;
		parms.viewportY = glConfig.vidHeight / 2;
	}

	parms.viewportWidth = tr.refdef.width;
	parms.viewportHeight = tr.refdef.height;

	parms.scissorX = parms.viewportX;
	parms.scissorY = parms.viewportY;
	parms.scissorWidth = parms.viewportWidth;
	parms.scissorHeight = parms.viewportHeight;

	Vector4Set( parms.viewportVerts[ 0 ], parms.viewportX, parms.viewportY, 0, 1 );
	Vector4Set( parms.viewportVerts[ 1 ], parms.viewportX + parms.viewportWidth, parms.viewportY, 0, 1 );
	Vector4Set( parms.viewportVerts[ 2 ], parms.viewportX + parms.viewportWidth, parms.viewportY + parms.viewportHeight, 0, 1 );
	Vector4Set( parms.viewportVerts[ 3 ], parms.viewportX, parms.viewportY + parms.viewportHeight, 0, 1 );

	parms.isPortal = false;

	parms.fovX = tr.refdef.fov_x;
	parms.fovY = tr.refdef.fov_y;

	VectorCopy( fd->vieworg, parms.orientation.origin );
	VectorCopy( fd->viewaxis[ 0 ], parms.orientation.axis[ 0 ] );
	VectorCopy( fd->viewaxis[ 1 ], parms.orientation.axis[ 1 ] );
	VectorCopy( fd->viewaxis[ 2 ], parms.orientation.axis[ 2 ] );

	VectorCopy( fd->vieworg, parms.pvsOrigin );
	Vector4Copy( fd->gradingWeights, parms.gradingWeights );

	R_RenderView( &parms );

	R_RenderPostProcess();

	// the next scene rendered in this frame will tack on after this one
	r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
	r_firstSceneInteraction = tr.refdef.numInteractions;
	r_firstSceneEntity = r_numEntities;
	r_firstSceneLight = r_numLights;
	r_firstScenePoly = r_numPolys;
	r_firstScenePolybuffer = r_numPolybuffers;
	r_firstSceneVisTest = r_numVisTests;

	tr.frontEndMsec += ri.Milliseconds() - startTime;
}
Esempio n. 5
0
/*
* R_RenderMeshGLSL_Shadowmap
*/
static void R_RenderMeshGLSL_Shadowmap( r_glslfeat_t programFeatures )
{
	int i;
	int state;
	int scissor[4], old_scissor[4];
	int program, object;
	vec3_t tdir, lightDir;
	shaderpass_t *pass = r_back.accumPasses[0];

	if( r_shadows_pcf->integer )
		programFeatures |= GLSL_SHADOWMAP_APPLY_PCF;
	if( r_shadows_dither->integer )
		programFeatures |= GLSL_SHADOWMAP_APPLY_DITHER;

	// update uniforms
	program = R_RegisterGLSLProgram( pass->program_type, pass->program, NULL, NULL, NULL, 0, programFeatures );
	object = R_GetProgramObject( program );
	if( !object )
		return;

	Vector4Copy( ri.scissor, old_scissor );

	for( i = 0, r_back.currentCastGroup = r_shadowGroups; i < r_numShadowGroups; i++, r_back.currentCastGroup++ )
	{
		if( !( r_back.currentShadowBits & r_back.currentCastGroup->bit ) )
			continue;

		// project the bounding box on to screen then use scissor test
		// so that fragment shader isn't run for unshadowed regions
		if( !R_ScissorForBounds( r_back.currentCastGroup->visCorners, 
			&scissor[0], &scissor[1], &scissor[2], &scissor[3] ) )
			continue;

		GL_Scissor( ri.refdef.x + scissor[0], ri.refdef.y + scissor[1], scissor[2], scissor[3] );

		R_BindShaderpass( pass, r_back.currentCastGroup->depthTexture, 0, NULL );

		GL_TexEnv( GL_MODULATE );

		qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
		qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );

		// calculate the fragment color
		R_ModifyColor( pass, qfalse, qfalse );

		// set shaderpass state (blending, depthwrite, etc)
		state = r_back.currentShaderState | ( pass->flags & r_back.currentShaderPassMask ) | GLSTATE_BLEND_MTEX;
		GL_SetState( state );

		qglUseProgramObjectARB( object );

		VectorCopy( r_back.currentCastGroup->direction, tdir );
		Matrix_TransformVector( ri.currententity->axis, tdir, lightDir );

		R_UpdateProgramUniforms( program, ri.viewOrigin, vec3_origin, lightDir,
			r_back.currentCastGroup->lightAmbient, NULL, NULL, qtrue,
			r_back.currentCastGroup->depthTexture->upload_width, r_back.currentCastGroup->depthTexture->upload_height,
			r_back.currentCastGroup->projDist,
			0, 0, 
			colorArrayCopy[0], r_back.overBrightBits, r_back.currentShaderTime, r_back.entityColor );

		R_FlushArrays();

		qglUseProgramObjectARB( 0 );

		qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
	}

	GL_Scissor( old_scissor[0], old_scissor[1], old_scissor[2], old_scissor[3] );
}
Esempio n. 6
0
/*
* FTLIB_DrawRawString - Doesn't care about aligning. Returns drawn len.
* It can stop when reaching maximum width when a value has been parsed.
*/
size_t FTLIB_DrawRawString( int x, int y, const char *str, size_t maxwidth, int *width, qfontface_t *font, vec4_t color, int flags )
{
	unsigned int xoffset = 0;
	vec4_t scolor;
	const char *s, *olds;
	int gc, colorindex;
	wchar_t num, prev_num = 0;
	qglyph_t *glyph, *prev_glyph = NULL;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	if( !str || !font )
		return 0;

	Vector4Copy( color, scolor );

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	for( s = str; s; )
	{
		olds = s;
		gc = FTLIB_GrabChar( &s, &num, &colorindex, flags );
		if( gc == GRABCHAR_CHAR )
		{
			if( num == '\n' )
				break;

			if( num < ' ' )
				continue;

			glyph = FTLIB_GetGlyph( font, num );
			if( !glyph )
			{
				num = FTLIB_REPLACEMENT_GLYPH;
				glyph = FTLIB_GetGlyph( font, num );
			}

			if( !glyph->shader )
				renderString( font, olds );

			// ignore kerning at this point so the full width of the previous character will always be returned
			if( maxwidth && ( ( xoffset + glyph->x_advance ) > maxwidth ) )
			{
				s = olds;
				break;
			}

			if( hasKerning && prev_num )
				xoffset += getKerning( font, prev_glyph, glyph );

			FTLIB_DrawRawChar( x + xoffset, y, num, font, scolor );

			xoffset += glyph->x_advance;

			prev_num = num;
			prev_glyph = glyph;
		}
		else if( gc == GRABCHAR_COLOR )
		{
			assert( ( unsigned )colorindex < MAX_S_COLORS );
			VectorCopy( color_table[colorindex], scolor );
		}
		else if( gc == GRABCHAR_END )
			break;
		else
			assert( 0 );
	}

	if( width )
		*width = xoffset;

	return ( s - str );
}
Esempio n. 7
0
void CM_AddFacetBevels( facet_t *facet ) {

	int i, j, k, l;
	int axis, dir, order, flipped;
	float plane[4], d, minBack, newplane[4];
	winding_t *w, *w2;
	vec3_t mins, maxs, vec, vec2;

#ifndef ADDBEVELS
	return;
#endif

	Vector4Copy( planes[ facet->surfacePlane ].plane, plane );

	w = BaseWindingForPlane( plane,  plane[3] );
	for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
		if ( facet->borderPlanes[j] == facet->surfacePlane ) {
			continue;
		}
		Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );

		if ( !facet->borderInward[j] ) {
			VectorSubtract( vec3_origin, plane, plane );
			plane[3] = -plane[3];
		}

		ChopWindingInPlace( &w, plane, plane[3], 0.1f );
	}
	if ( !w ) {
		return;
	}

	WindingBounds( w, mins, maxs );

	// add the axial planes
	order = 0;
	for ( axis = 0; axis < 3; axis++ ) {
		for ( dir = -1; dir <= 1; dir += 2, order++ ) {
			VectorClear( plane );
			plane[axis] = dir;
			if ( dir == 1 ) {
				plane[3] = maxs[axis];
			} else {
				plane[3] = -mins[axis];
			}
			//if it's the surface plane
			if ( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ) ) {
				continue;
			}
			// see if the plane is allready present
			for ( i = 0; i < facet->numBorders; i++ ) {
				if ( dir > 0 ) {
					if ( planes[facet->borderPlanes[i]].plane[axis] >= 0.9999f ) {
						break;
					}
				} else {
					if ( planes[facet->borderPlanes[i]].plane[axis] <= -0.9999f ) {
						break;
					}
				}
			}

			if ( i == facet->numBorders ) {
				if ( facet->numBorders > 4 + 6 + 16 ) {
					Com_Printf( "ERROR: too many bevels\n" );
				}
				facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped );
				facet->borderNoAdjust[facet->numBorders] = 0;
				facet->borderInward[facet->numBorders] = flipped;
				facet->numBorders++;
			}
		}
	}
	//
	// add the edge bevels
	//
	// test the non-axial plane edges
	for ( j = 0; j < w->numpoints; j++ )
	{
		k = ( j + 1 ) % w->numpoints;
		VectorSubtract( w->p[j], w->p[k], vec );
		//if it's a degenerate edge
		if ( VectorNormalize( vec ) < 0.5f ) {
			continue;
		}
		CM_SnapVector( vec );
		for ( k = 0; k < 3; k++ ) {
			if ( vec[k] == -1.0f || vec[k] == 1.0f || ( vec[k] == 0.0f && vec[( k + 1 ) % 3] == 0.0f ) ) {
				break;  // axial
			}
		}
		if ( k < 3 ) {
			continue;   // only test non-axial edges
		}

		// try the six possible slanted axials from this edge
		for ( axis = 0 ; axis < 3 ; axis++ )
		{
			for ( dir = -1 ; dir <= 1 ; dir += 2 )
			{
				// construct a plane
				VectorClear( vec2 );
				vec2[axis] = dir;
				CrossProduct( vec, vec2, plane );
				if ( VectorNormalize( plane ) < 0.5f ) {
					continue;
				}
				plane[3] = DotProduct( w->p[j], plane );

				// if all the points of the facet winding are
				// behind this plane, it is a proper edge bevel
				minBack = 0.0f;
				for ( l = 0; l < w->numpoints; l++ )
				{
					d = DotProduct( w->p[l], plane ) - plane[3];
					if ( d > 0.1f ) {
						break;  // point in front
					}
					if ( d < minBack ) {
						minBack = d;
					}
				}
				// if some point was at the front
				if ( l < w->numpoints ) {
					continue;
				}

				// if no points at the back then the winding is on the bevel plane
				if ( minBack > -0.1f ) {
					break;
				}

				//if it's the surface plane
				if ( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ) ) {
					continue;
				}
				// see if the plane is allready present
				for ( i = 0; i < facet->numBorders; i++ ) {
					if ( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ) ) {
						break;
					}
				}

				if ( i == facet->numBorders ) {
					if ( facet->numBorders > 4 + 6 + 16 ) {
						Com_Printf( "ERROR: too many bevels\n" );
					}
					facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped );

					for ( k = 0; k < facet->numBorders; k++ ) {
						if ( facet->borderPlanes[facet->numBorders] == facet->borderPlanes[k] ) {
							Com_Printf( "WARNING: bevel plane already used\n" );
						}
					}

					facet->borderNoAdjust[facet->numBorders] = 0;
					facet->borderInward[facet->numBorders] = flipped;
					//
					w2 = CopyWinding( w );
					Vector4Copy( planes[facet->borderPlanes[facet->numBorders]].plane, newplane );
					if ( !facet->borderInward[facet->numBorders] ) {
						VectorNegate( newplane, newplane );
						newplane[3] = -newplane[3];
					} //end if
					ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
					if ( !w2 ) {
						// TTimo: any map load spams with this error .. don't print it anymore
						//Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
						continue;
					} else {
						FreeWinding( w2 );
					}
					//
					facet->numBorders++;
					//already got a bevel
//					break;
				}
			}
		}
	}
	FreeWinding( w );

#ifndef BSPC
	//add opposite plane
	facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
	facet->borderNoAdjust[facet->numBorders] = 0;
	facet->borderInward[facet->numBorders] = qtrue;
	facet->numBorders++;
#endif //BSPC

}
Esempio n. 8
0
/*
==================
CM_ValidateFacet

If the facet isn't bounded by its borders, we screwed up.
==================
*/
static qboolean CM_ValidateFacet( cFacet_t *facet )
{
	float     plane[ 4 ];
	int       j;
	winding_t *w;
	vec3_t    bounds[ 2 ];

	if ( facet->surfacePlane == -1 )
	{
		return qfalse;
	}

	Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
	w = BaseWindingForPlane( plane, plane[ 3 ] );

	for ( j = 0; j < facet->numBorders && w; j++ )
	{
		if ( facet->borderPlanes[ j ] == -1 )
		{
			FreeWinding( w );
			return qfalse;
		}

		Vector4Copy( planes[ facet->borderPlanes[ j ] ].plane, plane );

		if ( !facet->borderInward[ j ] )
		{
			VectorSubtract( vec3_origin, plane, plane );
			plane[ 3 ] = -plane[ 3 ];
		}

		ChopWindingInPlace( &w, plane, plane[ 3 ], 0.1f );
	}

	if ( !w )
	{
		return qfalse; // winding was completely chopped away
	}

	// see if the facet is unreasonably large
	WindingBounds( w, bounds[ 0 ], bounds[ 1 ] );
	FreeWinding( w );

	for ( j = 0; j < 3; j++ )
	{
		if ( bounds[ 1 ][ j ] - bounds[ 0 ][ j ] > MAX_WORLD_COORD )
		{
			return qfalse; // we must be missing a plane
		}

		if ( bounds[ 0 ][ j ] >= MAX_WORLD_COORD )
		{
			return qfalse;
		}

		if ( bounds[ 1 ][ j ] <= MIN_WORLD_COORD )
		{
			return qfalse;
		}
	}

	return qtrue; // winding is fine
}
Esempio n. 9
0
static void FilterTraceWindingIntoNodes_r(traceWinding_t * tw, int nodeNum)
{
	int             num;
	vec4_t          plane1, plane2, reverse;
	traceNode_t    *node;
	traceWinding_t  front, back;


	/* don't filter if passed a bogus node (solid, etc) */
	if(nodeNum < 0 || nodeNum >= numTraceNodes)
		return;

	/* get node */
	node = &traceNodes[nodeNum];

	/* is this a decision node? */
	if(node->type >= 0)
	{
		/* create winding plane if necessary, filtering out bogus windings as well */
		if(nodeNum == headNodeNum)
		{
			if(!PlaneFromPoints(tw->plane, tw->v[0].xyz, tw->v[1].xyz, tw->v[2].xyz, qtrue))
				return;
		}

		/* validate the node */
		if(node->children[0] == 0 || node->children[1] == 0)
			Error("Invalid tracenode: %d", nodeNum);

		/* get node plane */
		Vector4Copy(node->plane, plane1);

		/* get winding plane */
		Vector4Copy(tw->plane, plane2);

		/* invert surface plane */
		VectorSubtract(vec3_origin, plane2, reverse);
		reverse[3] = -plane2[3];

		/* front only */
		if(DotProduct(plane1, plane2) > 0.999f && fabs(plane1[3] - plane2[3]) < 0.001f)
		{
			FilterTraceWindingIntoNodes_r(tw, node->children[0]);
			return;
		}

		/* back only */
		if(DotProduct(plane1, reverse) > 0.999f && fabs(plane1[3] - reverse[3]) < 0.001f)
		{
			FilterTraceWindingIntoNodes_r(tw, node->children[1]);
			return;
		}

		/* clip the winding by node plane */
		ClipTraceWinding(tw, plane1, &front, &back);

		/* filter by node plane */
		if(front.numVerts >= 3)
			FilterTraceWindingIntoNodes_r(&front, node->children[0]);
		if(back.numVerts >= 3)
			FilterTraceWindingIntoNodes_r(&back, node->children[1]);

		/* return to caller */
		return;
	}

	/* add winding to leaf node */
	num = AddTraceWinding(tw);
	AddItemToTraceNode(node, num);
}
Esempio n. 10
0
/*
==============
Tess_AddQuadStampExt2
==============
*/
void Tess_AddQuadStampExt2( vec4_t quadVerts[ 4 ], const vec4_t color, float s1, float t1, float s2, float t2 )
{
	int    i;
	vec3_t normal, tangent, binormal;
	int    ndx;

	GLimp_LogComment( "--- Tess_AddQuadStampExt2 ---\n" );

	Tess_CheckOverflow( 4, 6 );

	ndx = tess.numVertexes;

	// triangle indexes for a simple quad
	tess.indexes[ tess.numIndexes ] = ndx;
	tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
	tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;

	tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
	tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
	tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;

	VectorCopy( quadVerts[ 0 ], tess.verts[ ndx + 0 ].xyz );
	VectorCopy( quadVerts[ 1 ], tess.verts[ ndx + 1 ].xyz );
	VectorCopy( quadVerts[ 2 ], tess.verts[ ndx + 2 ].xyz );
	VectorCopy( quadVerts[ 3 ], tess.verts[ ndx + 3 ].xyz );

	tess.attribsSet |= ATTR_POSITION | ATTR_COLOR | ATTR_TEXCOORD | ATTR_QTANGENT;

	// constant normal all the way around
	vec2_t st[ 3 ] = { { s1, t1 }, { s2, t1 }, { s2, t2 } };
	R_CalcFaceNormal( normal, quadVerts[ 0 ], quadVerts[ 1 ], quadVerts[ 2 ] );
	R_CalcTangents( tangent, binormal,
			quadVerts[ 0 ], quadVerts[ 1 ], quadVerts[ 2 ],
			st[ 0 ], st[ 1 ], st[ 2 ] );
	//if ( !calcNormals )
	//{
	//	VectorNegate( backEnd.viewParms.orientation.axis[ 0 ], normal );
	//}

	R_TBNtoQtangents( tangent, binormal, normal, tess.verts[ ndx ].qtangents );
	Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 1 ].qtangents );
	Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 2 ].qtangents );
	Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 3 ].qtangents );

	// standard square texture coordinates
	tess.verts[ ndx ].texCoords[ 0 ] = floatToHalf( s1 );
	tess.verts[ ndx ].texCoords[ 1 ] = floatToHalf( t1 );

	tess.verts[ ndx + 1 ].texCoords[ 0 ] = floatToHalf( s2 );
	tess.verts[ ndx + 1 ].texCoords[ 1 ] = floatToHalf( t1 );

	tess.verts[ ndx + 2 ].texCoords[ 0 ] = floatToHalf( s2 );
	tess.verts[ ndx + 2 ].texCoords[ 1 ] = floatToHalf( t2 );

	tess.verts[ ndx + 3 ].texCoords[ 0 ] = floatToHalf( s1 );
	tess.verts[ ndx + 3 ].texCoords[ 1 ] = floatToHalf( t2 );

	// constant color all the way around
	// should this be identity and let the shader specify from entity?

	u8vec4_t iColor;
	floatToUnorm8( color, iColor );
	for ( i = 0; i < 4; i++ )
	{
		Vector4Copy( iColor, tess.verts[ ndx + i ].color );
	}

	tess.numVertexes += 4;
	tess.numIndexes += 6;
}
Esempio n. 11
0
/*
=============
Tess_SurfacePolychain
=============
*/
static void Tess_SurfacePolychain( srfPoly_t *p )
{
	int i, j;
	int numVertexes;
	int numIndexes;

	GLimp_LogComment( "--- Tess_SurfacePolychain ---\n" );

	Tess_CheckOverflow( p->numVerts, 3 * ( p->numVerts - 2 ) );

	// fan triangles into the tess array
	numVertexes = 0;

	for ( i = 0; i < p->numVerts; i++ )
	{
		VectorCopy( p->verts[ i ].xyz, tess.verts[ tess.numVertexes + i ].xyz );

		tess.verts[ tess.numVertexes + i ].texCoords[ 0 ] = floatToHalf( p->verts[ i ].st[ 0 ] );
		tess.verts[ tess.numVertexes + i ].texCoords[ 1 ] = floatToHalf( p->verts[ i ].st[ 1 ] );

		Vector4Copy( p->verts[ i ].modulate, tess.verts[ tess.numVertexes + i ].color );

		numVertexes++;
	}

	// generate fan indexes into the tess array
	numIndexes = 0;

	for ( i = 0; i < p->numVerts - 2; i++ )
	{
		tess.indexes[ tess.numIndexes + i * 3 + 0 ] = tess.numVertexes;
		tess.indexes[ tess.numIndexes + i * 3 + 1 ] = tess.numVertexes + i + 1;
		tess.indexes[ tess.numIndexes + i * 3 + 2 ] = tess.numVertexes + i + 2;
		numIndexes += 3;
	}

	tess.attribsSet |= ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR;

	// calc tangent spaces
	if ( tess.surfaceShader->interactLight && !tess.skipTangentSpaces )
	{
		int         i;
		float       *v;
		const float *v0, *v1, *v2;
		const int16_t *t0, *t1, *t2;
		vec3_t      tangent, *tangents;
		vec3_t      binormal, *binormals;
		vec3_t      normal, *normals;
		glIndex_t   *indices;

		tangents = (vec3_t *)ri.Hunk_AllocateTempMemory( numVertexes * sizeof( vec3_t ) );
		binormals = (vec3_t *)ri.Hunk_AllocateTempMemory( numVertexes * sizeof( vec3_t ) );
		normals = (vec3_t *)ri.Hunk_AllocateTempMemory( numVertexes * sizeof( vec3_t ) );

		for ( i = 0; i < numVertexes; i++ )
		{
			VectorClear( tangents[ i ] );
			VectorClear( binormals[ i ] );
			VectorClear( normals[ i ] );
		}

		for ( i = 0, indices = tess.indexes + tess.numIndexes; i < numIndexes; i += 3, indices += 3 )
		{
			v0 = tess.verts[ indices[ 0 ] ].xyz;
			v1 = tess.verts[ indices[ 1 ] ].xyz;
			v2 = tess.verts[ indices[ 2 ] ].xyz;

			t0 = tess.verts[ indices[ 0 ] ].texCoords;
			t1 = tess.verts[ indices[ 1 ] ].texCoords;
			t2 = tess.verts[ indices[ 2 ] ].texCoords;

			R_CalcFaceNormal( normal, v0, v1, v2 );
			R_CalcTangents( tangent, binormal, v0, v1, v2, t0, t1, t2 );

			for ( j = 0; j < 3; j++ )
			{
				v = tangents[ indices[ j ] - tess.numVertexes ];
				VectorAdd( v, tangent, v );
				v = binormals[ indices[ j ] - tess.numVertexes ];
				VectorAdd( v, binormal, v );
				v = normals[ indices[ j ] - tess.numVertexes ];
				VectorAdd( v, normal, v );
			}
		}

		for ( i = 0; i < numVertexes; i++ )
		{
			VectorNormalizeFast( normals[ i ] );
			R_TBNtoQtangents( tangents[ i ], binormals[ i ],
					  normals[ i ], tess.verts[ tess.numVertexes + i ].qtangents );
		}

		ri.Hunk_FreeTempMemory( normals );
		ri.Hunk_FreeTempMemory( binormals );
		ri.Hunk_FreeTempMemory( tangents );

		tess.attribsSet |= ATTR_QTANGENT;
	}

	tess.numIndexes += numIndexes;
	tess.numVertexes += numVertexes;
}
Esempio n. 12
0
/*
==============
Tess_AddQuadStampExt
==============
*/
void Tess_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, const vec4_t color, float s1, float t1, float s2, float t2 )
{
	int    i;
	vec3_t normal;
	int    ndx;

	GLimp_LogComment( "--- Tess_AddQuadStampExt ---\n" );

	Tess_CheckOverflow( 4, 6 );

	ndx = tess.numVertexes;

	// triangle indexes for a simple quad
	tess.indexes[ tess.numIndexes ] = ndx;
	tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
	tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;

	tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
	tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
	tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;

	tess.verts[ ndx ].xyz[ 0 ] = origin[ 0 ] + left[ 0 ] + up[ 0 ];
	tess.verts[ ndx ].xyz[ 1 ] = origin[ 1 ] + left[ 1 ] + up[ 1 ];
	tess.verts[ ndx ].xyz[ 2 ] = origin[ 2 ] + left[ 2 ] + up[ 2 ];

	tess.verts[ ndx + 1 ].xyz[ 0 ] = origin[ 0 ] - left[ 0 ] + up[ 0 ];
	tess.verts[ ndx + 1 ].xyz[ 1 ] = origin[ 1 ] - left[ 1 ] + up[ 1 ];
	tess.verts[ ndx + 1 ].xyz[ 2 ] = origin[ 2 ] - left[ 2 ] + up[ 2 ];

	tess.verts[ ndx + 2 ].xyz[ 0 ] = origin[ 0 ] - left[ 0 ] - up[ 0 ];
	tess.verts[ ndx + 2 ].xyz[ 1 ] = origin[ 1 ] - left[ 1 ] - up[ 1 ];
	tess.verts[ ndx + 2 ].xyz[ 2 ] = origin[ 2 ] - left[ 2 ] - up[ 2 ];

	tess.verts[ ndx + 3 ].xyz[ 0 ] = origin[ 0 ] + left[ 0 ] - up[ 0 ];
	tess.verts[ ndx + 3 ].xyz[ 1 ] = origin[ 1 ] + left[ 1 ] - up[ 1 ];
	tess.verts[ ndx + 3 ].xyz[ 2 ] = origin[ 2 ] + left[ 2 ] - up[ 2 ];

	// constant normal all the way around
	VectorSubtract( vec3_origin, backEnd.viewParms.orientation.axis[ 0 ], normal );
	R_TBNtoQtangents( left, up, normal, tess.verts[ ndx ].qtangents );
	Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 1 ].qtangents );
	Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 2 ].qtangents );
	Vector4Copy( tess.verts[ ndx ].qtangents, tess.verts[ ndx + 3 ].qtangents );

	// standard square texture coordinates
	tess.verts[ ndx ].texCoords[ 0 ] = floatToHalf( s1 );
	tess.verts[ ndx ].texCoords[ 1 ] = floatToHalf( t1 );

	tess.verts[ ndx + 1 ].texCoords[ 0 ] = floatToHalf( s2 );
	tess.verts[ ndx + 1 ].texCoords[ 1 ] = floatToHalf( t1 );

	tess.verts[ ndx + 2 ].texCoords[ 0 ] = floatToHalf( s2 );
	tess.verts[ ndx + 2 ].texCoords[ 1 ] = floatToHalf( t2 );

	tess.verts[ ndx + 3 ].texCoords[ 0 ] = floatToHalf( s1 );
	tess.verts[ ndx + 3 ].texCoords[ 1 ] = floatToHalf( t2 );

	// constant color all the way around
	// should this be identity and let the shader specify from entity?

	u8vec4_t iColor;
	floatToUnorm8( color, iColor );
	for ( i = 0; i < 4; i++ )
	{
		Vector4Copy( iColor, tess.verts[ ndx + i ].color );
	}

	tess.numVertexes += 4;
	tess.numIndexes += 6;

	tess.attribsSet |= ATTR_POSITION | ATTR_QTANGENT | ATTR_COLOR | ATTR_TEXCOORD;
}
Esempio n. 13
0
/*
==================
CM_AddFacetBevels
==================
*/
static void CM_AddFacetBevels( cfacet_t *facet )
{

	int		i, j, k, l;
	int		axis, dir, order, flipped;
	float		plane[4], d, newplane[4];
	vec3_t		mins, maxs, vec, vec2;
	cwinding_t	*w, *w2;

	Vector4Copy( planes[facet->surfacePlane].plane, plane );

	w = CM_BaseWindingForPlane( plane, plane[3] );

	for( j = 0; j < facet->numBorders && w; j++ )
	{
		if( facet->borderPlanes[j] == facet->surfacePlane )
			continue;
		Vector4Copy( planes[facet->borderPlanes[j]].plane, plane );

		if( !facet->borderInward[j] )
		{
			VectorNegate( plane, plane );
			plane[3] = -plane[3];
		}
		CM_ChopWindingInPlace( &w, plane, plane[3], ON_EPSILON );
	}

	if( !w ) return;

	CM_WindingBounds( w, mins, maxs );

	//
	// add the axial planes
	//
	order = 0;
	for( axis = 0; axis < 3; axis++ )
	{
		for( dir = -1; dir <= 1; dir += 2, order++ )
		{
			VectorClear( plane );
			plane[axis] = dir;

			if( dir == 1 ) plane[3] = maxs[axis];
			else plane[3] = -mins[axis];

			// if it's the surface plane
			if( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ))
				continue;

			// see if the plane is allready present
			for( i = 0; i < facet->numBorders; i++ )
			{
				if( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ))
					break;
			}

			if( i == facet->numBorders )
			{
				if( facet->numBorders > MAX_FACET_BEVELS )
					MsgDev( D_ERROR, "CM_AddFacetBevels: too many bevels\n" );

				facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
				facet->borderNoAdjust[facet->numBorders] = 0;
				facet->borderInward[facet->numBorders] = flipped;
				facet->numBorders++;
			}
		}
	}

	//
	// add the edge bevels
	//

	// test the non-axial plane edges
	for( j = 0; j < w->numpoints; j++ )
	{
		k = (j + 1) % w->numpoints;
		VectorSubtract( w->p[j], w->p[k], vec );

		// if it's a degenerate edge
		if( VectorNormalizeLength( vec ) < 0.5f )
			continue;

		CM_SnapVector( vec );
		for( k = 0; k < 3; k++ )
		{
			if( vec[k] == -1 || vec[k] == 1 )
				break; // axial
		}

		if( k < 3 ) continue; // only test non-axial edges

		// try the six possible slanted axials from this edge
		for( axis = 0; axis < 3; axis++ )
		{
			for( dir = -1; dir <= 1; dir += 2 )
			{
				// construct a plane
				VectorClear( vec2 );
				vec2[axis] = dir;
				CrossProduct( vec, vec2, plane );
				if( VectorNormalizeLength( plane ) < 0.5f )
					continue;
				plane[3] = DotProduct( w->p[j], plane );

				// if all the points of the facet winding are
				// behind this plane, it is a proper edge bevel
				for( l = 0; l < w->numpoints; l++ )
				{
					d = DotProduct( w->p[l], plane ) - plane[3];
					if( d > ON_EPSILON ) break; // point in front
				}

				if( l < w->numpoints ) continue;

				// if it's the surface plane
				if( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ))
					continue;

				// see if the plane is allready present
				for( i = 0; i < facet->numBorders; i++ )
				{
					if( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ))
						break;
				}

				if( i == facet->numBorders )
				{
					if( facet->numBorders > MAX_FACET_BEVELS )
						MsgDev( D_ERROR, "CM_AddFacetBevels: too many bevels\n" );
					facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped );

					for( k = 0; k < facet->numBorders; k++ )
					{
						if( facet->borderPlanes[facet->numBorders] == facet->borderPlanes[k] )
							MsgDev( D_WARN, "CM_AddFacetBevels: bevel plane already used\n" );
					}

					facet->borderNoAdjust[facet->numBorders] = 0;
					facet->borderInward[facet->numBorders] = flipped;

					w2 = CM_CopyWinding( w );
					Vector4Copy( planes[facet->borderPlanes[facet->numBorders]].plane, newplane );

					if( !facet->borderInward[facet->numBorders] )
					{
						VectorNegate( newplane, newplane );
						newplane[3] = -newplane[3];
					}

					CM_ChopWindingInPlace( &w2, newplane, newplane[3], ON_EPSILON );

					if( !w2 )
					{
						cm.numInvalidBevels++;
						continue;
					}
					else CM_FreeWinding( w2 );

					facet->numBorders++;
					// already got a bevel
				}
			}
		}
	}
	CM_FreeWinding( w );

	// add opposite plane
	facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
	facet->borderNoAdjust[facet->numBorders] = 0;
	facet->borderInward[facet->numBorders] = true;
	facet->numBorders++;
}
Esempio n. 14
0
/**
origin should be a point within a unit of the plane
dir should be the plane normal

temporary marks will not be stored or randomly oriented, but immediately
passed to the renderer.
*/
void CG_ImpactMark(qhandle_t markShader, const vec3_t origin, const vec3_t dir, float orientation,
	vec4_t color, qboolean alphaFade, float radius, qboolean temporary)
{
	vec3_t			axis[3];
	float			texCoordScale;
	vec3_t			originalPoints[4];
	int				i, j;
	int				numFragments;
	markFragment_t	markFragments[MAX_MARK_FRAGMENTS], *mf;
	vec3_t			markPoints[MAX_MARK_POINTS];
	vec3_t			projection;

	if (!cg_marks.integer) {
		return;
	}

	if (radius <= 0) {
		CG_Error("CG_ImpactMark called with <= 0 radius");
	}

	// create the texture axis
	VectorNormalize2(dir, axis[0]);
	PerpendicularVector(axis[1], axis[0]);
	RotatePointAroundVector(axis[2], axis[0], axis[1], orientation);
	CrossProduct(axis[0], axis[2], axis[1]);

	texCoordScale = 0.5 * 1.0 / radius;

	// create the full polygon
	for (i = 0; i < 3; i++) {
		originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
		originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
		originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
		originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
	}

	// get the fragments
	VectorScale(dir, -20, projection);
	numFragments = trap_CM_MarkFragments(4, (void *)originalPoints,
					projection, MAX_MARK_POINTS, markPoints[0],
					MAX_MARK_FRAGMENTS, markFragments);

	for (i = 0, mf = markFragments; i < numFragments; i++, mf++) {
		polyVert_t	*v;
		polyVert_t	verts[MAX_VERTS_ON_POLY];
		markPoly_t	*mark;

		// we have an upper limit on the complexity of polygons
		// that we store persistantly
		if (mf->numPoints > MAX_VERTS_ON_POLY) {
			mf->numPoints = MAX_VERTS_ON_POLY;
		}
		for (j = 0, v = verts; j < mf->numPoints; j++, v++) {
			vec3_t		delta;

			VectorCopy(markPoints[mf->firstPoint + j], v->xyz);

			VectorSubtract(v->xyz, origin, delta);
			v->st[0] = 0.5 + DotProduct(delta, axis[1]) * texCoordScale;
			v->st[1] = 0.5 + DotProduct(delta, axis[2]) * texCoordScale;
			SCR_SetRGBA(v->modulate, color);
		}

		// if it is a temporary (shadow) mark, add it immediately and forget about it
		if (temporary) {
			trap_R_AddPolyToScene(markShader, mf->numPoints, verts);
			continue;
		}

		// otherwise save it persistantly
		mark = CG_AllocMark();
		mark->time = cg.time;
		mark->alphaFade = alphaFade;
		mark->markShader = markShader;
		mark->poly.numVerts = mf->numPoints;
		Vector4Copy(color, mark->color);
		memcpy(mark->verts, verts, mf->numPoints * sizeof(verts[0]));
		markTotal++;
	}
}
Esempio n. 15
0
/*
* CG_SpawnPolyBeam
* Spawns a polygon from start to end points length and given width.
* shaderlenght makes reference to size of the texture it will draw, so it can be tiled.
*/
static cpoly_t *CG_SpawnPolyBeam( const vec3_t start, const vec3_t end, const vec4_t color, int width, unsigned int dietime, unsigned int fadetime, struct shader_s *shader, int shaderlength, int tag )
{
	cpoly_t *cgpoly;
	poly_t *poly;
	vec3_t angles, dir;
	int i;
	float xmin, ymin, xmax, ymax;
	float stx = 1.0f, sty = 1.0f;

	// find out beam polygon sizes
	VectorSubtract( end, start, dir );
	VecToAngles( dir, angles );

	xmin = 0;
	xmax = VectorNormalize( dir );
	ymin = -( width*0.5 );
	ymax = width*0.5;
	if( shaderlength && xmax > shaderlength )
		stx = xmax / (float)shaderlength;

	if( xmax - xmin < ymax - ymin ) {
		// do not render polybeams which have width longer than their length
		return NULL;
	}

	cgpoly = CG_SpawnPolygon( 1.0, 1.0, 1.0, 1.0, dietime ? dietime : cgs.snapFrameTime, fadetime, shader, tag );

	VectorCopy( angles, cgpoly->angles );
	VectorCopy( start, cgpoly->origin );
	if( color )
		Vector4Copy( color, cgpoly->color );

	// create the polygon inside the cgpolygon
	poly = cgpoly->poly;
	poly->shader = cgpoly->shader;
	poly->numverts = 0;

	// Vic: I think it's safe to assume there should be no fog applied to beams...
	poly->fognum = 0;

	// A
	Vector4Set( poly->verts[poly->numverts], xmin, 0, ymin, 1 );
	poly->stcoords[poly->numverts][0] = 0;
	poly->stcoords[poly->numverts][1] = 0;
	poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 );
	poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 );
	poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 );
	poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 );
	poly->numverts++;

	// B
	Vector4Set( poly->verts[poly->numverts], xmin, 0, ymax, 1 );
	poly->stcoords[poly->numverts][0] = 0;
	poly->stcoords[poly->numverts][1] = sty;
	poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 );
	poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 );
	poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 );
	poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 );
	poly->numverts++;

	// C
	Vector4Set( poly->verts[poly->numverts], xmax, 0, ymax, 1 );
	poly->stcoords[poly->numverts][0] = stx;
	poly->stcoords[poly->numverts][1] = sty;
	poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 );
	poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 );
	poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 );
	poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 );
	poly->numverts++;

	// D
	Vector4Set( poly->verts[poly->numverts], xmax, 0, ymin, 1 );
	poly->stcoords[poly->numverts][0] = stx;
	poly->stcoords[poly->numverts][1] = 0;
	poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 );
	poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 );
	poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 );
	poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 );
	poly->numverts++;

	// the verts data is stored inside cgpoly, cause it can be moved later
	for( i = 0; i < poly->numverts; i++ )
		Vector4Copy( poly->verts[i], cgpoly->verts[i] );

	return cgpoly;
}
Esempio n. 16
0
void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo )
{
	// get the texture associated with this surface
	mtexinfo_t	*tex = surf->texinfo;
	vec4_t		textureU, textureV;
	float		*sAxis = NULL;
	float		s, t, w, h;
	decal_t		*decal = surf->pdecals;

	// we in restore mode
	if( cls.state == ca_connected )
	{
		// NOTE: we may have the decal on this surface that come from another level.
		// check duplicate with same position and texture
		while( decal != NULL )
		{
			if( VectorCompare( decal->position, decalinfo->m_Position ) && decal->texture == decalinfo->m_iTexture )
				return; // decal already exists, don't place it again
			decal = decal->pnext;
		}
	}

	Vector4Copy( tex->vecs[0], textureU );
	Vector4Copy( tex->vecs[1], textureV );

	// project decal center into the texture space of the surface
	s = DotProduct( decalinfo->m_Position, textureU ) + textureU[3] - surf->texturemins[0];
	t = DotProduct( decalinfo->m_Position, textureV ) + textureV[3] - surf->texturemins[1];

	// Determine the decal basis (measured in world space)
	// Note that the decal basis vectors 0 and 1 will always lie in the same
	// plane as the texture space basis vectorstextureVecsTexelsPerWorldUnits.

	if( decalinfo->m_Flags & FDECAL_USESAXIS )
		sAxis = decalinfo->m_SAxis;

	R_DecalComputeBasis( surf, sAxis, decalinfo->m_Basis );

	// Compute an effective width and height (axis aligned) in the parent texture space
	// How does this work? decalBasis[0] represents the u-direction (width)
	// of the decal measured in world space, decalBasis[1] represents the 
	// v-direction (height) measured in world space.
	// textureVecsTexelsPerWorldUnits[0] represents the u direction of 
	// the surface's texture space measured in world space (with the appropriate
	// scale factor folded in), and textureVecsTexelsPerWorldUnits[1]
	// represents the texture space v direction. We want to find the dimensions (w,h)
	// of a square measured in texture space, axis aligned to that coordinate system.
	// All we need to do is to find the components of the decal edge vectors
	// (decalWidth * decalBasis[0], decalHeight * decalBasis[1])
	// in texture coordinates:

	w = fabs( decalinfo->m_decalWidth  * DotProduct( textureU, decalinfo->m_Basis[0] )) +
	    fabs( decalinfo->m_decalHeight * DotProduct( textureU, decalinfo->m_Basis[1] ));
	
	h = fabs( decalinfo->m_decalWidth  * DotProduct( textureV, decalinfo->m_Basis[0] )) +
	    fabs( decalinfo->m_decalHeight * DotProduct( textureV, decalinfo->m_Basis[1] ));

	// move s,t to upper left corner
	s -= ( w * 0.5f );
	t -= ( h * 0.5f );

	// Is this rect within the surface? -- tex width & height are unsigned
	if( s <= -w || t <= -h || s > (surf->extents[0] + w) || t > (surf->extents[1] + h))
	{
		return; // nope
	}

	// stamp it
	R_DecalCreate( decalinfo, surf, s, t );
}
Esempio n. 17
0
/*
* FTLIB_DrawClampString
*/
void FTLIB_DrawClampString( int x, int y, const char *str, int xmin, int ymin, int xmax, int ymax, qfontface_t *font, vec4_t color, int flags )
{
	int xoffset = 0;
	vec4_t scolor;
	int colorindex;
	wchar_t num, prev_num = 0;
	const char *s = str, *olds;
	int gc;
	qglyph_t *glyph, *prev_glyph = NULL;
	renderString_f renderString;
	getKerning_f getKerning;
	bool hasKerning;

	if( !str || !font )
		return;
	if( ( xmax <= xmin ) || ( ymax <= ymin ) || ( x > xmax ) || ( y > ymax ) )
		return;

	Vector4Copy( color, scolor );

	renderString = font->f->renderString;
	getKerning = font->f->getKerning;
	hasKerning = ( flags & TEXTDRAWFLAG_KERNING ) && font->hasKerning;

	while( 1 )
	{
		olds = s;
		gc = FTLIB_GrabChar( &s, &num, &colorindex, flags );
		if( gc == GRABCHAR_CHAR )
		{
			if( num == '\n' )
				break;

			if( num < ' ' )
				continue;

			glyph = FTLIB_GetGlyph( font, num );
			if( !glyph )
			{
				num = FTLIB_REPLACEMENT_GLYPH;
				glyph = FTLIB_GetGlyph( font, num );
			}

			if( !glyph->shader )
				renderString( font, olds );

			if( prev_num )
			{
				xoffset += prev_glyph->x_advance;
				if( hasKerning )
					xoffset += getKerning( font, prev_glyph, glyph );
			}

			if( x + xoffset > xmax )
				break;

			FTLIB_DrawClampChar( x + xoffset, y, num, xmin, ymin, xmax, ymax, font, scolor );

			prev_num = num;
			prev_glyph = glyph;
		}
		else if( gc == GRABCHAR_COLOR )
		{
			assert( ( unsigned )colorindex < MAX_S_COLORS );
			VectorCopy( color_table[colorindex], scolor );
		}
		else if( gc == GRABCHAR_END )
			break;
		else
			assert( 0 );
	}
}
Esempio n. 18
0
/**
 * @brief Calculates a per-vertex tangentspace basis and stores it in GL arrays attached to the mesh
 * @param mesh The mesh to calculate normals for
 * @param framenum The animation frame to calculate normals for
 * @param translate The frame translation for the given animation frame
 * @param backlerp Whether to store the results in the GL arrays for the previous keyframe or the next keyframe
 * @sa R_ModCalcUniqueNormalsAndTangents
 */
static void R_ModCalcNormalsAndTangents (mAliasMesh_t *mesh, int framenum, const vec3_t translate, qboolean backlerp)
{
	int i, j;
	mAliasVertex_t *vertexes = &mesh->vertexes[framenum * mesh->num_verts];
	mAliasCoord_t *stcoords = mesh->stcoords;
	const int numIndexes = mesh->num_tris * 3;
	const int32_t *indexArray = mesh->indexes;
	vec3_t triangleNormals[MAX_ALIAS_TRIS];
	vec3_t triangleTangents[MAX_ALIAS_TRIS];
	vec3_t triangleBitangents[MAX_ALIAS_TRIS];
	float *texcoords, *verts, *normals, *tangents;

	/* set up array pointers for either the previous keyframe or the next keyframe */
	texcoords = mesh->texcoords;
	if (backlerp) {
		verts = mesh->verts;
		normals = mesh->normals;
		tangents = mesh->tangents;
	} else {
		verts = mesh->next_verts;
		normals = mesh->next_normals;
		tangents = mesh->next_tangents;
	}

	/* calculate per-triangle surface normals and tangents*/
	for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
		vec3_t dir1, dir2;
		vec2_t dir1uv, dir2uv;

		/* calculate two mostly perpendicular edge directions */
		VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
		VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
		Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
		Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);

		/* we have two edge directions, we can calculate a third vector from
		 * them, which is the direction of the surface normal */
		CrossProduct(dir1, dir2, triangleNormals[j]);
		/* normalize */
		VectorNormalizeFast(triangleNormals[j]);

		/* then we use the texture coordinates to calculate a tangent space */
		if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
			const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
			vec3_t tmp1, tmp2;

			/* calculate tangent */
			VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
			VectorMul(dir1uv[1] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleTangents[j]);

			/* calculate bitangent */
			VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
			VectorMul(dir1uv[0] * frac, dir2, tmp2);
			VectorAdd(tmp1, tmp2, triangleBitangents[j]);

			/* normalize */
			VectorNormalizeFast(triangleTangents[j]);
			VectorNormalizeFast(triangleBitangents[j]);
		} else {
			VectorClear(triangleTangents[j]);
			VectorClear(triangleBitangents[j]);
		}
	}

	/* for each vertex */
	for (i = 0; i < mesh->num_verts; i++) {
		vec3_t n, b, v;
		vec4_t t;
		const int len = mesh->revIndexes[i].length;
		const int32_t *list = mesh->revIndexes[i].list;

		VectorClear(n);
		VectorClear(t);
		VectorClear(b);

		/* for each vertex that got mapped to this one (ie. for each triangle this vertex is a part of) */
		for (j = 0; j < len; j++) {
			const int32_t idx = list[j] / 3;
			VectorAdd(n, triangleNormals[idx], n);
			VectorAdd(t, triangleTangents[idx], t);
			VectorAdd(b, triangleBitangents[idx], b);
		}

		/* normalization here does shared-vertex smoothing */
		VectorNormalizeFast(n);
		VectorNormalizeFast(t);
		VectorNormalizeFast(b);

		/* Grahm-Schmidt orthogonalization */
		Orthogonalize(t, n);

		/* calculate handedness */
		CrossProduct(n, t, v);
		t[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;

		/* copy this vertex's info to all the right places in the arrays */
		for (j = 0; j < len; j++) {
			const int32_t idx = list[j];
			const int meshIndex = mesh->indexes[list[j]];
			Vector2Copy(stcoords[meshIndex], (texcoords + (2 * idx)));
			VectorAdd(vertexes[meshIndex].point, translate, (verts + (3 * idx)));
			VectorCopy(n, (normals + (3 * idx)));
			Vector4Copy(t, (tangents + (4 * idx)));
		}
	}
}
Esempio n. 19
0
void CM_DrawDebugSurface( void ( *drawPoly )( int color, int numPoints, float *points ) ) {
	static cvar_t   *cv;
#ifndef BSPC
	static cvar_t   *cv2;
#endif
	const patchCollide_t    *pc;
	facet_t         *facet;
	winding_t       *w;
	int i, j, k, n;
	int curplanenum, planenum, curinward, inward;
	float plane[4];
	vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28};
	//vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0};
	vec3_t v1, v2;

#ifndef BSPC
	if ( !cv2 ) {
		cv2 = Cvar_Get( "r_debugSurface", "0", 0 );
	}

	if ( cv2->integer != 1 ) {
		BotDrawDebugPolygons( drawPoly, cv2->integer );
		return;
	}
#endif

	if ( !debugPatchCollide ) {
		return;
	}

#ifndef BSPC
	if ( !cv ) {
		cv = Cvar_Get( "cm_debugSize", "2", 0 );
	}
#endif
	pc = debugPatchCollide;

	for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) {

		for ( k = 0 ; k < facet->numBorders + 1; k++ ) {
			//
			if ( k < facet->numBorders ) {
				planenum = facet->borderPlanes[k];
				inward = facet->borderInward[k];
			} else {
				planenum = facet->surfacePlane;
				inward = qfalse;
				//continue;
			}

			Vector4Copy( pc->planes[ planenum ].plane, plane );

			//planenum = facet->surfacePlane;
			if ( inward ) {
				VectorSubtract( vec3_origin, plane, plane );
				plane[3] = -plane[3];
			}

			plane[3] += cv->value;
			//*
			for ( n = 0; n < 3; n++ )
			{
				if ( plane[n] > 0 ) {
					v1[n] = maxs[n];
				} else { v1[n] = mins[n];}
			} //end for
			VectorNegate( plane, v2 );
			plane[3] += Q_fabs( DotProduct( v1, v2 ) );
			//*/

			w = BaseWindingForPlane( plane,  plane[3] );
			for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) {
				//
				if ( j < facet->numBorders ) {
					curplanenum = facet->borderPlanes[j];
					curinward = facet->borderInward[j];
				} else {
					curplanenum = facet->surfacePlane;
					curinward = qfalse;
					//continue;
				}
				//
				if ( curplanenum == planenum ) {
					continue;
				}

				Vector4Copy( pc->planes[ curplanenum ].plane, plane );
				if ( !curinward ) {
					VectorSubtract( vec3_origin, plane, plane );
					plane[3] = -plane[3];
				}
				//			if ( !facet->borderNoAdjust[j] ) {
				plane[3] -= cv->value;
				//			}
				for ( n = 0; n < 3; n++ )
				{
					if ( plane[n] > 0 ) {
						v1[n] = maxs[n];
					} else { v1[n] = mins[n];}
				} //end for
				VectorNegate( plane, v2 );
				plane[3] -= Q_fabs( DotProduct( v1, v2 ) );

				ChopWindingInPlace( &w, plane, plane[3], 0.1f );
			}
			if ( w ) {
				if ( facet == debugFacet ) {
					drawPoly( 4, w->numpoints, w->p[0] );
					//Com_Printf("blue facet has %d border planes\n", facet->numBorders);
				} else {
					drawPoly( 1, w->numpoints, w->p[0] );
				}
				FreeWinding( w );
			} else {
				Com_Printf( "winding chopped away by border planes\n" );
			}
		}
	}

	// draw the debug block
	{
		vec3_t v[3];

		VectorCopy( debugBlockPoints[0], v[0] );
		VectorCopy( debugBlockPoints[1], v[1] );
		VectorCopy( debugBlockPoints[2], v[2] );
		drawPoly( 2, 3, v[0] );

		VectorCopy( debugBlockPoints[2], v[0] );
		VectorCopy( debugBlockPoints[3], v[1] );
		VectorCopy( debugBlockPoints[0], v[2] );
		drawPoly( 2, 3, v[0] );
	}

#if 0
	vec3_t v[4];

	v[0][0] = pc->bounds[1][0];
	v[0][1] = pc->bounds[1][1];
	v[0][2] = pc->bounds[1][2];

	v[1][0] = pc->bounds[1][0];
	v[1][1] = pc->bounds[0][1];
	v[1][2] = pc->bounds[1][2];

	v[2][0] = pc->bounds[0][0];
	v[2][1] = pc->bounds[0][1];
	v[2][2] = pc->bounds[1][2];

	v[3][0] = pc->bounds[0][0];
	v[3][1] = pc->bounds[1][1];
	v[3][2] = pc->bounds[1][2];

	drawPoly( 4, v[0] );
#endif
}
Esempio n. 20
0
void CG_FilledBar(float x, float y, float w, float h, float *startColor, float *endColor, const float *bgColor, float frac, int flags) {
	vec4_t	backgroundcolor = {1, 1, 1, 0.25f}, colorAtPos;	// colorAtPos is the lerped color if necessary
	int indent = BAR_BORDERSIZE;

	if( frac > 1 ) {
		frac = 1.f;
	}
	if( frac < 0 ) {
		frac = 0;
	}

	if((flags&BAR_BG) && bgColor) {	// BAR_BG set, and color specified, use specified bg color
		Vector4Copy(bgColor, backgroundcolor);
	}

	if(flags&BAR_LERP_COLOR) {
		Vector4Average(startColor, endColor, frac, colorAtPos);
	}

	// background
	if((flags&BAR_BG)) {
		// draw background at full size and shrink the remaining box to fit inside with a border.  (alternate border may be specified by a BAR_BGSPACING_xx)
		CG_FillRect (	x,
						y,
						w,
						h,
						backgroundcolor );

		if(flags&BAR_BGSPACING_X0Y0) {			// fill the whole box (no border)

		} else if(flags&BAR_BGSPACING_X0Y5) {	// spacing created for weapon heat
			indent*=3;
			y+=indent;
			h-=(2*indent);

		} else {								// default spacing of 2 units on each side
			x+=indent;
			y+=indent;
			w-=(2*indent);
			h-=(2*indent);
		}
	}


	// adjust for horiz/vertical and draw the fractional box
	if(flags&BAR_VERT) {
		if(flags&BAR_LEFT) {	// TODO: remember to swap colors on the ends here
			y+=(h*(1-frac));
		} else if (flags&BAR_CENTER) {
			y+=(h*(1-frac)/2);
		}

		if(flags&BAR_LERP_COLOR) {
			CG_FillRect ( x, y, w, h * frac, colorAtPos );
		} else {
//			CG_FillRectGradient ( x, y, w, h * frac, startColor, endColor, 0 );
			CG_FillRect ( x, y, w, h * frac, startColor );
		}

	} else {

		if(flags&BAR_LEFT) {	// TODO: remember to swap colors on the ends here
			x+=(w*(1-frac));
		} else if (flags&BAR_CENTER) {
			x+=(w*(1-frac)/2);
		}

		if(flags&BAR_LERP_COLOR) {
			CG_FillRect ( x, y, w*frac, h, colorAtPos );
		} else {
//			CG_FillRectGradient ( x, y, w * frac, h, startColor, endColor, 0 );
			CG_FillRect ( x, y, w*frac, h, startColor );
		}
	}

}
Esempio n. 21
0
/*
=============
CG_Scanner
=============
*/
void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color )
{
  int     i;
  vec3_t  origin;
  vec3_t  relOrigin;
  vec4_t  hIabove;
  vec4_t  hIbelow;
  vec4_t  aIabove = { 1.0f, 0.0f, 0.0f, 0.75f };
  vec4_t  aIbelow = { 1.0f, 0.0f, 0.0f, 0.5f };

  Vector4Copy( color, hIabove );
  hIabove[ 3 ] *= 1.5f;
  Vector4Copy( color, hIbelow );

  VectorCopy( entityPositions.origin, origin );

  //draw human buildables below scanner plane
  for( i = 0; i < entityPositions.numHumanBuildables; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
      CG_DrawBlips( rect, relOrigin, hIbelow );
  }

  //draw alien buildables below scanner plane
  for( i = 0; i < entityPositions.numAlienBuildables; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
      CG_DrawBlips( rect, relOrigin, aIbelow );
  }

  //draw human clients below scanner plane
  for( i = 0; i < entityPositions.numHumanClients; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
      CG_DrawBlips( rect, relOrigin, hIbelow );
  }

  //draw alien buildables below scanner plane
  for( i = 0; i < entityPositions.numAlienClients; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
      CG_DrawBlips( rect, relOrigin, aIbelow );
  }

  if( !cg_disableScannerPlane.integer )
  {
    trap_R_SetColor( color );
    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
    trap_R_SetColor( NULL );
  }

  //draw human buildables above scanner plane
  for( i = 0; i < entityPositions.numHumanBuildables; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
      CG_DrawBlips( rect, relOrigin, hIabove );
  }

  //draw alien buildables above scanner plane
  for( i = 0; i < entityPositions.numAlienBuildables; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
      CG_DrawBlips( rect, relOrigin, aIabove );
  }

  //draw human clients above scanner plane
  for( i = 0; i < entityPositions.numHumanClients; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
      CG_DrawBlips( rect, relOrigin, hIabove );
  }

  //draw alien clients above scanner plane
  for( i = 0; i < entityPositions.numAlienClients; i++ )
  {
    VectorClear( relOrigin );
    VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );

    if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
      CG_DrawBlips( rect, relOrigin, aIabove );
  }
}
Esempio n. 22
0
/*
* CG_AddParticles
*/
void CG_AddParticles( void ) {
	int i, j, k;
	float alpha;
	float time, time2;
	vec3_t org;
	vec3_t corner;
	byte_vec4_t color;
	int maxparticle, activeparticles;
	float alphaValues[MAX_PARTICLES];
	cparticle_t *p, *free_particles[MAX_PARTICLES];

	if( !cg_numparticles ) {
		return;
	}

	j = 0;
	maxparticle = -1;
	activeparticles = 0;

	for( i = 0, p = particles; i < cg_numparticles; i++, p++ ) {
		time = ( cg.time - p->time ) * 0.001f;
		alpha = alphaValues[i] = p->alpha + time * p->alphavel;

		if( alpha <= 0 ) { // faded out
			free_particles[j++] = p;
			continue;
		}

		maxparticle = i;
		activeparticles++;

		time2 = time * time * 0.5f;

		org[0] = p->org[0] + p->vel[0] * time + p->accel[0] * time2;
		org[1] = p->org[1] + p->vel[1] * time + p->accel[1] * time2;
		org[2] = p->org[2] + p->vel[2] * time + p->accel[2] * time2;

		color[0] = (uint8_t)( bound( 0, p->color[0], 1.0f ) * 255 );
		color[1] = (uint8_t)( bound( 0, p->color[1], 1.0f ) * 255 );
		color[2] = (uint8_t)( bound( 0, p->color[2], 1.0f ) * 255 );
		color[3] = (uint8_t)( bound( 0, alpha, 1.0f ) * 255 );

		corner[0] = org[0];
		corner[1] = org[1] - 0.5f * p->scale;
		corner[2] = org[2] - 0.5f * p->scale;

		Vector4Set( p->pVerts[0], corner[0], corner[1] + p->scale, corner[2] + p->scale, 1 );
		Vector4Set( p->pVerts[1], corner[0], corner[1], corner[2] + p->scale, 1 );
		Vector4Set( p->pVerts[2], corner[0], corner[1], corner[2], 1 );
		Vector4Set( p->pVerts[3], corner[0], corner[1] + p->scale, corner[2], 1 );
		for( k = 0; k < 4; k++ ) {
			Vector4Copy( color, p->pColor[k] );
		}

		p->poly.numverts = 4;
		p->poly.verts = p->pVerts;
		p->poly.stcoords = p->pStcoords;
		p->poly.colors = p->pColor;
		p->poly.fognum = p->fog ? 0 : -1;
		p->poly.shader = ( p->shader == NULL ) ? CG_MediaShader( cgs.media.shaderParticle ) : p->shader;

		trap_R_AddPolyToScene( &p->poly );
	}

	i = 0;
	while( maxparticle >= activeparticles ) {
		*free_particles[i++] = particles[maxparticle--];

		while( maxparticle >= activeparticles ) {
			if( alphaValues[maxparticle] <= 0 ) {
				maxparticle--;
			} else {
				break;
			}
		}
	}

	cg_numparticles = activeparticles;
}
Esempio n. 23
0
/*
** CG_DrawChat
*/
void CG_DrawChat( cg_gamechat_t *chat, int x, int y, char *fontName, struct qfontface_s *font, int fontSize,
				  int width, int height, int padding_x, int padding_y, vec4_t backColor, struct shader_s *backShader ) {
	int i, j;
	int s, e, w;
	int utf_len;
	int l, total_lines, lines;
	int x_offset, y_offset;
	int font_height;
	int pass;
	int lastcolor;
	int message_mode;
	int wait_time, fade_time;
	const cg_gamemessage_t *msg;
	const char *text;
	char tstr[GAMECHAT_STRING_SIZE];
	vec4_t fontColor;
	bool chat_active = false;
	bool background_drawn = false;
	int corner_radius = 12 * cgs.vidHeight / 600;
	int background_y;
	int first_candidate;

	font_height = trap_SCR_FontHeight( font );
	message_mode = (int)trap_Cvar_Value( "con_messageMode" );
	chat_active = ( chat->lastMsgTime + GAMECHAT_WAIT_IN_TIME + GAMECHAT_FADE_IN_TIME > cg.realTime || message_mode );
	lines = 0;
	total_lines = /*!message_mode ? 0 : */ 1;

	if( chat_active ) {
		wait_time = GAMECHAT_WAIT_IN_TIME;
		fade_time = GAMECHAT_FADE_IN_TIME;
	} else {
		wait_time = GAMECHAT_WAIT_OUT_TIME;
		fade_time = GAMECHAT_FADE_OUT_TIME;
	}

	if( chat_active != chat->lastActive ) {
		// smooth fade ins and fade outs
		chat->lastActiveChangeTime = cg.realTime - ( 1.0 - chat->activeFrac ) * ( wait_time + fade_time );
	}

	if( cg.realTime >= chat->lastActiveChangeTime + wait_time ) {
		int time_diff, time_interval;

		time_diff = cg.realTime - ( chat->lastActiveChangeTime + wait_time );
		time_interval = fade_time;

		if( time_diff <= time_interval ) {
			chat->activeFrac = (float)time_diff / time_interval;
		} else {
			chat->activeFrac = 1;
		}
	} else {
		chat->activeFrac = 0;
	}

	if( chat_active ) {
		backColor[3] *= chat->activeFrac;
	} else {
		backColor[3] *= ( 1.0 - chat->activeFrac );
	}

	for( i = 0; i < GAMECHAT_STACK_SIZE; i++ ) {
		bool old_msg;

		l = chat->nextMsg - 1 - i;
		if( l < 0 ) {
			l = GAMECHAT_STACK_SIZE + l;
		}

		msg = &chat->messages[l];
		text = msg->text;
		old_msg = !message_mode && ( cg.realTime > msg->time + GAMECHAT_NOTIFY_TIME );

		if( !background_drawn && backColor[3] ) {
			if( old_msg ) {
				// keep the box being drawn for a while to prevent it from flickering
				// upon arrival of the possibly entered chat message
				if( !( !chat_active && cg.realTime <= chat->lastActiveChangeTime + 200 ) ) {
					break;
				}
			}

			background_y = y;
			trap_R_DrawStretchPic( x, background_y, width, height - corner_radius,
								   0.0f, 0.0f, 1.0f, 0.5f, backColor, backShader );
			background_y += height - corner_radius;

			if( trap_IN_IME_GetCandidates( NULL, 0, 10, NULL, &first_candidate ) ) {
				int candidates_height = ( first_candidate ? 3 : 5 ) * font_height;
				trap_R_DrawStretchPic( x, background_y, width, candidates_height,
									   0.0f, 0.5f, 1.0f, 0.5f, backColor, backShader );
				background_y += candidates_height;
			}

			trap_R_DrawStretchPic( x, background_y, corner_radius, corner_radius,
								   0.0f, 0.5f, 0.5f, 1.0f, backColor, backShader );
			trap_R_DrawStretchPic( x + corner_radius, background_y, width - corner_radius * 2, corner_radius,
								   0.5f, 0.5f, 0.5f, 1.0f, backColor, backShader );
			trap_R_DrawStretchPic( x + width - corner_radius, background_y, corner_radius, corner_radius,
								   0.5f, 0.5f, 1.0f, 1.0f, backColor, backShader );

			background_drawn = true;
		}

		// unless user is typing something, only display recent messages
		if( old_msg ) {
			break;
		}

		pass = 0;
		lines = 0;
		lastcolor = ColorIndex( COLOR_WHITE );

parse_string:
		l = 1;
		s = e = 0;
		while( 1 ) {
			int len;

			memset( tstr, 0, sizeof( tstr ) );

			// skip whitespaces at start
			for( ; text[s] == '\n' || Q_IsBreakingSpace( text + s ); s = Q_Utf8SyncPos( text, s + 1, UTF8SYNC_RIGHT ) ) ;

			// empty string
			if( !text[s] ) {
				break;
			}

			w = -1;
			len = trap_SCR_StrlenForWidth( text + s, font, width - padding_x * 2 );
			clamp_low( len, 1 );

			for( j = s; ( j < ( s + len ) ) && text[j] != '\0'; j += utf_len ) {
				utf_len = Q_Utf8SyncPos( text + j, 1, UTF8SYNC_RIGHT );
				memcpy( tstr + j - s, text + j, utf_len );

				if( text[j] == '\n' || Q_IsBreakingSpace( text + j ) ) {
					w = j; // last whitespace
				}
				if( text[j] == '\n' ) {
					break;
				}
			}
			e = j; // end

			// try to word avoid splitting words, unless no other options
			if( text[j] != '\0' && w > 0 ) {
				// stop at the last encountered whitespace
				j = w;
			}

			tstr[j - s] = '\0';

			Vector4Copy( color_table[lastcolor], fontColor );
			fontColor[3] = chat_active ? chat->activeFrac : 1.0 - chat->activeFrac;

			if( pass ) {
				// now actually render the line
				x_offset = padding_x;
				y_offset = height - padding_y - font_height - ( total_lines + lines - l ) * ( font_height + 2 );
				if( y_offset < padding_y ) {
					break;
				}

				trap_SCR_DrawClampString( x + x_offset, y + y_offset, tstr,
										  x + padding_x, y + padding_y, x - padding_x + width, y - padding_y + height, font, fontColor );

				l++;
			} else {
				// increase the lines counter
				lines++;
			}

			if( !text[j] ) {
				// fast path: we don't need two passes in case of one-liners..
				if( lines == 1 ) {
					x_offset = padding_x;
					y_offset = height - font_height - total_lines * ( font_height + 2 );
					if( y_offset < padding_y ) {
						break;
					}

					trap_SCR_DrawClampString( x + x_offset, y + y_offset, tstr,
											  x + padding_x, y + padding_y, x - padding_x + width, y - padding_y + height, font, fontColor );

					total_lines++;
					pass++;
				}
				break;
			}

			if( pass ) {
				// grab the last color token to carry it over to the next line
				lastcolor = Q_ColorStrLastColor( lastcolor, tstr, j - s );
			}

			s = j;
		}

		if( !pass ) {
			pass++;
			goto parse_string;
		} else {
			total_lines += lines;
		}
	}

	// let the engine know where the input line should be drawn
	trap_SCR_DrawChat( x + padding_x, y + height - padding_y - font_height, width - padding_x, font );

	chat->lastActive = chat_active;
}
Esempio n. 24
0
/*
* CG_AddFragmentedDecal
*/
void CG_AddFragmentedDecal( vec3_t origin, vec3_t dir, float orient, float radius,
							float r, float g, float b, float a, struct shader_s *shader ) {
	int i, j, c;
	vec3_t axis[3];
	byte_vec4_t color;
	fragment_t *fr, fragments[MAX_TEMPDECAL_FRAGMENTS];
	int numfragments;
	poly_t poly;
	vec4_t verts[MAX_BLOBSHADOW_VERTS];
	static vec4_t t_verts[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS];
	static vec4_t t_norms[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS];
	static vec2_t t_stcoords[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS];
	static byte_vec4_t t_colors[MAX_TEMPDECAL_VERTS * MAX_TEMPDECALS];

	if( radius <= 0 || VectorCompare( dir, vec3_origin ) ) {
		return; // invalid

	}

	// calculate orientation matrix
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orient );
	CrossProduct( axis[0], axis[2], axis[1] );

	numfragments = trap_R_GetClippedFragments( origin, radius, axis, // clip it
											   MAX_BLOBSHADOW_VERTS, verts, MAX_TEMPDECAL_FRAGMENTS, fragments );

	// no valid fragments
	if( !numfragments ) {
		return;
	}

	// clamp and scale colors
	if( r < 0 ) {
		r = 0;
	} else if( r > 1 ) {
		r = 255;
	} else {
		r *= 255;
	}
	if( g < 0 ) {
		g = 0;
	} else if( g > 1 ) {
		g = 255;
	} else {
		g *= 255;
	}
	if( b < 0 ) {
		b = 0;
	} else if( b > 1 ) {
		b = 255;
	} else {
		b *= 255;
	}
	if( a < 0 ) {
		a = 0;
	} else if( a > 1 ) {
		a = 255;
	} else {
		a *= 255;
	}

	color[0] = ( uint8_t )( r );
	color[1] = ( uint8_t )( g );
	color[2] = ( uint8_t )( b );
	color[3] = ( uint8_t )( a );
	c = *( int * )color;

	radius = 0.5f / radius;
	VectorScale( axis[1], radius, axis[1] );
	VectorScale( axis[2], radius, axis[2] );

	memset( &poly, 0, sizeof( poly ) );

	for( i = 0, fr = fragments; i < numfragments; i++, fr++ ) {
		if( fr->numverts <= 0 ) {
			continue;
		}
		if( cg_numDecalVerts + (unsigned)fr->numverts > sizeof( t_verts ) / sizeof( t_verts[0] ) ) {
			return;
		}

		poly.shader = shader;
		poly.verts = &t_verts[cg_numDecalVerts];
		poly.normals = &t_norms[cg_numDecalVerts];
		poly.stcoords = &t_stcoords[cg_numDecalVerts];
		poly.colors = &t_colors[cg_numDecalVerts];
		poly.numverts = fr->numverts;
		poly.fognum = fr->fognum;
		cg_numDecalVerts += (unsigned)fr->numverts;

		for( j = 0; j < fr->numverts; j++ ) {
			vec3_t v;

			Vector4Copy( verts[fr->firstvert + j], poly.verts[j] );
			VectorCopy( axis[0], poly.normals[j] ); poly.normals[j][3] = 0;
			VectorSubtract( poly.verts[j], origin, v );
			poly.stcoords[j][0] = DotProduct( v, axis[1] ) + 0.5f;
			poly.stcoords[j][1] = DotProduct( v, axis[2] ) + 0.5f;
			*( int * )poly.colors[j] = c;
		}

		trap_R_AddPolyToScene( &poly );
	}
}
void CG_BuildableStatusParse( const char *filename, buildStat_t *bs )
{
  pc_token_t token;
  int        handle;
  const char *s;
  int        i;
  float      f;
  vec4_t     c;

  handle = trap_Parse_LoadSource( filename );
  if( !handle )
    return;
  while( 1 )
  {
    if( !trap_Parse_ReadToken( handle, &token ) )
      break;
    if( !Q_stricmp( token.string, "frameShader" ) )
    {
      if( PC_String_Parse( handle, &s ) )
        bs->frameShader = trap_R_RegisterShader( s );
      continue;
    }
    else if( !Q_stricmp( token.string, "overlayShader" ) )
    {
      if( PC_String_Parse( handle, &s ) )
        bs->overlayShader = trap_R_RegisterShader( s );
      continue;
    }
    else if( !Q_stricmp( token.string, "noPowerShader" ) )
    {
      if( PC_String_Parse( handle, &s ) )
        bs->noPowerShader = trap_R_RegisterShader( s );
      continue;
    }
    else if( !Q_stricmp( token.string, "markedShader" ) )
    {
      if( PC_String_Parse( handle, &s ) )
        bs->markedShader = trap_R_RegisterShader( s );
      continue;
    }
    else if( !Q_stricmp( token.string, "healthSevereColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->healthSevereColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "healthHighColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->healthHighColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "healthElevatedColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->healthElevatedColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "healthGuardedColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->healthGuardedColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "healthLowColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->healthLowColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "foreColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->foreColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "backColor" ) )
    {
      if( PC_Color_Parse( handle, &c ) )
        Vector4Copy( c, bs->backColor );
      continue;
    }
    else if( !Q_stricmp( token.string, "frameHeight" ) )
    {
      if( PC_Int_Parse( handle, &i ) )
        bs->frameHeight = i;
      continue;
    }
    else if( !Q_stricmp( token.string, "frameWidth" ) )
    {
      if( PC_Int_Parse( handle, &i ) )
        bs->frameWidth = i;
      continue;
    }
    else if( !Q_stricmp( token.string, "healthPadding" ) )
    {
      if( PC_Int_Parse( handle, &i ) )
        bs->healthPadding = i;
      continue;
    }
    else if( !Q_stricmp( token.string, "overlayHeight" ) )
    {
      if( PC_Int_Parse( handle, &i ) )
        bs->overlayHeight = i;
      continue;
    }
    else if( !Q_stricmp( token.string, "overlayWidth" ) )
    {
      if( PC_Int_Parse( handle, &i ) )
        bs->overlayWidth = i;
      continue;
    }
    else if( !Q_stricmp( token.string, "verticalMargin" ) )
    {
      if( PC_Float_Parse( handle, &f ) )
        bs->verticalMargin = f;
      continue;
    }
    else if( !Q_stricmp( token.string, "horizontalMargin" ) )
    {
      if( PC_Float_Parse( handle, &f ) )
        bs->horizontalMargin = f;
      continue;
    }
    else
    {
      Com_Printf("CG_BuildableStatusParse: unknown token %s in %s\n",
        token.string, filename );
      bs->loaded = qfalse;
      return;
    }
  }
  bs->loaded = qtrue;
}
Esempio n. 26
0
/*
==================
CM_AddFacetBevels
==================
*/
static void CM_AddFacetBevels( facet_t *facet ) {

	int i, j, k, l;
	int axis, dir, order;
	float plane[4], d, newplane[4];
	winding_t *w, *w2;
	vec3_t mins, maxs, vec, vec2;

	Vector4Copy( planes[ facet->surfacePlane ].plane, plane );

	w = BaseWindingForPlane( plane,  plane[3] );
	for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
		if (facet->borderPlanes[j] == facet->surfacePlane) continue;
		Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );

		if ( !facet->borderInward[j] ) {
			VectorSubtract( vec3_origin, plane, plane );
			plane[3] = -plane[3];
		}

		ChopWindingInPlace( &w, plane, plane[3], 0.1f );
	}
	if ( !w ) {
		return;
	}

	WindingBounds(w, mins, maxs);

	// add the axial planes
	order = 0;
	qbool flipped;
	for ( axis = 0 ; axis < 3 ; axis++ )
	{
		for ( dir = -1 ; dir <= 1 ; dir += 2, order++ )
		{
			VectorClear(plane);
			plane[axis] = dir;
			plane[3] = (dir == 1) ? maxs[axis] : -mins[axis];

			//if it's the surface plane
			if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
				continue;
			}
			// see if the plane is allready present
			for ( i = 0 ; i < facet->numBorders ; i++ ) {
				if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped))
					break;
			}

			if ( i == facet->numBorders ) {
				if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
				facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
				facet->borderNoAdjust[facet->numBorders] = qfalse;
				facet->borderInward[facet->numBorders] = flipped;
				facet->numBorders++;
			}
		}
	}
	//
	// add the edge bevels
	//
	// test the non-axial plane edges
	for ( j = 0 ; j < w->numpoints ; j++ )
	{
		k = (j+1)%w->numpoints;
		VectorSubtract (w->p[j], w->p[k], vec);
		//if it's a degenerate edge
		if (VectorNormalize (vec) < 0.5)
			continue;
		CM_SnapVector(vec);
		for ( k = 0; k < 3 ; k++ )
			if ( vec[k] == -1 || vec[k] == 1 )
				break;	// axial
		if ( k < 3 )
			continue;	// only test non-axial edges

		// try the six possible slanted axials from this edge
		for ( axis = 0 ; axis < 3 ; axis++ )
		{
			for ( dir = -1 ; dir <= 1 ; dir += 2 )
			{
				// construct a plane
				VectorClear (vec2);
				vec2[axis] = dir;
				CrossProduct (vec, vec2, plane);
				if (VectorNormalize (plane) < 0.5)
					continue;
				plane[3] = DotProduct (w->p[j], plane);

				// if all the points of the facet winding are
				// behind this plane, it is a proper edge bevel
				for ( l = 0 ; l < w->numpoints ; l++ )
				{
					d = DotProduct (w->p[l], plane) - plane[3];
					if (d > 0.1)
						break;	// point in front
				}
				if ( l < w->numpoints )
					continue;

				//if it's the surface plane
				if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
					continue;
				}
				// see if the plane is allready present
				for ( i = 0 ; i < facet->numBorders ; i++ ) {
					if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) {
							break;
					}
				}

				if ( i == facet->numBorders ) {
					if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
					facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);

					for ( k = 0 ; k < facet->numBorders ; k++ ) {
						if (facet->borderPlanes[facet->numBorders] ==
							facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n");
					}

					facet->borderNoAdjust[facet->numBorders] = qfalse;
					facet->borderInward[facet->numBorders] = flipped;

					w2 = CopyWinding(w);
					Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane);
					if (!facet->borderInward[facet->numBorders])
					{
						VectorNegate(newplane, newplane);
						newplane[3] = -newplane[3];
					}
					ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
					if (!w2) {
						Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
						continue;
					}
					else {
						FreeWinding(w2);
					}

					facet->numBorders++;
					//already got a bevel
//					break;
				}
			}
		}
	}
	FreeWinding( w );

#ifndef BSPC
	//add opposite plane
	facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
	facet->borderNoAdjust[facet->numBorders] = qfalse;
	facet->borderInward[facet->numBorders] = qtrue;
	facet->numBorders++;
#endif //BSPC

}
Esempio n. 27
0
/*
* SCR_DrawPlayerTab
*/
static int SCR_DrawPlayerTab( const char **ptrptr, int team, int x, int y, int panelWidth, struct qfontface_s *font, int pass )
{
	int dir, align, i, columncount;
	char type, string[MAX_STRING_CHARS];
	const char *token, *layout;
	int height, width, xoffset, yoffset;
	vec4_t teamcolor = { 0.0f, 0.0f, 0.0f, 1.0f }, color;
	int iconnum;
	struct shader_s *icon;
	bool highlight = false, trans = false;

	if( GS_TeamBasedGametype() )
	{
		dir = ( team == TEAM_ALPHA ) ? -1 : 1;
		align = ( team == TEAM_ALPHA ) ? ALIGN_RIGHT_TOP : ALIGN_LEFT_TOP;
	}
	else
	{
		dir = 0;
		align = ALIGN_CENTER_TOP;
	}

	xoffset = 0;
	yoffset = 0;

	height = trap_SCR_FontHeight( font );

	// start from the center again
	xoffset = CG_HorizontalAlignForWidth( 0, align, panelWidth );
	xoffset += ( SCB_CENTERMARGIN * dir );

	// draw the background
	columncount = 0;
	if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) )
		CG_TeamColor( team, teamcolor );

	// draw the player tab column titles
	layout = cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT];

	while( SCR_GetNextColumnLayout( &layout, NULL, &type, &width, font ) != NULL )
	{
		// grab the actual scoreboard data
		if( !SCR_ParseToken( ptrptr, &token ) )
			break;

		if( SCR_SkipColumn( type ) )
			continue;

		Vector4Copy( colorWhite, color ); // reset to white after each column
		icon = NULL;
		string[0] = 0;

		// interpret the data based on the type defined in the layout
		switch( type )
		{
		default:
			CG_Error( "SCR_DrawPlayerTab: Invalid player tab layout\n" );
			break;

		case 's': // is a string
			{
				char l10n[MAX_STRING_CHARS];
				Q_strncpyz( string, CG_TranslateColoredString( token, l10n, sizeof( l10n ) ), sizeof( string ) );
			}
			break;

		case 'n': // is a player name indicated by player number
			i = atoi( token );

			if( i < 0 ) // negative numbers toggle transparency on
			{
				trans = true;
				i = -1 - i;
			}

			if( i < 0 || i >= gs.maxclients )
				Q_strncpyz( string, "invalid", sizeof( string ) );
			else
				Q_strncpyz( string, cgs.clientInfo[i].name, sizeof( string ) );

			if( ISVIEWERENTITY( i + 1 ) ) // highlight if it's our own player
				highlight = true;

			break;
		case 'i': // is a integer (negatives are colored in red)
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%i", i );
			VectorCopy( i >= 0 ? colorWhite : colorRed, color );
			break;

		case 'f': // is a float
			Q_snprintfz( string, sizeof( string ), "%.2f", atof( token ) );
			break;

		case 'l': // p is an integer colored in latency style
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%i", i );
			CG_PingColor( i, color );
			break;

		case 'b': // is a Y/N boolean
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%s", CG_TranslateString( ( i != 0 ) ? "Yes" : "No" ) );
			VectorCopy( i ? colorGreen : colorRed, color );
			break;

		case 'p': // is a picture. It uses height for width to get a square
			iconnum = atoi( token );
			if( ( iconnum > 0 ) && ( iconnum < MAX_IMAGES ) )
				icon = cgs.imagePrecache[iconnum];
			break;

		case 't': // is a race time. Convert time into MM:SS:mm
			{
				unsigned int milli, min, sec;

				milli = (unsigned int)( atoi( token ) );
				if( !milli )
					Q_snprintfz( string, sizeof( string ), CG_TranslateString( "no time" ) );
				else
				{
					min = milli / 60000;
					milli -= min * 60000;
					sec = milli / 1000;
					milli -= sec * 1000;
					Q_snprintfz( string, sizeof( string ), va( "%02i:%02i.%03i", min, sec, milli ) );
				}
			}
			break;

		case 'r': // is a ready state tick that is hidden when not in warmup
			if( atoi( token ) )
				icon = CG_MediaShader( cgs.media.shaderVSayIcon[VSAY_YES] );
			break;
		}

		if( !width )
			continue;

		// draw the column background
		teamcolor[3] = SCB_BACKGROUND_ALPHA;
		if( columncount & 1 )
			teamcolor[3] -= 0.15;

		if( highlight )
			teamcolor[3] += 0.3;

		if( trans )
			color[3] = 0.3;

		if( !pass ) {
			trap_R_DrawStretchPic( x + xoffset, y + yoffset, width, height, 0, 0, 1, 1, teamcolor, cgs.shaderWhite );

			if( icon )
				SCR_AddPlayerIcon( icon, x + xoffset, y + yoffset, color[3], font );
		}

		// draw the column value
		if( pass && string[0] )
		{
			trap_SCR_DrawClampString( x + xoffset, y + yoffset, string,
				x + xoffset, y + yoffset,
				x + xoffset + width, y + yoffset + height, font, color );
		}

		columncount++;

		xoffset += width;
	}

	yoffset += height;
	return yoffset;
}
Esempio n. 28
0
//================
//CG_DrawMiniMap
//================
void CG_DrawMiniMap( int x, int y, int iw, int ih, qboolean draw_playernames, qboolean draw_itemnames, int align, vec4_t color )
{
	int i, entnum;
	centity_t *cent;
	vec3_t coords;
	vec4_t tmp_col, tmp_white_alpha, tmp_yellow_alpha;		// background color of the map
	vec3_t mins, maxs, extend;
	int map_w, map_h, map_z;
	int x_lefttop, y_lefttop, z_lefttop;	// the negative y coordinate (bottom of the map)
	float map_div_w, map_div_h;
	qboolean isSelf;

	if( !cg_showminimap->integer )
		return;

	// if inside a team
	if( cg.predictedPlayerState.stats[STAT_REALTEAM] >= TEAM_PLAYERS && cg.predictedPlayerState.stats[STAT_REALTEAM] < GS_MAX_TEAMS )
	{
		if( !GS_CanShowMinimap() || !( cg_showminimap->integer & 1 ) )
			return;
	}
	else if( !( cg_showminimap->integer & 2 ) )
	{
		// allow only when chasing a player and the player is allowed to see it
		if( !GS_CanShowMinimap() || !( cg_showminimap->integer & 1 ) ||
			cg.predictedPlayerState.stats[STAT_REALTEAM] == cg.predictedPlayerState.stats[STAT_TEAM] )
			return;
	}

	if( !cgs.shaderMiniMap )
		return;

	x = CG_HorizontalAlignForWidth( x, align, iw );
	y = CG_VerticalAlignForHeight( y, align, ih );

	Vector4Copy( color, tmp_col );
	Vector4Copy( colorWhite, tmp_white_alpha );
	Vector4Copy( colorYellow, tmp_yellow_alpha );
	tmp_white_alpha[3] = color[3];
	tmp_yellow_alpha[3] = color[3];

	// Get Worldmodel bounds...
	trap_R_ModelBounds( NULL, mins, maxs ); // NULL for world model...

	// make it a square bounding box
	VectorSubtract( maxs, mins, extend );
	if( extend[1] > extend[0] )
	{
		mins[0] -= ( extend[1] - extend[0] ) * 0.5;
		maxs[0] += ( extend[1] - extend[0] ) * 0.5;
	}
	else
	{
		mins[1] -= ( extend[0] - extend[1] ) * 0.5;
		maxs[1] += ( extend[0] - extend[1] ) * 0.5;
	}

	map_w = maxs[0] - mins[0];      // map width (in game units)
	map_h = maxs[1] - mins[1];
	map_z = maxs[2] - mins[2];
	x_lefttop = -mins[0];   // the negative x coordinate ( left of the map )
	y_lefttop = -mins[1];   // the negative y coordinate (bottom of the map)
	z_lefttop = -mins[2];   // the negative y coordinate (bottom of the map)

	map_div_w = (float)map_w / (float)iw;
	map_div_h = (float)map_h / (float)ih;

	CG_DrawHUDRect( x, y, ALIGN_LEFT_TOP, iw, ih, 1, 1, tmp_col, cgs.shaderMiniMap );

	//alignment test, to display green dot at 0,0
	//CG_DrawHUDRect( x + x_lefttop/map_div_w -1, y + y_lefttop/map_div_h -1,ALIGN_LEFT_TOP,3,3,1,1, colorGreen, CG_MediaShader( cgs.media.shaderMiniMap ) );

	for( i = 0; i < cg.frame.numEntities; i++ )
	{
		entnum = cg.frame.parsedEntities[i&( MAX_PARSE_ENTITIES-1 )].number;

		// filter invalid ents
		if( entnum < 1 || entnum >= MAX_EDICTS )
			continue;

		// retrieve the centity_t
		cent = &cg_entities[entnum];
		isSelf = ( (unsigned)entnum == cg.predictedPlayerState.POVnum );

		if( ( cent->current.type != ET_PLAYER ) 
			&& ( cent->current.type != ET_MINIMAP_ICON )
			&& !( cent->item ) )
			continue;

		if( isSelf )
			VectorCopy( cg.predictedPlayerState.pmove.origin, coords );
		else
			VectorCopy( cent->current.origin, coords );

		coords[0] = ( coords[0] + x_lefttop ) / map_div_w;
		coords[1] = ih - ( coords[1] + y_lefttop ) / map_div_h;
		coords[2] = ( coords[2] + (float)z_lefttop ) / (float)map_z;

		// is it a player?
		if( ( cent->current.type == ET_PLAYER ) )
		{
			int box_size = (int)( 3.0 + coords[2] * 10.0 );

			// check if we're allowed to see team members only (coaches, CA)
			if( cg.predictedPlayerState.stats[STAT_LAYOUTS] & STAT_LAYOUT_SPECTEAMONLY ||
				(cg.predictedPlayerState.stats[STAT_REALTEAM] != TEAM_SPECTATOR && GS_TeamOnlyMinimap()) )
			{
				if( cg.predictedPlayerState.stats[STAT_REALTEAM] != cent->current.team )
					continue;
			}

			if( cent->current.team == TEAM_SPECTATOR )
			{
				if( entnum != cg.view.POVent )
					continue;
				VectorSet( tmp_col, 1, 1, 1 );
			}
			else
			{
				CG_TeamColor( cent->current.team, tmp_col );
			}

			// get color
			tmp_col[3] = bound( 0, color[3] + 0.3f, 1 );
			CG_DrawHUDRect( x + (int)coords[0] -box_size/2, y + (int)coords[1] -box_size/2,
				ALIGN_LEFT_TOP, box_size, box_size, box_size, box_size, tmp_col, NULL );

			// differentiate ourselves with an arrow
			if( isSelf )
			{
				int thisX, thisY, thisSize;

				thisSize = max( box_size, 8 );
				thisX = CG_VerticalAlignForHeight( x + (int)coords[0], ALIGN_CENTER_MIDDLE, thisSize );
				thisY = CG_VerticalAlignForHeight( y + (int)coords[1] - thisSize, ALIGN_CENTER_MIDDLE, thisSize );
				trap_R_DrawStretchPic( thisX, thisY, thisSize, thisSize, 0, 0, 1, 1, tmp_yellow_alpha, CG_MediaShader( cgs.media.shaderDownArrow ) );
			}

			// do we want names too?
			if( draw_playernames == qtrue )
				trap_SCR_DrawString( x + (int)coords[0] + 8,
				y + (int)coords[1] - 4,	ALIGN_LEFT_TOP,	COM_RemoveColorTokensExt( cgs.clientInfo[cent->current.number-1].name, qtrue ),
				cgs.fontSystemSmall, tmp_yellow_alpha );
		}
		else if( cent->current.type == ET_MINIMAP_ICON )
		{
			if( cent->ent.customShader )
			{
				vec4_t tmp_this_color;
				int thisX, thisY, thisSize;

				thisSize = (float)cent->prev.frame + (float)( cent->current.frame - cent->prev.frame ) * cg.lerpfrac;
				if( thisSize <= 0 )
					thisSize = 18;

				tmp_this_color[0] = (float)cent->ent.shaderRGBA[0] / 255.0f;
				tmp_this_color[1] = (float)cent->ent.shaderRGBA[1] / 255.0f;
				tmp_this_color[2] = (float)cent->ent.shaderRGBA[2] / 255.0f;
				tmp_this_color[3] = 1.0f;

				thisX = CG_VerticalAlignForHeight( x + coords[0], ALIGN_CENTER_MIDDLE, thisSize );
				thisY = CG_VerticalAlignForHeight( y + coords[1], ALIGN_CENTER_MIDDLE, thisSize );
				trap_R_DrawStretchPic( thisX, thisY, thisSize, thisSize, 0, 0, 1, 1, tmp_this_color, cent->ent.customShader );
			}
		}
		else if( cent->item && cent->item->icon )
		{
			// if ALIGN_CENTER_MIDDLE or something is used, images are f****d
			// so thats why they are set manually at the correct pos with -n
			CG_DrawHUDRect( x+(int)coords[0]-8, y+(int)coords[1]-8, ALIGN_LEFT_TOP, 15, 15, 1, 1, tmp_white_alpha, trap_R_RegisterPic( cent->item->icon ) );
			if( draw_itemnames == qtrue )
				trap_SCR_DrawString( x + (int)coords[0] + 16, y + (int)coords[1] - 8, ALIGN_LEFT_TOP, cent->item->shortname, cgs.fontSystemSmall, tmp_yellow_alpha );
		}
	}
}
Esempio n. 29
0
/*
====================
CM_TraceThroughPatchCollide
====================
*/
void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
	int i, j, hit, hitnum;
	float offset, enterFrac, leaveFrac, t;
	patchPlane_t *planes;
	facet_t *facet;
	float plane[4] = {0, 0, 0, 0}, bestplane[4] = {0, 0, 0, 0};
	vec3_t startp, endp;
#ifndef BSPC
	static cvar_t *cv;
#endif //BSPC

	if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
				pc->bounds[0], pc->bounds[1] ) ) {
		return;
	}

	if ( tw->isPoint ) {
		CM_TracePointThroughPatchCollide( tw, pc );
		return;
	}

	facet = pc->facets;
	for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
		enterFrac = -1.0;
		leaveFrac = 1.0;
		hitnum = -1;
		//
		planes = &pc->planes[ facet->surfacePlane ];
		VectorCopy( planes->plane, plane );
		plane[3] = planes->plane[3];
		if ( tw->sphere.use ) {
			// adjust the plane distance apropriately for radius
			plane[3] += tw->sphere.radius;

			// find the closest point on the capsule to the plane
			t = DotProduct( plane, tw->sphere.offset );
			if ( t > 0.0f ) {
				VectorSubtract( tw->start, tw->sphere.offset, startp );
				VectorSubtract( tw->end, tw->sphere.offset, endp );
			} else {
				VectorAdd( tw->start, tw->sphere.offset, startp );
				VectorAdd( tw->end, tw->sphere.offset, endp );
			}
		} else {
			offset = DotProduct( tw->offsets[ planes->signbits ], plane );
			plane[3] -= offset;
			VectorCopy( tw->start, startp );
			VectorCopy( tw->end, endp );
		}

		if ( !CM_CheckFacetPlane( plane, startp, endp, &enterFrac, &leaveFrac, &hit ) ) {
			continue;
		}
		if ( hit ) {
			Vector4Copy( plane, bestplane );
		}

		for ( j = 0; j < facet->numBorders; j++ ) {
			planes = &pc->planes[ facet->borderPlanes[j] ];
			if ( facet->borderInward[j] ) {
				VectorNegate( planes->plane, plane );
				plane[3] = -planes->plane[3];
			} else {
				VectorCopy( planes->plane, plane );
				plane[3] = planes->plane[3];
			}
			if ( tw->sphere.use ) {
				// adjust the plane distance apropriately for radius
				plane[3] += tw->sphere.radius;

				// find the closest point on the capsule to the plane
				t = DotProduct( plane, tw->sphere.offset );
				if ( t > 0.0f ) {
					VectorSubtract( tw->start, tw->sphere.offset, startp );
					VectorSubtract( tw->end, tw->sphere.offset, endp );
				} else {
					VectorAdd( tw->start, tw->sphere.offset, startp );
					VectorAdd( tw->end, tw->sphere.offset, endp );
				}
			} else {
				// NOTE: this works even though the plane might be flipped because the bbox is centered
				offset = DotProduct( tw->offsets[ planes->signbits ], plane );
				plane[3] += fabs( offset );
				VectorCopy( tw->start, startp );
				VectorCopy( tw->end, endp );
			}

			if ( !CM_CheckFacetPlane( plane, startp, endp, &enterFrac, &leaveFrac, &hit ) ) {
				break;
			}
			if ( hit ) {
				hitnum = j;
				Vector4Copy( plane, bestplane );
			}
		}
		if ( j < facet->numBorders ) {
			continue;
		}
		//never clip against the back side
		if ( hitnum == facet->numBorders - 1 ) {
			continue;
		}

		if ( enterFrac < leaveFrac && enterFrac >= 0 ) {
			if ( enterFrac < tw->trace.fraction ) {
				if ( enterFrac < 0 ) {
					enterFrac = 0;
				}
#ifndef BSPC
				if ( !cv ) {
					cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
				}
				if ( cv && cv->integer ) {
					debugPatchCollide = pc;
					debugFacet = facet;
				}
#endif //BSPC

				tw->trace.fraction = enterFrac;
				VectorCopy( bestplane, tw->trace.plane.normal );
				tw->trace.plane.dist = bestplane[3];
			}
		}
	}
}
Esempio n. 30
0
qbyte *_ColorForEntity( int entNum, byte_vec4_t color, qboolean player )
{
	centity_t *cent;
	int team;
	centity_t *owner;
	cvar_t *teamForceColor = NULL;
	int rgbcolor;
	int *forceColor;

	if( entNum < 1 || entNum >= MAX_EDICTS )
	{
		Vector4Set( color, 255, 255, 255, 255 );
		return color;
	}

	owner = cent = &cg_entities[entNum];
	if( cent->current.type == ET_CORPSE && cent->current.bodyOwner ) // it's a body
		owner = &cg_entities[cent->current.bodyOwner];

	team = CG_ForceTeam( owner->current.number, owner->current.team );

	switch( team )
	{
	case TEAM_ALPHA:
		{
			teamForceColor = cg_teamALPHAcolor;
			forceColor = &cgs.teamColor[TEAM_ALPHA];
		}
		break;
	case TEAM_BETA:
		{
			teamForceColor = cg_teamBETAcolor;
			forceColor = &cgs.teamColor[TEAM_BETA];
		}
		break;

	case TEAM_PLAYERS:
	default:
		{
			teamForceColor = cg_teamPLAYERScolor;
			forceColor = &cgs.teamColor[TEAM_PLAYERS];
		}
		break;
	}

	if( teamForceColor->modified )
	{
		CG_RegisterTeamColor( team );
	}

	//if forced models is enabled or it is color forced team we do,
	if( (teamForceColor->string[0] || team >= TEAM_ALPHA) && cent->current.type != ET_CORPSE )
	{
		// skin color to team color
		rgbcolor = *forceColor;
		Vector4Set( color, COLOR_R( rgbcolor ), COLOR_G( rgbcolor ), COLOR_B( rgbcolor ), 255 );
	}
	// user defined colors if it's a player
	else if( ( player && ( owner->current.number - 1 < gs.maxclients ) ) && cent->current.type != ET_CORPSE )
	{
		Vector4Copy( cgs.clientInfo[owner->current.number - 1].color, color );
	} 
	// Make corpses grey
	else if ( cent->current.type == ET_CORPSE && cent->current.bodyOwner ) 
	{
		Vector4Set( color, 60, 60, 60, 60 );
	}
	else // white for everything else
	{
		Vector4Set( color, 255, 255, 255, 255 );
	}

	return color;
}