Added Parallax Corrected Cubemaps

This commit is contained in:
Kamay Xutax 2024-09-16 23:59:15 +02:00
parent 75bf03a4bc
commit 14f87c6263
9 changed files with 228 additions and 18 deletions

View file

@ -207,7 +207,7 @@ char const *GetImpactDecal( C_BaseEntity *pEntity, int iMaterial, int iDamageTyp
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Perform custom effects based on the Decal index // Purpose: Perform custom effects based on the Decal index
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static ConVar cl_new_impact_effects( "cl_new_impact_effects", "0" ); static ConVar cl_new_impact_effects( "cl_new_impact_effects", "1" );
struct ImpactEffect_t struct ImpactEffect_t
{ {

View file

@ -73,6 +73,11 @@ BEGIN_VS_SHADER( LightmappedGeneric,
SHADER_PARAM( OUTLINESTART1, SHADER_PARAM_TYPE_FLOAT, "0.0", "inner start value for outline") SHADER_PARAM( OUTLINESTART1, SHADER_PARAM_TYPE_FLOAT, "0.0", "inner start value for outline")
SHADER_PARAM( OUTLINEEND0, SHADER_PARAM_TYPE_FLOAT, "0.0", "inner end value for outline") SHADER_PARAM( OUTLINEEND0, SHADER_PARAM_TYPE_FLOAT, "0.0", "inner end value for outline")
SHADER_PARAM( OUTLINEEND1, SHADER_PARAM_TYPE_FLOAT, "0.0", "outer end value for outline") SHADER_PARAM( OUTLINEEND1, SHADER_PARAM_TYPE_FLOAT, "0.0", "outer end value for outline")
// Parallax cubemaps
SHADER_PARAM( ENVMAPPARALLAXOBB1, SHADER_PARAM_TYPE_VEC4, "[1 0 0 0]", "The first line of the parallax correction OBB matrix" )
SHADER_PARAM( ENVMAPPARALLAXOBB2, SHADER_PARAM_TYPE_VEC4, "[0 1 0 0]", "The second line of the parallax correction OBB matrix" )
SHADER_PARAM( ENVMAPPARALLAXOBB3, SHADER_PARAM_TYPE_VEC4, "[0 0 1 0]", "The third line of the parallax correction OBB matrix" )
SHADER_PARAM( ENVMAPORIGIN, SHADER_PARAM_TYPE_VEC3, "[0 0 0]", "The world space position of the env_cubemap being corrected" )
END_SHADER_PARAMS END_SHADER_PARAMS
void SetupVars( LightmappedGeneric_DX9_Vars_t& info ) void SetupVars( LightmappedGeneric_DX9_Vars_t& info )
@ -134,6 +139,12 @@ END_SHADER_PARAMS
info.m_nOutlineStart1 = OUTLINESTART1; info.m_nOutlineStart1 = OUTLINESTART1;
info.m_nOutlineEnd0 = OUTLINEEND0; info.m_nOutlineEnd0 = OUTLINEEND0;
info.m_nOutlineEnd1 = OUTLINEEND1; info.m_nOutlineEnd1 = OUTLINEEND1;
// Parallax cubemaps
info.m_nEnvmapParallaxObb1 = ENVMAPPARALLAXOBB1;
info.m_nEnvmapParallaxObb2 = ENVMAPPARALLAXOBB2;
info.m_nEnvmapParallaxObb3 = ENVMAPPARALLAXOBB3;
info.m_nEnvmapOrigin = ENVMAPORIGIN;
} }
SHADER_FALLBACK SHADER_FALLBACK

View file

@ -58,6 +58,13 @@ public:
void InitParamsLightmappedGeneric_DX9( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, LightmappedGeneric_DX9_Vars_t &info ) void InitParamsLightmappedGeneric_DX9( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, LightmappedGeneric_DX9_Vars_t &info )
{ {
// Parallax cubemaps
// Cubemap parallax correction requires all 4 lines (if the 2nd, 3rd, or 4th are undef, undef the first one (checking done on first var)
if ( !( params[info.m_nEnvmapParallaxObb2]->IsDefined() && params[info.m_nEnvmapParallaxObb3]->IsDefined() && params[info.m_nEnvmapOrigin]->IsDefined() ) )
{
params[info.m_nEnvmapParallaxObb1]->SetUndefined();
}
if ( g_pHardwareConfig->SupportsBorderColor() ) if ( g_pHardwareConfig->SupportsBorderColor() )
{ {
params[FLASHLIGHTTEXTURE]->SetStringValue( "effects/flashlight_border" ); params[FLASHLIGHTTEXTURE]->SetStringValue( "effects/flashlight_border" );
@ -313,6 +320,8 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar**
(info.m_nBlendModulateTexture != -1) && (info.m_nBlendModulateTexture != -1) &&
(params[info.m_nBlendModulateTexture]->IsTexture() ); (params[info.m_nBlendModulateTexture]->IsTexture() );
bool hasNormalMapAlphaEnvmapMask = IS_FLAG_SET( MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK ); bool hasNormalMapAlphaEnvmapMask = IS_FLAG_SET( MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK );
// Parallax cubemaps
bool hasParallaxCorrection = params[info.m_nEnvmapParallaxObb1]->IsDefined();
if ( hasFlashlight && !IsX360() ) if ( hasFlashlight && !IsX360() )
{ {
@ -574,6 +583,8 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar**
#ifdef _X360 #ifdef _X360
SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, hasFlashlight); SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, hasFlashlight);
#endif #endif
// Parallax cubemaps enabled for 2_0b and onwards
SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, hasParallaxCorrection );
SET_STATIC_PIXEL_SHADER( lightmappedgeneric_ps20b ); SET_STATIC_PIXEL_SHADER( lightmappedgeneric_ps20b );
} }
else else
@ -601,6 +612,8 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar**
SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_BLEND_MODE, nDetailBlendMode ); SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_BLEND_MODE, nDetailBlendMode );
SET_STATIC_PIXEL_SHADER_COMBO( NORMAL_DECODE_MODE, 0 ); // No normal compression with ps_2_0 (yikes!) SET_STATIC_PIXEL_SHADER_COMBO( NORMAL_DECODE_MODE, 0 ); // No normal compression with ps_2_0 (yikes!)
SET_STATIC_PIXEL_SHADER_COMBO( NORMALMASK_DECODE_MODE, 0 ); // No normal compression with ps_2_0 SET_STATIC_PIXEL_SHADER_COMBO( NORMALMASK_DECODE_MODE, 0 ); // No normal compression with ps_2_0
// Parallax cubemaps
SET_STATIC_PIXEL_SHADER_COMBO( PARALLAXCORRECT, 0 ); // No parallax cubemaps with ps_2_0 :(
SET_STATIC_PIXEL_SHADER( lightmappedgeneric_ps20 ); SET_STATIC_PIXEL_SHADER( lightmappedgeneric_ps20 );
} }
// HACK HACK HACK - enable alpha writes all the time so that we have them for // HACK HACK HACK - enable alpha writes all the time so that we have them for
@ -857,6 +870,28 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar**
pContextData->m_SemiStaticCmdsOut.BindTexture( pShader, SHADER_SAMPLER3, info.m_nBlendModulateTexture, -1 ); pContextData->m_SemiStaticCmdsOut.BindTexture( pShader, SHADER_SAMPLER3, info.m_nBlendModulateTexture, -1 );
} }
// Parallax cubemaps
if ( hasParallaxCorrection )
{
pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, params[info.m_nEnvmapOrigin]->GetVecValue() );
float *vecs[3];
vecs[0] = const_cast<float *>( params[info.m_nEnvmapParallaxObb1]->GetVecValue() );
vecs[1] = const_cast<float *>( params[info.m_nEnvmapParallaxObb2]->GetVecValue() );
vecs[2] = const_cast<float *>( params[info.m_nEnvmapParallaxObb3]->GetVecValue() );
float matrix[4][4];
for ( int i = 0; i < 3; i++ )
{
for ( int j = 0; j < 4; j++ )
{
matrix[i][j] = vecs[i][j];
}
}
matrix[3][0] = matrix[3][1] = matrix[3][2] = 0;
matrix[3][3] = 1;
pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 22, &matrix[0][0], 4 );
}
pContextData->m_SemiStaticCmdsOut.End(); pContextData->m_SemiStaticCmdsOut.End();
} }
} }

