//===== Copyright 1996-2007, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // //===========================================================================// #ifndef BRUSHBATCHRENDER_H #define BRUSHBATCHRENDER_H #ifdef _WIN32 #pragma once #endif // UNDONE: These are really guesses. Do we ever exceed these limits? const int MAX_TRANS_NODES = 256; const int MAX_TRANS_DECALS = 256; const int MAX_TRANS_BATCHES = 1024; const int MAX_TRANS_SURFACES = 1024; class CBrushBatchRender { public: // These are the compact structs produced by the brush render cache. The goal is to have a compact // list of drawing instructions for drawing an opaque brush model in the most optimal order. // These structs contain ONLY the opaque surfaces of a brush model. struct brushrendersurface_t { short surfaceIndex; short planeIndex; }; // a batch is a list of surfaces with the same material - they can be drawn with one call to the materialsystem struct brushrenderbatch_t { short firstSurface; short surfaceCount; IMaterial *pMaterial; int sortID; int indexCount; }; // a mesh is a list of batches with the same vertex format. struct brushrendermesh_t { short firstBatch; short batchCount; }; // This is the top-level struct containing all data necessary to render an opaque brush model in optimal order struct brushrender_t { // UNDONE: Compact these arrays into a single allocation // UNDONE: Compact entire struct to a single allocation? Store brushrender_t * in the linked list? ~brushrender_t() { delete[] pPlanes; delete[] pMeshes; delete[] pBatches; delete[] pSurfaces; pPlanes = NULL; pMeshes = NULL; pBatches = NULL; pSurfaces = NULL; } cplane_t **pPlanes; brushrendermesh_t *pMeshes; brushrenderbatch_t *pBatches; brushrendersurface_t *pSurfaces; short planeCount; short meshCount; short batchCount; short surfaceCount; short totalIndexCount; short totalVertexCount; }; // Surfaces are stored in a list like this temporarily for sorting purposes only. The compact structs do not store these. struct surfacelist_t { SurfaceHandle_t surfID; short surfaceIndex; short planeIndex; }; // Builds a transrender_t, then executes it's drawing commands void DrawTranslucentBrushModel( IMatRenderContext *pRenderContext, model_t *model, IClientEntity *baseentity ); void LevelInit(); brushrender_t *FindOrCreateRenderBatch( model_t *pModel ); void DrawOpaqueBrushModel( IMatRenderContext *pRenderContext, IClientEntity *baseentity, model_t *model, ERenderDepthMode_t DepthMode ); void DrawTranslucentBrushModel( IMatRenderContext *pRenderContext, IClientEntity *baseentity, model_t *model, ERenderDepthMode_t DepthMode, bool bDrawOpaque, bool bDrawTranslucent ); void DrawBrushModelShadow( IMatRenderContext *pRenderContext, model_t *model, IClientRenderable *pRenderable ); void DrawBrushModelArray( IMatRenderContext* pRenderContext, int nCount, const BrushArrayInstanceData_t *pInstanceData ); void DrawBrushModelShadowArray( IMatRenderContext* pRenderContext, int nCount, const BrushArrayInstanceData_t *pInstanceData, int nModelTypeFlags ); private: struct BrushBatchRenderData_t { const BrushArrayInstanceData_t *m_pInstanceData; IMaterial *m_pMaterial; brushrender_t *m_pBrushRender; uint16 m_nBatchIndex : 15; uint16 m_nHasPaintedSurfaces : 1; int16 m_nLightmapPage : 15; uint16 m_nIsAlphaTested : 1; }; // These are the compact structs produced for translucent brush models. These structs contain // only the translucent surfaces of a brush model. // a batch is a list of surfaces with the same material - they can be drawn with one call to the materialsystem struct transbatch_t { short firstSurface; short surfaceCount; IMaterial *pMaterial; int sortID; int indexCount; }; // This is a list of surfaces that have decals. struct transdecal_t { short firstSurface; short surfaceCount; }; // A node is the list of batches that can be drawn without sorting errors. When no decals are present, surfaces // from the next node may be appended to this one to improve performance without causing sorting errors. struct transnode_t { short firstBatch; short batchCount; short firstDecalSurface; short decalSurfaceCount; }; // This is the top-level struct containing all data necessary to render a translucent brush model in optimal order. // NOTE: Unlike the opaque struct, the order of the batches is view-dependent, so caching this is pointless since // the view usually changes. struct transrender_t { transnode_t nodes[MAX_TRANS_NODES]; SurfaceHandle_t surfaces[MAX_TRANS_SURFACES]; SurfaceHandle_t decalSurfaces[MAX_TRANS_DECALS]; transbatch_t batches[MAX_TRANS_BATCHES]; transbatch_t *pLastBatch; // These are used to append surfaces to existing batches across nodes. transnode_t *pLastNode; // This improves performance. short nodeCount; short batchCount; short surfaceCount; short decalSurfaceCount; }; struct BrushInstanceGroup_t { BrushBatchRenderData_t *m_pRenderData; IMaterial *m_pActualMaterial; IMaterial *m_pMaterial; uint16 m_nCount : 15; uint16 m_nHasPaintedSurfaces : 1; uint16 m_nIndexCount; }; private: // build node lists void BuildTransLists_r( transrender_t &render, model_t *model, mnode_t *node ); void DrawTransLists( IMatRenderContext *pRenderContext, transrender_t &render, void *pProxyData ); void AddSurfaceToBatch( transrender_t &render, transnode_t *pNode, transbatch_t *pBatch, SurfaceHandle_t surfID ); void AddTransNode( transrender_t &render ); void AddTransBatch( transrender_t &render, SurfaceHandle_t surfID ); void BuildBatchListToDraw( int nCount, const BrushArrayInstanceData_t *pInstanceData, CUtlVectorFixedGrowable< BrushBatchRenderData_t, 1024 > &batchesToRender, brushrender_t **ppBrushRender ); bool DrawSortedBatchList( IMatRenderContext* pRenderContext, int nCount, BrushInstanceGroup_t *pInstanceGroup, int nMaxInstanceCount ); void DrawPaintForBatches( IMatRenderContext* pRenderContext, int nCount, const BrushInstanceGroup_t *pInstanceGroup, int nMaxInstanceCount ); void ComputeLightmapPages( int nCount, BrushBatchRenderData_t *pRenderData ); void ClearRenderHandles(); int ComputeInstanceGroups( IMatRenderContext *pRenderContext, int nCount, BrushBatchRenderData_t *pRenderData, CUtlVectorFixedGrowable< BrushInstanceGroup_t, 512 > &instanceGroups ); void DrawArrayDebugInformation( IMatRenderContext *pRenderContext, int nCount, const BrushBatchRenderData_t *pRenderData ); void DrawDecalsForBatches( IMatRenderContext *pRenderContext, int nCount, const BrushArrayInstanceData_t *pInstanceData, brushrender_t **ppBrushRender ); void BuildShadowBatchListToDraw( int nCount, const BrushArrayInstanceData_t *pInstanceData, CUtlVectorFixedGrowable< BrushBatchRenderData_t, 1024 > &batchesToRender, int nModelTypeFlags ); void DrawShadowBatchList( IMatRenderContext* pRenderContext, int nCount, BrushInstanceGroup_t *pInstanceGroup, int nMaxInstanceCount ); static int __cdecl SurfaceCmp(const surfacelist_t *s0, const surfacelist_t *s1 ); static bool __cdecl BatchSortLessFunc( const BrushBatchRenderData_t &left, const BrushBatchRenderData_t &right ); static bool __cdecl ShadowSortLessFunc( const BrushBatchRenderData_t &left, const BrushBatchRenderData_t &right ); CThreadFastMutex m_Mutex; CUtlLinkedList m_renderList; }; #if !defined( DEDICATED ) extern CBrushBatchRender g_BrushBatchRenderer; #endif #endif // BRUSHBATCHRENDER_H