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.
467 lines
16 KiB
467 lines
16 KiB
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
|
|
//
|
|
// The copyright to the contents herein is the property of Valve, L.L.C.
|
|
// The contents may be used and/or copied only with the written permission of
|
|
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
|
// the agreement/contract under which the contents have been supplied.
|
|
//
|
|
// $Header: $
|
|
// $NoKeywords: $
|
|
//
|
|
// model loading and caching
|
|
//
|
|
//=============================================================================
|
|
|
|
#ifndef IMDLCACHE_H
|
|
#define IMDLCACHE_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "tier0/platform.h"
|
|
|
|
#include "appframework/iappsystem.h"
|
|
#include "filesystem.h"
|
|
#include "string_t.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Forward declarations
|
|
//-----------------------------------------------------------------------------
|
|
struct studiohdr_t;
|
|
struct studiohwdata_t;
|
|
struct vcollide_t;
|
|
struct virtualmodel_t;
|
|
struct vertexFileHeader_t;
|
|
class KeyValues;
|
|
class IDataCacheSection;
|
|
class IVTFTexture;
|
|
|
|
namespace OptimizedModel
|
|
{
|
|
struct FileHeader_t;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Reference to a loaded studiomdl
|
|
//-----------------------------------------------------------------------------
|
|
typedef unsigned short MDLHandle_t;
|
|
|
|
|
|
inline MDLHandle_t VoidPtrToMDLHandle( void *ptr )
|
|
{
|
|
return ( MDLHandle_t ) ( int ) ( intp ) ptr;
|
|
}
|
|
|
|
inline void* MDLHandleToVirtual( MDLHandle_t hndl )
|
|
{
|
|
return (void*)(uintp)hndl;
|
|
}
|
|
|
|
enum
|
|
{
|
|
MDLHANDLE_INVALID = (MDLHandle_t)~0
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Cache data types
|
|
//-----------------------------------------------------------------------------
|
|
enum MDLCacheDataType_t
|
|
{
|
|
MDLCACHE_NONE = -1,
|
|
|
|
// Callbacks to get called when data is loaded or unloaded for these:
|
|
MDLCACHE_STUDIOHDR = 0,
|
|
MDLCACHE_STUDIOHWDATA,
|
|
MDLCACHE_VCOLLIDE,
|
|
|
|
// Callbacks NOT called when data is loaded or unloaded for these:
|
|
MDLCACHE_ANIMBLOCK,
|
|
MDLCACHE_VIRTUALMODEL,
|
|
MDLCACHE_VERTEXES,
|
|
MDLCACHE_DECODEDANIMBLOCK
|
|
};
|
|
|
|
abstract_class IMDLCacheNotify
|
|
{
|
|
public:
|
|
virtual ~IMDLCacheNotify() { };
|
|
|
|
// Called right after the data is loaded
|
|
virtual void OnDataLoaded( MDLCacheDataType_t type, MDLHandle_t handle ) = 0;
|
|
|
|
// Called right before combiner process data into cache
|
|
virtual void OnCombinerPreCache( MDLHandle_t OldHandle, MDLHandle_t NewHandle ) = 0;
|
|
|
|
// Called right before the data is unloaded
|
|
virtual void OnDataUnloaded( MDLCacheDataType_t type, MDLHandle_t handle ) = 0;
|
|
|
|
virtual bool ShouldSupressLoadWarning( MDLHandle_t handle ) = 0;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Flags for flushing
|
|
//-----------------------------------------------------------------------------
|
|
enum MDLCacheFlush_t
|
|
{
|
|
MDLCACHE_FLUSH_STUDIOHDR = 0x01,
|
|
MDLCACHE_FLUSH_STUDIOHWDATA = 0x02,
|
|
MDLCACHE_FLUSH_VCOLLIDE = 0x04,
|
|
MDLCACHE_FLUSH_ANIMBLOCK = 0x08,
|
|
MDLCACHE_FLUSH_VIRTUALMODEL = 0x10,
|
|
MDLCACHE_FLUSH_AUTOPLAY = 0x20,
|
|
MDLCACHE_FLUSH_VERTEXES = 0x40,
|
|
MDLCACHE_FLUSH_COMBINED_DATA = 0x80,
|
|
|
|
MDLCACHE_FLUSH_IGNORELOCK = 0x80000000,
|
|
MDLCACHE_FLUSH_ALL = 0xFFFFFFFF
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Combiner
|
|
//-----------------------------------------------------------------------------
|
|
#define COMBINER_MAX_MODELS 15
|
|
#define COMBINER_MAX_LODS 8
|
|
#define COMBINER_MAX_TEXTURES_PER_MATERIAL 5
|
|
#define COMBINER_MAX_ATLAS_GROUPS 5
|
|
#define COMBINER_MAX_MATERIALS_PER_INPUT_MODEL 4
|
|
|
|
|
|
enum ECombinedResult
|
|
{
|
|
COMBINE_RESULT_FLAG_OK = 0,
|
|
COMBINE_RESULT_FLAG_TOO_MANY_STRINGS,
|
|
COMBINE_RESULT_FLAG_OUT_OF_MEMORY,
|
|
COMBINE_RESULT_FLAG_TOO_MANY_BONES,
|
|
COMBINE_RESULT_FLAG_UNSUPPORTED_FEATURE, // Major feature of the formats that isn't supported. You'll need to debug the specific cause of this.
|
|
COMBINE_RESULT_FLAG_UNHANDLED_ISSUE, // Minor section of the formats that wasn't expected. You'll need to debug the specific cause of this.
|
|
COMBINE_RESULT_FLAG_MISSING_ASSET_FILE,
|
|
COMBINE_RESULT_FLAG_UNSUPPORTED_SHADER,
|
|
COMBINE_RESULT_FLAG_FAILED_GOOD_PRACTICE, // Not necessarily an error, but sanity checks to make sure we are doing good practices
|
|
COMBINE_RESULT_FLAG_KEY_VALUE_FAILURE,
|
|
};
|
|
|
|
|
|
enum EDetailedError
|
|
{
|
|
COMBINED_DETAIL_ERROR_NOT_SPECIFIED = 0,
|
|
COMBINED_DETAIL_ERROR_TEXTURE_PACKER_NO_SPACE,
|
|
COMBINED_DETAIL_ERROR_MODEL_PACKER_TOO_MANY_MATERIALS,
|
|
COMBINED_DETAIL_ERROR_TEXTURE_COORDINATES_WRAP,
|
|
COMBINED_DETAIL_ERROR_MODEL_LOWER_LOD_HIGHER_TRI_COUNT,
|
|
};
|
|
|
|
|
|
typedef struct SCombinedResults
|
|
{
|
|
// individual model info
|
|
int m_nNumVerts[ COMBINER_MAX_MODELS ][ COMBINER_MAX_LODS ];
|
|
int m_nNumIndexes[ COMBINER_MAX_MODELS ][ COMBINER_MAX_LODS ];
|
|
int m_nBatches[ COMBINER_MAX_MODELS ][ COMBINER_MAX_LODS ];
|
|
int m_nNumLODs[ COMBINER_MAX_MODELS ];
|
|
|
|
// cumulative combined info
|
|
int m_nCombinedNumVerts[ COMBINER_MAX_LODS ];
|
|
int m_nCombinedNumIndexes[ COMBINER_MAX_LODS ];
|
|
int m_nCombinedBatches[ COMBINER_MAX_LODS ];
|
|
int m_nCombinedNumLODs;
|
|
int m_nNumTexturePackIterations;
|
|
unsigned int m_nCombinedResults;
|
|
char m_szErrorMessage[ 256 ];
|
|
char m_szErrorDetails[ 4096 ];
|
|
unsigned int m_nDetailedError;
|
|
float m_flModelLoadDuration;
|
|
float m_flModelCombineDuration;
|
|
float m_flTextureLoadDuration;
|
|
float m_flTextureCombineDuration;
|
|
float m_flEngineProcessingDuration;
|
|
} TCombinedResults;
|
|
|
|
|
|
enum ECombinedAsset
|
|
{
|
|
COMBINED_ASSET_MATERIAL = 0,
|
|
COMBINED_ASSET_TEXTURE,
|
|
|
|
COMBINED_ASSET_MAX
|
|
};
|
|
|
|
|
|
enum ECombinerFlags
|
|
{
|
|
COMBINER_FLAG_THREADING = 0x00000001,
|
|
COMBINER_FLAG_NO_DATA_PROCESSING = 0x00000002,
|
|
};
|
|
|
|
struct STextureSubstitute_t
|
|
{
|
|
STextureSubstitute_t()
|
|
: m_iszMaterialParam( NULL_STRING )
|
|
, m_pVTFTexture( NULL )
|
|
{
|
|
}
|
|
|
|
string_t m_iszMaterialParam;
|
|
IVTFTexture *m_pVTFTexture;
|
|
};
|
|
|
|
struct SCombinerModelInput_t
|
|
{
|
|
SCombinerModelInput_t()
|
|
: m_iszModelName( NULL_STRING )
|
|
, m_nSkinFamily( 0 )
|
|
, m_nBodyGroupSubModelSelection ( -1 )
|
|
{
|
|
}
|
|
|
|
SCombinerModelInput_t( string_t iszModelName, int nSkinFamily = 0, int nBodyGroupSubModelSelection = -1 )
|
|
: m_iszModelName( iszModelName )
|
|
, m_nSkinFamily( nSkinFamily )
|
|
, m_nBodyGroupSubModelSelection( nBodyGroupSubModelSelection )
|
|
{
|
|
}
|
|
|
|
string_t m_iszModelName;
|
|
int m_nSkinFamily;
|
|
int m_nBodyGroupSubModelSelection; // -1 means no selection, include all body part sub models
|
|
STextureSubstitute_t m_textureSubstitutes[ COMBINER_MAX_MATERIALS_PER_INPUT_MODEL ][ COMBINER_MAX_TEXTURES_PER_MATERIAL ]; // entries can have NULL contents, it means don't substitute (use the one the mdl says)
|
|
};
|
|
|
|
// Callback for the combining process
|
|
// pUserData: the pointer you optionally specified in the FinishedCombinedModel() call
|
|
// OldHandle: either the temporary model model returned by CreateCombinedModel() or MDLHANDLE_INVALID if reusing an existing handle
|
|
// NewHandle: the combined model handle, which may be your reused model handle specified in CreateCombinedModel()
|
|
// CombinedResults: various statistical and timing information about the model and combining process
|
|
typedef void (*CombinedModelLoadedCallback)( void *pUserData, MDLHandle_t OldHandle, MDLHandle_t NewHandle, TCombinedResults &CombinedResults );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The main MDL cacher
|
|
//-----------------------------------------------------------------------------
|
|
abstract_class IMDLCache : public IAppSystem
|
|
{
|
|
public:
|
|
// Used to install callbacks for when data is loaded + unloaded
|
|
// Returns the prior notify
|
|
virtual void SetCacheNotify( IMDLCacheNotify *pNotify ) = 0;
|
|
|
|
// NOTE: This assumes the "GAME" path if you don't use
|
|
// the UNC method of specifying files. This will also increment
|
|
// the reference count of the MDL
|
|
virtual MDLHandle_t FindMDL( const char *pMDLRelativePath ) = 0;
|
|
|
|
// Reference counting
|
|
virtual int AddRef( MDLHandle_t handle ) = 0;
|
|
virtual int Release( MDLHandle_t handle ) = 0;
|
|
virtual int GetRef( MDLHandle_t handle ) = 0;
|
|
|
|
// Gets at the various data associated with a MDL
|
|
virtual studiohdr_t *GetStudioHdr( MDLHandle_t handle ) = 0;
|
|
virtual studiohwdata_t *GetHardwareData( MDLHandle_t handle ) = 0;
|
|
virtual vcollide_t *GetVCollide( MDLHandle_t handle ) = 0;
|
|
virtual unsigned char *GetAnimBlock( MDLHandle_t handle, int nBlock, bool preloadIfMissing ) = 0;
|
|
virtual bool HasAnimBlockBeenPreloaded( MDLHandle_t handle, int nBlock ) = 0;
|
|
virtual virtualmodel_t *GetVirtualModel( MDLHandle_t handle ) = 0;
|
|
virtual int GetAutoplayList( MDLHandle_t handle, unsigned short **pOut ) = 0;
|
|
virtual vertexFileHeader_t *GetVertexData( MDLHandle_t handle ) = 0;
|
|
|
|
// Brings all data associated with an MDL into memory
|
|
virtual void TouchAllData( MDLHandle_t handle ) = 0;
|
|
|
|
// Gets/sets user data associated with the MDL
|
|
virtual void SetUserData( MDLHandle_t handle, void* pData ) = 0;
|
|
virtual void *GetUserData( MDLHandle_t handle ) = 0;
|
|
|
|
// Is this MDL using the error model?
|
|
virtual bool IsErrorModel( MDLHandle_t handle ) = 0;
|
|
virtual bool IsOverBudget( MDLHandle_t handle ) = 0;
|
|
|
|
// Flushes the cache, force a full discard
|
|
virtual void Flush( MDLCacheFlush_t nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0;
|
|
|
|
// Flushes a particular model out of memory
|
|
virtual void Flush( MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL ) = 0;
|
|
|
|
// Returns the name of the model (its relative path)
|
|
virtual const char *GetModelName( MDLHandle_t handle ) = 0;
|
|
|
|
virtual IDataCacheSection *GetCacheSection( MDLCacheDataType_t type ) =0;
|
|
|
|
// faster access when you already have the studiohdr
|
|
virtual virtualmodel_t *GetVirtualModelFast( const studiohdr_t *pStudioHdr, MDLHandle_t handle ) = 0;
|
|
|
|
// all cache entries that subsequently allocated or successfully checked
|
|
// are considered "locked" and will not be freed when additional memory is needed
|
|
virtual void BeginLock() = 0;
|
|
|
|
// reset all protected blocks to normal
|
|
virtual void EndLock() = 0;
|
|
|
|
// returns a pointer to a counter that is incremented every time the cache has been out of the locked state (EVIL)
|
|
virtual int *GetFrameUnlockCounterPtrOLD() = 0;
|
|
|
|
// Finish all pending async operations
|
|
virtual void FinishPendingLoads() = 0;
|
|
|
|
virtual vcollide_t *GetVCollideEx( MDLHandle_t handle, bool synchronousLoad = true ) = 0;
|
|
virtual bool GetVCollideSize( MDLHandle_t handle, int *pVCollideSize ) = 0;
|
|
|
|
virtual bool GetAsyncLoad( MDLCacheDataType_t type ) = 0;
|
|
virtual bool SetAsyncLoad( MDLCacheDataType_t type, bool bAsync ) = 0;
|
|
|
|
virtual void BeginMapLoad() = 0;
|
|
virtual void EndMapLoad() = 0;
|
|
virtual void MarkAsLoaded( MDLHandle_t handle ) = 0;
|
|
|
|
virtual void InitPreloadData( bool rebuild ) = 0;
|
|
virtual void ShutdownPreloadData() = 0;
|
|
|
|
virtual bool IsDataLoaded( MDLHandle_t handle, MDLCacheDataType_t type ) = 0;
|
|
|
|
virtual int *GetFrameUnlockCounterPtr( MDLCacheDataType_t type ) = 0;
|
|
|
|
virtual studiohdr_t *LockStudioHdr( MDLHandle_t handle ) = 0;
|
|
virtual void UnlockStudioHdr( MDLHandle_t handle ) = 0;
|
|
|
|
virtual bool PreloadModel( MDLHandle_t handle ) = 0;
|
|
|
|
// Hammer uses this. If a model has an error loading in GetStudioHdr, then it is flagged
|
|
// as an error model and any further attempts to load it will just get the error model.
|
|
// That is, until you call this function. Then it will load the correct model.
|
|
virtual void ResetErrorModelStatus( MDLHandle_t handle ) = 0;
|
|
|
|
virtual void MarkFrame() = 0;
|
|
|
|
// Locking for things that we can lock over longer intervals than
|
|
// resources locked by BeginLock/EndLock
|
|
virtual void BeginCoarseLock() = 0;
|
|
virtual void EndCoarseLock() = 0;
|
|
|
|
virtual void ReloadVCollide( MDLHandle_t handle ) = 0;
|
|
|
|
virtual bool ReleaseAnimBlockAllocator() = 0;
|
|
|
|
virtual bool RestoreHardwareData( MDLHandle_t handle, FSAsyncControl_t *pAsyncVTXControl, FSAsyncControl_t *pAsyncVVDControl ) = 0;
|
|
|
|
virtual void DisableVCollideLoad() = 0;
|
|
virtual void EnableVCollideLoad() = 0;
|
|
|
|
virtual void DisableFileNotFoundWarnings() = 0;
|
|
virtual void EnableFileNotFoundWarnings() = 0;
|
|
|
|
virtual bool ProcessPendingHardwareRestore() = 0;
|
|
|
|
virtual void UnloadQueuedHardwareData( ) = 0;
|
|
|
|
virtual void DumpDictionaryState( ) = 0;
|
|
|
|
// ========================
|
|
// combined models
|
|
|
|
// This will create a combined model by the name specified in pszModelName and return back a temporary model handle.
|
|
// May return MDLHANDLE_INVALID if the name is a duplicate of an existing model
|
|
virtual MDLHandle_t CreateCombinedModel( const char *pszModelName ) = 0;
|
|
|
|
// This will create a combined model in replace of an existing model handle. The handle should be valid to use during the entire process.
|
|
// Returns true if the handle is acceptable to use for the combining process.
|
|
virtual bool CreateCombinedModel( MDLHandle_t handle ) = 0;
|
|
|
|
// Sets the models for the combining process
|
|
virtual bool SetCombineModels( MDLHandle_t handle, const CUtlVector< SCombinerModelInput_t > &vecModelsToCombine ) = 0;
|
|
|
|
// Indicates that you are done with the setup of the combining process. You must specify a callback function and optionally
|
|
// a user pointer that will be supplied to you in the callback
|
|
virtual bool FinishCombinedModel( MDLHandle_t handle, CombinedModelLoadedCallback pFunc, void *pUserData = NULL ) = 0;
|
|
|
|
// Lets you query a model handle to see if it is a placeholder returned by CreateCombinedModel()
|
|
virtual bool IsCombinedPlaceholder( MDLHandle_t handle ) = 0;
|
|
|
|
// Lets you query a model handle to see if it is a combined model
|
|
virtual bool IsCombinedModel( MDLHandle_t handle ) = 0;
|
|
|
|
// Returns the number of models contained in the combined model. Includes primary and all secondary models
|
|
virtual int GetNumCombinedSubModels( MDLHandle_t handle ) = 0;
|
|
|
|
// Gets the file name for a sub model
|
|
virtual void GetCombinedSubModelFilename( MDLHandle_t handle, int nSubModelIndex, char *pszResult, int nResultSize ) = 0;
|
|
|
|
// Returns the KV of the material set for the model. You are responsible for calling deleteThis() on the result.
|
|
virtual KeyValues *GetCombinedMaterialKV( MDLHandle_t handle, int nAtlasGroup = 0 ) = 0;
|
|
|
|
// Internal engine use function to help drive the combining process.
|
|
virtual void UpdateCombiner( ) = 0; // should be called from main thread after rendering has completed
|
|
|
|
// Internal engine function to help get access to specific combined assets
|
|
virtual void *GetCombinedInternalAsset( ECombinedAsset AssetType, const char *pszAssetID = NULL, int *nSize = NULL ) = 0;
|
|
|
|
// Set Combiner Flags
|
|
virtual void SetCombinerFlags( unsigned nFlags ) = 0;
|
|
|
|
// Clear Combiner Flags
|
|
virtual void ClearCombinerFlags( unsigned nFlags ) = 0;
|
|
|
|
// Dump out resident combiner info
|
|
virtual void DebugCombinerInfo( ) = 0;
|
|
};
|
|
|
|
DECLARE_TIER3_INTERFACE( IMDLCache, g_pMDLCache );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Critical section helper code
|
|
//-----------------------------------------------------------------------------
|
|
class CMDLCacheCriticalSection
|
|
{
|
|
public:
|
|
CMDLCacheCriticalSection( IMDLCache *pCache ) : m_pCache( pCache )
|
|
{
|
|
m_pCache->BeginLock();
|
|
}
|
|
|
|
~CMDLCacheCriticalSection()
|
|
{
|
|
m_pCache->EndLock();
|
|
}
|
|
|
|
private:
|
|
IMDLCache *m_pCache;
|
|
};
|
|
|
|
class CMDLCacheCoarseCriticalSection
|
|
{
|
|
public:
|
|
CMDLCacheCoarseCriticalSection( IMDLCache *pCache ) : m_pCache( pCache )
|
|
{
|
|
m_pCache->BeginCoarseLock();
|
|
}
|
|
|
|
~CMDLCacheCoarseCriticalSection()
|
|
{
|
|
m_pCache->EndCoarseLock();
|
|
}
|
|
|
|
private:
|
|
IMDLCache *m_pCache;
|
|
};
|
|
|
|
#define MDCACHE_FINE_GRAINED 1
|
|
|
|
#if defined(MDCACHE_FINE_GRAINED)
|
|
#define MDLCACHE_CRITICAL_SECTION_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache)
|
|
#define MDLCACHE_COARSE_LOCK_( pCache ) CMDLCacheCoarseCriticalSection cacheCoarseCriticalSection(pCache)
|
|
#elif defined(MDLCACHE_LEVEL_LOCKED)
|
|
#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0))
|
|
#define MDLCACHE_COARSE_LOCK_( pCache ) ((void)(0))
|
|
#else
|
|
#define MDLCACHE_CRITICAL_SECTION_( pCache ) ((void)(0))
|
|
#define MDLCACHE_COARSE_LOCK_( pCache ) CMDLCacheCriticalSection cacheCriticalSection(pCache); CMDLCacheCoarseCriticalSection cacheCoarseCriticalSection(pCache)
|
|
#endif
|
|
#define MDLCACHE_CRITICAL_SECTION() MDLCACHE_CRITICAL_SECTION_(mdlcache)
|
|
#define MDLCACHE_COARSE_LOCK() MDLCACHE_COARSE_LOCK_(mdlcache)
|
|
|
|
#endif // IMDLCACHE_H
|
|
|