View file

@ -86,7 +86,11 @@ struct LightmappedGeneric_DX9_Vars_t
int m_nOutlineStart1; int m_nOutlineStart1;
int m_nOutlineEnd0; int m_nOutlineEnd0;
int m_nOutlineEnd1; int m_nOutlineEnd1;
// Parallax cubemaps
int m_nEnvmapParallaxObb1;
int m_nEnvmapParallaxObb2;
int m_nEnvmapParallaxObb3;
int m_nEnvmapOrigin;
}; };
void InitParamsLightmappedGeneric_DX9( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, LightmappedGeneric_DX9_Vars_t &info ); void InitParamsLightmappedGeneric_DX9( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, LightmappedGeneric_DX9_Vars_t &info );

View file

@ -100,7 +100,11 @@ const float4 g_FlashlightAttenuationFactors : register( c13 );
const float3 g_FlashlightPos : register( c14 ); const float3 g_FlashlightPos : register( c14 );
const float4x4 g_FlashlightWorldToTexture : register( c15 ); // through c18 const float4x4 g_FlashlightWorldToTexture : register( c15 ); // through c18
const float4 g_ShadowTweaks : register( c19 ); const float4 g_ShadowTweaks : register( c19 );
// Parallax cubemaps
#if ( PARALLAXCORRECT )
const float3 g_CubemapPos : register( c21 );
const float4x4 g_ObbMatrix : register( c22 ); // Through c25
#endif
sampler BaseTextureSampler : register( s0 ); sampler BaseTextureSampler : register( s0 );
sampler LightmapSampler : register( s1 ); sampler LightmapSampler : register( s1 );
@ -530,7 +534,24 @@ HALF4 main( PS_INPUT i ) : COLOR
HALF fresnel = 1.0 - dot( worldSpaceNormal, eyeVect ); HALF fresnel = 1.0 - dot( worldSpaceNormal, eyeVect );
fresnel = pow( fresnel, 5.0 ); fresnel = pow( fresnel, 5.0 );
fresnel = fresnel * g_OneMinusFresnelReflection + g_FresnelReflection; fresnel = fresnel * g_OneMinusFresnelReflection + g_FresnelReflection;
// Parallax correction (2_0b and beyond)
// Adapted from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
#if !( defined( SHADER_MODEL_PS_1_1 ) || defined( SHADER_MODEL_PS_1_4 ) || defined( SHADER_MODEL_PS_2_0 ) )
#if ( PARALLAXCORRECT )
float3 worldPos = i.worldPos_projPosZ.xyz;
float3 positionLS = mul( float4( worldPos, 1 ), g_ObbMatrix );
float3 rayLS = mul( reflectVect, (float3x3)g_ObbMatrix );
float3 firstPlaneIntersect = ( float3( 1.0f, 1.0f, 1.0f ) - positionLS ) / rayLS;
float3 secondPlaneIntersect = ( -positionLS ) / rayLS;
float3 furthestPlane = max( firstPlaneIntersect, secondPlaneIntersect );
float distance = min( furthestPlane.x, min( furthestPlane.y, furthestPlane.z ) );
// Use distance in WS directly to recover intersection
float3 intersectPositionWS = worldPos + reflectVect * distance;
reflectVect = intersectPositionWS - g_CubemapPos;
#endif
#endif
specularLighting = ENV_MAP_SCALE * texCUBE( EnvmapSampler, reflectVect ); specularLighting = ENV_MAP_SCALE * texCUBE( EnvmapSampler, reflectVect );
specularLighting *= specularFactor; specularLighting *= specularFactor;

