You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
348 lines
9.1 KiB
348 lines
9.1 KiB
//========= 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); |
|
} |
|
|
|
|