diff options
Diffstat (limited to 'hammer/clipcode.cpp')
| -rw-r--r-- | hammer/clipcode.cpp | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/hammer/clipcode.cpp b/hammer/clipcode.cpp new file mode 100644 index 0000000..d3bcc14 --- /dev/null +++ b/hammer/clipcode.cpp @@ -0,0 +1,348 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "stdafx.h" +#include "IEditorTexture.h" +#include "MapFace.h" +#include "clipcode.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +static float g_vert[MAX_CLIPVERT][VERTEXSIZE]; +static int g_outCount; + + +// Quick and dirty sutherland Hodgman clipper +// Clip polygon to decal in texture space +// JAY: This code is lame, change it later. It does way too much work per frame +// It can be made to recursively call the clipping code and only copy the vertex list once +int Inside( float *vert, int edge ) +{ + switch( edge ) { + case 0: // left + if ( vert[3] > 0.0 ) + return 1; + return 0; + case 1: // right + if ( vert[3] < 1.0 ) + return 1; + return 0; + + case 2: // top + if ( vert[4] > 0.0 ) + return 1; + return 0; + + case 3: + if ( vert[4] < 1.0 ) + return 1; + return 0; + } + return 0; +} + + +void Intersect( float *one, float *two, int edge, float *out ) +{ + float t; + + // t is the parameter of the line between one and two clipped to the edge + // or the fraction of the clipped point between one & two + // vert[3] is u + // vert[4] is v + // vert[0], vert[1], vert[2] is X, Y, Z + if ( edge < 2 ) { + if ( edge == 0 ) { // left + t = ( (one[3] - 0) / (one[3] - two[3]) ); + out[3] = 0; + } + else { // right + t = ( (one[3] - 1) / (one[3] - two[3]) ); + out[3] = 1; + } + out[4] = one[4] + (two[4] - one[4]) * t; + } + else { + if ( edge == 2 ) { // top + t = ( (one[4] - 0) / (one[4] - two[4]) ); + out[4] = 0; + } + else { // bottom + t = ( (one[4] - 1) / (one[4] - two[4]) ); + out[4] = 1; + } + out[3] = one[3] + (two[3] - one[3]) * t; + } + out[0] = one[0] + (two[0] - one[0]) * t; + out[1] = one[1] + (two[1] - one[1]) * t; + out[2] = one[2] + (two[2] - one[2]) * t; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *vert - +// vertCount - +// *out - +// outSize - +// edge - +// Output : int +//----------------------------------------------------------------------------- +int SHClip( float *vert, int vertCount, float *out, int outSize, int edge ) +{ + int j, outCount; + float *s, *p; + + outCount = 0; + + s = &vert[ (vertCount-1) * VERTEXSIZE ]; + for ( j = 0; j < vertCount; j++ ) { + p = &vert[ j * VERTEXSIZE ]; + if ( Inside( p, edge ) ) { + if ( Inside( s, edge ) ) { + // Add a vertex and advance out to next vertex + memcpy( out, p, sizeof(float)*VERTEXSIZE ); + outCount++; + out += VERTEXSIZE; + } + else { + Intersect( s, p, edge, out ); + out += VERTEXSIZE; + outCount++; + memcpy( out, p, sizeof(float)*VERTEXSIZE ); + outCount++; + out += VERTEXSIZE; + } + } + else { + if ( Inside( s, edge ) ) { + Intersect( p, s, edge, out ); + out += VERTEXSIZE; + outCount++; + } + } + + if (outCount >= outSize) + { + Assert(FALSE); + break; + } + + s = p; + } + + return outCount; +} + + +#define SIN_45_DEGREES ( 0.70710678118654752440084436210485f ) + +// The world coordinate system is right handed with Z up. +// +// ^ Z +// | +// | +// | +//X<----| +// \ +// \ +// \ Y + +//----------------------------------------------------------------------------- +// compute the decal basis based on surface normal, and preferred saxis +//----------------------------------------------------------------------------- + +static void R_DecalComputeBasis( Vector const& surfaceNormal, Vector const* pSAxis, + bool flipNormal, Vector* textureSpaceBasis ) +{ + // s, t, textureSpaceNormal (T cross S = textureSpaceNormal(N)) + // N + // \ + // \ + // \ + // |---->S + // | + // | + // |T + // S = textureSpaceBasis[0] + // T = textureSpaceBasis[1] + // N = textureSpaceBasis[2] + + // Get the surface normal. + textureSpaceBasis[2] = surfaceNormal; + if (flipNormal) + VectorNegate( textureSpaceBasis[2] ); + + if (pSAxis) + { + // T = S cross N + CrossProduct( *pSAxis, textureSpaceBasis[2], textureSpaceBasis[1] ); + + // Name sure they aren't parallel or antiparallel + // In that case, fall back to the normal algorithm. + if ( DotProduct( textureSpaceBasis[1], textureSpaceBasis[1] ) > 1e-6 ) + { + // S = N cross T + CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] ); + + VectorNormalize( textureSpaceBasis[0] ); + VectorNormalize( textureSpaceBasis[1] ); + return; + } + + // Fall through to the standard algorithm for parallel or antiparallel + } + + // floor/ceiling? + if( fabs( surfaceNormal[2] ) > SIN_45_DEGREES ) + { + textureSpaceBasis[0][0] = 1.0f; + textureSpaceBasis[0][1] = 0.0f; + textureSpaceBasis[0][2] = 0.0f; + + // T = S cross N + CrossProduct( textureSpaceBasis[0], textureSpaceBasis[2], textureSpaceBasis[1] ); + + // S = N cross T + CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] ); + } + // wall + else + { + textureSpaceBasis[1][0] = 0.0f; + textureSpaceBasis[1][1] = 0.0f; + textureSpaceBasis[1][2] = -1.0f; + + // S = N cross T + CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] ); + // T = S cross N + CrossProduct( textureSpaceBasis[0], textureSpaceBasis[2], textureSpaceBasis[1] ); + } + + VectorNormalize( textureSpaceBasis[0] ); + VectorNormalize( textureSpaceBasis[1] ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Clips a texture to a face. Used for decal application. +// NOTE : HL and HL2 generate texcoords for decals differently!!! +// Input : pFace - +// pDecalTex - +// org - +// pOutPoints - +// Output : Returns the number of points places in the pOutPoints array. +//----------------------------------------------------------------------------- +int CreateClippedPoly(CMapFace *pFace, IEditorTexture *pDecalTex, Vector& org, vec5_t *pOutPoints, int nOutSize) +{ + float outvert[MAX_CLIPVERT][VERTEXSIZE]; + Assert(nOutSize <= MAX_CLIPVERT); // This code uses temp buffers of this size. + +/*#ifdef SDK_BUILD + BUG: THIS IS THE HL1 VERSION! SWITCH BETWEEN THESE ALGORITHMS AT RUNTIME + Vector vecOrg, vecSAxis, vecTAxis; + + // Copy the origin. + vecOrg = org; + + // Get the U/V axes for this face. + vecSAxis = pFace->texture.UAxis; + vecTAxis = pFace->texture.VAxis; + + float decalwidth = pDecalTex->GetWidth(); + float decalheight = pDecalTex->GetHeight(); + + float scale = 1.0f; + IEditorTexture *pFaceTex = pFace->GetTexture(); + float scalex = scale * (float)pFaceTex->GetWidth() / decalwidth; + float scaley = scale * (float)pFaceTex->GetHeight() / decalheight; + + float u = DotProduct(vecSAxis, vecOrg); + float v = DotProduct(vecTAxis, vecOrg); + + u -= decalwidth / 2; + v -= decalheight / 2; + + u /= pFaceTex->GetWidth(); + v /= pFaceTex->GetHeight(); + + // Generate texture coordinates for each vertex in decal s,t space + Vector *pVertex = pFace->Points; + float curU, curV; + for (int j = 0; j < pFace->nPoints; j++, pVertex++) + { + // Copy X, Y, & Z + g_vert[j][0] = pVertex[0][0]; + g_vert[j][1] = pVertex[0][1]; + g_vert[j][2] = pVertex[0][2]; + + // Get u, v coordinates of vertex in DECAL SPACE + curU = DotProduct(vecSAxis, *pVertex) / pFaceTex->GetWidth(); + curV = DotProduct(vecTAxis, *pVertex) / pFaceTex->GetHeight(); + + // Generate U & V + g_vert[j][3] = (curU - u) * scalex; // Decal relative texture coordinates + g_vert[j][4] = (curV - v) * scaley; + } +#else */ + // THIS IS THE HL2 VERSION! + float decalScale = pDecalTex->GetDecalScale(); + float decalWidth = pDecalTex->GetWidth(); + float decalHeight = pDecalTex->GetHeight(); + + Vector textureSpaceBasis[3]; + + R_DecalComputeBasis( pFace->plane.normal, NULL, + false, textureSpaceBasis ); + + float u = DotProduct(textureSpaceBasis[0], org); + float v = DotProduct(textureSpaceBasis[1], org); + + // subtract the world space dist from the center of the + // decal to the origin of the decal + u -= decalWidth * decalScale / 2.0f; + v -= decalHeight * decalScale / 2.0f; + + float scalex = 1.0f / ( decalScale * decalWidth ); + float scaley = 1.0f / ( decalScale * decalHeight ); + + // Generate texture coordinates for each vertex in decal s,t space + Vector *pVertex = pFace->Points; + float curU, curV; + for (int j = 0; j < pFace->nPoints; j++, pVertex++) + { + // Copy X, Y, & Z + g_vert[j][0] = pVertex[0][0]; + g_vert[j][1] = pVertex[0][1]; + g_vert[j][2] = pVertex[0][2]; + + // Get u, v coordinates of vertex in DECAL SPACE + curU = DotProduct(textureSpaceBasis[0], *pVertex); + curV = DotProduct(textureSpaceBasis[1], *pVertex); + + // Generate U & V + g_vert[j][3] = (curU - u) * scalex; // Decal relative texture coordinates + g_vert[j][4] = (curV - v) * scaley; + } +// #endif + + // Clip the polygon to the decal texture space + // FIXME: Yes this realy copies the vertex list 4 times !! + int nMaxVerts = min(nOutSize, MAX_CLIPVERT); + g_outCount = SHClip( g_vert[0], pFace->nPoints, outvert[0], nMaxVerts, 0 ); // clip left + g_outCount = SHClip( outvert[0], g_outCount, g_vert[0], nMaxVerts, 1 ); // clip right + g_outCount = SHClip( g_vert[0], g_outCount, outvert[0], nMaxVerts, 2 ); // clip top + g_outCount = SHClip( outvert[0], g_outCount, g_vert[0], nMaxVerts, 3 ); // clip bottom + + memcpy(pOutPoints, g_vert, sizeof(vec5_t) * g_outCount); + + return(g_outCount); +} + |