View file

@ -24,6 +24,7 @@
// STATIC: "NORMALMASK_DECODE_MODE" "0..0" [PC] // STATIC: "NORMALMASK_DECODE_MODE" "0..0" [PC]
// STATIC: "DETAIL_BLEND_MODE" "0..11" // STATIC: "DETAIL_BLEND_MODE" "0..11"
// STATIC: "FLASHLIGHT" "0..1" [ps20b] [XBOX] // STATIC: "FLASHLIGHT" "0..1" [ps20b] [XBOX]
// STATIC: "PARALLAXCORRECT" "0..1"
// DYNAMIC: "FASTPATHENVMAPCONTRAST" "0..1" // DYNAMIC: "FASTPATHENVMAPCONTRAST" "0..1"
// DYNAMIC: "FASTPATH" "0..1" // DYNAMIC: "FASTPATH" "0..1"
@ -54,6 +55,8 @@
// SKIP: ($DETAIL_BLEND_MODE == 8 ) || ($DETAIL_BLEND_MODE == 9 ) // SKIP: ($DETAIL_BLEND_MODE == 8 ) || ($DETAIL_BLEND_MODE == 9 )
// SKIP ($DETAIL_BLEND_MODE == 10 ) && ($BUMPMAP == 0 ) // SKIP ($DETAIL_BLEND_MODE == 10 ) && ($BUMPMAP == 0 )
// SKIP ($DETAIL_BLEND_MODE == 11 ) && ($BUMPMAP != 0 ) // SKIP ($DETAIL_BLEND_MODE == 11 ) && ($BUMPMAP != 0 )
// SKIP: $PARALLAXCORRECT && !$CUBEMAP
// SKIP: $PARALLAXCORRECT [ps20]
#include "lightmappedgeneric_ps2_3_x.h" #include "lightmappedgeneric_ps2_3_x.h"

