diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/gl_matsysiface.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'engine/gl_matsysiface.cpp')
| -rw-r--r-- | engine/gl_matsysiface.cpp | 1017 |
1 files changed, 1017 insertions, 0 deletions
diff --git a/engine/gl_matsysiface.cpp b/engine/gl_matsysiface.cpp new file mode 100644 index 0000000..a719942 --- /dev/null +++ b/engine/gl_matsysiface.cpp @@ -0,0 +1,1017 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +// wrapper for the material system for the engine. + +#include "render_pch.h" +#include "view.h" +#include "zone.h" +#include <float.h> +#include "sys_dll.h" +#include "materialsystem/imesh.h" +#include "gl_water.h" +#include "utlrbtree.h" +#include "istudiorender.h" +#include "tier0/dbg.h" +#include "KeyValues.h" +#include "vstdlib/random.h" +#include "lightcache.h" +#include "sysexternal.h" +#include "cmd.h" +#include "modelloader.h" +#include "tier0/icommandline.h" +#include "materialsystem/imaterial.h" +#include "toolframework/itoolframework.h" +#include "toolframework/itoolsystem.h" +#include "tier2/p4helpers.h" +#include "p4lib/ip4.h" +#include "vgui/ISystem.h" +#include <vgui_controls/Controls.h> + + +extern ConVar developer; +#ifdef _WIN32 +#include <crtdbg.h> +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifndef SWDS +extern IMaterialSystem *materials; + +IMaterial* g_materialWireframe; +IMaterial* g_materialTranslucentSingleColor; +IMaterial* g_materialTranslucentVertexColor; +IMaterial* g_materialWorldWireframe; +IMaterial* g_materialWorldWireframeZBuffer; +IMaterial* g_materialBrushWireframe; +IMaterial* g_materialDecalWireframe; +IMaterial* g_materialDebugLightmap; +IMaterial* g_materialDebugLightmapZBuffer; +IMaterial* g_materialDebugLuxels; +IMaterial* g_materialLeafVisWireframe; +IMaterial* g_pMaterialWireframeVertexColor; +IMaterial* g_pMaterialWireframeVertexColorIgnoreZ; +IMaterial* g_pMaterialLightSprite; +IMaterial* g_pMaterialShadowBuild; +IMaterial* g_pMaterialMRMWireframe; +IMaterial* g_pMaterialWriteZ; +IMaterial* g_pMaterialWaterDuDv; +IMaterial* g_pMaterialWaterFirstPass; +IMaterial* g_pMaterialWaterSecondPass; +IMaterial* g_pMaterialAmbientCube; +IMaterial* g_pMaterialDebugFlat; +IMaterial* g_pMaterialDepthWrite[2][2]; +IMaterial* g_pMaterialSSAODepthWrite[2][2]; + +#ifdef NEWMESH +CUtlVector<IVertexBuffer *> g_WorldStaticMeshes; // fixme - rename to g_WorldStaticVertexBuffers +#else +CUtlVector<IMesh *> g_WorldStaticMeshes; +#endif + +void WorldStaticMeshCreate( void ); +void WorldStaticMeshDestroy( void ); + + +bool TangentSpaceSurfaceSetup( SurfaceHandle_t surfID, Vector &tVect ); +void TangentSpaceComputeBasis( Vector& tangent, Vector& binormal, const Vector& normal, const Vector& tVect, bool negateTangent ); + + +//----------------------------------------------------------------------------- +// A console command edit a particular material +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_edit, "Bring up the material under the crosshair in the editor", FCVAR_CHEAT ) +{ + if ( !toolframework->InToolMode() ) + return; + + IMaterial* pMaterial = NULL; + if ( args.ArgC() < 2 ) + { + pMaterial = GetMaterialAtCrossHair(); + } + else + { + const char *pMaterialName = args[ 1 ]; + pMaterial = materials->FindMaterial( pMaterialName, "edited materials", false ); + } + + if ( !pMaterial ) + { + ConMsg( "no/bad material\n" ); + } + else + { + IToolSystem *pToolSystem = toolframework->SwitchToTool( "Material Editor" ); + if ( pToolSystem ) + { + ConMsg( "editing material \"%s\"\n", pMaterial->GetName() ); + + KeyValues *pKeyValues = new KeyValues( "EditMaterial" ); + pKeyValues->SetString( "material", pMaterial->GetName() ); + pToolSystem->PostMessage( 0, pKeyValues ); + pKeyValues->deleteThis(); + } + } +} + + +//----------------------------------------------------------------------------- +// A console command to spew out the material under the crosshair +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_crosshair, "Display the name of the material under the crosshair", FCVAR_CHEAT ) +{ + IMaterial* pMaterial = GetMaterialAtCrossHair(); + if (!pMaterial) + ConMsg ("no/bad material\n"); + else + ConMsg ("hit material \"%s\"\n", pMaterial->GetName()); +} + +//----------------------------------------------------------------------------- +// A console command to open the material under the crosshair in the associated editor. +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_crosshair_edit, "open the material under the crosshair in the editor defined by mat_crosshair_edit_editor", FCVAR_CHEAT ) +{ + IMaterial* pMaterial = GetMaterialAtCrossHair(); + if (!pMaterial) + { + ConMsg ("no/bad material\n"); + } + else + { + char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0}; + Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vmt", pMaterial->GetName() ); + char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 ); + if ( p4 ) + { + CP4AutoEditAddFile autop4( szResolvedName ); + } + else + { + Warning( "run with -p4 to get p4 operations upon mat_crosshair_edit\n" ); + } + vgui::system()->ShellExecute( "open", szResolvedName ); + } +} + +//----------------------------------------------------------------------------- +// A console command to open the material under the crosshair in the associated editor. +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_crosshair_explorer, "open the material under the crosshair in explorer and highlight the vmt file", FCVAR_CHEAT ) +{ + IMaterial* pMaterial = GetMaterialAtCrossHair(); + if (!pMaterial) + { + ConMsg ("no/bad material\n"); + } + else + { + char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0}; + Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vmt", pMaterial->GetName() ); + char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 ); + char params[256]; + Q_snprintf( params, sizeof( params ) - 1, "/E,/SELECT,%s", szResolvedName ); + vgui::system()->ShellExecuteEx( "open", "explorer.exe", params ); + } +} + +//----------------------------------------------------------------------------- +// A console command to open the material under the crosshair in the associated editor. +//----------------------------------------------------------------------------- +CON_COMMAND_F( mat_crosshair_reloadmaterial, "reload the material under the crosshair", FCVAR_CHEAT ) +{ + IMaterial* pMaterial = GetMaterialAtCrossHair(); + if (!pMaterial) + { + ConMsg ("no/bad material\n"); + } + else + { + materials->ReloadMaterials( pMaterial->GetName() ); + } +} + +CON_COMMAND_F( mat_crosshair_printmaterial, "print the material under the crosshair", FCVAR_CHEAT ) +{ + IMaterial* pMaterial = GetMaterialAtCrossHair(); + if (!pMaterial) + { + ConMsg ("no/bad material\n"); + } + else + { + materials->DebugPrintUsedMaterials( pMaterial->GetName(), true ); + } +} + +static void RegisterLightmappedSurface( SurfaceHandle_t surfID ) +{ + int lightmapSize[2]; + int allocationWidth, allocationHeight; + bool bNeedsBumpmap; + + // fixme: lightmapSize needs to be in msurface_t once we + // switch over to having lightmap size untied to base texture + // size + lightmapSize[0] = ( MSurf_LightmapExtents( surfID )[0] ) + 1; + lightmapSize[1] = ( MSurf_LightmapExtents( surfID )[1] ) + 1; + + // Allocate all bumped lightmaps next to each other so that we can just + // increment the s texcoord by pSurf->bumpSTexCoordOffset to render the next + // of the three lightmaps + bNeedsBumpmap = SurfNeedsBumpedLightmaps( surfID ); + if( bNeedsBumpmap ) + { + MSurf_Flags( surfID ) |= SURFDRAW_BUMPLIGHT; + allocationWidth = lightmapSize[0] * ( NUM_BUMP_VECTS+1 ); + } + else + { + MSurf_Flags( surfID ) &= ~SURFDRAW_BUMPLIGHT; + allocationWidth = lightmapSize[0]; + } + allocationHeight = lightmapSize[1]; + + // register this surface's lightmap + int offsetIntoLightmapPage[2]; + MSurf_MaterialSortID( surfID ) = materials->AllocateLightmap( + allocationWidth, + allocationHeight, + offsetIntoLightmapPage, + MSurf_TexInfo( surfID )->material ); + + MSurf_OffsetIntoLightmapPage( surfID )[0] = offsetIntoLightmapPage[0]; + MSurf_OffsetIntoLightmapPage( surfID )[1] = offsetIntoLightmapPage[1]; +} + +static void RegisterUnlightmappedSurface( SurfaceHandle_t surfID ) +{ + MSurf_MaterialSortID( surfID ) = materials->AllocateWhiteLightmap( MSurf_TexInfo( surfID )->material ); + MSurf_OffsetIntoLightmapPage( surfID )[0] = 0; + MSurf_OffsetIntoLightmapPage( surfID )[1] = 0; +} + +static bool LightmapLess( const SurfaceHandle_t& surfID1, const SurfaceHandle_t& surfID2 ) +{ + // FIXME: This really should be in the material system, + // as it completely depends on the behavior of the lightmap packer + bool hasLightmap1 = (MSurf_Flags( surfID1 ) & SURFDRAW_NOLIGHT) == 0; + bool hasLightmap2 = (MSurf_Flags( surfID2 ) & SURFDRAW_NOLIGHT) == 0; + + // We want lightmapped surfaces to show up first + if (hasLightmap1 != hasLightmap2) + return hasLightmap1 > hasLightmap2; + + // The sort by enumeration ID + IMaterial* pMaterial1 = MSurf_TexInfo( surfID1 )->material; + IMaterial* pMaterial2 = MSurf_TexInfo( surfID2 )->material; + int enum1 = pMaterial1->GetEnumerationID(); + int enum2 = pMaterial2->GetEnumerationID(); + if (enum1 != enum2) + return enum1 < enum2; + + bool hasLightstyle1 = (MSurf_Flags( surfID1 ) & SURFDRAW_HASLIGHTSYTLES) == 0; + bool hasLightstyle2 = (MSurf_Flags( surfID2 ) & SURFDRAW_HASLIGHTSYTLES) == 0; + + // We want Lightstyled surfaces to show up first + if (hasLightstyle1 != hasLightstyle2) + return hasLightstyle1 > hasLightstyle2; + + // Then sort by lightmap area for better packing... (big areas first) + // NOTE: Don't care about bumpmap increasing area here because it is a linear factor + // (all surfs with the same material have the same bumpmapping cost) +#if 1 + int area1 = MSurf_LightmapExtents( surfID1 )[0] * MSurf_LightmapExtents( surfID1 )[1]; + int area2 = MSurf_LightmapExtents( surfID2 )[0] * MSurf_LightmapExtents( surfID2 )[1]; + return area2 < area1; +#else + // Previous algorithm: pack minimum height first + // NOTE: In d1_trainstation_05, greatest area results in fewer material splits + // so I've switched over to that heuristic + return MSurf_LightmapExtents( surfID1 )[1] < MSurf_LightmapExtents( surfID2 )[1]; +#endif +} + +void MaterialSystem_RegisterLightmapSurfaces( void ) +{ + SurfaceHandle_t surfID = SURFACE_HANDLE_INVALID; + + materials->BeginLightmapAllocation(); + + // Add all the surfaces to a list, sorted by lightmapped + // then by material enumeration then by area + CUtlRBTree< SurfaceHandle_t, int > surfaces( 0, host_state.worldbrush->numsurfaces, LightmapLess ); + for( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ ) + { + surfID = SurfaceHandleFromIndex( surfaceIndex ); + if( ( MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT ) || + ( MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) ) + { + MSurf_Flags( surfID ) |= SURFDRAW_NOLIGHT; + } + else + { + MSurf_Flags( surfID ) &= ~SURFDRAW_NOLIGHT; + } + + surfaces.Insert(surfID); + } + + // iterate sorted surfaces + surfID = SURFACE_HANDLE_INVALID; + for (int i = surfaces.FirstInorder(); i != surfaces.InvalidIndex(); i = surfaces.NextInorder(i) ) + { + surfID = surfaces[i]; + + bool hasLightmap = ( MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) == 0; + if ( hasLightmap ) + { + RegisterLightmappedSurface( surfID ); + } + else + { + RegisterUnlightmappedSurface( surfID ); + } + } + materials->EndLightmapAllocation(); +} + +static void TestBumpSanity( SurfaceHandle_t surfID ) +{ + ASSERT_SURF_VALID( surfID ); + // use the last one to check if we need a bumped lightmap, but don't have it so that we can warn. + bool needsBumpmap = SurfNeedsBumpedLightmaps( surfID ); + bool hasBumpmap = SurfHasBumpedLightmaps( surfID ); + + if ( needsBumpmap && !hasBumpmap && MSurf_Samples( surfID ) ) + { + Warning( "Need to rebuild map to get bumped lighting on material %s\n", + materialSortInfoArray[MSurf_MaterialSortID( surfID )].material->GetName() ); + } +} + +void MaterialSytsem_DoBumpWarnings( void ) +{ + int sortID; + IMaterial *pPrevMaterial = NULL; + + for( sortID = 0; sortID < g_WorldStaticMeshes.Count(); sortID++ ) + { + if( pPrevMaterial == materialSortInfoArray[sortID].material ) + { + continue; + } + // Find one surface in each material sort info type + for ( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ ) + { + SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex ); + + if( MSurf_MaterialSortID( surfID ) == sortID ) + { + TestBumpSanity( surfID ); + break; + } + } + pPrevMaterial = materialSortInfoArray[sortID].material; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +static void GenerateTexCoordsForPrimVerts( void ) +{ + int j, k, l; + for ( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ ) + { + SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex ); +/* + if( pSurf->numPrims > 0 ) + { + ConMsg( "pSurf %d has %d prims (normal: %f %f %f dist: %f)\n", + ( int )i, ( int )pSurf->numPrims, + pSurf->plane->normal[0], pSurf->plane->normal[1], pSurf->plane->normal[2], + pSurf->plane->dist ); + ConMsg( "\tfirst primID: %d\n", ( int )pSurf->firstPrimID ); + } +*/ + for( j = 0; j < MSurf_NumPrims( surfID ); j++ ) + { + mprimitive_t *pPrim; + assert( MSurf_FirstPrimID( surfID ) + j < host_state.worldbrush->numprimitives ); + pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( surfID ) + j]; + for( k = 0; k < pPrim->vertCount; k++ ) + { + int lightmapSize[2]; + int lightmapPageSize[2]; + float sOffset, sScale, tOffset, tScale; + + materials->GetLightmapPageSize( + SortInfoToLightmapPage( MSurf_MaterialSortID( surfID ) ), + &lightmapPageSize[0], &lightmapPageSize[1] ); + lightmapSize[0] = ( MSurf_LightmapExtents( surfID )[0] ) + 1; + lightmapSize[1] = ( MSurf_LightmapExtents( surfID )[1] ) + 1; + + sScale = 1.0f / ( float )lightmapPageSize[0]; + sOffset = ( float )MSurf_OffsetIntoLightmapPage( surfID )[0] * sScale; + sScale = MSurf_LightmapExtents( surfID )[0] * sScale; + + tScale = 1.0f / ( float )lightmapPageSize[1]; + tOffset = ( float )MSurf_OffsetIntoLightmapPage( surfID )[1] * tScale; + tScale = MSurf_LightmapExtents( surfID )[1] * tScale; + + for ( l = 0; l < pPrim->vertCount; l++ ) + { + // world-space vertex + assert( l+pPrim->firstVert < host_state.worldbrush->numprimverts ); + mprimvert_t &vert = host_state.worldbrush->primverts[l+pPrim->firstVert]; + Vector& vec = vert.pos; + + // base texture coordinate + vert.texCoord[0] = DotProduct (vec, MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[0].AsVector3D()) + + MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[0][3]; + vert.texCoord[0] /= MSurf_TexInfo( surfID )->material->GetMappingWidth(); + + vert.texCoord[1] = DotProduct (vec, MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[1].AsVector3D()) + + MSurf_TexInfo( surfID )->textureVecsTexelsPerWorldUnits[1][3]; + vert.texCoord[1] /= MSurf_TexInfo( surfID )->material->GetMappingHeight(); + + if ( (MSurf_Flags( surfID ) & SURFDRAW_NOLIGHT) ) + { + vert.lightCoord[0] = 0.5f; + vert.lightCoord[1] = 0.5f; + } + else if ( MSurf_LightmapExtents( surfID )[0] == 0 ) + { + vert.lightCoord[0] = sOffset; + vert.lightCoord[1] = tOffset; + } + else + { + vert.lightCoord[0] = DotProduct (vec, MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[0].AsVector3D()) + + MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[0][3]; + vert.lightCoord[0] -= MSurf_LightmapMins( surfID )[0]; + vert.lightCoord[0] += 0.5f; + vert.lightCoord[0] /= ( float )MSurf_LightmapExtents( surfID )[0]; //pSurf->texinfo->texture->width; + + vert.lightCoord[1] = DotProduct (vec, MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[1].AsVector3D()) + + MSurf_TexInfo( surfID )->lightmapVecsLuxelsPerWorldUnits[1][3]; + vert.lightCoord[1] -= MSurf_LightmapMins( surfID )[1]; + vert.lightCoord[1] += 0.5f; + vert.lightCoord[1] /= ( float )MSurf_LightmapExtents( surfID )[1]; //pSurf->texinfo->texture->height; + + vert.lightCoord[0] = sOffset + vert.lightCoord[0] * sScale; + vert.lightCoord[1] = tOffset + vert.lightCoord[1] * tScale; + } + } + } + } + } +} + +struct sortmap_t +{ + MaterialSystem_SortInfo_t info; + int index; +}; + +IMatRenderContext *pSortMapRenderContext; + +int __cdecl SortMapCompareFunc( const void *pElem0, const void *pElem1 ) +{ + const sortmap_t *pMap0 = (const sortmap_t *)pElem0; + const sortmap_t *pMap1 = (const sortmap_t *)pElem1; + return pSortMapRenderContext->CompareMaterialCombos( pMap0->info.material, pMap1->info.material, pMap0->info.lightmapPageID, pMap1->info.lightmapPageID ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void MaterialSystem_CreateSortinfo( void ) +{ + Assert( !materialSortInfoArray ); + + int nSortIDs = materials->GetNumSortIDs(); + materialSortInfoArray = ( MaterialSystem_SortInfo_t * )new MaterialSystem_SortInfo_t[ nSortIDs ]; + Assert( materialSortInfoArray ); + materials->GetSortInfo( materialSortInfoArray ); + + int i = 0; + sortmap_t *pMap = (sortmap_t *)_alloca( sizeof(sortmap_t) * nSortIDs ); + for ( i = 0; i < nSortIDs; i++ ) + { + pMap[i].info = materialSortInfoArray[i]; + pMap[i].index = i; + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pSortMapRenderContext = pRenderContext; + + qsort( pMap, nSortIDs, sizeof( sortmap_t ), SortMapCompareFunc ); + + int *pSortIDRemap = (int *)_alloca( sizeof(int) * nSortIDs ); + for ( i = 0; i < nSortIDs; i++ ) + { + materialSortInfoArray[i] = pMap[i].info; + pSortIDRemap[pMap[i].index] = i; + //Msg("Material %s, lightmap %d ", materialSortInfoArray[i].material->GetName(), materialSortInfoArray[i].lightmapPageID ); + } + + for ( int surfaceIndex = 0; surfaceIndex < host_state.worldbrush->numsurfaces; surfaceIndex++ ) + { + SurfaceHandle_t surfID = SurfaceHandleFromIndex( surfaceIndex ); + int sortID = MSurf_MaterialSortID( surfID ); +#if _DEBUG + IMaterial *pMaterial = MSurf_TexInfo( surfID )->material; + + if ( !HushAsserts() ) + { + Assert ( materialSortInfoArray[pSortIDRemap[sortID]].material == pMaterial ); + } +#endif + MSurf_MaterialSortID( surfID ) = pSortIDRemap[sortID]; + } + + // Create texcoords for subdivided surfaces + GenerateTexCoordsForPrimVerts(); + // Create the hardware vertex buffers for each face + WorldStaticMeshCreate(); + if ( developer.GetInt() ) + { + MaterialSytsem_DoBumpWarnings(); + } +} + +bool SurfHasBumpedLightmaps( SurfaceHandle_t surfID ) +{ + ASSERT_SURF_VALID( surfID ); + bool hasBumpmap = false; + if( ( MSurf_TexInfo( surfID )->flags & SURF_BUMPLIGHT ) && + ( !( MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT ) ) && + ( host_state.worldbrush->lightdata ) && + ( MSurf_Samples( surfID ) ) ) + { + hasBumpmap = true; + } + return hasBumpmap; +} + +bool SurfNeedsBumpedLightmaps( SurfaceHandle_t surfID ) +{ + ASSERT_SURF_VALID( surfID ); + assert( MSurf_TexInfo( surfID ) ); + assert( MSurf_TexInfo( surfID )->material ); + return MSurf_TexInfo( surfID )->material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ); +} + +bool SurfHasLightmap( SurfaceHandle_t surfID ) +{ + ASSERT_SURF_VALID( surfID ); + + bool hasLightmap = false; + if( ( !( MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT ) ) && + ( host_state.worldbrush->lightdata ) && + ( MSurf_Samples( surfID ) ) ) + { + hasLightmap = true; + } + return hasLightmap; +} + +bool SurfNeedsLightmap( SurfaceHandle_t surfID ) +{ + ASSERT_SURF_VALID( surfID ); + assert( MSurf_TexInfo( surfID ) ); + assert( MSurf_TexInfo( surfID )->material ); + if (MSurf_TexInfo( surfID )->flags & SURF_NOLIGHT) + return false; + + return MSurf_TexInfo( surfID )->material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: This builds the surface info for a terrain face +//----------------------------------------------------------------------------- + +void BuildMSurfaceVerts( const worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, Vector *verts, + Vector2D *texCoords, Vector2D lightCoords[][4] ) +{ + SurfaceCtx_t ctx; + SurfSetupSurfaceContext( ctx, surfID ); + + int vertCount = MSurf_VertCount( surfID ); + int vertFirstIndex = MSurf_FirstVertIndex( surfID ); + for ( int i = 0; i < vertCount; i++ ) + { + int vertIndex = pBrushData->vertindices[vertFirstIndex + i]; + + // world-space vertex + Vector& vec = pBrushData->vertexes[vertIndex].position; + + // output to mesh + if ( verts ) + { + VectorCopy( vec, verts[i] ); + } + + if ( texCoords ) + { + SurfComputeTextureCoordinate( ctx, surfID, vec, texCoords[i] ); + } + + // + // garymct: normalized (within space of surface) lightmap texture coordinates + // + if ( lightCoords ) + { + SurfComputeLightmapCoordinate( ctx, surfID, vec, lightCoords[i][0] ); + + if ( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT ) + { + // bump maps appear left to right in lightmap page memory, calculate the offset for the + // width of a single map + for ( int bumpID = 1; bumpID <= NUM_BUMP_VECTS; bumpID++ ) + { + lightCoords[i][bumpID][0] = lightCoords[i][0][0] + (bumpID * ctx.m_BumpSTexCoordOffset); + lightCoords[i][bumpID][1] = lightCoords[i][0][1]; + } + } + } + } +} + + + +void BuildMSurfacePrimVerts( worldbrushdata_t *pBrushData, mprimitive_t *prim, CMeshBuilder &builder, SurfaceHandle_t surfID ) +{ + Vector tVect; + bool negate = false; +// FIXME: For some reason, normals are screwed up on water surfaces. Revisit this once we have normals started in primverts. + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + negate = TangentSpaceSurfaceSetup( surfID, tVect ); + } +// Vector& normal = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID )] ]; + + for ( int i = 0; i < prim->vertCount; i++ ) + { + mprimvert_t &primVert = pBrushData->primverts[prim->firstVert + i]; + builder.Position3fv( primVert.pos.Base() ); + builder.Normal3fv( MSurf_Plane( surfID ).normal.Base() ); +// builder.Normal3fv( normal.Base() ); + builder.TexCoord2fv( 0, primVert.texCoord ); + builder.TexCoord2fv( 1, primVert.lightCoord ); + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + Vector tangentS, tangentT; + TangentSpaceComputeBasis( tangentS, tangentT, MSurf_Plane( surfID ).normal, tVect, false ); + builder.TangentS3fv( tangentS.Base() ); + builder.TangentT3fv( tangentT.Base() ); + } + builder.AdvanceVertex(); + } +} + +void BuildMSurfacePrimIndices( worldbrushdata_t *pBrushData, mprimitive_t *prim, CMeshBuilder &builder ) +{ + for ( int i = 0; i < prim->indexCount; i++ ) + { + unsigned short primIndex = pBrushData->primindices[prim->firstIndex + i]; + builder.Index( primIndex - prim->firstVert ); + builder.AdvanceIndex(); + } +} + +//----------------------------------------------------------------------------- +// Here's a version of the mesh builder used to allow for client DLL to draw brush models +//----------------------------------------------------------------------------- + +void BuildBrushModelVertexArray(worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, BrushVertex_t* pVerts ) +{ + SurfaceCtx_t ctx; + SurfSetupSurfaceContext( ctx, surfID ); + + Vector tVect; + bool negate = false; + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + negate = TangentSpaceSurfaceSetup( surfID, tVect ); + } + + for ( int i = 0; i < MSurf_VertCount( surfID ); i++ ) + { + int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID ) + i]; + + // world-space vertex + Vector& vec = pBrushData->vertexes[vertIndex].position; + + // output to mesh + VectorCopy( vec, pVerts[i].m_Pos ); + + Vector2D uv; + SurfComputeTextureCoordinate( ctx, surfID, vec, pVerts[i].m_TexCoord ); + + // garymct: normalized (within space of surface) lightmap texture coordinates + SurfComputeLightmapCoordinate( ctx, surfID, vec, pVerts[i].m_LightmapCoord ); + +// Activate this if necessary +// if ( surf->flags & SURFDRAW_BUMPLIGHT ) +// { +// // bump maps appear left to right in lightmap page memory, calculate +// // the offset for the width of a single map. The pixel shader will use +// // this to compute the actual texture coordinates +// builder.TexCoord2f( 2, ctx.m_BumpSTexCoordOffset, 0.0f ); +// } + + Vector& normal = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID ) + i] ]; + VectorCopy( normal, pVerts[i].m_Normal ); + + if ( MSurf_Flags( surfID ) & SURFDRAW_TANGENTSPACE ) + { + Vector tangentS, tangentT; + TangentSpaceComputeBasis( tangentS, tangentT, normal, tVect, negate ); + VectorCopy( tangentS, pVerts[i].m_TangentS ); + VectorCopy( tangentT, pVerts[i].m_TangentT ); + } + } +} +#endif // SWDS + +void CMSurfaceSortList::Init( int maxSortIDs, int minMaterialLists ) +{ + m_list.RemoveAll(); + m_list.EnsureCapacity(minMaterialLists); + m_maxSortIDs = maxSortIDs; + int groupMax = maxSortIDs*MAX_MAT_SORT_GROUPS; + m_groups.RemoveAll(); + m_groups.EnsureCount(groupMax); + int groupBytes = (groupMax+7)>>3; + m_groupUsed.EnsureCount(groupBytes); + Q_memset(m_groupUsed.Base(), 0, groupBytes); + + for ( int i = 0; i < MAX_MAT_SORT_GROUPS; i++ ) + { + m_sortGroupLists[i].RemoveAll(); + int cap = (i==0) ? 128 : 16; + m_sortGroupLists[i].EnsureCapacity(cap); + groupOffset[i] = m_maxSortIDs * i; + } + InitGroup(&m_emptyGroup); +} + +void CMSurfaceSortList::InitGroup( surfacesortgroup_t *pGroup ) +{ + pGroup->listHead = -1; + pGroup->listTail = -1; + pGroup->vertexCount = 0; + pGroup->groupListIndex = -1; + pGroup->vertexCountNoDetail = 0; + pGroup->indexCountNoDetail = 0; + pGroup->triangleCount = 0; + pGroup->surfaceCount = 0; +} + +void CMSurfaceSortList::Shutdown() +{ +} + +void CMSurfaceSortList::Reset() +{ + Init( m_maxSortIDs, m_list.NumAllocated() ); +} + +// this resizes the groups and groupUsed arrays +void CMSurfaceSortList::EnsureMaxSortIDs( int newMaxSortIDs ) +{ + if ( newMaxSortIDs > m_maxSortIDs ) + { + int oldMax = m_maxSortIDs; + // compute new size, expand by minimum of 256 + newMaxSortIDs += 255; + newMaxSortIDs -= (newMaxSortIDs&255); + int groupMax = newMaxSortIDs * MAX_MAT_SORT_GROUPS; + int groupBytes = (groupMax+7)>>3; + // resize the arrays + m_groups.EnsureCount(groupMax); + m_groupUsed.EnsureCount(groupBytes); + // now loop through the list backwards and move the old data over + for ( int i = MAX_MAT_SORT_GROUPS; --i >= 0; ) + { + for ( int j = newMaxSortIDs; --j >= 0; ) + { + int newIndex = (i * newMaxSortIDs) + j; + if ( j < oldMax ) + { + // when i == 0, the group indices overlap so they don't need to be remapped + if ( i != 0 ) + { + int oldIndex = (i * oldMax) + j; + MarkGroupNotUsed(newIndex); + if ( IsGroupUsed(oldIndex) ) + { + MarkGroupNotUsed(oldIndex); + MarkGroupUsed(newIndex); + m_groups[newIndex] = m_groups[oldIndex]; + InitGroup( &m_groups[oldIndex] ); + } + } + if ( IsGroupUsed(newIndex) && m_groups[newIndex].groupListIndex >= 0 ) + { + m_sortGroupLists[i][m_groups[newIndex].groupListIndex] = &m_groups[newIndex]; + } + } + else + { + MarkGroupNotUsed(newIndex); + } + } + groupOffset[i] = i*newMaxSortIDs; + } + m_maxSortIDs = newMaxSortIDs; + } +} + + +void CMSurfaceSortList::AddSurfaceToTail( msurface2_t *pSurface, int sortGroup, int sortID ) +{ + Assert(sortGroup<MAX_MAT_SORT_GROUPS); + int index = groupOffset[sortGroup] + sortID; + surfacesortgroup_t *pGroup = &m_groups[index]; + if ( !IsGroupUsed(index) ) + { + MarkGroupUsed(index); + InitGroup(pGroup); + } + materiallist_t *pList = NULL; + short prevIndex = -1; + int vertCount = MSurf_VertCount(pSurface); + int triangleCount = vertCount - 2; + pGroup->triangleCount += triangleCount; + pGroup->surfaceCount++; + pGroup->vertexCount += vertCount; + if (MSurf_Flags(pSurface) & SURFDRAW_NODE) + { + pGroup->vertexCountNoDetail += vertCount; + pGroup->indexCountNoDetail += triangleCount * 3; + } + if ( pGroup->listTail != m_list.InvalidIndex() ) + { + // existing block + pList = &m_list[pGroup->listTail]; + if ( pList->count >= ARRAYSIZE(pList->pSurfaces) ) + { + prevIndex = pGroup->listTail; + // no space in existing block + pList = NULL; + } + } + // use existing block? + if ( pList ) + { + pList->pSurfaces[pList->count] = pSurface; + pList->count++; + } + else + { + // allocate a new block + short nextBlock = m_list.AddToTail(); + if ( prevIndex >= 0 ) + { + m_list[prevIndex].nextBlock = nextBlock; + } + pGroup->listTail = nextBlock; + // handle the first use case + if ( pGroup->listHead == m_list.InvalidIndex() ) + { + // UNDONE: This should really be sorted by sortID would help reduce state changes + // NOTE: Doesn't seem to help much in benchmarks to sort this vector + index = m_sortGroupLists[sortGroup].AddToTail(pGroup); + pGroup->groupListIndex = index; + pGroup->listHead = nextBlock; + } + pList = &m_list[nextBlock]; + pList->nextBlock = m_list.InvalidIndex(); + pList->count = 1; + pList->pSurfaces[0] = pSurface; + } +} + +msurface2_t *CMSurfaceSortList::GetSurfaceAtHead( const surfacesortgroup_t &group ) const +{ + if ( group.listHead == m_list.InvalidIndex() ) + return NULL; + Assert(m_list[group.listHead].count>0); + return m_list[group.listHead].pSurfaces[0]; +} + +void CMSurfaceSortList::GetSurfaceListForGroup( CUtlVector<msurface2_t *> &list, const surfacesortgroup_t &group ) const +{ + MSL_FOREACH_SURFACE_IN_GROUP_BEGIN( *this, group, surfID ) + { + list.AddToTail(surfID); + } + MSL_FOREACH_SURFACE_IN_GROUP_END() +} + +#ifndef SWDS +IMaterial *GetMaterialAtCrossHair( void ) +{ + Vector endPoint; + Vector lightmapColor; + + // max_range * sqrt(3) + VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint ); + + SurfaceHandle_t hitSurfID = R_LightVec( MainViewOrigin(), endPoint, false, lightmapColor ); + if( IS_SURF_VALID( hitSurfID ) ) + { + return MSurf_TexInfo( hitSurfID )->material; + } + else + { + return NULL; + } +} + +// hack +extern void DrawLightmapPage( int lightmapPageID ); + +static float textureS, textureT; +static SurfaceHandle_t s_CrossHairSurfID;; +static Vector crossHairDiffuseLightColor; +static Vector crossHairBaseColor; +static float lightmapCoords[2]; + +void SaveSurfAtCrossHair() +{ + Vector endPoint; + Vector lightmapColor; + + // max_range * sqrt(3) + VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint ); + + s_CrossHairSurfID = R_LightVec( MainViewOrigin(), endPoint, false, lightmapColor, + &textureS, &textureT, &lightmapCoords[0], &lightmapCoords[1] ); +} + + +void DebugDrawLightmapAtCrossHair() +{ + return; + IMaterial *pMaterial; + int lightmapPageSize[2]; + + if( s_CrossHairSurfID <= 0 ) + { + return; + } + materials->GetLightmapPageSize( materialSortInfoArray[MSurf_MaterialSortID( s_CrossHairSurfID )].lightmapPageID, + &lightmapPageSize[0], &lightmapPageSize[1] ); + pMaterial = MSurf_TexInfo( s_CrossHairSurfID )->material; +// pMaterial->GetLowResColorSample( textureS, textureT, baseColor ); + DrawLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( s_CrossHairSurfID )].lightmapPageID ); + +#if 0 + int i; + for( i = 0; i < 2; i++ ) + { + xy[i] = + ( ( float )pCrossHairSurf->offsetIntoLightmapPage[i] / ( float )lightmapPageSize[i] ) + + lightmapCoord[i] * ( pCrossHairSurf->lightmapExtents[i] / ( float )lightmapPageSize[i] ); + } + + materials->Bind( g_materialWireframe ); + IMesh* pMesh = materials->GetDynamicMesh( g_materialWireframe ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUAD, 1 ); + + meshBuilder.Position3f( + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +#endif +} + +void ReleaseMaterialSystemObjects(); +void RestoreMaterialSystemObjects( int nChangeFlags ); + +void ForceMatSysRestore() +{ + ReleaseMaterialSystemObjects(); + RestoreMaterialSystemObjects( 0 ); +} + +#endif |