Skip to content

Instantly share code, notes, and snippets.

@Kefta
Last active June 26, 2018 01:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kefta/045c3b839aac8aaae88f9bcb3494c9f6 to your computer and use it in GitHub Desktop.
Save Kefta/045c3b839aac8aaae88f9bcb3494c9f6 to your computer and use it in GitHub Desktop.
/// Lua method declaration ///
// Placeholders, better methods probably already defined somewhere
bool CheckDefaultValue( int iStackPos, int iType )
{
int iRetType = g_Lua->GetType( iStackPos );
if ( iRetType == iType )
return true;
if ( iRetType != GarrysMod::Lua::Type::NONE && iRetType != GarrysMod::Lua::Type::NIL )
g_Lua->ArgError( iStackPos, sprintf( "%s expected, got %s", g_Lua->GetTypeName( iType ), g_Lua->GetTypeName( iRetType ) ) );
return false;
}
int CheckMultiValue( int iStackPos, int iType1, int iType2 )
{
int iRetType = g_Lua->GetType( iStackPos );
if ( iRetType == iType1 )
return iType1;
if ( iRetType == iType2 )
return iType2;
g_Lua->ArgError( iStackPos, sprintf( "%s or %s expected, got %s", g_Lua->GetTypeName( iType1 ), g_Lua->GetTypeName( iType2 ), g_Lua->GetTypeName( iRetType ) ) );
return iRetType;
}
/* Lua header:
// Maybe even make this a struct, there's a lotta args
ENTITY:AddDecal(Vector rayStart, Vector rayEnd, Vector decalCenter, IMaterial or string decalMat,
table (trace result struct) tr = nil, number w = IMaterial:GetMappingWidth(), number h = IMaterial:GetMappingHeight(),
Vector saxis = Vector(0, 0, 1) for studio mdls or nil for brush models, number (integer) flags = 0, number (integer) maxLODToDecal = ADDDECAL_TO_ALL_LODS)
*/
void LUA_ENTITY_AddDecal()
{
g_Lua->CheckType( 1, GarrysMod::Lua::Type::ENTITY ); // ENTITY
g_Lua->CheckType( 2, GarrysMod::Lua::Type::VECTOR ); // rayStart
g_Lua->CheckType( 3, GarrysMod::Lua::Type::VECTOR ); // rayEnd
g_Lua->CheckType( 4, GarrysMod::Lua::Type::VECTOR ); // decalCenter
bool bMaterial = CheckMultiValue( 5, GarrysMod::Lua::Type::MATERIAL, GarrysMod::Lua::Type::STRING ) == GarrysMod::Lua::Type::MATERIAL // decalName
bool doTrace = !CheckDefaultValue( 6, GarrysMod::Lua::Type::TABLE ); // tr
bool bWidth = CheckDefaultValue( 7, GarrysMod::Lua::Type::NUMBER ); // w
bool bHeight = CheckDefaultValue( 8, GarrysMod::Lua::Type::NUMBER ); // h
bool bAxis = CheckDefaultValue( 9, GarrysMod::Lua::Type::VECTOR ); // saxis
int iFlags = CheckDefaultValue( 10, GarrysMod::Lua::Type::NUMBER )
? (int)g_Lua->ReadNumber( 10 ) : 0;
int maxLODToDecal = CheckDefaultValue( 11, GarrysMod::Lua::Type::NUMBER ) // maxLODToDecal
? (int)g_Lua->ReadNumber( 11 ) : ADDDECAL_TO_ALL_LODS;
// or whatever the method is
C_BaseEntity* pEntity = GetEntityValid( g_Lua, 1 );
IMaterial* pMaterial;
if ( bMaterial )
pMaterial = g_Lua->GetUserType<IMaterial>( 5, GarrysMod::Lua::Type::MATERIAL );
else
// Get IMaterial by string
Assert( pMaterial != NULL );
const Vector &rayStart = g_Lua->GetVector( 2 );
const Vector &rayEnd = g_Lua->GetVector( 3 );
trace_t tr;
if ( !doTrace )
tr = GetTraceStruct( g_Lua, 6 );
pEntity->AddDecal( rayStart, rayEnd, g_Lua->GetVector( 4 ), pMaterial, doTrace, tr,
bWidth ? g_Lua->GetNumber( 7 ) : pMaterial->GetMappingWidth(),
bHeight ? g_Lua->GetNumber( 8 ) : pMaterial->GetMappingHeight(),
bAxis ? &g_Lua->GetVector( 9 ) : NULL, iFlags, maxLODToDecal );
}
/// c_baseentity.h ///
// New methods:
virtual void AddDecal( const Vector& rayStart, const Vector& rayEnd, IMaterial* decalMat, bool doTrace, trace_t& tr,
float w, float h, const Vector* saxis = NULL, int iFlags = 0, int maxLODToDecal = ADDDECAL_TO_ALL_LODS );
void AddStudioDecal( const Ray_t& ray, IMaterial* decalMat,
float w, float h, const Vector* upaxis = NULL, int maxLODToDecal = ADDDECAL_TO_ALL_LODS, bool pokeThruSkip = false );
void AddBrushModelDecal( const Vector& decalCenter, IMaterial* decalMat,
float w, float h, const Vector* saxis = NULL, int iFlags = 0 );
// Backwards compatible:
virtual void AddDecal( const Vector& rayStart, const Vector& rayEnd,
const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS );
void AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS );
void AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter, int decalIndex, bool doTrace, trace_t& tr );
/// c_baseentity.cpp ///
inline void DecalTrace( trace_t& tr, const Ray_t& ray )
{
enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr );
/// This shouldn't be needed, the trace is already clipped to the entity
// Set the trace index appropriately...
//tr.m_pEnt = this;
}
// New methods:
void C_BaseEntity::AddDecal( const Vector& rayStart, const Vector& rayEnd, IMaterial* decalMat,
bool doTrace, trace_t& tr, float w, float h, const Vector* saxis, int iFlags, int maxLODToDecal );
{
Ray_t ray;
ray.Init( rayStart, rayEnd );
if ( doTrace )
{
/// Only bloat the ray if we're simulating a trace
// FIXME: Better bloat?
// Bloat a little bit so we get the intersection
ray.m_Delta *= 1.1f;
::DecalTrace( tr, ray );
}
if (tr.Fraction == 1.0f)
return;
int modelType = modelinfo->GetModelType( model );
switch ( modelType )
{
case mod_studio:
bool pokeThruSkip = false;
if (doTrace && (GetSolid() == SOLID_VPHYSICS) && !tr.startsolid && !tr.allsolid)
{
// Choose a more accurate normal direction
// Also, since we have more accurate info, we can avoid pokethru
Vector temp;
VectorSubtract( tr.endpos, tr.plane.normal, temp );
ray.Init( tr.endpos, temp );
pokeThruSkip = true;
}
AddStudioDecal( ray, decalMat, w, h, saxis, maxLODToDecal, pokeThruSkip );
break;
case mod_brush:
// Use the trace's hitpos as the centre of the decal
AddBrushModelDecal( ray, tr.endpos, decalMat, w, h, saxis, iFlags );
break;
default:
// By default, no collision
tr.fraction = 1.0f;
break;
}
}
void C_BaseEntity::AddStudioDecal( const Ray_t& ray, IMaterial* decalMat,
float w, float h, const Vector* upaxis, int maxLODToDecal, bool pokeThruSkip )
{
// Exit out after doing the trace so any other effects that want to happen can happen.
if ( !r_drawmodeldecals.GetBool() )
return;
// Found the point, now lets apply the decals
CreateModelInstance();
modelrender->AddDecal( m_ModelInstance, ray, upaxis == NULL ? Vector(0, 0, 1) : *upaxis, decalMat, GetStudioBody(), w, h, pokeThruSkip, maxLODToDecal );
}
void C_BaseEntity::AddBrushModelDecal( const Vector& decalCenter, IMaterial* decalMat,
float w, float h, const Vector* saxis, int iFlags )
{
effects->DecalShoot( decalMat, index,
model, GetAbsOrigin(), GetAbsAngles(), decalCenter, w, h, saxis, iFlags );
}
// Backwards compatible:
void C_BaseEntity::AddDecal( const Vector& rayStart, const Vector& rayEnd,
const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Vector* saxis, int iFlags, int maxLODToDecal )
{
IMaterial* decalMat;
float w, h;
R_DecalGetMaterialAndSize( decalIndex, decalMat, w, h );
// Material validity will be checked later, at least get a trace
AddDecal( rayStart, rayEnd, decalMat, doTrace, tr, w, h, NULL, 0, maxLODToDecal );
}
void C_BaseEntity::AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal )
{
if ( doTrace )
::DecalTrace( tr, ray );
if (tr.Fraction == 1.0f)
return;
IMaterial* decalMat;
float w, h;
R_DecalGetMaterialAndSize( decalIndex, decalMat, w, h );
AddStudioDecal( ray, decalMat, w, h, NULL, maxLODToDecal, doTrace );
}
void C_BaseEntity::AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter, int decalIndex, bool doTrace, trace_t& tr )
{
if ( doTrace )
::DecalTrace( tr, ray );
if (tr.Fraction == 1.0f)
return;
IMaterial* decalMat;
float w, h;
R_DecalGetMaterialAndSize( decalIndex, decalMat, w, h );
AddBrushModelDecal( decalCenter, decalMat, w, h, NULL, 0 );
}
/// l_studio.cpp ///
// New header:
AddDecal( ModelInstanceHandle_t handle, Ray_t const& ray,
const Vector& decalUp, IMaterial* decalMat, int body, float w, float h, bool noPokeThru, int maxLODToDecal );
// Backwards compatible:
AddDecal( ModelInstanceHandle_t handle, Ray_t const& ray,
const Vector& decalUp, int decalIndex, int body, bool noPokeThru, int maxLODToDecal );
// New method:
void CModelRender::AddDecal( ModelInstanceHandle_t handle, Ray_t const& ray,
const Vector& decalUp, IMaterial* decalMat, int body, float w, float h, bool noPokeThru, int maxLODToDecal )
{
if (handle == MODEL_INSTANCE_INVALID || decalMat == NULL)
return;
// FIXME: For now, don't render fading decals on props...
bool found = false;
decalMat->FindVar( "$decalFadeDuration", &found, false );
if (found)
return;
/// This doesn't seem possible with how the renderer currently draws decals
/// Just use the width/height as the radius for now..
// FIXME: Pass w and h into AddDecal
float radius = (w > h) ? w : h;
radius *= 0.5;
ModelInstance_t& inst = m_ModelInstances[handle];
if (!IsModelInstanceValid(handle))
{
g_pStudioRender->DestroyDecalList(inst.m_DecalHandle);
inst.m_DecalHandle = STUDIORENDER_DECAL_INVALID;
}
Assert( modelloader->IsLoaded( inst.m_pModel ) && ( inst.m_pModel->type == mod_studio ) );
if ( inst.m_DecalHandle == STUDIORENDER_DECAL_INVALID )
{
studiohwdata_t *pStudioHWData = g_pMDLCache->GetHardwareData( inst.m_pModel->studio );
inst.m_DecalHandle = g_pStudioRender->CreateDecalList( pStudioHWData );
}
matrix3x4_t *pBoneToWorld = SetupModelState( inst.m_pRenderable );
g_pStudioRender->AddDecal( inst.m_DecalHandle, g_pMDLCache->GetStudioHdr( inst.m_pModel->studio ),
pBoneToWorld, ray, decalUp, decalMat, radius, body, noPokeThru, maxLODToDecal );
}
// Backwards compatible:
void CModelRender::AddDecal( ModelInstanceHandle_t handle, Ray_t const& ray,
const Vector& decalUp, int decalIndex, int body, bool noPokeThru, int maxLODToDecal )
{
if (handle == MODEL_INSTANCE_INVALID)
return;
// Get the decal material + radius
IMaterial* pDecalMaterial;
float w, h;
R_DecalGetMaterialAndSize( decalIndex, pDecalMaterial, w, h );
if ( pDecalMaterial == NULL )
{
DevWarning("Bad decal index %d\n", decalIndex );
return;
}
AddDecal( handle, ray, decalUp, pDecalMaterial, body, w, h, noPokeThru, maxLODToDecal );
}
/// r_efx.h ///
// New headers:
virtual void DecalShoot( IMaterial* decalMat, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, float w, float h, const Vector *saxis, int flags);
virtual void DecalColorShoot( IMaterial* decalMat, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, float w, float h, const Vector *saxis, int flags, const color32 &rgbaColor);
// Backwards compatible:
virtual void DecalShoot( int textureIndex, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, const Vector *saxis, int flags);
virtual void DecalColorShoot( int textureIndex, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, const Vector *saxis, int flags, const color32 &rgbaColor);
/// r_efx.cpp ///
// New methods:
void CVEfx::DecalShoot( IMaterial* decalMat, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, float w, float h, const Vector *saxis, int flags)
{
color32 white = {255,255,255,255};
DecalColorShoot( decalMat, entity, model, model_origin, model_angles, position, w, h, saxis, flags, white );
}
void CVEfx::DecalColorShoot( IMaterial* decalMat, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles,
const Vector& position, float w, float h, const Vector *saxis, int flags, const color32 &rgbaColor)
{
Vector localPosition = position;
if ( entity ) // Not world?
{
matrix3x4_t matrix;
AngleMatrix( model_angles, model_origin, matrix );
VectorITransform( position, matrix, localPosition );
}
::R_DecalShoot( textureIndex, entity, model, localPosition, w, h, saxis, flags, rgbaColor );
}
// Backward compatible:
void CVEfx::DecalShoot( int textureIndex, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles, const Vector& position, const Vector *saxis, int flags)
{
IMaterial* pDecalMaterial;
float w, h;
R_DecalGetMaterialAndSize( textureIndex, pDecalMaterial, w, h );
DecalShoot( pDecalMaterial, entity, model, model_origin, model_angles, position, w, h, saxis, flags );
}
void CVEfx::DecalColorShoot( int textureIndex, int entity, const model_t *model, const Vector& model_origin, const QAngle& model_angles,
const Vector& position, const Vector *saxis, int flags, const color32 &rgbaColor)
{
IMaterial* pDecalMaterial;
float w, h;
R_DecalGetMaterialAndSize( textureIndex, pDecalMaterial, w, h );
DecalColorShoot( pDecalMaterial, entity, model, model_origin, model_angles, position, w, h, saxis, flags, rgbaColor );
}
/// r_decal.cpp ///
// New header:
void R_DecalShoot( IMaterial* pMaterial, int entity, const model_t *model, const Vector &position, const float *saxis, int flags, const color32 &rgbaColor );
// Backwards compatible:
void R_DecalShoot( int textureIndex, int entity, const model_t *model, const Vector &position, const float *saxis, int flags, const color32 &rgbaColor );
// New methods:
void R_DecalShoot( IMaterial* pMaterial, int entity, const model_t *model, const Vector &position, float w, float h, const Vector *saxis, int flags, const color32 &rgbaColor )
{
R_DecalShoot_( pMaterial, entity, model, position, w, h, saxis, flags, rgbaColor );
}
static void R_DecalShoot_( IMaterial *pMaterial, int entity, const model_t *model, const Vector &position,
float w, float h, const Vector *saxis, int flags, const color32 &rgbaColor, void *userdata = 0 )
{
if ( !model || model->type != mod_brush || !pMaterial )
return;
decalinfo_t decalInfo;
VectorCopy( position, decalInfo.m_Position ); // Pass position in global
decalInfo.m_pModel = (model_t *)model;
decalInfo.m_pBrush = model->brush.pShared;
// Deal with the s axis if one was passed in
if (saxis)
{
flags |= FDECAL_USESAXIS;
VectorCopy( *saxis, decalInfo.m_SAxis );
}
// More state used by R_DecalNode()
decalInfo.m_pMaterial = pMaterial;
decalInfo.m_pUserData = userdata;
// Don't optimize custom decals
if ( !(flags & FDECAL_CUSTOM) )
flags |= FDECAL_CLIPTEST;
decalInfo.m_Flags = flags;
decalInfo.m_Entity = entity;
decalInfo.m_Size = w >> 1;
if ( (int)(h >> 1) > decalInfo.m_Size )
decalInfo.m_Size = h >> 1;
// Compute scale of surface
// FIXME: cache this?
IMaterialVar *decalScaleVar;
bool found;
decalScaleVar = decalInfo.m_pMaterial->FindVar( "$decalScale", &found, false );
if( found )
{
decalInfo.m_scale = 1.0f / decalScaleVar->GetFloatValue();
decalInfo.m_Size *= decalScaleVar->GetFloatValue();
}
else
{
decalInfo.m_scale = 1.0f;
}
// compute the decal dimensions in world space
decalInfo.m_decalWidth = w / decalInfo.m_scale;
decalInfo.m_decalHeight = h / decalInfo.m_scale;
decalInfo.m_Color = rgbaColor;
decalInfo.m_aApplySurfs.Purge();
// Clear the displacement tags because we use them in R_DecalNode.
DispInfo_ClearAllTags( decalInfo.m_pBrush->hDispInfos );
mnode_t *pnodes = decalInfo.m_pBrush->nodes + decalInfo.m_pModel->brush.firstnode;
R_DecalNode( pnodes, &decalInfo );
}
// Backwards compatible:
void R_DecalShoot( int textureIndex, int entity, const model_t *model, const Vector &position, const Vector *saxis, int flags, const color32 &rgbaColor )
{
IMaterial* pMaterial = Draw_DecalMaterial( textureIndex );
if ( pMaterial == NULL )
return;
R_DecalShoot_( pMaterial, entity, model, position, pMaterial->GetMappingWidth(), pMaterial->GetMappingHeight(), saxis, flags, rgbaColor );
}
static void R_DecalShoot_( IMaterial *pMaterial, int entity, const model_t *model,
const Vector &position, const Vector *saxis, int flags, const color32 &rgbaColor, void *userdata = 0 )
{
if ( pMaterial == NULL )
return;
R_DecalShoot_( pMaterial, entity, model, position, pMaterial->GetMappingWidth(), pMaterial->GetMappingHeight(), saxis, flags, rgbaColor, userdata );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment