summaryrefslogtreecommitdiff
path: root/hammer/sprite.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/sprite.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'hammer/sprite.cpp')
-rw-r--r--hammer/sprite.cpp593
1 files changed, 593 insertions, 0 deletions
diff --git a/hammer/sprite.cpp b/hammer/sprite.cpp
new file mode 100644
index 0000000..f1d8699
--- /dev/null
+++ b/hammer/sprite.cpp
@@ -0,0 +1,593 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "stdafx.h"
+#include "const.h"
+#include "Sprite.h"
+#include "Material.h" // FIXME: we need to work only with IEditorTexture!
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "Render3d.h"
+#include "camera.h"
+#include "tier1/utldict.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+class CSpriteDataCache
+{
+public:
+ CMaterial *m_pMaterial;
+ IMaterialVar *m_pFrameVar;
+ IMaterialVar *m_pRenderModeVar;
+ IMaterialVar *m_pOrientationVar;
+ IMaterialVar *m_pOriginVar;
+ int m_Width;
+ int m_Height;
+ bool m_bOriginVarFound;
+ bool m_bOrientationVarFound;
+};
+
+
+CUtlDict<CSpriteDataCache*, int> g_SpriteDataCache;
+SpriteCache_t CSpriteCache::m_Cache[SPRITE_CACHE_SIZE];
+int CSpriteCache::m_nItems = 0;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns an instance of a particular studio model. If the model is
+// in the cache, a pointer to that model is returned. If not, a new one
+// is created and added to the cache.
+// Input : pszModelPath - Full path of the .MDL file.
+//-----------------------------------------------------------------------------
+CSpriteModel *CSpriteCache::CreateSprite(const char *pszSpritePath)
+{
+ //
+ // First look for the sprite in the cache. If it's there, increment the
+ // reference count and return a pointer to the cached sprite.
+ //
+ for (int i = 0; i < m_nItems; i++)
+ {
+ if (!stricmp(pszSpritePath, m_Cache[i].pszPath))
+ {
+ m_Cache[i].nRefCount++;
+ return(m_Cache[i].pSprite);
+ }
+ }
+
+ //
+ // If it isn't there, try to create one.
+ //
+ CSpriteModel *pSprite = new CSpriteModel;
+
+ if (pSprite != NULL)
+ {
+ if (!pSprite->LoadSprite(pszSpritePath))
+ {
+ delete pSprite;
+ pSprite = NULL;
+ }
+ }
+
+ //
+ // If we successfully created it, add it to the cache.
+ //
+ if (pSprite != NULL)
+ {
+ CSpriteCache::AddSprite(pSprite, pszSpritePath);
+ }
+
+ return(pSprite);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds the model to the cache, setting the reference count to one.
+// Input : pModel - Model to add to the cache.
+// pszSpritePath - The full path of the .MDL file, which is used as a
+// key in the sprite cache.
+// Output : Returns TRUE if the sprite was successfully added, FALSE if we ran
+// out of memory trying to add the sprite to the cache.
+//-----------------------------------------------------------------------------
+bool CSpriteCache::AddSprite(CSpriteModel *pSprite, const char *pszSpritePath)
+{
+ //
+ // Copy the sprite pointer.
+ //
+ m_Cache[m_nItems].pSprite = pSprite;
+
+ //
+ // Allocate space for and copy the model path.
+ //
+ m_Cache[m_nItems].pszPath = new char [strlen(pszSpritePath) + 1];
+ if (m_Cache[m_nItems].pszPath != NULL)
+ {
+ strcpy(m_Cache[m_nItems].pszPath, pszSpritePath);
+ }
+ else
+ {
+ return(false);
+ }
+
+ m_Cache[m_nItems].nRefCount = 1;
+
+ m_nItems++;
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Increments the reference count on a sprite in the cache. Called by
+// client code when a pointer to the sprite is copied, making that
+// reference independent.
+// Input : pModel - Sprite for which to increment the reference count.
+//-----------------------------------------------------------------------------
+void CSpriteCache::AddRef(CSpriteModel *pSprite)
+{
+ for (int i = 0; i < m_nItems; i++)
+ {
+ if (m_Cache[i].pSprite == pSprite)
+ {
+ m_Cache[i].nRefCount++;
+ return;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called by client code to release an instance of a model. If the
+// model's reference count is zero, the model is freed.
+// Input : pModel - Pointer to the model to release.
+//-----------------------------------------------------------------------------
+void CSpriteCache::Release(CSpriteModel *pSprite)
+{
+ for (int i = 0; i < m_nItems; i++)
+ {
+ if (m_Cache[i].pSprite == pSprite)
+ {
+ m_Cache[i].nRefCount--;
+ Assert(m_Cache[i].nRefCount >= 0);
+
+ //
+ // If this model is no longer referenced, free it and remove it
+ // from the cache.
+ //
+ if (m_Cache[i].nRefCount <= 0)
+ {
+ //
+ // Free the path, which was allocated by AddModel.
+ //
+ delete [] m_Cache[i].pszPath;
+ delete m_Cache[i].pSprite;
+
+ //
+ // Decrement the item count and copy the last element in the cache over
+ // this element.
+ //
+ m_nItems--;
+
+ m_Cache[i].pSprite = m_Cache[m_nItems].pSprite;
+ m_Cache[i].pszPath = m_Cache[m_nItems].pszPath;
+ m_Cache[i].nRefCount = m_Cache[m_nItems].nRefCount;
+ }
+
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+CSpriteModel::CSpriteModel(void) :
+ m_pMaterial(0), m_NumFrames(-1), m_fScale(1.0), m_Origin(0,0,0), m_UL(0,0), m_LR(0,0), m_TexUL(0,1), m_TexLR(1,0), m_bInvert(false)
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor. Frees the sprite image and descriptor.
+//-----------------------------------------------------------------------------
+CSpriteModel::~CSpriteModel(void)
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the render mode
+//-----------------------------------------------------------------------------
+void CSpriteModel::SetRenderMode( const int mode )
+{
+ if (m_pMaterial && m_pRenderModeVar)
+ {
+ if ( mode != m_pRenderModeVar->GetIntValue() )
+ {
+ m_pRenderModeVar->SetIntValue( mode );
+ m_pMaterial->GetMaterial()->RecomputeStateSnapshots();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pEntity -
+// type -
+// forward -
+// right -
+// up -
+//-----------------------------------------------------------------------------
+void CSpriteModel::GetSpriteAxes(QAngle& Angles, int type, Vector& forward, Vector& right, Vector& up, Vector& ViewUp, Vector& ViewRight, Vector& ViewForward)
+{
+ int i;
+ float dot, angle, sr, cr;
+ Vector tvec;
+
+ // Automatically roll parallel sprites if requested
+ if (Angles[2] != 0 && type == SPR_VP_PARALLEL )
+ {
+ type = SPR_VP_PARALLEL_ORIENTED;
+ }
+
+ switch (type)
+ {
+ case SPR_FACING_UPRIGHT:
+ {
+ // generate the sprite's axes, with vup straight up in worldspace, and
+ // r_spritedesc.vright perpendicular to modelorg.
+ // This will not work if the view direction is very close to straight up or
+ // down, because the cross product will be between two nearly parallel
+ // vectors and starts to approach an undefined state, so we don't draw if
+ // the two vectors are less than 1 degree apart
+ tvec[0] = -m_Origin[0];
+ tvec[1] = -m_Origin[1];
+ tvec[2] = -m_Origin[2];
+ VectorNormalize (tvec);
+ dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
+ // r_spritedesc.vup is 0, 0, 1
+ if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
+ return;
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 1;
+ right[0] = tvec[1];
+ // CrossProduct(r_spritedesc.vup, -modelorg,
+ right[1] = -tvec[0];
+ // r_spritedesc.vright)
+ right[2] = 0;
+ VectorNormalize (right);
+ forward[0] = -right[1];
+ forward[1] = right[0];
+ forward[2] = 0;
+ // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
+ // r_spritedesc.vpn)
+ break;
+ }
+
+ case SPR_VP_PARALLEL:
+ {
+ // generate the sprite's axes, completely parallel to the viewplane. There
+ // are no problem situations, because the sprite is always in the same
+ // position relative to the viewer
+ for (i=0 ; i<3 ; i++)
+ {
+ up[i] = ViewUp[i];
+ right[i] = ViewRight[i];
+ forward[i] = ViewForward[i];
+ }
+ break;
+ }
+
+ case SPR_VP_PARALLEL_UPRIGHT:
+ {
+ // generate the sprite's axes, with vup straight up in worldspace, and
+ // r_spritedesc.vright parallel to the viewplane.
+ // This will not work if the view direction is very close to straight up or
+ // down, because the cross product will be between two nearly parallel
+ // vectors and starts to approach an undefined state, so we don't draw if
+ // the two vectors are less than 1 degree apart
+ dot = ViewForward[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
+ // r_spritedesc.vup is 0, 0, 1
+ if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
+ return;
+
+ up[0] = 0;
+ up[1] = 0;
+ up[2] = 1;
+
+ right[0] = ViewForward[1];
+ right[1] = -ViewForward[0];
+ right[2] = 0;
+ VectorNormalize (right);
+
+ forward[0] = -right[1];
+ forward[1] = right[0];
+ forward[2] = 0;
+ break;
+ }
+
+ case SPR_ORIENTED:
+ {
+ // generate the sprite's axes, according to the sprite's world orientation
+ AngleVectors(Angles, &forward, &right, &up);
+ break;
+ }
+
+ case SPR_VP_PARALLEL_ORIENTED:
+ {
+ // generate the sprite's axes, parallel to the viewplane, but rotated in
+ // that plane around the center according to the sprite entity's roll
+ // angle. So vpn stays the same, but vright and vup rotate
+ angle = Angles[ROLL] * (M_PI*2 / 360);
+ sr = sin(angle);
+ cr = cos(angle);
+
+ for (i=0 ; i<3 ; i++)
+ {
+ forward[i] = ViewForward[i];
+ right[i] = ViewRight[i] * cr + ViewUp[i] * sr;
+ up[i] = ViewRight[i] * -sr + ViewUp[i] * cr;
+ }
+ break;
+ }
+
+ default:
+ {
+ //Sys_Error ("R_DrawSprite: Bad sprite type %d", type);
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Sets the sprite's scale
+//-----------------------------------------------------------------------------
+
+void CSpriteModel::SetScale( const float fScale )
+{
+ m_fScale = fScale;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the sprite's origin
+//-----------------------------------------------------------------------------
+
+void CSpriteModel::SetOrigin( const Vector &v )
+{
+ m_Origin = v;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the sprite's origin
+//-----------------------------------------------------------------------------
+
+void CSpriteModel::GetOrigin( Vector &v )
+{
+ v = m_Origin;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the sprite's vertical inversion
+//-----------------------------------------------------------------------------
+
+void CSpriteModel::SetInvert( const bool b )
+{
+ m_bInvert = b;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the Euler angles for the model.
+// Input : fAngles - A pointer to engine PITCH, YAW, and ROLL angles.
+//-----------------------------------------------------------------------------
+void CSpriteModel::SetAngles( const QAngle& pfAngles )
+{
+ m_Angles[PITCH] = pfAngles[PITCH];
+ m_Angles[YAW] = pfAngles[YAW];
+ m_Angles[ROLL] = pfAngles[ROLL];
+}
+
+//-----------------------------------------------------------------------------
+// Sets the material's primative type
+//-----------------------------------------------------------------------------
+
+void CSpriteModel::SetMaterialPrimitiveType( const MaterialPrimitiveType_t type )
+{
+ m_MaterialPrimitiveType = type;
+}
+
+//-----------------------------------------------------------------------------
+// Renders the sprite in 3D mode
+//-----------------------------------------------------------------------------
+
+void CSpriteModel::DrawSprite3D( CRender3D *pRender, unsigned char color[3] )
+{
+ Vector corner, spritex, spritey, spritez;
+ Vector ViewUp;
+ Vector ViewRight;
+ Vector ViewForward;
+
+ pRender->GetViewUp( ViewUp );
+ pRender->GetViewRight( ViewRight );
+ pRender->GetViewForward( ViewForward );
+
+ GetSpriteAxes(m_Angles, GetType(), spritez, spritex, spritey, ViewUp, ViewRight, ViewForward);
+
+ Vector2D ul, lr;
+ Vector2DMultiply( m_UL, m_fScale, ul );
+ Vector2DMultiply( m_LR, m_fScale, lr );
+
+ VectorMA( m_Origin, ul.x, spritex, corner );
+ VectorMA( corner, lr.y, spritey, corner );
+ spritex *= (lr.x - ul.x);
+ spritey *= (ul.y - lr.y);
+
+ Vector2D texul, texlr;
+ texul.x = m_TexUL.x;
+ texul.y = m_bInvert ? m_TexLR.y : m_TexUL.y;
+ texlr.x = m_TexLR.x;
+ texlr.y = m_bInvert ? m_TexUL.y : m_TexLR.y;
+
+
+ CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
+ pRender->BindTexture( m_pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, m_MaterialPrimitiveType, 4 );
+
+ meshBuilder.Position3fv(corner.Base());
+ meshBuilder.TexCoord2f(0, texul.x, texul.y);
+ meshBuilder.Color3ub( color[0], color[1], color[2] );
+ meshBuilder.AdvanceVertex();
+
+ corner += spritey;
+ meshBuilder.Position3fv(corner.Base());
+ meshBuilder.TexCoord2f(0, texul.x, texlr.y);
+ meshBuilder.Color3ub( color[0], color[1], color[2] );
+ meshBuilder.AdvanceVertex();
+
+ corner += spritex;
+ meshBuilder.Position3fv(corner.Base());
+ meshBuilder.TexCoord2f(0, texlr.x, texlr.y);
+ meshBuilder.Color3ub( color[0], color[1], color[2] );
+ meshBuilder.AdvanceVertex();
+
+ corner -= spritey;
+ meshBuilder.Position3fv(corner.Base());
+ meshBuilder.TexCoord2f(0, texlr.x, texul.y);
+ meshBuilder.Color3ub( color[0], color[1], color[2] );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Binds a sprite
+//-----------------------------------------------------------------------------
+void CSpriteModel::Bind( CRender* pRender, int frame )
+{
+ if (m_pMaterial && m_pFrameVar)
+ {
+ m_pFrameVar->SetIntValue( frame );
+ pRender->BindTexture( m_pMaterial );
+ }
+}
+
+
+CSpriteDataCache* LookupSpriteDataCache( const char *pSpritePath )
+{
+ char filename[MAX_PATH];
+ V_strncpy( filename, pSpritePath, sizeof( filename ) );
+ V_FixSlashes( filename );
+
+ CSpriteDataCache *pData;
+ int i = g_SpriteDataCache.Find( filename );
+ if ( i == g_SpriteDataCache.InvalidIndex() )
+ {
+ pData = new CSpriteDataCache;
+ memset( pData, 0, sizeof( *pData ) );
+ g_SpriteDataCache.Insert( filename, pData );
+
+ pData->m_pMaterial = CMaterial::CreateMaterial( filename, true );
+ if ( pData->m_pMaterial && pData->m_pMaterial->GetMaterial() )
+ {
+ pData->m_Width = pData->m_pMaterial->GetWidth();
+ pData->m_Height = pData->m_pMaterial->GetHeight();
+ pData->m_pFrameVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriteFrame", 0 );
+ pData->m_pRenderModeVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriterendermode", 0 );
+
+ pData->m_pOrientationVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriteOrientation", &pData->m_bOrientationVarFound, false );
+ pData->m_pOriginVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriteorigin", &pData->m_bOriginVarFound );
+ }
+ }
+ else
+ {
+ pData = g_SpriteDataCache[i];
+ }
+
+ return pData;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads a sprite material.
+// Input : pszSpritePath -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+
+bool CSpriteModel::LoadSprite(const char *pszSpritePath)
+{
+ CSpriteDataCache *pCache = LookupSpriteDataCache( pszSpritePath );
+
+ m_pMaterial = pCache->m_pMaterial;
+ if( m_pMaterial && m_pMaterial->GetMaterial() )
+ {
+ m_Width = pCache->m_Width;
+ m_Height = pCache->m_Height;
+ // FIXME: m_NumFrames = m_pMaterial->GetMaterial()->GetNumAnimationFrames();
+ m_pFrameVar = pCache->m_pFrameVar;
+ m_pRenderModeVar = pCache->m_pRenderModeVar;
+
+ IMaterialVar *orientationVar = pCache->m_pOrientationVar;
+ bool found = pCache->m_bOrientationVarFound;
+ if( found )
+ {
+ m_Type = orientationVar->GetIntValue();
+ }
+ else
+ {
+ m_Type = SPR_VP_PARALLEL_UPRIGHT;
+ }
+
+ IMaterialVar *pOriginVar = pCache->m_pOriginVar;
+ Vector origin;
+ found = pCache->m_bOriginVarFound;
+ if( !found || ( pOriginVar->GetType() != MATERIAL_VAR_TYPE_VECTOR ) )
+ {
+ origin[0] = -m_Width * 0.5f;
+ origin[1] = m_Height * 0.5f;
+ }
+ else
+ {
+ Vector originVarValue;
+ pOriginVar->GetVecValue( originVarValue.Base(), 3);
+ origin[0] = -m_Width * originVarValue[0];
+ origin[1] = m_Height * originVarValue[1];
+ }
+
+ m_UL.y = origin[1];
+ m_LR.y = origin[1] - m_Height;
+ m_UL.x = origin[0];
+ m_LR.x = m_Width + origin[0];
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Kind of a hack...
+//-----------------------------------------------------------------------------
+int CSpriteModel::GetFrameCount()
+{
+ // FIXME: Figure out the correct time to cache in this info
+ if ((m_NumFrames < 0) && m_pMaterial)
+ {
+ m_NumFrames = m_pMaterial->GetMaterial()->GetNumAnimationFrames();
+ }
+ return (m_NumFrames < 0) ? 0 : m_NumFrames;
+} \ No newline at end of file