View file

@ -76,7 +76,7 @@ struct CubemapSideData_t
}; };
static CubemapSideData_t s_aCubemapSideData[MAX_MAP_BRUSHSIDES]; static CubemapSideData_t s_aCubemapSideData[MAX_MAP_BRUSHSIDES];
char *g_pParallaxObbStrs[MAX_MAP_CUBEMAPSAMPLES];
inline bool SideHasCubemapAndWasntManuallyReferenced( int iSide ) inline bool SideHasCubemapAndWasntManuallyReferenced( int iSide )
@ -85,8 +85,10 @@ inline bool SideHasCubemapAndWasntManuallyReferenced( int iSide )
} }
void Cubemap_InsertSample( const Vector& origin, int size ) void Cubemap_InsertSample( const Vector &origin, int size, char *pParallaxObbStr = "" )
{ {
g_pParallaxObbStrs[g_nCubemapSamples] = pParallaxObbStr;
dcubemapsample_t *pSample = &g_CubemapSamples[g_nCubemapSamples]; dcubemapsample_t *pSample = &g_CubemapSamples[g_nCubemapSamples];
pSample->origin[0] = ( int )origin[0]; pSample->origin[0] = ( int )origin[0];
pSample->origin[1] = ( int )origin[1]; pSample->origin[1] = ( int )origin[1];
@ -528,7 +530,7 @@ static void GeneratePatchedName( const char *pMaterialName, const PatchInfo_t &i
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Patches the $envmap for a material and all its dependents, returns true if any patching happened // Patches the $envmap for a material and all its dependents, returns true if any patching happened
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, const PatchInfo_t &info, const char *pCubemapTexture ) static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, const PatchInfo_t &info, const char *pCubemapTexture, const char *pParallaxObbMatrix = "" )
{ {
// Do *NOT* patch the material if there is an $envmap specified and it's not 'env_cubemap' // Do *NOT* patch the material if there is an $envmap specified and it's not 'env_cubemap'
@ -546,7 +548,7 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons
const char *pDependentMaterial = FindDependentMaterial( pMaterialName, &pDependentMaterialVar ); const char *pDependentMaterial = FindDependentMaterial( pMaterialName, &pDependentMaterialVar );
if ( pDependentMaterial ) if ( pDependentMaterial )
{ {
bDependentMaterialPatched = PatchEnvmapForMaterialAndDependents( pDependentMaterial, info, pCubemapTexture ); bDependentMaterialPatched = PatchEnvmapForMaterialAndDependents( pDependentMaterial, info, pCubemapTexture, pParallaxObbMatrix );
} }
// If we have neither to patch, we're done // If we have neither to patch, we're done
@ -557,7 +559,7 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons
char pPatchedMaterialName[1024]; char pPatchedMaterialName[1024];
GeneratePatchedName( pMaterialName, info, true, pPatchedMaterialName, 1024 ); GeneratePatchedName( pMaterialName, info, true, pPatchedMaterialName, 1024 );
MaterialPatchInfo_t pPatchInfo[2]; MaterialPatchInfo_t pPatchInfo[6];
int nPatchCount = 0; int nPatchCount = 0;
if ( bShouldPatchEnvCubemap ) if ( bShouldPatchEnvCubemap )
{ {
@ -578,7 +580,30 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons
++nPatchCount; ++nPatchCount;
} }
CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_REPLACE ); // Parallax cubemap matrix
CUtlVector<char *> matRowList;
if ( pParallaxObbMatrix[0] != '\0' )
{
V_SplitString( pParallaxObbMatrix, ";", matRowList );
pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB1";
pPatchInfo[nPatchCount].m_pValue = matRowList[0];
++nPatchCount;
pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB2";
pPatchInfo[nPatchCount].m_pValue = matRowList[1];
++nPatchCount;
pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB3";
pPatchInfo[nPatchCount].m_pValue = matRowList[2];
++nPatchCount;
pPatchInfo[nPatchCount].m_pKey = "$envMapOrigin";
pPatchInfo[nPatchCount].m_pValue = matRowList[3];
++nPatchCount;
}
CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_INSERT );
// Clean up parallax stuff
matRowList.PurgeAndDeleteElements();
return true; return true;
} }
@ -597,7 +622,7 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons
// default (skybox) cubemap into this file so the cubemap doesn't have the pink checkerboard at // default (skybox) cubemap into this file so the cubemap doesn't have the pink checkerboard at
// runtime before they run buildcubemaps. // runtime before they run buildcubemaps.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3] ) static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3], int cubemapIndex )
{ {
// Don't make cubemap tex infos for nodes // Don't make cubemap tex infos for nodes
if ( originalTexInfo == TEXINFO_NODE ) if ( originalTexInfo == TEXINFO_NODE )
@ -638,9 +663,16 @@ static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3] )
char pTextureName[1024]; char pTextureName[1024];
GeneratePatchedName( "c", info, false, pTextureName, 1024 ); GeneratePatchedName( "c", info, false, pTextureName, 1024 );
// Append origin info if this cubemap has a parallax OBB
char originAppendedString[1024] = "";
if ( g_pParallaxObbStrs[cubemapIndex][0] != '\0' )
{
Q_snprintf( originAppendedString, 1024, "%s;[%d %d %d]", g_pParallaxObbStrs[cubemapIndex], origin[0], origin[1], origin[2] );
}
// Hook the texture into the material and all dependent materials // Hook the texture into the material and all dependent materials
// but if no hooking was necessary, exit out // but if no hooking was necessary, exit out
if ( !PatchEnvmapForMaterialAndDependents( pMaterialName, info, pTextureName ) ) if ( !PatchEnvmapForMaterialAndDependents( pMaterialName, info, pTextureName, originAppendedString ) )
return originalTexInfo; return originalTexInfo;
// Store off the name of the cubemap that we need to create since we successfully patched // Store off the name of the cubemap that we need to create since we successfully patched
@ -730,7 +762,7 @@ void Cubemap_FixupBrushSidesMaterials( void )
} }
#endif #endif
pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[cubemapID].origin ); pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[cubemapID].origin, cubemapID );
if ( pSide->pMapDisp ) if ( pSide->pMapDisp )
{ {
pSide->pMapDisp->face.texinfo = pSide->texinfo; pSide->pMapDisp->face.texinfo = pSide->texinfo;
@ -946,7 +978,7 @@ void Cubemap_AttachDefaultCubemapToSpecularSides( void )
Assert( pSide->texinfo == pSide->pMapDisp->face.texinfo ); Assert( pSide->texinfo == pSide->pMapDisp->face.texinfo );
} }
#endif #endif
pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[iCubemap].origin ); pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[iCubemap].origin, iCubemap );
if ( pSide->pMapDisp ) if ( pSide->pMapDisp )
{ {
pSide->pMapDisp->face.texinfo = pSide->texinfo; pSide->pMapDisp->face.texinfo = pSide->texinfo;

View file

@ -5,6 +5,7 @@
// $NoKeywords: $ // $NoKeywords: $
//=============================================================================// //=============================================================================//
#include "matrixinvert.h"
#include "vbsp.h" #include "vbsp.h"
#include "map_shared.h" #include "map_shared.h"
#include "disp_vbsp.h" #include "disp_vbsp.h"
@ -1617,17 +1618,97 @@ ChunkFileResult_t CMapFile::LoadEntityCallback(CChunkFile *pFile, int nParam)
{ {
if( ( g_nDXLevel == 0 ) || ( g_nDXLevel >= 70 ) ) if( ( g_nDXLevel == 0 ) || ( g_nDXLevel >= 70 ) )
{ {
const char *pSideListStr = ValueForKey( mapent, "sides" ); const char* pSideListStr = ValueForKey( mapent, "sides" );
char *pParallaxObbStr = ValueForKey( mapent, "parallaxobb" );
int size; int size;
size = IntForKey( mapent, "cubemapsize" ); size = IntForKey( mapent, "cubemapsize" );
Cubemap_InsertSample( mapent->origin, size ); Cubemap_InsertSample( mapent->origin, size, pParallaxObbStr );
Cubemap_SaveBrushSides( pSideListStr );
} }
// clear out this entity // clear out this entity
mapent->epairs = NULL; mapent->epairs = NULL;
return(ChunkFile_Ok); return(ChunkFile_Ok);
} }
//
// parallax_obb brushes are removed after the transformation matrix is found and saved into
// the entity's data (ent will be removed after data transferred to patched materials)
//
if ( !strcmp( "parallax_obb", pClassName ) )
{
matrix3x4_t obbMatrix, invObbMatrix;
SetIdentityMatrix( obbMatrix );
SetIdentityMatrix( invObbMatrix );
// Get corner and its 3 edges (scaled, local x, y, and z axes)
mapbrush_t *brush = &mapbrushes[mapent->firstbrush];
Vector corner, x, y, z;
// Find first valid winding (with these whiles, if not enough valid windings then identity matrix is passed through to VMTs)
int i = 0;
while ( i < brush->numsides )
{
winding_t *wind = brush->original_sides[i].winding;
if ( !wind )
{
i++;
continue;
}
corner = wind->p[0];
y = wind->p[1] - corner;
z = wind->p[3] - corner;
x = CrossProduct( y, z ).Normalized();
i++;
break;
}
// Skip second valid winding (opposite face from first, unusable for finding Z's length)
while ( i < brush->numsides )
{
winding_t *wind = brush->original_sides[i].winding;
if ( !wind )
{
i++;
continue;
}
i++;
break;
}
// Find third valid winding
while ( i < brush->numsides )
{
winding_t *wind = brush->original_sides[i].winding;
if ( !wind )
{
i++;
continue;
}
// Find length of X
// Start with diagonal, then scale X by the projection of diag onto X
Vector diag = wind->p[0] - wind->p[2];
x *= abs( DotProduct( diag, x ) );
// Build transformation matrix (what is needed to turn a [0,0,0] - [1,1,1] cube into this brush)
MatrixSetColumn( x, 0, obbMatrix );
MatrixSetColumn( y, 1, obbMatrix );
MatrixSetColumn( z, 2, obbMatrix );
MatrixSetColumn( corner, 3, obbMatrix );
// Find inverse (we need the world to local matrix, "transformationmatrix" is kind of a misnomer)
MatrixInversion( obbMatrix, invObbMatrix );
break;
}
char szMatrix[1024];
Q_snprintf( szMatrix, 1024, "[%f %f %f %f];[%f %f %f %f];[%f %f %f %f]", invObbMatrix[0][0], invObbMatrix[0][1], invObbMatrix[0][2], invObbMatrix[0][3], invObbMatrix[1][0], invObbMatrix[1][1], invObbMatrix[1][2], invObbMatrix[1][3], invObbMatrix[2][0], invObbMatrix[2][1], invObbMatrix[2][2], invObbMatrix[2][3] );
SetKeyValue( mapent, "transformationmatrix", szMatrix );
return ( ChunkFile_Ok );
}
if ( !strcmp( "test_sidelist", pClassName ) ) if ( !strcmp( "test_sidelist", pClassName ) )
{ {
ConvertSideList(mapent, "sides"); ConvertSideList(mapent, "sides");
@ -2611,6 +2692,28 @@ bool LoadMapFile( const char *pszFileName )
if ((eResult == ChunkFile_Ok) || (eResult == ChunkFile_EOF)) if ((eResult == ChunkFile_Ok) || (eResult == ChunkFile_EOF))
{ {
// Fill out parallax obb matrix array
for ( int i = 0; i < g_nCubemapSamples; i++ )
{
if ( g_pParallaxObbStrs[i][0] != '\0' )
{
entity_t *obbEnt = EntityByName( g_pParallaxObbStrs[i] );
g_pParallaxObbStrs[i] = ValueForKey( obbEnt, "transformationmatrix" );
}
}
// Remove parallax_obb entities (in a nice slow linear search)
for ( int i = 0; i < g_MainMap->num_entities; i++ )
{
entity_t *mapent = &g_MainMap->entities[i];
const char *pClassName = ValueForKey( mapent, "classname" );
if ( !strcmp( "parallax_obb", pClassName ) )
{
mapent->numbrushes = 0;
mapent->epairs = NULL;
}
}
// Update the overlay/side list(s). // Update the overlay/side list(s).
Overlay_UpdateSideLists( g_LoadingMap->m_StartMapOverlays ); Overlay_UpdateSideLists( g_LoadingMap->m_StartMapOverlays );
OverlayTransition_UpdateSideLists( g_LoadingMap->m_StartMapWaterOverlays ); OverlayTransition_UpdateSideLists( g_LoadingMap->m_StartMapWaterOverlays );

View file

@ -607,7 +607,8 @@ void SaveVertexNormals( void );
//============================================================================= //=============================================================================
// cubemap.cpp // cubemap.cpp
void Cubemap_InsertSample( const Vector& origin, int size ); extern char *g_pParallaxObbStrs[MAX_MAP_CUBEMAPSAMPLES];
void Cubemap_InsertSample( const Vector &origin, int size, char *pParallaxObbStr );
void Cubemap_CreateDefaultCubemaps( void ); void Cubemap_CreateDefaultCubemaps( void );
void Cubemap_SaveBrushSides( const char *pSideListStr ); void Cubemap_SaveBrushSides( const char *pSideListStr );
void Cubemap_FixupBrushSidesMaterials( void ); void Cubemap_FixupBrushSidesMaterials( void );