|
|
//=========== (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: $
//
//=============================================================================
// tier 1
#include "tier1/strtools.h"
#include "utlvector.h"
#include "mathlib/vmatrix.h"
#include "FileSystem.h"
#include "bitmap/tgaloader.h"
#include "tier1/utlbuffer.h"
#include "tier1/utlstring.h"
#include "pixelwriter.h"
#include "vguimaterial.h"
#include "materialsystem/itexture.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/materialsystemutil.h"
#include "toolutils/enginetools_int.h"
#include "bitmap/imageformat.h"
#include "vtf/vtf.h"
#include "tier1/keyvalues.h"
#include "tier1/utllinkedlist.h"
#include "materialsystem/imesh.h"
#include <vstdlib/random.h>
#include "tier0/vprof.h"
#include "bitmap/psheet.h"
#include "materialsystem/imaterialvar.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <vfw.h>
#define MAX_LAYERS 10
enum { SUBLAYER_STATIC, SUBLAYER_DYNAMIC, SUBLAYER_FONT, SUBLAYER_MAX, };
//-----------------------------------------------------------------------------
// Class to render a zillion boxes with a tga material.
//-----------------------------------------------------------------------------
class CTGARenderer : public ITGARenderer { public: void Init( int screenWidth, int screenHeight, int numTiles ); void Render(); void Shutdown();
private:
struct UIQuadInfo { public: UIQuadInfo() { sublayer = -1; sheetSequenceNumber = -1; color.r = 255; color.g = 255; color.b = 255; color.a = 255;
textureName = ""; }
UIQuadInfo( int inXPos, int inYPos, int inWidth, int inHeight, int inSublayer, int inSheetSeqNo ) { Assign( inXPos, inYPos, inWidth, inHeight, inSublayer, inSheetSeqNo, color ); }
UIQuadInfo( int inXPos, int inYPos, int inWidth, int inHeight, int inSublayer, int inSheetSeqNo, color32 inColor ) { Assign( inXPos, inYPos, inWidth, inHeight, inSublayer, inSheetSeqNo, inColor ); }
void Assign( int inXPos, int inYPos, int inWidth, int inHeight, int inSublayer, int inSheetSeqNo, color32 inColor ) { x1Pos = inXPos; y1Pos = inYPos; width = inWidth; height = inHeight; x2Pos = x1Pos + width; y2Pos = y1Pos + height; Assert( inSheetSeqNo != -1 ); sublayer = inSublayer; sheetSequenceNumber = inSheetSeqNo; color = inColor; }
int x1Pos; int y1Pos; int x2Pos; int y2Pos; int width; int height; CUtlString textureName; // name if the texture that is inside the sheet
int sheetSequenceNumber; color32 color; int sublayer; };
struct SheetInfo { CUtlVector< CUtlString > m_SheetTexEntry; };
SheetInfo m_sheetDict[SUBLAYER_MAX];
void AddSheetTextureEntry( int sublayer, const char *pTextureName ); int FindSheetTextureEntry( int sublayer, const char *pTextureName );
bool InitSheetTexture( int sublayer, const char *pBaseTextureName ); CSheet *CTGARenderer::LoadSheet( IMaterial *pMaterial ); CSheet *CTGARenderer::LoadSheet( char const *pszFname, ITexture *pTexture ); void GenerateUIMesh( CMatRenderContextPtr &pRenderContext, IMesh* pMesh, CUtlLinkedList< UIQuadInfo > &quads, CSheet *pSheet );
void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, color32 color, const char *pTextureName = NULL ); void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, const char *pTextureName ); void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo, color32 color ); void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo ); UIQuadInfo CreateQuad( int xPos, int yPos, int width, int height, int sublayer, const char *pTextureName = NULL ); UIQuadInfo CreateQuad( int xPos, int yPos, int width, int height, int sublayer, color32 color, const char *pTextureName = NULL ); void AddQuad( UIQuadInfo &quadInfo, int layer );
struct LayerTextureInfo { CMaterialReference m_SublayerMaterial; CUtlReference< CSheet > m_Sheet; }; LayerTextureInfo m_LayerTextureInfo[SUBLAYER_MAX];
struct LayerInfo { CUtlLinkedList< UIQuadInfo > *pQuads; };
// For 3 draw call per layer test.
struct Layer { public: // Layer 0 is static
// Layer 1 is dynamic
// Layer 2 is font
LayerInfo layerInfo[SUBLAYER_MAX]; };
// Test with 10 layers, 3 draw calls per layer.
CUtlVector< Layer > m_Layers;
bool m_bInitialized;
};
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
static CTGARenderer s_TGARenderer; extern ITGARenderer *g_pTGARenderer = &s_TGARenderer;
// 3 drawcall one texture test.
void CTGARenderer::Init( int screenWidth, int screenHeight, int numTiles ) { m_bInitialized = false;
// Build texture dictionary
AddSheetTextureEntry( SUBLAYER_STATIC, "pixel.tga" ); AddSheetTextureEntry( SUBLAYER_STATIC, "decalposter003a.tga" ); AddSheetTextureEntry( SUBLAYER_STATIC, "decalgraffiti037a.tga" ); AddSheetTextureEntry( SUBLAYER_STATIC, "Climb_node.tga" ); AddSheetTextureEntry( SUBLAYER_STATIC, "gibshooter.tga" ); AddSheetTextureEntry( SUBLAYER_STATIC, "ErrorIcon.tga" );;
AddSheetTextureEntry( SUBLAYER_DYNAMIC, "glassclock001a.tga" ); AddSheetTextureEntry( SUBLAYER_DYNAMIC, "decalgraffiti038a.tga" ); AddSheetTextureEntry( SUBLAYER_DYNAMIC, "Air_node_hint.tga" ); AddSheetTextureEntry( SUBLAYER_DYNAMIC, "info_lighting.tga" ); AddSheetTextureEntry( SUBLAYER_DYNAMIC, "SelfIllumIcon.tga" );
AddSheetTextureEntry( SUBLAYER_FONT, "glasswindow006a.tga" ); AddSheetTextureEntry( SUBLAYER_FONT, "decalgraffiti043a.tga" ); AddSheetTextureEntry( SUBLAYER_FONT, "Ground_node.tga" ); AddSheetTextureEntry( SUBLAYER_FONT, "info_target.tga" ); AddSheetTextureEntry( SUBLAYER_FONT, "translucenticon.tga" );
// Load the sheet textures.
bool bSuccess = InitSheetTexture( SUBLAYER_STATIC, "debug/sheettest/debug_meta1" ); if ( !bSuccess ) { Warning( "CDataModel: Unable to load sheet for %s\n", "debug/sheettest/debug_meta1" ); return; } bSuccess = InitSheetTexture( SUBLAYER_DYNAMIC, "debug/sheettest/debug_meta2" ); if ( !bSuccess ) { Warning( "CDataModel: Unable to load sheet for %s\n", "debug/sheettest/debug_meta2" ); return; } bSuccess = InitSheetTexture( SUBLAYER_FONT, "debug/sheettest/debug_meta3" ); if ( !bSuccess ) { Warning( "CDataModel: Unable to load sheet for %s\n", "debug/sheettest/debug_meta3" ); return; }
// Create an array of quads for each sublayer on each layer.
m_Layers.RemoveAll(); for ( int i = 0; i < MAX_LAYERS; ++i ) { m_Layers.AddToTail(); for ( int j = 0; j < SUBLAYER_MAX; ++j ) { m_Layers[i].layerInfo[j].pQuads = new CUtlLinkedList< UIQuadInfo >; } }
UIQuadInfo testQuad; testQuad = CreateQuad( 0, 0, 64, 64, SUBLAYER_STATIC, "gibshooter.tga" ); AddQuad( testQuad, 0 );
testQuad = CreateQuad( 0, 128, 128, 128, SUBLAYER_DYNAMIC, "Air_node_hint.tga" ); AddQuad( testQuad, 0 );
m_bInitialized = true; }
bool CTGARenderer::InitSheetTexture( int sublayer, const char *pBaseTextureName ) { CUtlString materialName; switch (sublayer) { case SUBLAYER_STATIC: materialName = "statictx"; break; case SUBLAYER_DYNAMIC: materialName = "dynamictx"; break; case SUBLAYER_FONT: materialName = "fonttx"; break; default: Warning( "CTGARenderer: Invalid sublayer for %s\n", pBaseTextureName ); Assert(0); break; };
KeyValues *pVMTKeyValues = new KeyValues( "GameControls" ); pVMTKeyValues->SetString( "$basetexture", pBaseTextureName ); m_LayerTextureInfo[sublayer].m_SublayerMaterial.Init( materialName, TEXTURE_GROUP_OTHER, pVMTKeyValues ); m_LayerTextureInfo[sublayer].m_SublayerMaterial->Refresh(); CSheet *pSheet = LoadSheet( m_LayerTextureInfo[sublayer].m_SublayerMaterial ); if ( pSheet == NULL ) { Warning( "CTGARenderer: Unable to load sheet for %s %s\n", materialName.Get(), pBaseTextureName ); return false; } else { m_LayerTextureInfo[sublayer].m_Sheet.Set( pSheet ); return true; } }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo, color32 color ) {
CUtlLinkedList< UIQuadInfo > *pQuads = m_Layers[layer].layerInfo[sublayer].pQuads;
for ( int i = 0; i < count; ++i ) { UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo, color ); pQuads->AddToTail( quadInfo );
xPos += width; if ( xPos >= screenWidth ) { xPos = 0; yPos += height; }
if ( yPos >= screenHeight ) { // just wrap.
yPos = 0; } } }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo ) { for ( int i = 0; i < count; ++i ) { UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo ); AddQuad( quadInfo, layer );
xPos += width; if ( xPos >= screenWidth ) { xPos = 0; yPos += height; }
if ( yPos >= screenHeight ) { // just wrap.
yPos = 0; } } }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, color32 color, const char *pTextureName ) { int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName ); Assert( sheetSeqNo != -1 ); InitTiles( screenWidth, screenHeight, xPos, yPos, width, height, count, layer, sublayer, sheetSeqNo, color ); }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, const char *pTextureName ) { int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName ); InitTiles( screenWidth, screenHeight, xPos, yPos, width, height, count, layer, sublayer, sheetSeqNo ); }
//-----------------------------------------------------------------------------
// Create a quad on a sublayer
// Texture name is optional.
//-----------------------------------------------------------------------------
CTGARenderer::UIQuadInfo CTGARenderer::CreateQuad( int xPos, int yPos, int width, int height, int sublayer, const char *pTextureName ) { int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName ); UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo );
return quadInfo; }
//-----------------------------------------------------------------------------
// Create a quad on a sublayer
// Texture name is optional.
//-----------------------------------------------------------------------------
CTGARenderer::UIQuadInfo CTGARenderer::CreateQuad( int xPos, int yPos, int width, int height, int sublayer, color32 color, const char *pTextureName ) { int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName ); UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo, color );
return quadInfo; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::AddQuad( UIQuadInfo &quadInfo, int layer ) { CUtlLinkedList< UIQuadInfo > *pQuads = m_Layers[layer].layerInfo[quadInfo.sublayer].pQuads; pQuads->AddToTail( quadInfo ); }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::AddSheetTextureEntry( int sublayer, const char *pTextureName ) { m_sheetDict[sublayer].m_SheetTexEntry.AddToTail( pTextureName ); }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CTGARenderer::FindSheetTextureEntry( int sublayer, const char *pTextureName ) { if ( pTextureName == NULL ) return 0;
for ( int i = 0; i < m_sheetDict[sublayer].m_SheetTexEntry.Count(); ++i ) { if ( !Q_strcmp( m_sheetDict[sublayer].m_SheetTexEntry[i], pTextureName ) ) return i; }
Assert(0); return -1; }
#include "vgui/ISurface.h"
#include "vguimatsurface/imatsystemsurface.h"
//-----------------------------------------------------------------------------
// 3 draw calls per layer.
//-----------------------------------------------------------------------------
void CTGARenderer::Render() { VPROF_BUDGET( "Render", "Render" ); if ( !m_bInitialized ) { Warning( "CTGARenderer: Unable to render.\n" ); return; }
int x, y, width, height;
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); pRenderContext->ClearColor4ub( 76, 88, 68, 255 ); pRenderContext->ClearBuffers( true, true );
pRenderContext->GetViewport( x, y, width, height);
float flPixelOffsetX = 0.5f; float flPixelOffsetY = 0.5f;
pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity(); pRenderContext->Scale( 1, -1, 1 ); pRenderContext->Ortho( flPixelOffsetX, flPixelOffsetY, width + flPixelOffsetX, height + flPixelOffsetY, -1.0f, 1.0f );
// make sure there is no translation and rotation laying around
pRenderContext->MatrixMode( MATERIAL_MODEL ); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity();
// each sublayer should correspond to one meta texture binding.
for ( int i = 0; i < MAX_LAYERS; ++i ) { for ( int j = 0; j < SUBLAYER_MAX; ++j ) { if ( m_Layers[i].layerInfo[j].pQuads->Count() == 0 ) { continue; }
pRenderContext->Bind( m_LayerTextureInfo[j].m_SublayerMaterial, NULL ); IMesh* pMesh = pRenderContext->GetDynamicMesh( true ); GenerateUIMesh( pRenderContext, pMesh, *(m_Layers[i].layerInfo[j].pQuads), m_LayerTextureInfo[j].m_Sheet ); pMesh->Draw(); } }
// Restore the matrices
pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_MODEL ); pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PopMatrix(); }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::Shutdown() { int count = 0; for ( int i = 0; i < MAX_LAYERS; ++i ) { for ( int j = 0; j < SUBLAYER_MAX; j++ ) { count += m_Layers[i].layerInfo[j].pQuads->Count(); } }
Warning( "Total generated quads = %d\n", count ); m_Layers.RemoveAll(); }
//--------------------------------------------------------------------------------
// UI sheets
//--------------------------------------------------------------------------------
CSheet *CTGARenderer::LoadSheet( char const *pszFname, ITexture *pTexture ) { CSheet *pNewSheet = NULL;
// get compact sheet representation held by texture
size_t numBytes; void const *pSheet = pTexture->GetResourceData( VTF_RSRC_SHEET, &numBytes ); if ( pSheet ) { // expand compact sheet into fatter runtime form
CUtlBuffer bufLoad( pSheet, numBytes, CUtlBuffer::READ_ONLY ); pNewSheet = new CSheet( bufLoad ); }
//m_SheetList[ pszFname ] = pNewSheet;
return pNewSheet; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CSheet *CTGARenderer::LoadSheet( IMaterial *pMaterial ) { if ( !pMaterial ) return NULL;
bool bFoundVar = false; IMaterialVar *pVar = pMaterial->FindVar( "$basetexture", &bFoundVar, true );
if ( bFoundVar && pVar && pVar->IsDefined() ) { ITexture *pTex = pVar->GetTextureValue(); if ( pTex && !pTex->IsError() ) return LoadSheet( pTex->GetName(), pTex ); }
return NULL; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CTGARenderer::GenerateUIMesh( CMatRenderContextPtr &pRenderContext, IMesh* pMesh, CUtlLinkedList< UIQuadInfo > &quads, CSheet *pSheet ) { VPROF_BUDGET( "GenerateUIMesh", "GenerateUIMesh" );
if ( quads.Count() == 0 ) return;
CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, quads.Count() );
int x, y, width, height; pRenderContext->GetViewport( x, y, width, height);
{ VPROF_BUDGET( "meshBuilder", "meshBuilder" ); for( int i = quads.Head(); i != quads.InvalidIndex(); i = quads.Next( i ) ) { Assert( pSheet ); Assert( pSheet->m_SheetInfo[quads[i].sheetSequenceNumber].m_pSamples ); SheetSequenceSample_t *pSample = pSheet->m_SheetInfo[quads[i].sheetSequenceNumber].m_pSamples; Assert( pSample ); const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]); Assert( pSample0 ); color32 c = quads[i].color;
// Top left
meshBuilder.Position3f( quads[i].x1Pos, quads[i].y1Pos, 0.0f ); meshBuilder.Color4ub( c.r, c.g, c.b, c.a ); meshBuilder.TexCoord3f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, 0 ); meshBuilder.AdvanceVertex();
// Top right
meshBuilder.Position3f( quads[i].x2Pos, quads[i].y1Pos, 0.0f ); meshBuilder.Color4ub( c.r, c.g, c.b, c.a ); meshBuilder.TexCoord3f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0, 0 ); meshBuilder.AdvanceVertex();
// Bottom right
meshBuilder.Position3f( quads[i].x2Pos, quads[i].y2Pos, 0.0f ); meshBuilder.Color4ub( c.r, c.g, c.b, c.a ); meshBuilder.TexCoord3f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0, 0 ); meshBuilder.AdvanceVertex();
// Bottom left
meshBuilder.Position3f( quads[i].x1Pos, quads[i].y2Pos, 0.0f ); meshBuilder.Color4ub( c.r, c.g, c.b, c.a ); meshBuilder.TexCoord3f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0, 0 ); meshBuilder.AdvanceVertex(); } }
meshBuilder.End(); }
|