diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vgui2/vgui_surfacelib/FontEffects.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'vgui2/vgui_surfacelib/FontEffects.cpp')
| -rw-r--r-- | vgui2/vgui_surfacelib/FontEffects.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/vgui2/vgui_surfacelib/FontEffects.cpp b/vgui2/vgui_surfacelib/FontEffects.cpp new file mode 100644 index 0000000..9acea90 --- /dev/null +++ b/vgui2/vgui_surfacelib/FontEffects.cpp @@ -0,0 +1,241 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Font effects that operate on linear rgba data +// +//=====================================================================================// + +#include "tier0/platform.h" +#include <tier0/dbg.h> +#include <math.h> +#include "FontEffects.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: Adds center line to font +//----------------------------------------------------------------------------- +void ApplyRotaryEffectToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, bool bRotary ) +{ + if ( !bRotary ) + return; + + int y = rgbaTall * 0.5; + + unsigned char *line = &rgba[(y * rgbaWide) * 4]; + + // Draw a line down middle + for (int x = 0; x < rgbaWide; x++, line+=4) + { + line[0] = 127; + line[1] = 127; + line[2] = 127; + line[3] = 255; + } +} + +//----------------------------------------------------------------------------- +// Purpose: adds scanlines to the texture +//----------------------------------------------------------------------------- +void ApplyScanlineEffectToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iScanLines ) +{ + if ( iScanLines < 2 ) + return; + + float scale; + scale = 0.7f; + + // darken all the areas except the scanlines + for (int y = 0; y < rgbaTall; y++) + { + // skip the scan lines + if (y % iScanLines == 0) + continue; + + unsigned char *pBits = &rgba[(y * rgbaWide) * 4]; + + // darken the other lines + for (int x = 0; x < rgbaWide; x++, pBits += 4) + { + pBits[0] *= scale; + pBits[1] *= scale; + pBits[2] *= scale; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: adds a dropshadow the the font texture +//----------------------------------------------------------------------------- +void ApplyDropShadowToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iDropShadowOffset ) +{ + if ( !iDropShadowOffset ) + return; + + // walk the original image from the bottom up + // shifting it down and right, and turning it black (the dropshadow) + for (int y = rgbaTall - 1; y >= iDropShadowOffset; y--) + { + for (int x = rgbaWide - 1; x >= iDropShadowOffset; x--) + { + unsigned char *dest = &rgba[(x + (y * rgbaWide)) * 4]; + if (dest[3] == 0) + { + // there is nothing in this spot, copy in the dropshadow + unsigned char *src = &rgba[(x - iDropShadowOffset + ((y - iDropShadowOffset) * rgbaWide)) * 4]; + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + dest[3] = src[3]; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: adds an outline to the font texture +//----------------------------------------------------------------------------- +void ApplyOutlineToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iOutlineSize ) +{ + if ( !iOutlineSize ) + return; + + int x, y; + for( y = 0; y < rgbaTall; y++ ) + { + for( x = 0; x < rgbaWide; x++ ) + { + unsigned char *src = &rgba[(x + (y * rgbaWide)) * 4]; + if( src[3] == 0 ) + { + // We have a valid font texel. Make all the alpha == 0 neighbors black. + int shadowX, shadowY; + for( shadowX = -(int)iOutlineSize; shadowX <= (int)iOutlineSize; shadowX++ ) + { + for( shadowY = -(int)iOutlineSize; shadowY <= (int)iOutlineSize; shadowY++ ) + { + if( shadowX == 0 && shadowY == 0 ) + { + continue; + } + int testX, testY; + testX = shadowX + x; + testY = shadowY + y; + if( testX < 0 || testX >= rgbaWide || + testY < 0 || testY >= rgbaTall ) + { + continue; + } + unsigned char *test = &rgba[(testX + (testY * rgbaWide)) * 4]; + if( test[0] != 0 && test[1] != 0 && test[2] != 0 && test[3] != 0 ) + { + src[0] = 0; + src[1] = 0; + src[2] = 0; + src[3] = 255; + } + } + } + } + } + } +} + +namespace +{ + + unsigned char CalculatePixelBlur(const unsigned char* src, int nStride, const float* distribution, int nValues) + { + float accum = 0.0; + for ( int n = 0; n != nValues; ++n ) + { + accum += distribution[n]*static_cast<float>(src[n*nStride]); + } + + return static_cast<unsigned char>(accum); + } + +} + +//----------------------------------------------------------------------------- +// Purpose: blurs the texture +//----------------------------------------------------------------------------- +void ApplyGaussianBlurToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int nBlur ) +{ + if ( !nBlur ) + return; + + // generate the gaussian field + float *pGaussianDistribution = (float*) stackalloc( (nBlur*2+1) * sizeof(float) ); + double sigma = 0.683 * nBlur; + for (int x = 0; x <= (nBlur * 2); x++) + { + int val = x - nBlur; + pGaussianDistribution[x] = (float)( 1.0f / sqrt(2 * 3.14 * sigma * sigma)) * pow(2.7, -1 * (val * val) / (2 * sigma * sigma)); + } + + // alloc a new buffer + unsigned char *src = (unsigned char *) stackalloc( rgbaWide * rgbaTall * 4); + + // copy in + memcpy(src, rgba, rgbaWide * rgbaTall * 4); + + //make an initial horizontal pass + for ( int x = 0; x < rgbaWide; x++ ) + { + const float* dist = pGaussianDistribution; + int nValues = nBlur*2 + 1; + int nOffset = 0; + if ( x < nBlur ) + { + nOffset += nBlur - x; + dist += nOffset; + nValues -= nOffset; + } + + if ( x >= rgbaWide - nBlur ) + { + nValues = rgbaWide - (x - nOffset); + } + + for ( int y = 0; y < rgbaTall; y++ ) + { + const unsigned char* read_from = src + (y*rgbaWide + x + nOffset - nBlur)*4 + 3; + unsigned char* dst = rgba + (y*rgbaWide + x)*4; + unsigned char alpha = CalculatePixelBlur(read_from, 4, dist, nValues); + dst[0] = dst[1] = dst[2] = alpha > 0 ? 255 : 0; + dst[3] = alpha; + } + } + + // refresh the source buffer for a second vertical pass + memcpy(src, rgba, rgbaWide * rgbaTall * 4); + + for ( int y = 0; y < rgbaTall; y++ ) + { + const float* dist = pGaussianDistribution; + int nValues = nBlur*2 + 1; + int nOffset = 0; + if ( y < nBlur ) + { + nOffset += nBlur - y; + dist += nOffset; + nValues -= nOffset; + } + + if ( y >= rgbaTall - nBlur ) + { + nValues = rgbaTall - (y - nOffset); + } + + for ( int x = 0; x < rgbaWide; x++ ) + { + const unsigned char* read_from = src + ((y + nOffset - nBlur)*rgbaWide + x)*4 + 3; + unsigned char* dst = rgba + (y*rgbaWide + x)*4; + unsigned char alpha = CalculatePixelBlur(read_from, 4*rgbaWide, dist, nValues); + dst[0] = dst[1] = dst[2] = alpha > 0 ? 255 : 0; + dst[3] = alpha; + } + } +} |