1
This commit is contained in:
348
hammer/clipcode.cpp
Normal file
348
hammer/clipcode.cpp
Normal file
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user