//----------------------------------------------------------------------------- // Purpose: // Input : pMaterial - // source - // color - //----------------------------------------------------------------------------- void DrawHaloOriented( const Vector& source, float scale, float const *color, float roll ) { Vector point, screen; CMatRenderContextPtr pRenderContext( materials ); IMesh* pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); // Transform source into screen space ScreenTransform( source, screen ); Vector right, up; float sr, cr; SinCos( roll, &sr, &cr ); for ( int i = 0; i < 3; i++ ) { right[i] = CurrentViewRight()[i] * cr + CurrentViewUp()[i] * sr; up[i] = CurrentViewRight()[i] * -sr + CurrentViewUp()[i] * cr; } meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 0, 1); VectorMA (source, -scale, up, point); VectorMA (point, -scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 0, 0); VectorMA (source, scale, up, point); VectorMA (point, -scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 1, 0); VectorMA (source, scale, up, point); VectorMA (point, scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 1, 1); VectorMA (source, -scale, up, point); VectorMA (point, scale, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); }
//----------------------------------------------------------------------------- // Purpose: // Input : pMaterial - // source - // color - //----------------------------------------------------------------------------- void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale ) { static unsigned int nHDRColorScaleCache = 0; Vector point, screen; if( pMaterial ) { IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache ); if( pHDRColorScaleVar ) { pHDRColorScaleVar->SetFloatValue( flHDRColorScale ); } } CMatRenderContextPtr pRenderContext( materials ); IMesh* pMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); // Transform source into screen space ScreenTransform( source, screen ); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 0, 1); VectorMA (source, -scale, CurrentViewUp(), point); VectorMA (point, -scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 0, 0); VectorMA (source, scale, CurrentViewUp(), point); VectorMA (point, -scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 1, 0); VectorMA (source, scale, CurrentViewUp(), point); VectorMA (point, scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color3fv (color); meshBuilder.TexCoord2f (0, 1, 1); VectorMA (source, -scale, CurrentViewUp(), point); VectorMA (point, scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); }
float PixelVisibility_DrawProxy( IMatRenderContext *pRenderContext, OcclusionQueryObjectHandle_t queryHandle, Vector origin, float scale, float proxyAspect, IMaterial *pMaterial, bool screenspace ) { Vector point; // don't expand this with distance to fit pixels or the sprite will poke through // only expand the parts perpendicular to the view float forwardScale = scale; // draw a pyramid of points touching a sphere of radius "scale" at origin float pixelsPerUnit = pRenderContext->ComputePixelDiameterOfSphere( origin, 1.0f ); pixelsPerUnit = MAX( pixelsPerUnit, 1e-4f ); if ( screenspace ) { // Force this to be the size of a sphere of diameter "scale" at some reference distance (1.0 unit) float pixelsPerUnit2 = pRenderContext->ComputePixelDiameterOfSphere( CurrentViewOrigin() + CurrentViewForward()*1.0f, scale*0.5f ); // force drawing of "scale" pixels scale = pixelsPerUnit2 / pixelsPerUnit; } else { float pixels = scale * pixelsPerUnit; // make the radius larger to ensure a minimum screen space size of the proxy geometry if ( pixels < MIN_PROXY_PIXELS ) { scale = MIN_PROXY_PIXELS / pixelsPerUnit; } } // collapses the pyramid to a plane - so this could be a quad instead Vector dir = origin - CurrentViewOrigin(); VectorNormalize(dir); origin -= dir * forwardScale; forwardScale = 0.0f; // Vector verts[5]; const float sqrt2 = 0.707106781f; // sqrt(2) - keeps all vectors the same length from origin scale *= sqrt2; float scale45x = scale; float scale45y = scale / proxyAspect; verts[0] = origin - CurrentViewForward() * forwardScale; // the apex of the pyramid verts[1] = origin + CurrentViewUp() * scale45y - CurrentViewRight() * scale45x; // these four form the base verts[2] = origin + CurrentViewUp() * scale45y + CurrentViewRight() * scale45x; // the pyramid is a sprite with a point that verts[3] = origin - CurrentViewUp() * scale45y + CurrentViewRight() * scale45x; // pokes back toward the camera through any nearby verts[4] = origin - CurrentViewUp() * scale45y - CurrentViewRight() * scale45x; // geometry // get screen coords of edges Vector screen[4]; for ( int i = 0; i < 4; i++ ) { extern int ScreenTransform( const Vector& point, Vector& screen ); if ( ScreenTransform( verts[i+1], screen[i] ) ) return -1; } // compute area and screen-clipped area float w = screen[1].x - screen[0].x; float h = screen[0].y - screen[3].y; float ws = MIN(1.0f, screen[1].x) - MAX(-1.0f, screen[0].x); float hs = MIN(1.0f, screen[0].y) - MAX(-1.0f, screen[3].y); float area = w*h; // area can be zero when we ALT-TAB float areaClipped = ws*hs; float ratio = 0.0f; if ( area != 0 ) { // compute the ratio of the area not clipped by the frustum to total area ratio = areaClipped / area; ratio = clamp(ratio, 0.0f, 1.0f); } pRenderContext->BeginOcclusionQueryDrawing( queryHandle ); CMeshBuilder meshBuilder; IMesh* pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, pMaterial ); meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 4 ); // draw a pyramid for ( int i = 0; i < 4; i++ ) { int a = i+1; int b = (a%4)+1; meshBuilder.Position3fv( verts[0].Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( verts[a].Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( verts[b].Base() ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); pMesh->Draw(); // sprite/quad proxy #if 0 meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); VectorMA (origin, -scale, CurrentViewUp(), point); VectorMA (point, -scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); VectorMA (origin, scale, CurrentViewUp(), point); VectorMA (point, -scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); VectorMA (origin, scale, CurrentViewUp(), point); VectorMA (point, scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); VectorMA (origin, -scale, CurrentViewUp(), point); VectorMA (point, scale, CurrentViewRight(), point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); #endif pRenderContext->EndOcclusionQueryDrawing( queryHandle ); // fraction clipped by frustum return ratio; }
//----------------------------------------------------------------------------- // Purpose: Determine sprite orientation axes // Input : type - // forward - // right - // up - //----------------------------------------------------------------------------- void C_SpriteRenderer::GetSpriteAxes( SPRITETYPE type, const Vector& origin, const QAngle& angles, Vector& forward, Vector& right, Vector& up ) { int i; float dot, angle, sr, cr; Vector tvec; // Automatically roll parallel sprites if requested if ( angles[2] != 0 && type == SPR_VP_PARALLEL ) { type = SPR_VP_PARALLEL_ORIENTED; } switch( type ) { case SPR_FACING_UPRIGHT: { // generate the sprite's axes, with vup straight up in worldspace, and // r_spritedesc.vright perpendicular to modelorg. // This will not work if the view direction is very close to straight up or // down, because the cross product will be between two nearly parallel // vectors and starts to approach an undefined state, so we don't draw if // the two vectors are less than 1 degree apart tvec[0] = -origin[0]; tvec[1] = -origin[1]; tvec[2] = -origin[2]; VectorNormalize (tvec); dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because // r_spritedesc.vup is 0, 0, 1 if ((dot > 0.999848f) || (dot < -0.999848f)) // cos(1 degree) = 0.999848 return; up[0] = 0; up[1] = 0; up[2] = 1; right[0] = tvec[1]; // CrossProduct(r_spritedesc.vup, -modelorg, right[1] = -tvec[0]; // r_spritedesc.vright) right[2] = 0; VectorNormalize (right); forward[0] = -right[1]; forward[1] = right[0]; forward[2] = 0; // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, // r_spritedesc.vpn) } break; case SPR_VP_PARALLEL: { // generate the sprite's axes, completely parallel to the viewplane. There // are no problem situations, because the sprite is always in the same // position relative to the viewer for (i=0 ; i<3 ; i++) { up[i] = CurrentViewUp()[i]; right[i] = CurrentViewRight()[i]; forward[i] = CurrentViewForward()[i]; } } break; case SPR_VP_PARALLEL_UPRIGHT: { // generate the sprite's axes, with g_vecVUp straight up in worldspace, and // r_spritedesc.vright parallel to the viewplane. // This will not work if the view direction is very close to straight up or // down, because the cross product will be between two nearly parallel // vectors and starts to approach an undefined state, so we don't draw if // the two vectors are less than 1 degree apart dot = CurrentViewForward()[2]; // same as DotProduct (vpn, r_spritedesc.g_vecVUp) because // r_spritedesc.vup is 0, 0, 1 if ((dot > 0.999848f) || (dot < -0.999848f)) // cos(1 degree) = 0.999848 return; up[0] = 0; up[1] = 0; up[2] = 1; right[0] = CurrentViewForward()[1]; // CrossProduct (r_spritedesc.vup, vpn, right[1] = -CurrentViewForward()[0]; // r_spritedesc.vright) right[2] = 0; VectorNormalize (right); forward[0] = -right[1]; forward[1] = right[0]; forward[2] = 0; // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, // r_spritedesc.vpn) } break; case SPR_ORIENTED: { // generate the sprite's axes, according to the sprite's world orientation AngleVectors( angles, &forward, &right, &up ); } break; case SPR_VP_PARALLEL_ORIENTED: { // generate the sprite's axes, parallel to the viewplane, but rotated in // that plane around the center according to the sprite entity's roll // angle. So vpn stays the same, but vright and vup rotate angle = angles[ROLL] * (M_PI*2.0f/360.0f); SinCos( angle, &sr, &cr ); for (i=0 ; i<3 ; i++) { forward[i] = CurrentViewForward()[i]; right[i] = CurrentViewRight()[i] * cr + CurrentViewUp()[i] * sr; up[i] = CurrentViewRight()[i] * -sr + CurrentViewUp()[i] * cr; } } break; default: Warning( "GetSpriteAxes: Bad sprite type %d\n", type ); break; } }
static void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ) { unsigned char pColor[4] = { color.r, color.g, color.b, color.a }; // Generate half-widths flWidth *= 0.5f; flHeight *= 0.5f; // Compute direction vectors for the sprite Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 ); VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd ); float flDist = VectorNormalize( fwd ); if (flDist >= 1e-3) { CrossProduct( CurrentViewUp(), fwd, right ); flDist = VectorNormalize( right ); if (flDist >= 1e-3) { CrossProduct( fwd, right, up ); } else { // In this case, fwd == g_vecVUp, it's right above or // below us in screen space CrossProduct( fwd, CurrentViewRight(), up ); VectorNormalize( up ); CrossProduct( up, fwd, right ); } } Vector left = -right; Vector down = -up; Vector back = -fwd; CMeshBuilder meshBuilder; Vector point; IMesh* pMesh = materials->GetDynamicMesh( ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 0, 1); VectorMA (vecOrigin, -flHeight, up, point); VectorMA (point, -flWidth, right, point); meshBuilder.TangentS3fv( left.Base() ); meshBuilder.TangentT3fv( down.Base() ); meshBuilder.Normal3fv( back.Base() ); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 0, 0); VectorMA (vecOrigin, flHeight, up, point); VectorMA (point, -flWidth, right, point); meshBuilder.TangentS3fv( left.Base() ); meshBuilder.TangentT3fv( down.Base() ); meshBuilder.Normal3fv( back.Base() ); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 1, 0); VectorMA (vecOrigin, flHeight, up, point); VectorMA (point, flWidth, right, point); meshBuilder.TangentS3fv( left.Base() ); meshBuilder.TangentT3fv( down.Base() ); meshBuilder.Normal3fv( back.Base() ); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 1, 1); VectorMA (vecOrigin, -flHeight, up, point); VectorMA (point, flWidth, right, point); meshBuilder.TangentS3fv( left.Base() ); meshBuilder.TangentT3fv( down.Base() ); meshBuilder.Normal3fv( back.Base() ); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); }
//----------------------------------------------------------------------------- // Purpose: // Input : noise_divisions - // *prgNoise - // *spritemodel - // frame - // rendermode - // source - // delta - // flags - // *color - // fadescale - //----------------------------------------------------------------------------- void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, float frame, int rendermode, const Vector& source, const Vector& delta, float startWidth, float endWidth, float scale, float freq, float speed, int segments, int flags, float* color, float fadeLength, float flHDRColorScale ) { int i, noiseIndex, noiseStep; float div, length, fraction, factor, vLast, vStep, brightness; Assert( fadeLength >= 0.0f ); CEngineSprite *pSprite = Draw_SetSpriteTexture( spritemodel, frame, rendermode ); if ( !pSprite ) return; if ( segments < 2 ) return; IMaterial *pMaterial = pSprite->GetMaterial( (RenderMode_t)rendermode ); if( pMaterial ) { static unsigned int nHDRColorScaleCache = 0; IMaterialVar *pHDRColorScaleVar = pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache ); if( pHDRColorScaleVar ) { pHDRColorScaleVar->SetFloatValue( flHDRColorScale ); } } length = VectorLength( delta ); float flMaxWidth = MAX(startWidth, endWidth) * 0.5f; div = 1.0 / (segments-1); if ( length*div < flMaxWidth * 1.414 ) { // Here, we have too many segments; we could get overlap... so lets have less segments segments = (int)(length / (flMaxWidth * 1.414)) + 1; if ( segments < 2 ) { segments = 2; } } if ( segments > noise_divisions ) // UNDONE: Allow more segments? { segments = noise_divisions; } div = 1.0 / (segments-1); length *= 0.01; // UNDONE: Expose texture length scale factor to control "fuzziness" if ( flags & FBEAM_NOTILE ) { // Don't tile vStep = div; } else { // Texture length texels per space pixel vStep = length*div; } // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam vLast = fmod(freq*speed,1); // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) if ( flags & FBEAM_SINENOISE ) { if ( segments < 16 ) { segments = 16; div = 1.0 / (segments-1); } scale *= 100; length = segments * (1.0/10); } else { scale *= length; } // Iterator to resample noise waveform (it needs to be generated in powers of 2) noiseStep = (int)((float)(noise_divisions-1) * div * 65536.0f); noiseIndex = 0; if ( flags & FBEAM_SINENOISE ) { noiseIndex = 0; } brightness = 1.0; if ( flags & FBEAM_SHADEIN ) { brightness = 0; } // What fraction of beam should be faded Assert( fadeLength >= 0.0f ); float fadeFraction = fadeLength/ delta.Length(); // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST! fadeFraction = clamp(fadeFraction,1.e-6f,1.f); // Choose two vectors that are perpendicular to the beam Vector perp1; ComputeBeamPerpendicular( delta, &perp1 ); // Specify all the segments. CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); CBeamSegDraw segDraw; segDraw.Start( pRenderContext, segments, NULL ); for ( i = 0; i < segments; i++ ) { Assert( noiseIndex < (noise_divisions<<16) ); BeamSeg_t curSeg; curSeg.m_flAlpha = 1; fraction = i * div; // Fade in our out beam to fadeLength if ( (flags & FBEAM_SHADEIN) && (flags & FBEAM_SHADEOUT) ) { if (fraction < 0.5) { brightness = 2*(fraction/fadeFraction); } else { brightness = 2*(1.0 - (fraction/fadeFraction)); } } else if ( flags & FBEAM_SHADEIN ) { brightness = fraction/fadeFraction; } else if ( flags & FBEAM_SHADEOUT ) { brightness = 1.0 - (fraction/fadeFraction); } // clamps if (brightness < 0 ) { brightness = 0; } else if (brightness > 1) { brightness = 1; } VectorScale( *((Vector*)color), brightness, curSeg.m_vColor ); // UNDONE: Make this a spline instead of just a line? VectorMA( source, fraction, delta, curSeg.m_vPos ); // Distort using noise if ( scale != 0 ) { factor = prgNoise[noiseIndex>>16] * scale; if ( flags & FBEAM_SINENOISE ) { float s, c; SinCos( fraction*M_PI*length + freq, &s, &c ); VectorMA( curSeg.m_vPos, factor * s, CurrentViewUp(), curSeg.m_vPos ); // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal VectorMA( curSeg.m_vPos, factor * c, CurrentViewRight(), curSeg.m_vPos ); } else { VectorMA( curSeg.m_vPos, factor, perp1, curSeg.m_vPos ); } } // Specify the next segment. if( endWidth == startWidth ) { curSeg.m_flWidth = startWidth * 2; } else { curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2; } curSeg.m_flTexCoord = vLast; segDraw.NextSeg( &curSeg ); vLast += vStep; // Advance texture scroll (v axis only) noiseIndex += noiseStep; }