From f9added066d7fd9d4524c6395eae650650ed1ce1 Mon Sep 17 00:00:00 2001 From: Er2 Date: Tue, 9 May 2023 19:57:22 +0300 Subject: [PATCH 01/11] add utils --- fgdlib/gamedata.cpp | 13 +- fgdlib/gdclass.cpp | 4 +- fgdlib/gdvar.cpp | 6 +- fgdlib/inputoutput.cpp | 2 +- fgdlib/wckeyvalues.cpp | 46 ++--- fgdlib/wscript | 54 ++++++ public/chunkfile.cpp | 2 +- public/fgdlib/fgdlib.h | 8 +- public/fgdlib/gamedata.h | 19 +- public/fgdlib/gdclass.h | 8 +- public/fgdlib/gdvar.h | 2 +- public/fgdlib/inputoutput.h | 2 +- public/fgdlib/wckeyvalues.h | 16 +- public/loadcmdline.cpp | 2 +- public/tier0/threadtools.h | 2 +- public/zip_utils.cpp | 2 +- raytrace/wscript | 53 ++++++ utils/bsppack/wscript | 70 +++++++ utils/common/cmdlib.cpp | 26 +-- utils/common/cmdlib.h | 4 +- utils/common/map_shared.h | 2 +- utils/common/mstristrip.cpp | 2 +- utils/common/scriplib.cpp | 2 +- utils/common/threads.cpp | 119 +++++++++--- utils/common/utilmatlib.cpp | 19 +- utils/lzma/wscript | 56 ++++++ utils/vbsp/boundbox.cpp | 2 +- utils/vbsp/brushbsp.cpp | 4 +- utils/vbsp/cubemap.cpp | 2 +- utils/vbsp/detailobjects.cpp | 11 +- utils/vbsp/disp_vbsp.cpp | 2 +- utils/vbsp/disp_vbsp.h | 30 ++- utils/vbsp/leakfile.cpp | 4 +- utils/vbsp/manifest.cpp | 7 + utils/vbsp/map.cpp | 2 +- utils/vbsp/materialpatch.cpp | 2 +- utils/vbsp/staticprop.cpp | 33 ++-- utils/vbsp/textures.cpp | 1 - utils/vbsp/vbsp.cpp | 20 +- utils/vbsp/vbsp.h | 2 +- utils/vbsp/worldvertextransitionfixup.cpp | 4 +- utils/vbsp/writebsp.cpp | 4 +- utils/vbsp/wscript | 122 +++++++++++++ utils/vbspinfo/vbspinfo.cpp | 57 ++++-- utils/vbspinfo/wscript | 71 ++++++++ utils/vpk/packtest.cpp | 8 +- utils/vpk/wscript | 61 +++++++ utils/vrad/disp_vrad.cpp | 7 +- utils/vrad/incremental.cpp | 19 +- utils/vrad/incremental.h | 3 +- utils/vrad/leaf_ambient_lighting.cpp | 11 +- utils/vrad/lightmap.cpp | 18 +- utils/vrad/radial.cpp | 44 ++--- utils/vrad/trace.cpp | 14 +- utils/vrad/vismat.cpp | 4 +- utils/vrad/vrad.cpp | 69 ++++++- utils/vrad/vrad.h | 16 +- utils/vrad/vrad_dispcoll.cpp | 17 +- utils/vrad/vrad_dispcoll.h | 4 +- utils/vrad/vraddetailprops.cpp | 21 ++- utils/vrad/vraddisps.cpp | 21 +-- utils/vrad/vraddll.cpp | 14 +- utils/vrad/vradstaticprops.cpp | 132 ++++++++------ utils/vrad/wscript | 118 ++++++++++++ utils/vrad_launcher/stdafx.cpp | 15 -- utils/vrad_launcher/stdafx.h | 32 ---- utils/vrad_launcher/vrad_launcher.cpp | 15 +- utils/vrad_launcher/wscript | 55 ++++++ utils/vvis/flow.cpp | 7 +- utils/vvis/vvis.cpp | 43 ++++- utils/vvis/wscript | 79 ++++++++ utils/vvis_launcher/vvis_launcher.cpp | 13 +- utils/vvis_launcher/wscript | 53 ++++++ utils/xbox/xbspinfo/wscript | 53 ++++++ utils/xbox/xbspinfo/xbspinfo.cpp | 9 +- utils/xbox/xbspinfo/xbspinfo.h | 15 +- wscript | 212 +++++++++++----------- 77 files changed, 1612 insertions(+), 511 deletions(-) create mode 100755 fgdlib/wscript create mode 100755 raytrace/wscript create mode 100755 utils/bsppack/wscript create mode 100755 utils/lzma/wscript create mode 100755 utils/vbsp/wscript create mode 100755 utils/vbspinfo/wscript create mode 100755 utils/vpk/wscript create mode 100755 utils/vrad/wscript delete mode 100644 utils/vrad_launcher/stdafx.cpp delete mode 100644 utils/vrad_launcher/stdafx.h create mode 100755 utils/vrad_launcher/wscript create mode 100755 utils/vvis/wscript create mode 100755 utils/vvis_launcher/wscript create mode 100755 utils/xbox/xbspinfo/wscript diff --git a/fgdlib/gamedata.cpp b/fgdlib/gamedata.cpp index f3689ee99..4039480c2 100644 --- a/fgdlib/gamedata.cpp +++ b/fgdlib/gamedata.cpp @@ -2,12 +2,15 @@ // //============================================================================= +#ifndef POSIX #include #include #include -#include -#include "fgdlib/GameData.h" -#include "fgdlib/HelperInfo.h" +#endif + +#include "worldsize.h" +#include "fgdlib/gamedata.h" +#include "fgdlib/helperinfo.h" #include "KeyValues.h" #include "filesystem_tools.h" #include "tier1/strtools.h" @@ -276,12 +279,14 @@ void GameData::ClearData(void) // Input : pszFilename - // Output : Returns TRUE on success, FALSE on failure. //----------------------------------------------------------------------------- -BOOL GameData::Load(const char *pszFilename) +bool GameData::Load(const char *pszFilename) { TokenReader tr; +#ifndef POSIX if(GetFileAttributes(pszFilename) == 0xffffffff) return FALSE; +#endif if(!tr.Open(pszFilename)) return FALSE; diff --git a/fgdlib/gdclass.cpp b/fgdlib/gdclass.cpp index 1de57b6a7..779d0b64f 100644 --- a/fgdlib/gdclass.cpp +++ b/fgdlib/gdclass.cpp @@ -4,8 +4,8 @@ // //============================================================================= -#include "fgdlib/GameData.h" // FGDLIB: eliminate dependency -#include "fgdlib/GDClass.h" +#include "fgdlib/gamedata.h" // FGDLIB: eliminate dependency +#include "fgdlib/gdclass.h" // memdbgon must be the last include file in a .cpp file!!! #include diff --git a/fgdlib/gdvar.cpp b/fgdlib/gdvar.cpp index fe8df025c..2a4c5f12c 100644 --- a/fgdlib/gdvar.cpp +++ b/fgdlib/gdvar.cpp @@ -3,8 +3,8 @@ //============================================================================= #include "fgdlib/fgdlib.h" -#include "fgdlib/GameData.h" -#include "fgdlib/WCKeyValues.h" +#include "fgdlib/gamedata.h" +#include "fgdlib/wckeyvalues.h" #include "fgdlib/gdvar.h" // memdbgon must be the last include file in a .cpp file!!! @@ -669,7 +669,7 @@ void GDinputvariable::ToKeyValue(MDkeyvalue *pkv) } else if (eStoreAs == INTEGER) { - itoa(m_nValue, pkv->szValue, 10); + Q_snprintf(pkv->szValue, sizeof(pkv->szValue), "%d", m_nValue); } } diff --git a/fgdlib/inputoutput.cpp b/fgdlib/inputoutput.cpp index ee2b6033b..d58b05470 100644 --- a/fgdlib/inputoutput.cpp +++ b/fgdlib/inputoutput.cpp @@ -6,7 +6,7 @@ #include -#include "fgdlib/InputOutput.h" +#include "fgdlib/inputoutput.h" // memdbgon must be the last include file in a .cpp file!!! #include diff --git a/fgdlib/wckeyvalues.cpp b/fgdlib/wckeyvalues.cpp index 83e52007c..b8eea51df 100644 --- a/fgdlib/wckeyvalues.cpp +++ b/fgdlib/wckeyvalues.cpp @@ -4,7 +4,7 @@ // //============================================================================= -#include "fgdlib/WCKeyValues.h" +#include "fgdlib/wckeyvalues.h" // memdbgon must be the last include file in a .cpp file!!! #include @@ -34,11 +34,11 @@ MDkeyvalue &MDkeyvalue::operator =(const MDkeyvalue &other) void WCKVBase_Vector::RemoveKeyAt(int nIndex) { Assert(nIndex >= 0); - Assert(nIndex < (int)m_KeyValues.Count()); + Assert(nIndex < (int)this->m_KeyValues.Count()); - if ((nIndex >= 0) && (nIndex < (int)m_KeyValues.Count())) + if ((nIndex >= 0) && (nIndex < (int)this->m_KeyValues.Count())) { - m_KeyValues.Remove(nIndex); + this->m_KeyValues.Remove(nIndex); } } @@ -71,14 +71,14 @@ void WCKVBase_Vector::AddKeyValue(const char *pszKey, const char *pszValue) MDkeyvalue newkv; V_strcpy_safe(newkv.szKey, szTmpKey); V_strcpy_safe(newkv.szValue, szTmpValue); - m_KeyValues.AddToTail(newkv); + this->m_KeyValues.AddToTail(newkv); } int WCKVBase_Vector::FindByKeyName( const char *pKeyName ) const { - for ( int i=0; i < m_KeyValues.Count(); i++ ) + for ( int i=0; i < this->m_KeyValues.Count(); i++ ) { - if ( V_stricmp( m_KeyValues[i].szKey, pKeyName ) == 0 ) + if ( V_stricmp( this->m_KeyValues[i].szKey, pKeyName ) == 0 ) return i; } return GetInvalidIndex(); @@ -86,7 +86,7 @@ int WCKVBase_Vector::FindByKeyName( const char *pKeyName ) const void WCKVBase_Vector::InsertKeyValue( const MDkeyvalue &kv ) { - m_KeyValues.AddToTail( kv ); + this->m_KeyValues.AddToTail( kv ); } @@ -94,18 +94,18 @@ void WCKVBase_Vector::InsertKeyValue( const MDkeyvalue &kv ) //----------------------------------------------------------------------------- void WCKVBase_Dict::RemoveKeyAt(int nIndex) { - m_KeyValues.RemoveAt(nIndex); + this->m_KeyValues.RemoveAt(nIndex); } int WCKVBase_Dict::FindByKeyName( const char *pKeyName ) const { - return m_KeyValues.Find( pKeyName ); + return this->m_KeyValues.Find( pKeyName ); } void WCKVBase_Dict::InsertKeyValue( const MDkeyvalue &kv ) { - m_KeyValues.Insert( kv.szKey, kv ); + this->m_KeyValues.Insert( kv.szKey, kv ); } @@ -125,9 +125,9 @@ template WCKeyValuesT::~WCKeyValuesT(void) { //int i = 0; - //while (i < m_KeyValues.GetSize()) + //while (i < this->m_KeyValues.GetSize()) //{ - // delete m_KeyValues.GetAt(i++); + // delete this->m_KeyValues.GetAt(i++); //} RemoveAll(); @@ -139,8 +139,8 @@ WCKeyValuesT::~WCKeyValuesT(void) template const char *WCKeyValuesT::GetValue(const char *pszKey, int *piIndex) const { - int i = FindByKeyName( pszKey ); - if ( i == GetInvalidIndex() ) + int i = this->FindByKeyName( pszKey ); + if ( i == this->GetInvalidIndex() ) { return NULL; } @@ -149,7 +149,7 @@ const char *WCKeyValuesT::GetValue(const char *pszKey, int *piIndex) const if(piIndex) piIndex[0] = i; - return m_KeyValues[i].szValue; + return this->m_KeyValues[i].szValue; } } @@ -169,7 +169,7 @@ template void WCKeyValuesT::SetValue(const char *pszKey, int iValue) { char szValue[100]; - itoa(iValue, szValue, 10); + Q_snprintf(szValue, sizeof(szValue), "%d", iValue); SetValue(pszKey, szValue); } @@ -233,8 +233,8 @@ void WCKeyValuesT::SetValue(const char *pszKey, const char *pszValue) StripEdgeWhiteSpace(szTmpKey); StripEdgeWhiteSpace(szTmpValue); - int i = FindByKeyName( szTmpKey ); - if ( i == GetInvalidIndex() ) + int i = this->FindByKeyName( szTmpKey ); + if ( i == this->GetInvalidIndex() ) { if ( pszValue ) { @@ -244,21 +244,21 @@ void WCKeyValuesT::SetValue(const char *pszKey, const char *pszValue) MDkeyvalue newkv; Q_strncpy( newkv.szKey, szTmpKey, sizeof( newkv.szKey ) ); Q_strncpy( newkv.szValue, szTmpValue, sizeof( newkv.szValue ) ); - InsertKeyValue( newkv ); + this->InsertKeyValue( newkv ); } } else { if (pszValue != NULL) { - V_strncpy(m_KeyValues[i].szValue, szTmpValue, sizeof(m_KeyValues[i].szValue)); + V_strncpy(this->m_KeyValues[i].szValue, szTmpValue, sizeof(this->m_KeyValues[i].szValue)); } // // If we are setting to a NULL value, delete the key. // else { - RemoveKeyAt( i ); + this->RemoveKeyAt( i ); } } } @@ -270,7 +270,7 @@ void WCKeyValuesT::SetValue(const char *pszKey, const char *pszValue) template void WCKeyValuesT::RemoveAll(void) { - m_KeyValues.RemoveAll(); + this->m_KeyValues.RemoveAll(); } diff --git a/fgdlib/wscript b/fgdlib/wscript new file mode 100755 index 000000000..c86528304 --- /dev/null +++ b/fgdlib/wscript @@ -0,0 +1,54 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'fgdlib' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'gamedata.cpp', + 'gdclass.cpp', + 'gdvar.cpp', + 'inputoutput.cpp', + 'wckeyvalues.cpp', + ] + + includes = [ + '.', + '../public', + '../public/tier0', + '../public/tier1', + '../public/fgdlib', + '../utils/common' + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'tier3', 'vstdlib', 'mathlib'] + + if bld.env.DEST_OS == 'win32': + libs += ['USER32'] + + bld.stlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/public/chunkfile.cpp b/public/chunkfile.cpp index 81a77dd3b..71b3f8713 100644 --- a/public/chunkfile.cpp +++ b/public/chunkfile.cpp @@ -151,7 +151,7 @@ ChunkHandler_t CChunkHandlerMap::GetHandler(const char *pszChunkName, void **ppD pNode = pNode->pNext; } - return(false); + return NULL; } diff --git a/public/fgdlib/fgdlib.h b/public/fgdlib/fgdlib.h index 76051cfb5..c7856f28d 100644 --- a/public/fgdlib/fgdlib.h +++ b/public/fgdlib/fgdlib.h @@ -10,9 +10,9 @@ #pragma once #endif -#include "HelperInfo.h" -#include "GameData.h" -#include "GDClass.h" -#include "InputOutput.h" +#include "helperinfo.h" +#include "gamedata.h" +#include "gdclass.h" +#include "inputoutput.h" #endif // FGDLIB_H diff --git a/public/fgdlib/gamedata.h b/public/fgdlib/gamedata.h index cf8b5be12..60b58388c 100644 --- a/public/fgdlib/gamedata.h +++ b/public/fgdlib/gamedata.h @@ -10,24 +10,19 @@ #pragma once #endif -#pragma warning(push, 1) -#pragma warning(disable:4701 4702 4530) -#include -#pragma warning(pop) -#include "TokenReader.h" -#include "GDClass.h" -#include "InputOutput.h" -#include "UtlString.h" +#include "tier0/platform.h" +#include "tier1/tokenreader.h" +#include "gdclass.h" +#include "inputoutput.h" +#include "utlstring.h" #include "utlvector.h" +#include "utlmap.h" class MDkeyvalue; class GameData; class KeyValues; -enum TEXTUREFORMAT; - - typedef void (*GameDataMessageFunc_t)(int level, PRINTF_FORMAT_STRING const char *fmt, ...); // FGD-based AutoMaterialExclusion data @@ -71,7 +66,7 @@ class GameData GameData(); ~GameData(); - BOOL Load(const char *pszFilename); + bool Load(const char *pszFilename); GDclass *ClassForName(const char *pszName, int *piIndex = NULL); diff --git a/public/fgdlib/gdclass.h b/public/fgdlib/gdclass.h index fe81bb375..8fa3d07ce 100644 --- a/public/fgdlib/gdclass.h +++ b/public/fgdlib/gdclass.h @@ -17,10 +17,10 @@ #pragma once #endif -#include "HelperInfo.h" -#include "TokenReader.h" -#include "GDVar.h" -#include "InputOutput.h" +#include "helperinfo.h" +#include "tokenreader.h" +#include "gdvar.h" +#include "inputoutput.h" #include "mathlib/vector.h" class CHelperInfo; diff --git a/public/fgdlib/gdvar.h b/public/fgdlib/gdvar.h index 197ff30de..832dd6fbc 100644 --- a/public/fgdlib/gdvar.h +++ b/public/fgdlib/gdvar.h @@ -10,7 +10,7 @@ #pragma once #include -#include // dvs: for MAX_STRING. Fix. +#include "tokenreader.h" // dvs: for MAX_STRING. Fix. class MDkeyvalue; diff --git a/public/fgdlib/inputoutput.h b/public/fgdlib/inputoutput.h index 7438f08f4..a491d5538 100644 --- a/public/fgdlib/inputoutput.h +++ b/public/fgdlib/inputoutput.h @@ -10,7 +10,7 @@ #include -#include "fgdlib/EntityDefs.h" +#include "fgdlib/entitydefs.h" enum InputOutputType_t diff --git a/public/fgdlib/wckeyvalues.h b/public/fgdlib/wckeyvalues.h index 730d92d19..8542b3c59 100644 --- a/public/fgdlib/wckeyvalues.h +++ b/public/fgdlib/wckeyvalues.h @@ -112,8 +112,8 @@ class WCKVBase_Vector public: // Iteration helpers. - inline int GetCount() const { return m_KeyValues.Count(); } - inline int GetFirst() const { return m_KeyValues.Count() - 1; } + inline int GetCount() const { return this->m_KeyValues.Count(); } + inline int GetFirst() const { return this->m_KeyValues.Count() - 1; } inline int GetNext( int i ) const { return i - 1; } static inline int GetInvalidIndex() { return -1; } @@ -138,8 +138,8 @@ class WCKVBase_Dict // Iteration helpers. Note that there is no GetCount() because you can't iterate // these by incrementing a counter. - inline int GetFirst() const { return m_KeyValues.First(); } - inline int GetNext( int i ) const { return m_KeyValues.Next( i ); } + inline int GetFirst() const { return this->m_KeyValues.First(); } + inline int GetNext( int i ) const { return this->m_KeyValues.Next( i ); } static inline int GetInvalidIndex() { return CUtlDict::InvalidIndex(); } int FindByKeyName( const char *pKeyName ) const; // Returns the same value as GetInvalidIndex if not found. @@ -188,7 +188,7 @@ typedef WCKeyValuesT WCKeyValuesVector; template inline const char *WCKeyValuesT::GetKey(int nIndex) const { - return(m_KeyValues.Element(nIndex).szKey); + return(this->m_KeyValues.Element(nIndex).szKey); } @@ -200,7 +200,7 @@ inline const char *WCKeyValuesT::GetKey(int nIndex) const template inline MDkeyvalue &WCKeyValuesT::GetKeyValue(int nIndex) { - return(m_KeyValues.Element(nIndex)); + return(this->m_KeyValues.Element(nIndex)); } @@ -212,7 +212,7 @@ inline MDkeyvalue &WCKeyValuesT::GetKeyValue(int nIndex) template inline const MDkeyvalue& WCKeyValuesT::GetKeyValue(int nIndex) const { - return(m_KeyValues.Element(nIndex)); + return(this->m_KeyValues.Element(nIndex)); } @@ -223,7 +223,7 @@ inline const MDkeyvalue& WCKeyValuesT::GetKeyValue(int nIndex) const template inline const char *WCKeyValuesT::GetValue(int nIndex) const { - return(m_KeyValues.Element(nIndex).szValue); + return(this->m_KeyValues.Element(nIndex).szValue); } diff --git a/public/loadcmdline.cpp b/public/loadcmdline.cpp index 30c616f31..fc809c3cd 100644 --- a/public/loadcmdline.cpp +++ b/public/loadcmdline.cpp @@ -7,7 +7,7 @@ #include "KeyValues.h" #include "tier1/strtools.h" -#include "FileSystem_Tools.h" +#include "filesystem_tools.h" #include "tier1/utlstring.h" // So we know whether or not we own argv's memory diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index b72161937..81b6c41c5 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -520,7 +520,7 @@ PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p); #ifndef NO_THREAD_LOCAL -#if defined(WIN32) || defined(OSX) || defined( _PS3 ) || ( defined (_LINUX) ) || defined(PLATFORM_BSD) +#if defined(WIN32) || defined(POSIX) || defined( _PS3 ) #ifndef __AFXTLS_H__ // not compatible with some Windows headers #if defined(_PS3) diff --git a/public/zip_utils.cpp b/public/zip_utils.cpp index 858931ab9..9649e9d29 100644 --- a/public/zip_utils.cpp +++ b/public/zip_utils.cpp @@ -7,7 +7,7 @@ // If we are going to include windows.h then we need to disable protected_things.h // or else we get many warnings. #undef PROTECTED_THINGS_ENABLE -#include +#include "tier0/platform.h" #ifdef IS_WINDOWS_PC #include #else diff --git a/raytrace/wscript b/raytrace/wscript new file mode 100755 index 000000000..12857611e --- /dev/null +++ b/raytrace/wscript @@ -0,0 +1,53 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'raytrace' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'raytrace.cpp', + 'trace2.cpp', + 'trace3.cpp', + ] + + includes = [ + '.', + '../public', + '../public/tier0', + '../public/tier1', + '../public/tier2', + '../public/tier3', + '../utils/common' + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'vstdlib', 'mathlib'] + + if bld.env.DEST_OS == 'win32': + libs += ['USER32'] + + bld.stlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/bsppack/wscript b/utils/bsppack/wscript new file mode 100755 index 000000000..78ed77b18 --- /dev/null +++ b/utils/bsppack/wscript @@ -0,0 +1,70 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'bsppack' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('BSPPACK_EXPORTS', 1) + conf.define('ZIP_SUPPORT_LZMA_ENCODE', 1) + return + +def build(bld): + source = [ + 'bsppack.cpp', + '../common/bsplib.cpp', + '../common/cmdlib.cpp', + '../common/scriplib.cpp', + '../common/filesystem_tools.cpp', + '../../public/filesystem_helpers.cpp', + '../../public/filesystem_init.cpp', + '../../public/lumpfiles.cpp', + '../../public/zip_utils.cpp', + ] + + if bld.env.DEST_OS != 'win32': + source += ['../../filesystem/linux_support.cpp'] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + '../../public/tier3', + '../../public/mathlib' + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'tier3', 'mathlib', 'lzma', 'vstdlib'] + + if bld.env.DEST_OS == 'win32': + libs += ['ADVAPI32', 'WS2_32'] + else: + libs += ['DL', 'M', 'LOG'] + + install_path = bld.env.LIBDIR + + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/common/cmdlib.cpp b/utils/common/cmdlib.cpp index a3796dcea..5ab2267a4 100644 --- a/utils/common/cmdlib.cpp +++ b/utils/common/cmdlib.cpp @@ -61,8 +61,6 @@ CUtlLinkedList g_ExtraSpewHooks; bool g_bStopOnExit = false; void (*g_ExtraSpewHook)(const char*) = NULL; -#if defined( _WIN32 ) || defined( WIN32 ) - void CmdLib_FPrintf( FileHandle_t hFile, const char *pFormat, ... ) { static CUtlVector buf; @@ -128,10 +126,6 @@ char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile ) return pOut; } -#if !defined( _X360 ) -#include -#endif - // This pauses before exiting if they use -StopOnExit. Useful for debugging. class CExitStopper { @@ -141,7 +135,7 @@ class CExitStopper if ( g_bStopOnExit ) { Warning( "\nPress any key to quit.\n" ); - getch(); + getchar(); } } } g_ExitStopper; @@ -153,7 +147,7 @@ static unsigned short g_BadColor = 0xFFFF; static WORD g_BackgroundFlags = 0xFFFF; static void GetInitialColors( ) { -#if !defined( _X360 ) +#if !defined( _X360 ) && defined( _WIN32 ) // Get the old background attributes. CONSOLE_SCREEN_BUFFER_INFO oldInfo; GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo ); @@ -175,7 +169,7 @@ static void GetInitialColors( ) WORD SetConsoleTextColor( int red, int green, int blue, int intensity ) { WORD ret = g_LastColor; -#if !defined( _X360 ) +#if !defined( _X360 ) && defined( _WIN32 ) g_LastColor = 0; if( red ) g_LastColor |= FOREGROUND_RED; @@ -194,7 +188,7 @@ WORD SetConsoleTextColor( int red, int green, int blue, int intensity ) void RestoreConsoleTextColor( WORD color ) { -#if !defined( _X360 ) +#if !defined( _X360 ) && defined( _WIN32 ) SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags ); g_LastColor = color; #endif @@ -216,6 +210,7 @@ void Error( char const *pMsg, ... ) #else +#ifdef _WIN32 CRITICAL_SECTION g_SpewCS; bool g_bSpewCSInitted = false; bool g_bSuppressPrintfOutput = false; @@ -326,14 +321,16 @@ SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg ) return retVal; } - +#endif void InstallSpewFunction() { setvbuf( stdout, NULL, _IONBF, 0 ); setvbuf( stderr, NULL, _IONBF, 0 ); +#ifdef _WIN32 SpewOutputFunc( CmdLib_SpewOutputFunc ); +#endif GetInitialColors(); } @@ -413,18 +410,13 @@ void CmdLib_Cleanup() void CmdLib_Exit( int exitCode ) { - TerminateProcess( GetCurrentProcess(), 1 ); + exit(exitCode); } #endif -#endif - - - - /* =================== ExpandWildcards diff --git a/utils/common/cmdlib.h b/utils/common/cmdlib.h index 5b5b2c7c9..f0f2410ca 100644 --- a/utils/common/cmdlib.h +++ b/utils/common/cmdlib.h @@ -132,7 +132,9 @@ void CmdLib_Cleanup(); void CmdLib_Exit( int exitCode ); // Use this to cleanup and call exit(). // entrypoint if chaining spew functions +#ifdef _WIN32 SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg ); +#endif unsigned short SetConsoleTextColor( int red, int green, int blue, int intensity ); void RestoreConsoleTextColor( unsigned short color ); @@ -175,4 +177,4 @@ typedef struct } cblock_t; -#endif // CMDLIB_H \ No newline at end of file +#endif // CMDLIB_H diff --git a/utils/common/map_shared.h b/utils/common/map_shared.h index 5f2b2b62d..dd5f6d00c 100644 --- a/utils/common/map_shared.h +++ b/utils/common/map_shared.h @@ -11,7 +11,7 @@ #endif -#include "ChunkFile.h" +#include "chunkfile.h" #include "bsplib.h" #include "cmdlib.h" diff --git a/utils/common/mstristrip.cpp b/utils/common/mstristrip.cpp index 41b6efc51..ad6ebdc8e 100644 --- a/utils/common/mstristrip.cpp +++ b/utils/common/mstristrip.cpp @@ -867,7 +867,7 @@ struct SortEntry int iFirstUsed; int iOrigIndex; - bool operator<(const SortEntry& rhs) + bool operator<(const SortEntry& rhs) const { return iFirstUsed < rhs.iFirstUsed; } diff --git a/utils/common/scriplib.cpp b/utils/common/scriplib.cpp index 1c8b47f83..1eb61b99a 100644 --- a/utils/common/scriplib.cpp +++ b/utils/common/scriplib.cpp @@ -1216,7 +1216,7 @@ int CScriptLib::GetFileList( const char* pDirPath, const char* pPattern, CUtlVec FIND_DATA findData; Q_FixSlashes( fullPath ); void *h = FindFirstFile( fullPath, &findData ); - if ( (int)h == -1 ) + if ( (int)(size_t)h == -1 ) { return 0; } diff --git a/utils/common/threads.cpp b/utils/common/threads.cpp index 74e457a9c..388e01241 100644 --- a/utils/common/threads.cpp +++ b/utils/common/threads.cpp @@ -13,14 +13,21 @@ #define USED +#ifdef _WIN32 #include +#elif defined(POSIX) +#include +#else +#error +#endif #include "cmdlib.h" #define NO_THREAD_NAMES #include "threads.h" #include "pacifier.h" -#define MAX_THREADS 16 +#define MAX_THREADS 40 +int numthreads = -1; class CRunThreadsData { @@ -40,8 +47,11 @@ qboolean pacifier; qboolean threaded; bool g_bLowPriorityThreads = false; +#ifdef _WIN32 HANDLE g_ThreadHandles[MAX_THREADS]; - +#elif defined(POSIX) +pthread_t g_ThreadHandles[MAX_THREADS]; +#endif /* @@ -97,7 +107,21 @@ void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, ThreadWorkerFn RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); } +void ThreadSetDefault (void) +{ + const CPUInformation *ci; + if (numthreads == -1) // not set manually + { + ci = GetCPUInformation(); + numthreads = ci->m_nLogicalProcessors; + if (numthreads < 1) numthreads = 1; + if (numthreads > MAX_THREADS) numthreads = MAX_THREADS; + } + + Msg ("%i threads\n", numthreads); +} +#ifdef _WIN32 /* =================================================================== @@ -106,7 +130,6 @@ WIN32 =================================================================== */ -int numthreads = -1; CRITICAL_SECTION crit; static int enter; @@ -120,30 +143,12 @@ class CCritInit } } g_CritInit; - - void SetLowPriority() { SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS ); } -void ThreadSetDefault (void) -{ - SYSTEM_INFO info; - - if (numthreads == -1) // not set manually - { - GetSystemInfo (&info); - numthreads = info.dwNumberOfProcessors; - if (numthreads < 1 || numthreads > 32) - numthreads = 1; - } - - Msg ("%i threads\n", numthreads); -} - - void ThreadLock (void) { if (!threaded) @@ -173,7 +178,6 @@ DWORD WINAPI InternalRunThreadsFn( LPVOID pParameter ) return 0; } - void RunThreads_Start( RunThreadsFn fn, void *pUserData, ERunThreadsPriority ePriority ) { Assert( numthreads > 0 ); @@ -218,7 +222,76 @@ void RunThreads_End() threaded = false; } - +#elif defined(POSIX) +/* +=================================================================== + +POSIX + +=================================================================== +*/ + +pthread_mutex_t crit = PTHREAD_MUTEX_INITIALIZER; +static int enter; + +void SetLowPriority() +{ +} +void ThreadLock (void) +{ + if (!threaded) + return; + pthread_mutex_lock (&crit); + if (enter) + Error ("Recursive ThreadLock\n"); + enter = 1; +} + +void ThreadUnlock (void) +{ + if (!threaded) + return; + if (!enter) + Error ("ThreadUnlock without lock\n"); + enter = 0; + pthread_mutex_unlock (&crit); +} + +void *InternalRunThreadsFn( void *pParameter ) +{ + CRunThreadsData *pData = (CRunThreadsData*)pParameter; + pData->m_Fn( pData->m_iThread, pData->m_pUserData ); + return NULL; +} + +void RunThreads_Start( RunThreadsFn fn, void *pUserData, ERunThreadsPriority ePriority ) +{ + Assert( numthreads > 0 ); + threaded = true; + + if ( numthreads > MAX_TOOL_THREADS ) + numthreads = MAX_TOOL_THREADS; + + for ( int i=0; i < numthreads ;i++ ) + { + g_RunThreadsData[i].m_iThread = i; + g_RunThreadsData[i].m_pUserData = pUserData; + g_RunThreadsData[i].m_Fn = fn; + + pthread_create( &g_ThreadHandles[i], NULL, InternalRunThreadsFn, &g_RunThreadsData[i] ); + } +} + + +void RunThreads_End() +{ + for ( int i=0; i < numthreads; i++ ) + pthread_join( g_ThreadHandles[i], NULL ); + + threaded = false; +} +#endif + /* ============= diff --git a/utils/common/utilmatlib.cpp b/utils/common/utilmatlib.cpp index f2dc49fa8..c2e4babff 100644 --- a/utils/common/utilmatlib.cpp +++ b/utils/common/utilmatlib.cpp @@ -12,26 +12,25 @@ #include "materialsystem/imaterialsystem.h" #include "materialsystem/imaterial.h" #include "materialsystem/imaterialvar.h" -#include +#include "cmdlib.h" #include "utilmatlib.h" #include "tier0/dbg.h" -#include #include "filesystem.h" #include "materialsystem/materialsystem_config.h" -#include "mathlib/Mathlib.h" +#include "mathlib/mathlib.h" void LoadMaterialSystemInterface( CreateInterfaceFn fileSystemFactory ) { if( g_pMaterialSystem ) return; - + // materialsystem.dll should be in the path, it's in bin along with vbsp. - const char *pDllName = "materialsystem.dll"; + const char *pDllName = "materialsystem" DLL_EXT_STRING; CSysModule *materialSystemDLLHInst; materialSystemDLLHInst = g_pFullFileSystem->LoadModule( pDllName ); if( !materialSystemDLLHInst ) { - Error( "Can't load MaterialSystem.dll\n" ); + Error( "Can't load MaterialSystem\n" ); } CreateInterfaceFn clientFactory = Sys_GetFactory( materialSystemDLLHInst ); @@ -40,17 +39,17 @@ void LoadMaterialSystemInterface( CreateInterfaceFn fileSystemFactory ) g_pMaterialSystem = (IMaterialSystem *)clientFactory( MATERIAL_SYSTEM_INTERFACE_VERSION, NULL ); if ( !g_pMaterialSystem ) { - Error( "Could not get the material system interface from materialsystem.dll (" __FILE__ ")" ); + Error( "Could not get the material system interface from materialsystem library (" __FILE__ ")" ); } } else { - Error( "Could not find factory interface in library MaterialSystem.dll" ); + Error( "Could not find factory interface in library MaterialSystem!" ); } - if (!g_pMaterialSystem->Init( "shaderapiempty.dll", 0, fileSystemFactory )) + if (!g_pMaterialSystem->Init( "shaderapiempty" DLL_EXT_STRING, 0, fileSystemFactory )) { - Error( "Could not start the empty shader (shaderapiempty.dll)!" ); + Error( "Could not start the empty shader (shaderapiempty)!" ); } } diff --git a/utils/lzma/wscript b/utils/lzma/wscript new file mode 100755 index 000000000..1a3138483 --- /dev/null +++ b/utils/lzma/wscript @@ -0,0 +1,56 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'lzma' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('_NO_EXCEPTIONS', 1) + conf.define('_LZMA_PROB32', 1) + conf.define('_7ZIP_ST', 1) + return + +def build(bld): + source = [ + 'lzma.cpp', + 'C/LzmaEnc.c', + 'C/LzmaDec.c', + 'C/LzFind.c', + ] + + includes = [ + '.', + './C', + '../common', + '../../public', + ] + + defines = [] + + libs = [] + + if bld.env.DEST_OS == 'win32': + libs += ['ADVAPI32', 'WS2_32'] + else: + libs += ['DL', 'M', 'LOG'] + + bld.stlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vbsp/boundbox.cpp b/utils/vbsp/boundbox.cpp index a62e9e2f7..3bb5e2b70 100644 --- a/utils/vbsp/boundbox.cpp +++ b/utils/vbsp/boundbox.cpp @@ -6,7 +6,7 @@ //=============================================================================// #include "vbsp.h" -#include "BoundBox.h" +#include "boundbox.h" //#include "hammer_mathlib.h" //#include "MapDefs.h" diff --git a/utils/vbsp/brushbsp.cpp b/utils/vbsp/brushbsp.cpp index d455f30b7..7421021ac 100644 --- a/utils/vbsp/brushbsp.cpp +++ b/utils/vbsp/brushbsp.cpp @@ -337,7 +337,7 @@ bspbrush_t *AllocBrush (int numsides) bspbrush_t *bb; int c; - c = (int)&(((bspbrush_t *)0)->sides[numsides]); + c = (int)(size_t)&(((bspbrush_t *)0)->sides[numsides]); bb = (bspbrush_t*)malloc(c); memset (bb, 0, c); bb->id = s_BrushId++; @@ -394,7 +394,7 @@ bspbrush_t *CopyBrush (bspbrush_t *brush) int size; int i; - size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); + size = (int)(size_t)&(((bspbrush_t *)0)->sides[brush->numsides]); newbrush = AllocBrush (brush->numsides); memcpy (newbrush, brush, size); diff --git a/utils/vbsp/cubemap.cpp b/utils/vbsp/cubemap.cpp index 829efdfb9..f6c9bdb8c 100644 --- a/utils/vbsp/cubemap.cpp +++ b/utils/vbsp/cubemap.cpp @@ -7,7 +7,7 @@ #include "vbsp.h" #include "bsplib.h" -#include "tier1/UtlBuffer.h" +#include "tier1/utlbuffer.h" #include "tier1/utlvector.h" #include "bitmap/imageformat.h" #include diff --git a/utils/vbsp/detailobjects.cpp b/utils/vbsp/detailobjects.cpp index c6c1fc2be..17003516c 100644 --- a/utils/vbsp/detailobjects.cpp +++ b/utils/vbsp/detailobjects.cpp @@ -6,26 +6,23 @@ // $NoKeywords: $ //=============================================================================// -#include #include "vbsp.h" #include "bsplib.h" #include "KeyValues.h" #include "utlsymbol.h" #include "utlvector.h" -#include #include "bspfile.h" #include "utilmatlib.h" #include "gamebspfile.h" -#include "mathlib/VMatrix.h" +#include "mathlib/vmatrix.h" #include "materialpatch.h" #include "pacifier.h" #include "vstdlib/random.h" #include "builddisp.h" #include "disp_vbsp.h" -#include "UtlBuffer.h" -#include "CollisionUtils.h" -#include -#include "UtlLinkedList.h" +#include "utlbuffer.h" +#include "collisionutils.h" +#include "utllinkedlist.h" #include "byteswap.h" #include "writebsp.h" diff --git a/utils/vbsp/disp_vbsp.cpp b/utils/vbsp/disp_vbsp.cpp index f36885954..d5ba80c3f 100644 --- a/utils/vbsp/disp_vbsp.cpp +++ b/utils/vbsp/disp_vbsp.cpp @@ -13,7 +13,7 @@ #include "mstristrip.h" #include "writebsp.h" #include "pacifier.h" -#include "disp_ivp.h" +#include "disp_vbsp.h" #include "builddisp.h" #include "mathlib/vector.h" diff --git a/utils/vbsp/disp_vbsp.h b/utils/vbsp/disp_vbsp.h index 5af77601b..d0e5ea5f2 100644 --- a/utils/vbsp/disp_vbsp.h +++ b/utils/vbsp/disp_vbsp.h @@ -11,13 +11,37 @@ #pragma once #endif - #include "vbsp.h" +#include "utlvector.h" +#include "disp_tesselate.h" - +class CPhysCollisionEntry; class CCoreDispInfo; - +struct dmodel_t; + +// This provides the template functions that the engine's tesselation code needs +// so we can share the code in VBSP. +class CVBSPTesselateHelper : public CBaseTesselateHelper +{ +public: + void EndTriangle() + { + m_pIndices->AddToTail( m_TempIndices[0] ); + m_pIndices->AddToTail( m_TempIndices[1] ); + m_pIndices->AddToTail( m_TempIndices[2] ); + } + + DispNodeInfo_t& GetNodeInfo( int iNodeBit ) + { + // VBSP doesn't care about these. Give it back something to play with. + static DispNodeInfo_t dummy; + return dummy; + } + +public: + CUtlVector *m_pIndices; +}; extern CUtlVector g_CoreDispInfos; diff --git a/utils/vbsp/leakfile.cpp b/utils/vbsp/leakfile.cpp index d6038830f..05f3abc6a 100644 --- a/utils/vbsp/leakfile.cpp +++ b/utils/vbsp/leakfile.cpp @@ -7,7 +7,7 @@ //=============================================================================// #include "vbsp.h" -#include "color.h" +#include "Color.h" /* ============================================================================== @@ -165,4 +165,4 @@ void AreaportalLeakFile( tree_t *tree, portal_t *pStartPortal, portal_t *pEndPor Warning( "Wrote %s\n", filename ); Color red(255,0,0,255); ColorSpewMessage( SPEW_MESSAGE, &red, "Areaportal leak ! File: %s ", filename ); -} \ No newline at end of file +} diff --git a/utils/vbsp/manifest.cpp b/utils/vbsp/manifest.cpp index c72a95646..1a28f1201 100644 --- a/utils/vbsp/manifest.cpp +++ b/utils/vbsp/manifest.cpp @@ -3,7 +3,9 @@ #include "map_shared.h" #include "fgdlib/fgdlib.h" #include "manifest.h" +#ifdef _WIN32 #include "windows.h" +#endif //----------------------------------------------------------------------------- // Purpose: default constructor @@ -358,6 +360,7 @@ bool CManifest::LoadVMFManifestUserPrefs( const char *pszFileName ) char UserName[ MAX_PATH ], FileName[ MAX_PATH ], UserPrefsFileName[ MAX_PATH ]; DWORD UserNameSize; +#ifdef _WIN32 UserNameSize = sizeof( UserName ); if ( GetUserName( UserName, &UserNameSize ) == 0 ) { @@ -365,6 +368,10 @@ bool CManifest::LoadVMFManifestUserPrefs( const char *pszFileName ) } sprintf( UserPrefsFileName, "\\%s.vmm_prefs", UserName ); +#else + // TODO: Er2: Detect user + Q_strcpy(UserPrefsFileName, "default.vmm_prefs"); +#endif V_StripExtension( pszFileName, FileName, sizeof( FileName ) ); strcat( FileName, UserPrefsFileName ); diff --git a/utils/vbsp/map.cpp b/utils/vbsp/map.cpp index 2221c79ff..0fb397620 100644 --- a/utils/vbsp/map.cpp +++ b/utils/vbsp/map.cpp @@ -1271,7 +1271,7 @@ void ConvertSideList( entity_t *mapent, char *key ) } char szIndex[15]; - itoa( nIndex, szIndex, 10 ); + Q_snprintf( szIndex, sizeof(szIndex), "%d", szNewValue ); strcat( szNewValue, szIndex ); } } diff --git a/utils/vbsp/materialpatch.cpp b/utils/vbsp/materialpatch.cpp index 96a30edbf..146f3922d 100644 --- a/utils/vbsp/materialpatch.cpp +++ b/utils/vbsp/materialpatch.cpp @@ -6,7 +6,7 @@ // //=============================================================================// #include "vbsp.h" -#include "UtlBuffer.h" +#include "utlbuffer.h" #include "utlsymbol.h" #include "utlrbtree.h" #include "KeyValues.h" diff --git a/utils/vbsp/staticprop.cpp b/utils/vbsp/staticprop.cpp index 3ba6b95ac..4ceb2148f 100644 --- a/utils/vbsp/staticprop.cpp +++ b/utils/vbsp/staticprop.cpp @@ -11,14 +11,13 @@ #include "utlvector.h" #include "bspfile.h" #include "gamebspfile.h" -#include "VPhysics_Interface.h" -#include "Studio.h" +#include "vphysics_interface.h" +#include "studio.h" #include "byteswap.h" -#include "UtlBuffer.h" -#include "CollisionUtils.h" -#include -#include "CModel.h" -#include "PhysDll.h" +#include "utlbuffer.h" +#include "collisionutils.h" +#include "cmodel.h" +#include "physdll.h" #include "utlsymbol.h" #include "tier1/strtools.h" #include "KeyValues.h" @@ -183,8 +182,8 @@ bool LoadStudioModel( char const* pModelName, char const* pEntityType, CUtlBuffe } // ensure reset - pHdr->pVertexBase = NULL; - pHdr->pIndexBase = NULL; + pHdr->SetVertexBase(NULL); + pHdr->SetIndexBase(NULL); return true; } @@ -247,7 +246,7 @@ static CPhysCollide* GetCollisionModel( char const* pModelName ) // Convert to a common string char* pTemp = (char*)_alloca(strlen(pModelName) + 1); strcpy( pTemp, pModelName ); - _strlwr( pTemp ); + strlwr( pTemp ); char* pSlash = strchr( pTemp, '\\' ); while( pSlash ) @@ -296,7 +295,9 @@ static CPhysCollide* GetCollisionModel( char const* pModelName ) static int propNum = 0; char tmp[128]; sprintf( tmp, "staticprop%03d.txt", propNum ); +#ifdef _WIN32 DumpCollideToGlView( lookup.m_pCollide, tmp ); +#endif ++propNum; } @@ -692,10 +693,10 @@ static void FreeCurrentModelVertexes() { Assert( g_pActiveStudioHdr ); - if ( g_pActiveStudioHdr->pVertexBase ) + if ( g_pActiveStudioHdr->VertexBase() ) { - free( g_pActiveStudioHdr->pVertexBase ); - g_pActiveStudioHdr->pVertexBase = NULL; + free( g_pActiveStudioHdr->VertexBase() ); + g_pActiveStudioHdr->SetVertexBase(NULL); } } @@ -708,9 +709,9 @@ const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void * pModelData ) Assert( pModelData == NULL ); Assert( g_pActiveStudioHdr ); - if ( g_pActiveStudioHdr->pVertexBase ) + if ( g_pActiveStudioHdr->VertexBase() ) { - return (vertexFileHeader_t *)g_pActiveStudioHdr->pVertexBase; + return (vertexFileHeader_t *)g_pActiveStudioHdr->VertexBase(); } // mandatory callback to make requested data resident @@ -753,7 +754,7 @@ const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void * pModelData ) Error("Error Vertex File %s checksum %d should be %d\n", fileName, pVvdHdr->checksum, g_pActiveStudioHdr->checksum); } - g_pActiveStudioHdr->pVertexBase = (void*)pVvdHdr; + g_pActiveStudioHdr->SetVertexBase((void*)pVvdHdr); return pVvdHdr; } diff --git a/utils/vbsp/textures.cpp b/utils/vbsp/textures.cpp index 4f49c5d47..c223f8684 100644 --- a/utils/vbsp/textures.cpp +++ b/utils/vbsp/textures.cpp @@ -10,7 +10,6 @@ #include "utilmatlib.h" #include "physdll.h" #include -#include #include "tier1/strtools.h" #include "materialpatch.h" #include "KeyValues.h" diff --git a/utils/vbsp/vbsp.cpp b/utils/vbsp/vbsp.cpp index 7b8c05936..a44af3fd3 100644 --- a/utils/vbsp/vbsp.cpp +++ b/utils/vbsp/vbsp.cpp @@ -14,7 +14,9 @@ #include "tier0/icommandline.h" #include "materialsystem/imaterialsystem.h" #include "map.h" +#ifdef _WIN32 #include "tools_minidump.h" +#endif #include "materialsub.h" #include "loadcmdline.h" #include "byteswap.h" @@ -46,7 +48,9 @@ qboolean noopt; qboolean leaktest; qboolean verboseentities; qboolean dumpcollide = false; +#ifdef _WIN32 qboolean g_bLowPriority = false; +#endif qboolean g_DumpStaticProps = false; qboolean g_bSkyVis = false; // skybox vis is off by default, toggle this to enable it bool g_bLightIfMissing = false; @@ -1088,10 +1092,12 @@ int RunVBSP( int argc, char **argv ) { g_BumpAll = true; } +#ifdef _WIN32 else if( !Q_stricmp( argv[i], "-low" ) ) { g_bLowPriority = true; } +#endif else if( !Q_stricmp( argv[i], "-lightifmissing" ) ) { g_bLightIfMissing = true; @@ -1133,10 +1139,12 @@ int RunVBSP( int argc, char **argv ) { g_NodrawTriggers = true; } +#ifdef _WIN32 else if ( !Q_stricmp( argv[i], "-FullMinidumps" ) ) { EnableFullMinidumps( true ); } +#endif else if ( !Q_stricmp( argv[i], "-embed" ) && i < argc - 1 ) { V_MakeAbsolutePath( g_szEmbedDir, sizeof( g_szEmbedDir ), argv[++i], "." ); @@ -1182,7 +1190,9 @@ int RunVBSP( int argc, char **argv ) " -nodetail : Get rid of all detail geometry. The geometry left over is\n" " what affects visibility.\n" " -nowater : Get rid of water brushes.\n" +#ifdef _WIN32 " -low : Run as an idle-priority process.\n" +#endif " -embed : Use as an additional search path for assets\n" " and embed all assets in this directory into the compiled\n" " map\n" @@ -1235,7 +1245,9 @@ int RunVBSP( int argc, char **argv ) " -x360 : Generate Xbox360 version of vsp\n" " -nox360 : Disable generation Xbox360 version of vsp (default)\n" " -replacematerials : Substitute materials according to materialsub.txt in content\\maps\n" +#ifdef _WIN32 " -FullMinidumps : Write large minidumps on crash.\n" +#endif ); } @@ -1257,11 +1269,13 @@ int RunVBSP( int argc, char **argv ) start = Plat_FloatTime(); +#ifdef _WIN32 // Run in the background? if( g_bLowPriority ) { SetLowPriority(); } +#endif if( ( g_nDXLevel != 0 ) && ( g_nDXLevel < 80 ) ) { @@ -1332,7 +1346,7 @@ int RunVBSP( int argc, char **argv ) g_nCubemapSamples = 0; // Mark as stale since the lighting could be screwed with new ents. - AddBufferToPak( GetPakFile(), "stale.txt", "stale", strlen( "stale" ) + 1, false ); + AddBufferToPak( GetPakFile(), "stale.txt", (void *)"stale", strlen( "stale" ) + 1, false ); LoadMapFile (name); SetModelNumbers (); @@ -1389,7 +1403,7 @@ int RunVBSP( int argc, char **argv ) { LoadBSPFile_FileSystemOnly (mapFile); // Mark as stale since the lighting could be screwed with new ents. - AddBufferToPak( GetPakFile(), "stale.txt", "stale", strlen( "stale" ) + 1, false ); + AddBufferToPak( GetPakFile(), "stale.txt", (void *)"stale", strlen( "stale" ) + 1, false ); } LoadMapFile (name); @@ -1435,8 +1449,10 @@ main */ int main (int argc, char **argv) { +#ifdef _WIN32 // Install an exception handler. SetupDefaultToolsMinidumpHandler(); +#endif return RunVBSP( argc, argv ); } diff --git a/utils/vbsp/vbsp.h b/utils/vbsp/vbsp.h index 689bbaa87..79c44acd0 100644 --- a/utils/vbsp/vbsp.h +++ b/utils/vbsp/vbsp.h @@ -18,7 +18,7 @@ #include "bsplib.h" #include "qfiles.h" #include "utilmatlib.h" -#include "ChunkFile.h" +#include "chunkfile.h" #ifdef WIN32 #pragma warning( disable: 4706 ) diff --git a/utils/vbsp/worldvertextransitionfixup.cpp b/utils/vbsp/worldvertextransitionfixup.cpp index f97f39337..8eafbc8af 100644 --- a/utils/vbsp/worldvertextransitionfixup.cpp +++ b/utils/vbsp/worldvertextransitionfixup.cpp @@ -6,7 +6,7 @@ #include "bsplib.h" #include "vbsp.h" -#include "tier1/UtlBuffer.h" +#include "tier1/utlbuffer.h" #include "tier1/utlvector.h" #include "KeyValues.h" #include "materialpatch.h" @@ -209,4 +209,4 @@ void WorldVertexTransitionFixup( void ) pSide->texinfo = CreateBrushVersionOfWorldVertexTransitionMaterial( pSide->texinfo ); } -} \ No newline at end of file +} diff --git a/utils/vbsp/writebsp.cpp b/utils/vbsp/writebsp.cpp index 005990d64..687bbbf74 100644 --- a/utils/vbsp/writebsp.cpp +++ b/utils/vbsp/writebsp.cpp @@ -931,7 +931,7 @@ void WriteBSP (node_t *headnode, face_t *pLeafFaceList ) } } - EmitWaterVolumesForBSP( &dmodels[nummodels], headnode ); +// EmitWaterVolumesForBSP( &dmodels[nummodels], headnode ); qprintf ("%5i nodes with faces\n", c_facenodes); qprintf ("%5i nodes without faces\n", c_nofaces); qprintf ("%5i faces\n", numfaces-oldfaces); @@ -1257,7 +1257,7 @@ void EndBSPFile (void) OverlayTransition_EmitOverlayFaces(); // phys collision needs dispinfo to operate (needs to generate phys collision for displacement surfs) - EmitPhysCollision(); +// EmitPhysCollision(); // We can't calculate this properly until vvis (since we need vis to do this), so we set // to zero everywhere by default. diff --git a/utils/vbsp/wscript b/utils/vbsp/wscript new file mode 100755 index 000000000..bb5334740 --- /dev/null +++ b/utils/vbsp/wscript @@ -0,0 +1,122 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vbsp' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'boundbox.cpp', + 'brushbsp.cpp', + 'csg.cpp', + 'cubemap.cpp', + 'detail.cpp', + 'detailobjects.cpp', + 'disp_vbsp.cpp', + 'faces.cpp', + 'glfile.cpp', + 'leakfile.cpp', + 'map.cpp', + 'manifest.cpp', + 'materialpatch.cpp', + 'materialsub.cpp', + 'nodraw.cpp', + 'normals.cpp', + 'overlay.cpp', + 'portals.cpp', + 'prtfile.cpp', + 'staticprop.cpp', + 'textures.cpp', + 'tree.cpp', + 'vbsp.cpp', + 'worldvertextransitionfixup.cpp', + 'writebsp.cpp', + '../common/mstristrip.cpp', + '../common/physdll.cpp', +# '../common/scratchpad_helpers.cpp', + '../common/utilmatlib.cpp', + '../../public/collisionutils.cpp', + '../../public/disp_common.cpp', + '../../public/disp_powerinfo.cpp', + '../../public/loadcmdline.cpp', + '../../public/lumpfiles.cpp', +# '../../public/scratchpad3d.cpp', + '../../public/zip_utils.cpp', + + # Common files + '../common/bsplib.cpp', + '../common/cmdlib.cpp', + '../common/filesystem_tools.cpp', + '../common/map_shared.cpp', + '../common/pacifier.cpp', + '../common/polylib.cpp', + '../common/scriplib.cpp', + '../common/threads.cpp', + '../../public/builddisp.cpp', + '../../public/chunkfile.cpp', + '../../public/filesystem_helpers.cpp', + '../../public/filesystem_init.cpp', + ] + + if bld.env.DEST_OS == 'win32': + source += ['../common/tools_minidump.cpp'] + else: + source += ['../../filesystem/linux_support.cpp'] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + '../../public/tier3', + '../../public/vtf', + '../../public/vstdlib', + '../../public/fgdlib', + ] + + defines = [] + + libs = [ + 'tier0', 'tier1', 'tier2', + 'vtf', + 'bitmap', + 'fgdlib', + 'mathlib', + 'vstdlib', + 'lzma', + 'vphysics', + 'shaderapiempty', + 'materialsystem', + ] + + if bld.env.DEST_OS == 'win32': + libs += ['USER32'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vbspinfo/vbspinfo.cpp b/utils/vbspinfo/vbspinfo.cpp index 69567b54a..57bb76845 100644 --- a/utils/vbspinfo/vbspinfo.cpp +++ b/utils/vbspinfo/vbspinfo.cpp @@ -9,17 +9,23 @@ #include "mathlib/mathlib.h" #include "bsplib.h" #include "tier0/icommandline.h" +#ifdef ENABLE_SCRATCHPAD #include "iscratchpad3d.h" +#endif + #include "filesystem_tools.h" #include "tier2/fileutils.h" #include "gamebspfile.h" -#include "tier1/utlstringmap.h" +#include "tier1/UtlStringMap.h" +#ifdef _WIN32 #include "tools_minidump.h" +#endif #include "cmdlib.h" bool g_bTreeInfo = false; +#ifdef ENABLE_SCRATCHPAD bool g_bDrawTree = false; - +#endif float g_nOptimumDepth; int g_nMinTreeDepth; @@ -48,7 +54,7 @@ void CalculateTreeInfo_R( int iNode, int depth ) } } - +#ifdef ENABLE_SCRATCHPAD void DrawTreeToScratchPad_R( IScratchPad3D *pPad, int iNode, // Which node we're drawing. @@ -98,7 +104,7 @@ void DrawTreeToScratchPad_R( &vMyPos ); } } - +#endif void CalcTreeDepth_R( int iNode, int iLevel, int &iMaxDepth ) { @@ -110,7 +116,7 @@ void CalcTreeDepth_R( int iNode, int iLevel, int &iMaxDepth ) CalcTreeDepth_R( dnodes[iNode].children[1], iLevel+1, iMaxDepth ); } - +#ifdef ENABLE_SCRATCHPAD void DrawTreeToScratchPad() { IScratchPad3D *pPad = ScratchPad3D_Create(); @@ -131,6 +137,7 @@ void DrawTreeToScratchPad() pPad->Release(); } +#endif struct WorldTextureStats_t { @@ -319,10 +326,12 @@ void PrintCommandLine( int argc, char **argv ) Warning( "\n\n" ); } -void main (int argc, char **argv) +int main( int argc, char **argv ) { +#ifdef _WIN32 // Install an exception handler. SetupDefaultToolsMinidumpHandler(); +#endif int i; char source[1024]; @@ -347,15 +356,17 @@ void main (int argc, char **argv) printf("usage: vbspinfo [parameters] bspfile [bspfiles]\n"); printf(" -treeinfo \n"); -// printf(" -drawtree \n"); Remove for now until the option can be fixed +#ifdef ENABLE_SCRATCHPAD + printf(" -drawtree \n"); +#endif printf(" -worldtexturestats \n"); printf(" -modelstats \n"); printf(" -liststaticprops \n"); printf(" -X[lump ID] Extract BSP lump to file. i.e -X0 extracts entity lump.\n"); - printf(" -size Show .bsp worldmodel bounds\n"); - Error("Incorrect syntax."); + printf(" -size Show .bsp worldmodel bounds\n"); + Error("Incorrect syntax.\n"); } - + bool bWorldTextureStats = false; bool bModelStats = false; bool bListStaticProps = false; @@ -368,11 +379,13 @@ void main (int argc, char **argv) g_bTreeInfo = true; continue; } +#ifdef ENABLE_SCRATCHPAD else if ( stricmp( argv[i], "-drawtree" ) == 0 ) { g_bDrawTree = true; continue; } +#endif else if( stricmp( argv[i], "-worldtexturestats" ) == 0 ) { bWorldTextureStats = true; @@ -415,7 +428,7 @@ void main (int argc, char **argv) } strcpy (source, argv[i]); Q_DefaultExtension (source, ".bsp", sizeof( source ) ); - + strcpy( source, ExpandPath( source ) ); f = fopen (source, "rb"); if (f) @@ -430,8 +443,8 @@ void main (int argc, char **argv) if( !bWorldTextureStats && !bModelStats && !bListStaticProps ) { Msg ("reading %s (%d)\n", source, size); - } - + } + // If we're extracting, do that and quit. if ( bHaveAnyToExtract ) @@ -440,7 +453,11 @@ void main (int argc, char **argv) // If the filename doesn't have a path, prepend with the current directory char fullbspname[MAX_PATH]; +#ifdef _WIN32 _fullpath( fullbspname, source, sizeof( fullbspname ) ); +#else + realpath( source, fullbspname ); +#endif for ( int extract = 0; extract < HEADER_LUMPS; extract++ ) { @@ -454,12 +471,12 @@ void main (int argc, char **argv) CloseBSPFile(); printf ("Finished extraction.\n" ); - return; + return 0; } - LoadBSPFile (source); + LoadBSPFile (source); if( bWorldTextureStats ) { @@ -519,8 +536,6 @@ void main (int argc, char **argv) PrintBSPFileSizes (); } - - if ( g_bTreeInfo ) { g_nOptimumDepth = (int)( log( ( float )numnodes ) / log( 2.0f ) ); @@ -547,15 +562,19 @@ void main (int argc, char **argv) (float)g_TotalTreeDepth / numnodes, (float)g_TotalVariance / numnodes ); } - + +#ifdef ENABLE_SCRATCHPAD if ( g_bDrawTree ) { DrawTreeToScratchPad(); } - +#endif + if( !bWorldTextureStats && !bModelStats && !bListStaticProps ) { printf ("---------------------\n"); } } + + return 0; } diff --git a/utils/vbspinfo/wscript b/utils/vbspinfo/wscript new file mode 100755 index 000000000..d25a6dfd2 --- /dev/null +++ b/utils/vbspinfo/wscript @@ -0,0 +1,71 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vbspinfo' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('DONT_PROTECT_FILEIO_FUNCTIONS', 1) + return + +def build(bld): + source = [ + 'vbspinfo.cpp', + '../common/bsplib.cpp', + '../common/cmdlib.cpp', + '../common/scriplib.cpp', + '../common/filesystem_tools.cpp', + '../../public/filesystem_helpers.cpp', + '../../public/filesystem_init.cpp', + '../../public/lumpfiles.cpp', + '../../public/zip_utils.cpp', + ] + + if bld.env.DEST_OS == 'win32': + source += ['../common/tools_minidump.cpp'] + else: + source += ['../../filesystem/linux_support.cpp'] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + '../../public/tier3', + '../../public/mathlib' + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'mathlib', 'lzma', 'vstdlib'] + + if bld.env.DEST_OS == 'win32': + libs += ['ADVAPI32', 'WS2_32'] + else: + libs += ['DL', 'M', 'LOG'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vpk/packtest.cpp b/utils/vpk/packtest.cpp index 8a9195969..453db0031 100644 --- a/utils/vpk/packtest.cpp +++ b/utils/vpk/packtest.cpp @@ -1922,7 +1922,7 @@ int main(int argc, char **argv) { switch( argv[nCurArg][1] ) { - case '?': // args + case 'h': // args { PrintArgSummaryAndExit( 0 ); // return success in this case. } @@ -2012,7 +2012,7 @@ int main(int argc, char **argv) if ( argc < 2 ) { - Error( "No command specified. Try 'vpk -?' for info.\n" ); + Error( "No command specified. Try 'vpk -h' for info.\n" ); } const char *pszCommand = argv[1]; @@ -2144,6 +2144,7 @@ int main(int argc, char **argv) //BenchMark( files ); //printf( " time pack = %f\n", Plat_FloatTime() - stime ); } +#ifdef VPK_ENABLE_SIGNING else if ( V_strcmp( pszCommand, "rehash" ) == 0 ) { if ( argc != 3 ) @@ -2168,7 +2169,6 @@ int main(int argc, char **argv) CheckHashes( argv[2] ); } -#ifdef VPK_ENABLE_SIGNING else if ( V_strcmp( pszCommand, "generate_keypair" ) == 0 ) { if ( argc != 3 ) @@ -2210,7 +2210,7 @@ int main(int argc, char **argv) } else { - Error( "Unknown command '%s'. Try 'vpk -?' for info.\n", pszCommand ); + Error( "Unknown command '%s'. Try 'vpk -h' for info.\n", pszCommand ); } return 0; diff --git a/utils/vpk/wscript b/utils/vpk/wscript new file mode 100755 index 000000000..10b77a172 --- /dev/null +++ b/utils/vpk/wscript @@ -0,0 +1,61 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vpk' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'packtest.cpp', + '../../public/filesystem_init.cpp', + '../../filesystem/linux_support.cpp', + ] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + ] + + defines = [] + + libs = [ + 'tier0', 'tier1', 'tier2', 'tier3', + 'vstdlib', + 'mathlib', + 'vpklib', + 'bitmap', + ] + + if bld.env.DEST_OS == 'win32': + libs += ['USER32'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vrad/disp_vrad.cpp b/utils/vrad/disp_vrad.cpp index b1d63b6e1..74ac1ef6b 100644 --- a/utils/vrad/disp_vrad.cpp +++ b/utils/vrad/disp_vrad.cpp @@ -8,13 +8,10 @@ #include "disp_vrad.h" #include "utllinkedlist.h" #include "utlvector.h" +#if defined( USE_SCRATCHPAD ) #include "iscratchpad3d.h" #include "scratchpadutils.h" - - -//#define USE_SCRATCHPAD -#if defined( USE_SCRATCHPAD ) - static IScratchPad3D *g_pPad = 0; +static IScratchPad3D *g_pPad = 0; #endif diff --git a/utils/vrad/incremental.cpp b/utils/vrad/incremental.cpp index ad46d04d1..bebe3693a 100644 --- a/utils/vrad/incremental.cpp +++ b/utils/vrad/incremental.cpp @@ -310,10 +310,13 @@ void CIncremental::AddLightToFace( else { bool bNew; - +#ifdef _WIN32 EnterCriticalSection( &pLight->m_CS ); +#endif pFace = pLight->FindOrCreateLightFace( iFace, lmSize, &bNew ); +#ifdef _WIN32 LeaveCriticalSection( &pLight->m_CS ); +#endif pLight->m_pCachedFaces[iThread] = pFace; @@ -460,10 +463,14 @@ void CIncremental::FinishFace( if( pFace->m_CompressedData.TellPut() == 0 ) { // No contribution.. delete this face from the light. +#ifdef _WIN32 EnterCriticalSection( &pLight->m_CS ); +#endif pLight->m_LightFaces.Remove( pFace->m_LightFacesIndex ); delete pFace; +#ifdef _WIN32 LeaveCriticalSection( &pLight->m_CS ); +#endif } else { @@ -574,7 +581,7 @@ void CIncremental::AddLightsForActiveLights() // Copy the light information. pLight->m_Light = dl->light; - pLight->m_flMaxIntensity = max( dl->light.intensity[0], max( dl->light.intensity[1], dl->light.intensity[2] ) ); + pLight->m_flMaxIntensity = MAX( dl->light.intensity[0], MAX( dl->light.intensity[1], dl->light.intensity[2] ) ); } } @@ -609,8 +616,8 @@ bool CIncremental::LoadIncrementalFile() FileRead( fp, pLight->m_Light ); pLight->m_flMaxIntensity = - max( pLight->m_Light.intensity.x, - max( pLight->m_Light.intensity.y, pLight->m_Light.intensity.z ) ); + MAX( pLight->m_Light.intensity.x, + MAX( pLight->m_Light.intensity.y, pLight->m_Light.intensity.z ) ); int nFaces; FileRead( fp, nFaces ); @@ -719,14 +726,18 @@ void CIncremental::LinkLightsToFaces( CUtlVector &faceLights ) CIncLight::CIncLight() { memset( m_pCachedFaces, 0, sizeof(m_pCachedFaces) ); +#ifdef _WIN32 InitializeCriticalSection( &m_CS ); +#endif } CIncLight::~CIncLight() { m_LightFaces.PurgeAndDeleteElements(); +#ifdef _WIN32 DeleteCriticalSection( &m_CS ); +#endif } diff --git a/utils/vrad/incremental.h b/utils/vrad/incremental.h index 9e98054b3..88254a7a2 100644 --- a/utils/vrad/incremental.h +++ b/utils/vrad/incremental.h @@ -58,8 +58,9 @@ class CIncLight public: - +#ifdef _WIN32 CRITICAL_SECTION m_CS; +#endif // This is the light for which m_LightFaces was built. dworldlight_t m_Light; diff --git a/utils/vrad/leaf_ambient_lighting.cpp b/utils/vrad/leaf_ambient_lighting.cpp index c96804541..507e0a511 100644 --- a/utils/vrad/leaf_ambient_lighting.cpp +++ b/utils/vrad/leaf_ambient_lighting.cpp @@ -13,9 +13,11 @@ #include "coordsize.h" #include "vstdlib/random.h" #include "bsptreedata.h" +#ifdef MPI #include "messbuf.h" #include "vmpi.h" #include "vmpi_distribute_work.h" +#endif static TableVector g_BoxDirections[6] = { @@ -191,8 +193,8 @@ bool IsLeafAmbientSurfaceLight( dworldlight_t *wl ) if ( wl->style != 0 ) return false; - float intensity = max( wl->intensity[0], wl->intensity[1] ); - intensity = max( intensity, wl->intensity[2] ); + float intensity = MAX( wl->intensity[0], wl->intensity[1] ); + intensity = MAX( intensity, wl->intensity[2] ); return (intensity * g_flWorldLightMinEmitSurfaceDistanceRatio) < g_flWorldLightMinEmitSurface; } @@ -584,6 +586,7 @@ static void ThreadComputeLeafAmbient( int iThread, void *pUserData ) } } +#ifdef MPI void VMPI_ProcessLeafAmbient( int iThread, uint64 iLeaf, MessageBuffer *pBuf ) { CUtlVector list; @@ -615,7 +618,7 @@ void VMPI_ReceiveLeafAmbientResults( uint64 leafID, MessageBuffer *pBuf, int iWo pBuf->read(g_LeafAmbientSamples[leafID].Base(), nSamples * sizeof(ambientsample_t) ); } } - +#endif void ComputePerLeafAmbientLighting() { @@ -642,6 +645,7 @@ void ComputePerLeafAmbientLighting() g_LeafAmbientSamples.SetCount(numleafs); +#ifdef MPI if ( g_bUseMPI ) { // Distribute the work among the workers. @@ -649,6 +653,7 @@ void ComputePerLeafAmbientLighting() DistributeWork( numleafs, VMPI_DISTRIBUTEWORK_PACKETID, VMPI_ProcessLeafAmbient, VMPI_ReceiveLeafAmbientResults ); } else +#endif { RunThreadsOn(numleafs, true, ThreadComputeLeafAmbient); } diff --git a/utils/vrad/lightmap.cpp b/utils/vrad/lightmap.cpp index 49360efc4..661012626 100644 --- a/utils/vrad/lightmap.cpp +++ b/utils/vrad/lightmap.cpp @@ -11,7 +11,9 @@ #include "radial.h" #include "mathlib/bumpvects.h" #include "tier1/utlvector.h" +#ifdef MPI #include "vmpi.h" +#endif #include "mathlib/anorms.h" #include "map_utils.h" #include "mathlib/halton.h" @@ -90,8 +92,8 @@ int CNormalList::FindOrAddNormal( Vector const &vNormal ) for( int iDim=0; iDim < 3; iDim++ ) { gi[iDim] = (int)( ((vNormal[iDim] + 1.0f) * 0.5f) * NUM_SUBDIVS - 0.000001f ); - gi[iDim] = min( gi[iDim], NUM_SUBDIVS ); - gi[iDim] = max( gi[iDim], 0 ); + gi[iDim] = MIN( gi[iDim], NUM_SUBDIVS ); + gi[iDim] = MAX( gi[iDim], 0 ); } // Look for a matching vector in there. @@ -1327,8 +1329,8 @@ bool CanLeafTraceToSky( int iLeaf ) for ( int j = 0; j < NUMVERTEXNORMALS; j+=4 ) { // search back to see if we can hit a sky brush - delta.LoadAndSwizzle( g_anorms[j], g_anorms[min( j+1, NUMVERTEXNORMALS-1 )], - g_anorms[min( j+2, NUMVERTEXNORMALS-1 )], g_anorms[min( j+3, NUMVERTEXNORMALS-1 )] ); + delta.LoadAndSwizzle( g_anorms[j], g_anorms[MIN( j+1, NUMVERTEXNORMALS-1 )], + g_anorms[MIN( j+2, NUMVERTEXNORMALS-1 )], g_anorms[MIN( j+3, NUMVERTEXNORMALS-1 )] ); delta *= -MAX_TRACE_LENGTH; delta += center4; @@ -2534,7 +2536,11 @@ static void GatherSampleLightAt4Points( SSE_SampleInfo_t& info, int sampleIdx, i if (info.m_WarnFace != info.m_FaceNum) { Warning ("\nWARNING: Too many light styles on a face at (%f, %f, %f)\n", +#ifdef VRAD_SSE info.m_Points.x.m128_f32[0], info.m_Points.y.m128_f32[0], info.m_Points.z.m128_f32[0] ); +#else + info.m_Points.x[0], info.m_Points.y[0], info.m_Points.z[0] ); +#endif info.m_WarnFace = info.m_FaceNum; } continue; @@ -3119,7 +3125,7 @@ void BuildFacelights (int iThread, int facenum) int nSample = 4 * grp; sample_t *sample = sampleInfo.m_pFaceLight->sample + nSample; - int numSamples = min ( 4, sampleInfo.m_pFaceLight->numsamples - nSample ); + int numSamples = MIN ( 4, sampleInfo.m_pFaceLight->numsamples - nSample ); FourVectors positions; FourVectors normals; @@ -3174,7 +3180,9 @@ void BuildFacelights (int iThread, int facenum) } } +#ifdef MPI if (!g_bUseMPI) +#endif { // // This is done on the master node when MPI is used diff --git a/utils/vrad/radial.cpp b/utils/vrad/radial.cpp index 5dc99b50e..26dd1a725 100644 --- a/utils/vrad/radial.cpp +++ b/utils/vrad/radial.cpp @@ -10,8 +10,8 @@ #include "lightmap.h" #include "radial.h" #include "mathlib/bumpvects.h" -#include "utlrbtree.h" -#include "mathlib/VMatrix.h" +#include "tier1/utlrbtree.h" +#include "mathlib/vmatrix.h" #include "macro_texture.h" @@ -89,19 +89,19 @@ void AddDirectToRadial( radial_t *rad, s_max = ( int )( coordmaxs[0] + 0.9999f ) + 1; // ???? t_max = ( int )( coordmaxs[1] + 0.9999f ) + 1; - s_min = max( s_min, 0 ); - t_min = max( t_min, 0 ); - s_max = min( s_max, rad->w ); - t_max = min( t_max, rad->h ); + s_min = MAX( s_min, 0 ); + t_min = MAX( t_min, 0 ); + s_max = MIN( s_max, rad->w ); + t_max = MIN( t_max, rad->h ); for( s = s_min; s < s_max; s++ ) { for( t = t_min; t < t_max; t++ ) { - float s0 = max( coordmins[0] - s, -1.0 ); - float t0 = max( coordmins[1] - t, -1.0 ); - float s1 = min( coordmaxs[0] - s, 1.0 ); - float t1 = min( coordmaxs[1] - t, 1.0 ); + float s0 = MAX( coordmins[0] - s, -1.0 ); + float t0 = MAX( coordmins[1] - t, -1.0 ); + float s1 = MIN( coordmaxs[0] - s, 1.0 ); + float t1 = MIN( coordmaxs[1] - t, 1.0 ); area = (s1 - s0) * (t1 - t0); @@ -110,7 +110,7 @@ void AddDirectToRadial( radial_t *rad, ds = fabs( coord[0] - s ); dt = fabs( coord[1] - t ); - r = max( ds, dt ); + r = MAX( ds, dt ); if (r < 0.1) { @@ -176,8 +176,8 @@ void AddBouncedToRadial( radial_t *rad, distt = (coordmaxs[1] - coordmins[1]); // patches less than a luxel in size could be mistakeningly filtered, so clamp. - dists = max( 1.0, dists ); - distt = max( 1.0, distt ); + dists = MAX( 1.0, dists ); + distt = MAX( 1.0, distt ); // find possible domain of patch influence s_min = ( int )( coord[0] - dists * RADIALDIST ); @@ -186,10 +186,10 @@ void AddBouncedToRadial( radial_t *rad, t_max = ( int )( coord[1] + distt * RADIALDIST + 1.0f ); // clamp to valid luxel - s_min = max( s_min, 0 ); - t_min = max( t_min, 0 ); - s_max = min( s_max, rad->w ); - t_max = min( t_max, rad->h ); + s_min = MAX( s_min, 0 ); + t_min = MAX( t_min, 0 ); + s_max = MIN( s_max, rad->w ); + t_max = MIN( t_max, rad->h ); for( s = s_min; s < s_max; s++ ) { @@ -249,10 +249,10 @@ void PatchLightmapCoordRange( radial_t *rad, int ndxPatch, Vector2D &mins, Vecto for (i = 0; i < w->numpoints; i++) { WorldToLuxelSpace( &rad->l, w->p[i], coord ); - mins[0] = min( mins[0], coord[0] ); - maxs[0] = max( maxs[0], coord[0] ); - mins[1] = min( mins[1], coord[1] ); - maxs[1] = max( maxs[1], coord[1] ); + mins[0] = MIN( mins[0], coord[0] ); + maxs[0] = MAX( maxs[0], coord[0] ); + mins[1] = MIN( mins[1], coord[1] ); + maxs[1] = MAX( maxs[1], coord[1] ); } } @@ -810,7 +810,7 @@ void FinalLightFace( int iThread, int facenum ) // garymct: minlight is a per entity minimum light value? for( i=0; i<3; i++ ) { - lb[bumpSample].m_vecLighting[i] = max( lb[bumpSample].m_vecLighting[i], minlight ); + lb[bumpSample].m_vecLighting[i] = MAX( lb[bumpSample].m_vecLighting[i], minlight ); } // Do the average light computation, I'm assuming (perhaps incorrectly?) diff --git a/utils/vrad/trace.cpp b/utils/vrad/trace.cpp index e0926e296..3bca83503 100644 --- a/utils/vrad/trace.cpp +++ b/utils/vrad/trace.cpp @@ -11,7 +11,7 @@ #include "vrad.h" #include "trace.h" -#include "Cmodel.h" +#include "cmodel.h" #include "mathlib/vmatrix.h" @@ -133,7 +133,11 @@ class CCoverageCountTexture : public CCoverageCount addedCoverage[s] = 0.0f; if ( ( sign >> s) & 0x1 ) { +#ifdef VRAD_SSE addedCoverage[s] = ComputeCoverageFromTexture( b0->m128_f32[s], b1->m128_f32[s], b2->m128_f32[s], hitID ); +#else + addedCoverage[s] = ComputeCoverageFromTexture( b0[0][s], b1[0][s], b2[0][s], hitID ); +#endif } } m_coverage = AddSIMD( m_coverage, LoadUnalignedSIMD( addedCoverage ) ); @@ -169,7 +173,11 @@ void TestLine( const FourVectors& start, const FourVectors& stop, { visibility[i] = 1.0f; if ( ( rt_result.HitIds[i] != -1 ) && +#ifdef VRAD_SSE ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) ) +#else + ( rt_result.HitDistance[i] < len[i] ) ) +#endif { visibility[i] = 0.0f; } @@ -373,7 +381,11 @@ void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop, { aOcclusion[i] = 0.0f; if ( ( rt_result.HitIds[i] != -1 ) && +#ifdef VRAD_SSE ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) ) +#else + ( rt_result.HitDistance[i] < len[i] ) ) +#endif { int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID; if ( !( id & TRACE_ID_SKY ) ) diff --git a/utils/vrad/vismat.cpp b/utils/vrad/vismat.cpp index ca9398ecb..d33cd0171 100644 --- a/utils/vrad/vismat.cpp +++ b/utils/vrad/vismat.cpp @@ -7,8 +7,8 @@ //=============================================================================// #include "vrad.h" -#include "vmpi.h" #ifdef MPI +#include "vmpi.h" #include "messbuf.h" static MessageBuffer mb; #endif @@ -467,11 +467,13 @@ BuildVisMatrix */ void BuildVisMatrix (void) { +#ifdef MPI if ( g_bUseMPI ) { RunMPIBuildVisLeafs(); } else +#endif { RunThreadsOn (dvis->numclusters, true, BuildVisLeafs); } diff --git a/utils/vrad/vrad.cpp b/utils/vrad/vrad.cpp index c77409a56..1eb47467a 100644 --- a/utils/vrad/vrad.cpp +++ b/utils/vrad/vrad.cpp @@ -12,9 +12,11 @@ #include "physdll.h" #include "lightmap.h" #include "tier1/strtools.h" +#ifdef MPI #include "vmpi.h" -#include "macro_texture.h" #include "vmpi_tools_shared.h" +#endif +#include "macro_texture.h" #include "leaf_ambient_lighting.h" #include "tools_minidump.h" #include "loadcmdline.h" @@ -24,6 +26,10 @@ static FileHandle_t pFpTrans = NULL; +#ifdef POSIX +char g_FileName[MAX_PATH]; +#endif + /* NOTES @@ -94,7 +100,7 @@ bool g_bOnlyStaticProps = false; bool g_bShowStaticPropNormals = false; -float gamma = 0.5; +float qgamma = 0.5; float indirect_sun = 1.0; float reflectivityScale = 1.0; qboolean do_extra = true; @@ -284,7 +290,7 @@ void ReadLightFile (char *filename) texlights[j].filename = filename; file_texlights ++; - num_texlights = max( num_texlights, j + 1 ); + num_texlights = MAX( num_texlights, j + 1 ); } } qprintf ( "[%i texlights parsed from '%s']\n\n", file_texlights, filename); @@ -819,7 +825,7 @@ int CreateChildPatch( int nParentIndex, winding_t *pWinding, float flArea, const if ( (child->face_maxs[i] == child->maxs[i] || child->face_mins[i] == child->mins[i] ) && total[i] > minchop ) { - child->chop = max( minchop, child->chop / 2 ); + child->chop = MAX( minchop, child->chop / 2 ); break; } } @@ -879,7 +885,7 @@ void SubdividePatch( int ndxPatch ) if (patch->chop > minchop) { bSubdivide = true; - patch->chop = max( minchop, patch->chop / 2 ); + patch->chop = MAX( minchop, patch->chop / 2 ); } } } @@ -2019,6 +2025,7 @@ bool RadWorld_Go() BuildFacesVisibleToLights( true ); } +#ifdef MPI // build initial facelights if (g_bUseMPI) { @@ -2026,6 +2033,7 @@ bool RadWorld_Go() RunMPIBuildFacelights(); } else +#endif { RunThreadsOnIndividual (numfaces, true, BuildFacelights); } @@ -2079,13 +2087,16 @@ bool RadWorld_Go() StaticDispMgr()->InsertPatchSampleDataIntoHashTable(); StaticDispMgr()->EndTimer(); +#ifdef MPI // blend bounced light into direct light and save VMPI_SetCurrentStage( "FinalLightFace" ); if ( !g_bUseMPI || g_bMPIMaster ) +#endif RunThreadsOnIndividual (numfaces, true, FinalLightFace); - +#ifdef MPI // Distribute the lighting data to workers. VMPI_DistributeLightData(); +#endif Msg("FinalLightFace Done\n"); fflush(stdout); } @@ -2099,7 +2110,7 @@ FileHandle_t pFileSamples[4][4]; void LoadPhysicsDLL( void ) { - PhysicsDLLPath( "VPHYSICS.DLL" ); + PhysicsDLLPath( "vphysics" DLL_EXT_STRING ); } @@ -2128,10 +2139,12 @@ void VRAD_LoadBSP( char const *pFilename ) g_flStartTime = Plat_FloatTime(); +#ifdef _WIN32 if( g_bLowPriority ) { SetLowPriority(); } +#endif strcpy( level_name, source ); @@ -2143,7 +2156,9 @@ void VRAD_LoadBSP( char const *pFilename ) // so we prepend qdir here. strcpy( source, ExpandPath( source ) ); +#ifdef MPI if ( !g_bUseMPI ) +#endif { // Setup the logfile. char logFile[512]; @@ -2160,7 +2175,11 @@ void VRAD_LoadBSP( char const *pFilename ) // Otherwise, try looking in the BIN directory from which we were run from Msg( "Could not find lights.rad in %s.\nTrying VRAD BIN directory instead...\n", global_lights ); +#ifdef _WIN32 GetModuleFileName( NULL, global_lights, sizeof( global_lights ) ); +#else + Q_strncpy(global_lights, g_FileName, sizeof(global_lights)); +#endif Q_ExtractFilePath( global_lights, global_lights, sizeof( global_lights ) ); strcat( global_lights, "lights.rad" ); } @@ -2181,9 +2200,12 @@ void VRAD_LoadBSP( char const *pFilename ) Q_DefaultExtension(source, ".bsp", sizeof( source )); Msg( "Loading %s\n", source ); +#ifdef MPI VMPI_SetCurrentStage( "LoadBSPFile" ); +#endif LoadBSPFile (source); +#ifdef MPI // Add this bsp to our search path so embedded resources can be found if ( g_bUseMPI && g_bMPIMaster ) { @@ -2192,6 +2214,7 @@ void VRAD_LoadBSP( char const *pFilename ) g_pOriginalPassThruFileSystem->AddSearchPath(source, "MOD", PATH_ADD_TO_HEAD); } else if ( !g_bUseMPI ) +#endif { // Non-MPI g_pFullFileSystem->AddSearchPath(source, "GAME", PATH_ADD_TO_HEAD); @@ -2323,7 +2346,9 @@ void VRAD_Finish() } Msg( "Writing %s\n", source ); +#ifdef MPI VMPI_SetCurrentStage( "WriteBSPFile" ); +#endif WriteBSPFile(source); if ( g_bDumpPatches ) @@ -2601,10 +2626,12 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail ) { ++i; } +#ifdef _WIN32 else if ( !Q_stricmp( argv[i], "-FullMinidumps" ) ) { EnableFullMinidumps( true ); } +#endif else if ( !Q_stricmp( argv[i], "-hdr" ) ) { SetHDRMode( true ); @@ -2640,7 +2667,7 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail ) Warning("Error: expected positive value after '-chop'\n" ); return -1; } - minchop = min( minchop, maxchop ); + minchop = MIN( minchop, maxchop ); } else { @@ -2751,6 +2778,7 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail ) } } #endif +#ifdef MPI // NOTE: the -mpi checks must come last here because they allow the previous argument // to be -mpi as well. If it game before something else like -game, then if the previous // argument was -mpi and the current argument was something valid like -game, it would skip it. @@ -2763,6 +2791,7 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail ) if ( i == argc - 1 && V_stricmp( argv[i], "-mpi_ListParams" ) != 0 ) break; } +#endif else if ( mapArg == -1 ) { mapArg = i; @@ -2805,7 +2834,9 @@ void PrintUsage( int argc, char **argv ) " -final : High quality processing. equivalent to -extrasky 16.\n" " -extrasky n : trace N times as many rays for indirect light and sky ambient.\n" " -low : Run as an idle-priority process.\n" +#ifdef MPI " -mpi : Use VMPI to distribute computations.\n" +#endif " -rederror : Show errors in red.\n" "\n" " -vproject : Override the VPROJECT environment variable.\n" @@ -2828,7 +2859,9 @@ void PrintUsage( int argc, char **argv ) " -dlightmap : Force direct lighting into different lightmap than\n" " radiosity.\n" " -stoponexit : Wait for a keypress on exit.\n" +#ifdef MPI " -mpi_pw : Use a password to choose a specific set of VMPI workers.\n" +#endif " -nodetaillight : Don't light detail props.\n" " -centersamples : Move sample centers.\n" " -luxeldensity # : Rescale all luxels by the specified amount (default: 1.0).\n" @@ -2840,7 +2873,9 @@ void PrintUsage( int argc, char **argv ) " -softsun : Treat the sun as an area light source of size degrees." " Produces soft shadows.\n" " Recommended values are between 0 and 5. Default is 0.\n" +#ifdef _WIN32 " -FullMinidumps : Write large minidumps on crash.\n" +#endif " -chop : Smallest number of luxel widths for a bounce patch, used on edges\n" " -maxchop : Coarsest allowed number of luxel widths for a patch, used in face interiors\n" "\n" @@ -2885,16 +2920,24 @@ void PrintUsage( int argc, char **argv ) #endif } +#ifdef _WIN32 +#define APP_EXT ".exe" +#else +#define APP_EXT "" +#endif + int RunVRAD( int argc, char **argv ) { #if defined(_MSC_VER) && ( _MSC_VER >= 1310 ) - Msg("Valve Software - vrad.exe SSE (" __DATE__ ")\n" ); + Msg("Valve Software - vrad" APP_EXT " SSE (" __DATE__ ")\n" ); #else - Msg("Valve Software - vrad.exe (" __DATE__ ")\n" ); + Msg("Valve Software - vrad" APP_EXT " (" __DATE__ ")\n" ); #endif Msg("\n Valve Radiosity Simulator \n"); + Q_strncpy(g_FileName, argv[0], MAX_PATH); + verbose = true; // Originally FALSE bool onlydetail; @@ -2922,7 +2965,9 @@ int RunVRAD( int argc, char **argv ) VRAD_Finish(); +#ifdef MPI VMPI_SetCurrentStage( "master done" ); +#endif DeleteCmdLine( argc, argv ); CmdLib_Cleanup(); @@ -2936,6 +2981,7 @@ int VRAD_Main(int argc, char **argv) VRAD_Init(); +#ifdef MPI // This must come first. VRAD_SetupMPI( argc, argv ); @@ -2945,10 +2991,13 @@ int VRAD_Main(int argc, char **argv) SetupToolsMinidumpHandler( VMPI_ExceptionFilter ); } else +#endif #endif { LoadCmdLineFromFile( argc, argv, source, "vrad" ); // Don't do this if we're a VMPI worker.. +#ifdef _WIN32 SetupDefaultToolsMinidumpHandler(); +#endif } return RunVRAD( argc, argv ); diff --git a/utils/vrad/vrad.h b/utils/vrad/vrad.h index e741ee6b4..372187628 100644 --- a/utils/vrad/vrad.h +++ b/utils/vrad/vrad.h @@ -24,9 +24,9 @@ #include "polylib.h" #include "threads.h" #include "builddisp.h" -#include "VRAD_DispColl.h" -#include "UtlMemory.h" -#include "UtlHash.h" +#include "vrad_dispcoll.h" +#include "utlmemory.h" +#include "utlhash.h" #include "utlvector.h" #include "iincremental.h" #include "raytrace.h" @@ -34,17 +34,13 @@ #ifdef _WIN32 #include +#include +#include #endif #include #include - -#pragma warning(disable: 4142 4028) -#include -#pragma warning(default: 4142 4028) - #include -#include #include @@ -337,7 +333,7 @@ extern dface_t *g_pFaces; extern bool g_bMPIProps; extern byte nodehit[MAX_MAP_NODES]; -extern float gamma; +extern float qgamma; extern float indirect_sun; extern float smoothing_threshold; extern int dlight_map; diff --git a/utils/vrad/vrad_dispcoll.cpp b/utils/vrad/vrad_dispcoll.cpp index 2edd1ca9b..b04b2f985 100644 --- a/utils/vrad/vrad_dispcoll.cpp +++ b/utils/vrad/vrad_dispcoll.cpp @@ -6,11 +6,11 @@ //=============================================================================// #include "vrad.h" -#include "VRAD_DispColl.h" -#include "DispColl_Common.h" +#include "vrad_dispcoll.h" +#include "dispcoll_common.h" #include "radial.h" -#include "CollisionUtils.h" -#include "tier0\dbg.h" +#include "collisionutils.h" +#include "tier0/dbg.h" #define SAMPLE_BBOX_SLOP 5.0f #define TRIEDGE_EPSILON 0.001f @@ -110,6 +110,7 @@ void CVRADDispColl::CalcSampleRadius2AndBox( dface_t *pFace ) // Calculate the patch radius - the max sample edge length * the number of luxels per edge "chop." float flSampleSize = max( m_flSampleWidth, m_flSampleHeight ); + // Calculate the patch radius - the MAX sample edge length * the number of luxels per edge "chop." float flPatchSampleRadius = flSampleSize * dispchop * 2.2f; if ( flPatchSampleRadius > g_MaxDispPatchRadius ) { @@ -440,7 +441,7 @@ void CVRADDispColl::CreateChildPatchesFromRoot( int iParentPatch, int *pChildPat vecEdges[3] = pParentPatch->winding->p[3] - pParentPatch->winding->p[0]; // Should the patch be subdivided - check the area. - float flMaxLength = max( m_flSampleWidth, m_flSampleHeight ); + float flMaxLength = MAX( m_flSampleWidth, m_flSampleHeight ); float flMinEdgeLength = flMaxLength * dispchop; // Find the longest edge. @@ -551,7 +552,7 @@ void CVRADDispColl::CreateChildPatches( int iParentPatch, int nLevel ) return; // Should the patch be subdivided - check the area. - float flMaxLength = max( m_flSampleWidth, m_flSampleHeight ); + float flMaxLength = MAX( m_flSampleWidth, m_flSampleHeight ); float flMinEdgeLength = flMaxLength * dispchop; // Split along the longest edge. @@ -659,7 +660,7 @@ void CVRADDispColl::CreateChildPatchesSub( int iParentPatch ) return; // Should the patch be subdivided - check the area. - float flMaxLength = max( m_flSampleWidth, m_flSampleHeight ); + float flMaxLength = MAX( m_flSampleWidth, m_flSampleHeight ); float flMinEdgeLength = flMaxLength * dispchop; // Split along the longest edge. @@ -1077,4 +1078,4 @@ void CVRADDispColl::AddPolysForRayTrace( void ) fullCoverage.x = 1.0f; g_RtEnv.AddTriangle( TRACE_ID_OPAQUE, m_aVerts[v[0]], m_aVerts[v[1]], m_aVerts[v[2]], fullCoverage ); } -} \ No newline at end of file +} diff --git a/utils/vrad/vrad_dispcoll.h b/utils/vrad/vrad_dispcoll.h index 787c3137a..d1ac322db 100644 --- a/utils/vrad/vrad_dispcoll.h +++ b/utils/vrad/vrad_dispcoll.h @@ -10,7 +10,7 @@ #pragma once #include -#include "DispColl_Common.h" +#include "dispcoll_common.h" //============================================================================= // @@ -77,4 +77,4 @@ class CVRADDispColl : public CDispCollTree CUtlVector m_aVertNormals; // Displacement vertex normals }; -#endif // VRAD_DISPCOLL_H \ No newline at end of file +#endif // VRAD_DISPCOLL_H diff --git a/utils/vrad/vraddetailprops.cpp b/utils/vrad/vraddetailprops.cpp index a024af9c9..8c40bb011 100644 --- a/utils/vrad/vraddetailprops.cpp +++ b/utils/vrad/vraddetailprops.cpp @@ -10,16 +10,18 @@ //=============================================================================// #include "vrad.h" -#include "Bsplib.h" -#include "GameBSPFile.h" -#include "UtlBuffer.h" -#include "utlvector.h" -#include "CModel.h" +#include "bsplib.h" +#include "gamebspfile.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlvector.h" +#include "cmodel.h" #include "studio.h" #include "pacifier.h" #include "vraddetailprops.h" #include "mathlib/halton.h" +#ifdef MPI #include "messbuf.h" +#endif #include "byteswap.h" bool LoadStudioModel( char const* pModelName, CUtlBuffer& buf ); @@ -227,7 +229,11 @@ static void ComputeMaxDirectLighting( DetailObjectLump_t& prop, Vector* maxcolor normal4.DuplicateVector( normal ); GatherSampleLightSSE ( out, dl, -1, origin4, &normal4, 1, iThread ); +#ifdef VRAD_SSE VectorMA( maxcolor[dl->light.style], out.m_flFalloff.m128_f32[0] * out.m_flDot[0].m128_f32[0], dl->light.intensity, maxcolor[dl->light.style] ); +#else + VectorMA( maxcolor[dl->light.style], out.m_flFalloff[0] * out.m_flDot[0][0], dl->light.intensity, maxcolor[dl->light.style] ); +#endif } } @@ -524,7 +530,8 @@ class CLightSurface : public IBSPNodeEnumerator bool TestPointAgainstSkySurface( Vector const &pt, dface_t *pFace ) { // Create sky face winding. - winding_t *pWinding = WindingFromFace( pFace, Vector( 0.0f, 0.0f, 0.0f ) ); + Vector vec( 0.0f, 0.0f, 0.0f ); + winding_t *pWinding = WindingFromFace( pFace, vec ); // Test point in winding. (Since it is at the node, it is in the plane.) bool bRet = PointInWinding( pt, pWinding ); @@ -958,6 +965,7 @@ void UnserializeDetailPropLighting( int lumpID, int lumpVersion, CUtlVectorread( &l->m_Style, sizeof( l->m_Style ) ); } } +#endif //----------------------------------------------------------------------------- // Computes lighting for the detail props diff --git a/utils/vrad/vraddisps.cpp b/utils/vrad/vraddisps.cpp index d0fe3e762..957ffccee 100644 --- a/utils/vrad/vraddisps.cpp +++ b/utils/vrad/vraddisps.cpp @@ -8,14 +8,13 @@ #include "vrad.h" #include "utlvector.h" #include "cmodel.h" -#include "BSPTreeData.h" -#include "VRAD_DispColl.h" -#include "CollisionUtils.h" +#include "bsptreedata.h" +#include "vrad_dispcoll.h" +#include "collisionutils.h" #include "lightmap.h" -#include "Radial.h" -#include "CollisionUtils.h" +#include "radial.h" #include "mathlib/bumpvects.h" -#include "utlrbtree.h" +#include "tier1/utlrbtree.h" #include "tier0/fasttimer.h" #include "disp_vrad.h" @@ -562,7 +561,7 @@ bool CVRadDispMgr::ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray ) ctx.m_pDispTested = &dispTested; // If it got through without a hit, it returns true - return !m_pBSPTreeData->EnumerateLeavesAlongRay( ray, &m_EnumDispRay, ( int )&ctx ); + return !m_pBSPTreeData->EnumerateLeavesAlongRay( ray, &m_EnumDispRay, ( int )(size_t)&ctx ); } @@ -575,7 +574,7 @@ bool CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &r ctx.m_pRay = &ray; ctx.m_pDispTested = &dispTested; - return !m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, ( int )&ctx ); + return !m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, ( int )(size_t)&ctx ); } //----------------------------------------------------------------------------- @@ -1135,7 +1134,7 @@ void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal if( bNeighborBump ) { float flScale = patchNormal.Dot( normals[0] ); - flScale = max( 0.0f, flScale ); + flScale = MAX( 0.0f, flScale ); float flBumpInfluence = influence * flScale; for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ ) @@ -1148,7 +1147,7 @@ void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal else { float flScale = patchNormal.Dot( normals[0] ); - flScale = max( 0.0f, flScale ); + flScale = MAX( 0.0f, flScale ); float flBumpInfluence = influence * flScale * 0.05f; for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ ) @@ -1162,7 +1161,7 @@ void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal else { float flScale = patchNormal.Dot( luxelNormal ); - flScale = max( 0.0f, flScale ); + flScale = MAX( 0.0f, flScale ); influence *= flScale; pRadial->light[0][ndxRadial].AddWeighted( pPatchLight[0], influence ); diff --git a/utils/vrad/vraddll.cpp b/utils/vrad/vraddll.cpp index bc9f2f457..9abb38968 100644 --- a/utils/vrad/vraddll.cpp +++ b/utils/vrad/vraddll.cpp @@ -119,7 +119,9 @@ bool CVRadDLL::Init( char const *pFilename ) // Set options and run vrad startup code. do_fast = true; +#ifdef _WIN32 g_bLowPriorityThreads = true; +#endif g_pIncremental = GetIncremental(); VRAD_LoadBSP( pFilename ); @@ -169,10 +171,18 @@ void CVRadDLL::GetBSPInfo( CBSPInfo *pInfo ) bool CVRadDLL::DoIncrementalLight( char const *pVMFFile ) { - char tempPath[MAX_PATH], tempFilename[MAX_PATH]; + char +#ifdef _WIN32 + tempPath[MAX_PATH], +#endif + tempFilename[MAX_PATH]; +#ifdef _WIN32 GetTempPath( sizeof( tempPath ), tempPath ); GetTempFileName( tempPath, "vmf_entities_", 0, tempFilename ); - +#else + struct tm *timeinfo = localtime(NULL); + strftime( tempFilename, MAX_PATH, "/tmp/vmf_entities_%F-%T", timeinfo ); +#endif FileHandle_t fp = g_pFileSystem->Open( tempFilename, "wb" ); if( !fp ) return false; diff --git a/utils/vrad/vradstaticprops.cpp b/utils/vrad/vradstaticprops.cpp index e4d92edd9..69e889d0c 100644 --- a/utils/vrad/vradstaticprops.cpp +++ b/utils/vrad/vradstaticprops.cpp @@ -11,16 +11,16 @@ #include "vrad.h" #include "mathlib/vector.h" -#include "UtlBuffer.h" +#include "utlbuffer.h" #include "utlvector.h" -#include "GameBSPFile.h" -#include "BSPTreeData.h" -#include "VPhysics_Interface.h" -#include "Studio.h" -#include "Optimize.h" -#include "Bsplib.h" -#include "CModel.h" -#include "PhysDll.h" +#include "gamebspfile.h" +#include "bsptreedata.h" +#include "vphysics_interface.h" +#include "studio.h" +#include "optimize.h" +#include "bsplib.h" +#include "cmodel.h" +#include "physdll.h" #include "phyfile.h" #include "collisionutils.h" #include "tier1/KeyValues.h" @@ -29,15 +29,17 @@ #include "materialsystem/hardwareverts.h" #include "materialsystem/hardwaretexels.h" #include "byteswap.h" -#include "mpivrad.h" #include "vtf/vtf.h" #include "tier1/utldict.h" #include "tier1/utlsymbol.h" #include "bitmap/tgawriter.h" +#ifdef MPI +#include "mpivrad.h" #include "messbuf.h" #include "vmpi.h" #include "vmpi_distribute_work.h" +#endif #define ALIGN_TO_POW2(x,y) (((x)+(y-1))&~(y-1)) @@ -155,20 +157,20 @@ void Rasterizer::Build() const float baseY = mUvStepY / 2.0f; - float fMinX = min(min(mT0.x, mT1.x), mT2.x); - float fMinY = min(min(mT0.y, mT1.y), mT2.y); - float fMaxX = max(max(mT0.x, mT1.x), mT2.x); - float fMaxY = max(max(mT0.y, mT1.y), mT2.y); + float fMinX = MIN(MIN(mT0.x, mT1.x), mT2.x); + float fMinY = MIN(MIN(mT0.y, mT1.y), mT2.y); + float fMaxX = MAX(MAX(mT0.x, mT1.x), mT2.x); + float fMaxY = MAX(MAX(mT0.y, mT1.y), mT2.y); // Degenerate. Consider warning about these, but otherwise no problem. if (fMinX == fMaxX || fMinY == fMaxY) return; // Clamp to 0..1 - fMinX = max(0, fMinX); - fMinY = max(0, fMinY); - fMaxX = min(1.0f, fMaxX); - fMaxY = min(1.0f, fMaxY); + fMinX = MAX(0, fMinX); + fMinY = MAX(0, fMinY); + fMaxX = MIN(1.0f, fMaxX); + fMaxY = MIN(1.0f, fMaxY); // We puff the interesting area up by 1 so we can hit an inflated region for the necessary bilerp data. // If we wanted to support better texturing (almost definitely unnecessary), we'd change this to a larger size. @@ -180,13 +182,14 @@ void Rasterizer::Build() int iMaxY = GetRow(fMaxY) + 1 + kFilterSampleRadius; // Clamp to valid texture (integer) locations - iMinX = max(0, iMinX); - iMinY = max(0, iMinY); - iMaxX = min(iMaxX, mResX - 1); - iMaxY = min(iMaxY, mResY - 1); + iMinX = MAX(0, iMinX); + iMinY = MAX(0, iMinY); + iMaxX = MIN(iMaxX, mResX - 1); + iMaxY = MIN(iMaxY, mResY - 1); // Set the size to be as expected. // TODO: Pass this in from outside to minimize allocations + // TODO: Pass this in from outside to minimize allocations int count = (iMaxY - iMinY + 1) * (iMaxX - iMinX + 1); mRasterizedLocations.EnsureCount(count); @@ -259,11 +262,13 @@ class CVradStaticPropMgr : public IVradStaticPropMgr void ComputeLighting( int iThread ); private: +#ifdef MPI // VMPI stuff. static void VMPI_ProcessStaticProp_Static( int iThread, uint64 iStaticProp, MessageBuffer *pBuf ); static void VMPI_ReceiveStaticPropResults_Static( uint64 iStaticProp, MessageBuffer *pBuf, int iWorker ); void VMPI_ProcessStaticProp( int iThread, int iStaticProp, MessageBuffer *pBuf ); void VMPI_ReceiveStaticPropResults( int iStaticProp, MessageBuffer *pBuf, int iWorker ); +#endif // local thread version static void ThreadComputeStaticPropLighting( int iThread, void *pUserData ); @@ -495,8 +500,8 @@ bool LoadStudioModel( char const* pModelName, CUtlBuffer& buf ) } // ensure reset - pHdr->pVertexBase = NULL; - pHdr->pIndexBase = NULL; + pHdr->SetVertexBase(NULL); + pHdr->SetIndexBase(NULL); return true; } @@ -779,15 +784,15 @@ class CShadowTextureList // HACKHACK: Compute the average coverage for this triangle by sampling the AABB of its texture space float ComputeCoverageForTriangle( int shadowTextureIndex, const Vector2D &t0, const Vector2D &t1, const Vector2D &t2 ) { - float umin = min(t0.x, t1.x); - umin = min(umin, t2.x); - float umax = max(t0.x, t1.x); - umax = max(umax, t2.x); + float umin = MIN(t0.x, t1.x); + umin = MIN(umin, t2.x); + float umax = MAX(t0.x, t1.x); + umax = MAX(umax, t2.x); - float vmin = min(t0.y, t1.y); - vmin = min(vmin, t2.y); - float vmax = max(t0.y, t1.y); - vmax = max(vmax, t2.y); + float vmin = MIN(t0.y, t1.y); + vmin = MIN(vmin, t2.y); + float vmax = MAX(t0.y, t1.y); + vmax = MAX(vmax, t2.y); // UNDONE: Do something about tiling umin = clamp(umin, 0, 1); @@ -1064,7 +1069,7 @@ void CVradStaticPropMgr::UnserializeStaticProps() if ( g_GameLumps.GetGameLumpVersion( handle ) != GAMELUMP_STATIC_PROPS_VERSION ) { - Error( "Cannot load the static props... encountered a stale map version. Re-vbsp the map." ); + Error( "Cannot load the static props... encountered a stale map version. Re-vbsp the map.\n" ); } if ( g_GameLumps.GetGameLump( handle ) ) @@ -1110,9 +1115,9 @@ void CVradStaticPropMgr::Shutdown() studiohdr_t *pStudioHdr = m_StaticPropDict[i].m_pStudioHdr; if ( pStudioHdr ) { - if ( pStudioHdr->pVertexBase ) + if ( pStudioHdr->VertexBase() ) { - free( pStudioHdr->pVertexBase ); + free( pStudioHdr->VertexBase() ); } free( pStudioHdr ); } @@ -1200,8 +1205,12 @@ void ComputeDirectLightingAtPoint( Vector &position, Vector &normal, Vector &out GatherSampleLightSSE( sampleOutput, dl, -1, adjusted_pos4, &normal4, 1, iThread, nLFlags | GATHERLFLAGS_FORCE_FAST, static_prop_id_to_skip, flEpsilon ); - + +#ifdef VRAD_SSE VectorMA( outColor, sampleOutput.m_flFalloff.m128_f32[0] * sampleOutput.m_flDot[0].m128_f32[0], dl->light.intensity, outColor ); +#else + VectorMA( outColor, sampleOutput.m_flFalloff[0] * sampleOutput.m_flDot[0][0], dl->light.intensity, outColor ); +#endif } } @@ -1329,7 +1338,9 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr const int skip_prop = (g_bDisablePropSelfShadowing || (prop.m_Flags & STATIC_PROP_NO_SELF_SHADOWING)) ? prop_index : -1; const int nFlags = ( prop.m_Flags & STATIC_PROP_IGNORE_NORMALS ) ? GATHERLFLAGS_IGNORE_NORMALS : 0; +#ifdef MPI VMPI_SetCurrentStage( "ComputeLighting" ); +#endif matrix3x4_t matPos, matNormal; AngleMatrix(prop.m_Angles, prop.m_Origin, matPos); @@ -1553,7 +1564,7 @@ void CVradStaticPropMgr::SerializeLighting() // align to start of vertex data unsigned char *pVertexData = (unsigned char *)(sizeof( HardwareVerts::FileHeader_t ) + m_StaticProps[i].m_MeshData.Count()*sizeof(HardwareVerts::MeshHeader_t)); - pVertexData = (unsigned char*)pVhvHdr + ALIGN_TO_POW2( (unsigned int)pVertexData, 512 ); + pVertexData = (unsigned char*)pVhvHdr + ALIGN_TO_POW2( (uintp)pVertexData, 512 ); // construct header pVhvHdr->m_nVersion = VHV_VERSION; @@ -1569,7 +1580,7 @@ void CVradStaticPropMgr::SerializeLighting() HardwareVerts::MeshHeader_t *pMesh = pVhvHdr->pMesh( n ); pMesh->m_nLod = m_StaticProps[i].m_MeshData[n].m_nLod; pMesh->m_nVertexes = m_StaticProps[i].m_MeshData[n].m_VertexColors.Count(); - pMesh->m_nOffset = (unsigned int)pVertexData - (unsigned int)pVhvHdr; + pMesh->m_nOffset = (uintp)pVertexData - (uintp)pVhvHdr; // construct vertexes for (int k=0; km_nVertexes; k++) @@ -1591,8 +1602,8 @@ void CVradStaticPropMgr::SerializeLighting() } // align to end of file - pVertexData = (unsigned char *)((unsigned int)pVertexData - (unsigned int)pVhvHdr); - pVertexData = (unsigned char*)pVhvHdr + ALIGN_TO_POW2( (unsigned int)pVertexData, 512 ); + pVertexData = (unsigned char *)((uintp)pVertexData - (uintp)pVhvHdr); + pVertexData = (unsigned char*)pVhvHdr + ALIGN_TO_POW2( (uintp)pVertexData, 512 ); AddBufferToPak( GetPakFile(), filename, (void*)pVhvHdr, pVertexData - (unsigned char*)pVhvHdr, false ); } @@ -1609,7 +1620,7 @@ void CVradStaticPropMgr::SerializeLighting() ImageFormat fmt = m_StaticProps[i].m_LightmapImageFormat; - unsigned int totalTexelSizeBytes = 0; + uintp totalTexelSizeBytes = 0; for (int j = 0; j < m_StaticProps[i].m_MeshData.Count(); j++) { totalTexelSizeBytes += m_StaticProps[i].m_MeshData[j].m_TexelsEncoded.Count(); @@ -1628,7 +1639,7 @@ void CVradStaticPropMgr::SerializeLighting() // align start of texel data unsigned char *pTexelData = (unsigned char *)(sizeof(HardwareTexels::FileHeader_t) + m_StaticProps[i].m_MeshData.Count() * sizeof(HardwareTexels::MeshHeader_t)); - pTexelData = (unsigned char*)pVhtHdr + ALIGN_TO_POW2((unsigned int)pTexelData, kAlignment); + pTexelData = (unsigned char*)pVhtHdr + ALIGN_TO_POW2((uintp)pTexelData, kAlignment); pVhtHdr->m_nVersion = VHT_VERSION; pVhtHdr->m_nChecksum = m_StaticPropDict[m_StaticProps[i].m_ModelIdx].m_pStudioHdr->checksum; @@ -1639,7 +1650,7 @@ void CVradStaticPropMgr::SerializeLighting() { HardwareTexels::MeshHeader_t *pMesh = pVhtHdr->pMesh(n); pMesh->m_nLod = m_StaticProps[i].m_MeshData[n].m_nLod; - pMesh->m_nOffset = (unsigned int)pTexelData - (unsigned int)pVhtHdr; + pMesh->m_nOffset = (uintp)pTexelData - (uintp)pVhtHdr; pMesh->m_nBytes = m_StaticProps[i].m_MeshData[n].m_TexelsEncoded.Count(); pMesh->m_nWidth = m_StaticProps[i].m_LightmapImageWidth; pMesh->m_nHeight = m_StaticProps[i].m_LightmapImageHeight; @@ -1648,13 +1659,14 @@ void CVradStaticPropMgr::SerializeLighting() pTexelData += m_StaticProps[i].m_MeshData[n].m_TexelsEncoded.Count(); } - pTexelData = (unsigned char *)((unsigned int)pTexelData - (unsigned int)pVhtHdr); - pTexelData = (unsigned char*)pVhtHdr + ALIGN_TO_POW2((unsigned int)pTexelData, kAlignment); + pTexelData = (unsigned char *)((uintp)pTexelData - (uintp)pVhtHdr); + pTexelData = (unsigned char*)pVhtHdr + ALIGN_TO_POW2((uintp)pTexelData, kAlignment); AddBufferToPak(GetPakFile(), filename, (void*)pVhtHdr, pTexelData - (unsigned char*)pVhtHdr, false); } } +#ifdef MPI void CVradStaticPropMgr::VMPI_ProcessStaticProp_Static( int iThread, uint64 iStaticProp, MessageBuffer *pBuf ) { g_StaticPropMgr.VMPI_ProcessStaticProp( iThread, iStaticProp, pBuf ); @@ -1739,7 +1751,7 @@ void CVradStaticPropMgr::VMPI_ReceiveStaticPropResults( int iStaticProp, Message // Apply the results. ApplyLightingToStaticProp( iStaticProp, m_StaticProps[iStaticProp], &results ); } - +#endif void CVradStaticPropMgr::ComputeLightingForProp( int iThread, int iStaticProp ) { @@ -1780,6 +1792,7 @@ void CVradStaticPropMgr::ComputeLighting( int iThread ) // ensure any traces against us are ignored because we have no inherit lighting contribution m_bIgnoreStaticPropTrace = true; +#ifdef MPI if ( g_bUseMPI ) { // Distribute the work among the workers. @@ -1792,6 +1805,7 @@ void CVradStaticPropMgr::ComputeLighting( int iThread ) &CVradStaticPropMgr::VMPI_ReceiveStaticPropResults_Static ); } else +#endif { RunThreadsOn(count, true, ThreadComputeStaticPropLighting); } @@ -2169,9 +2183,9 @@ const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void *pModelData ) studiohdr_t *pActiveStudioHdr = static_cast(pModelData); Assert( pActiveStudioHdr ); - if ( pActiveStudioHdr->pVertexBase ) + if ( pActiveStudioHdr->VertexBase() ) { - return (vertexFileHeader_t *)pActiveStudioHdr->pVertexBase; + return (vertexFileHeader_t *)pActiveStudioHdr->VertexBase(); } // mandatory callback to make requested data resident @@ -2230,7 +2244,7 @@ const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void *pModelData ) free( pVvdHdr ); pVvdHdr = pNewVvdHdr; - pActiveStudioHdr->pVertexBase = (void*)pVvdHdr; + pActiveStudioHdr->SetVertexBase((void*)pVvdHdr); return pVvdHdr; } @@ -2247,8 +2261,8 @@ struct ColorTexelValue // ------------------------------------------------------------------------------------------------ inline int ComputeLinearPos( int _x, int _y, int _resX, int _resY ) { - return Min( Max( 0, _y ), _resY - 1 ) * _resX - + Min( Max( 0, _x ), _resX - 1 ); + return MIN( MAX( 0, _y ), _resY - 1 ) * _resX + + MIN( MAX( 0, _x ), _resX - 1 ); } // ------------------------------------------------------------------------------------------------ @@ -2455,8 +2469,8 @@ static int GetTexelCount(unsigned int _resX, unsigned int _resY, bool _mipmaps) while (_resX > 1 || _resY > 1) { retVal += _resX * _resY; - _resX = max(1, _resX >> 1); - _resY = max(1, _resY >> 1); + _resX = MAX(1, _resX >> 1); + _resY = MAX(1, _resY >> 1); } // Add in the 1x1 mipmap level, which wasn't hit above. This could be done in the initializer of @@ -2582,8 +2596,8 @@ static void FilterCoarserMipmaps(unsigned int _resX, unsigned int _resY, CUtlVec int srcResX = _resX; int srcResY = _resY; - int dstResX = max(1, (srcResX >> 1)); - int dstResY = max(1, (srcResY >> 1)); + int dstResX = MAX(1, (srcResX >> 1)); + int dstResY = MAX(1, (srcResY >> 1)); int dstOffset = GetTexelCount(srcResX, srcResY, false); // Build mipmaps here, after being converted to linear space. @@ -2618,8 +2632,8 @@ static void FilterCoarserMipmaps(unsigned int _resX, unsigned int _resY, CUtlVec srcResX = dstResX; srcResY = dstResY; - dstResX = max(1, (srcResX >> 1)); - dstResY = max(1, (srcResY >> 1)); + dstResX = MAX(1, (srcResX >> 1)); + dstResY = MAX(1, (srcResY >> 1)); dstOffset += GetTexelCount(srcResX, srcResY, false); } } @@ -2650,8 +2664,8 @@ static void ConvertToDestinationFormat(unsigned int _resX, unsigned int _resY, I srcOffset += GetTexelCount(srcResX, srcResY, false); dstOffset += ImageLoader::GetMemRequired(srcResX, srcResY, 1, _destFmt, false); - srcResX = max(1, (srcResX >> 1)); - srcResY = max(1, (srcResY >> 1)); + srcResX = MAX(1, (srcResX >> 1)); + srcResY = MAX(1, (srcResY >> 1)); } // Do the 1x1 level also. diff --git a/utils/vrad/wscript b/utils/vrad/wscript new file mode 100755 index 000000000..a3b85479e --- /dev/null +++ b/utils/vrad/wscript @@ -0,0 +1,118 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vrad' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('PROTECTED_THINGS_DISABLE', 1) + conf.define('VRAD', 1) + conf.define('MAX_TOOL_THREADS', 1) + conf.define('THREADINDEX_MAIN', 0) + conf.define('NO_THREAD_NAMES', 1) + return + +def build(bld): + source = [ + 'disp_vrad.cpp', + 'imagepacker.cpp', + 'incremental.cpp', + 'leaf_ambient_lighting.cpp', + 'lightmap.cpp', + 'macro_texture.cpp', + 'origface.cpp', + 'radial.cpp', + 'samplehash.cpp', + 'trace.cpp', + 'vismat.cpp', + 'vrad.cpp', + 'vrad_dispcoll.cpp', + 'vraddetailprops.cpp', + 'vraddisps.cpp', + 'vraddll.cpp', + 'vradstaticprops.cpp', + '../common/physdll.cpp', + '../common/utilmatlib.cpp', + '../../public/bsptreedata.cpp', + '../../public/collisionutils.cpp', + '../../public/disp_common.cpp', + '../../public/disp_powerinfo.cpp', + '../../public/dispcoll_common.cpp', + '../../public/loadcmdline.cpp', + '../../public/lumpfiles.cpp', + '../../public/zip_utils.cpp', + + # Common files + '../common/bsplib.cpp', + '../common/cmdlib.cpp', + '../common/filesystem_tools.cpp', + '../common/map_shared.cpp', + '../common/polylib.cpp', + '../common/scriplib.cpp', + '../common/threads.cpp', + '../common/pacifier.cpp', + '../../public/builddisp.cpp', + '../../public/chunkfile.cpp', + '../../public/filesystem_helpers.cpp', + '../../public/filesystem_init.cpp', + '../../filesystem/linux_support.cpp', + ] + + if bld.env.DEST_OS == 'win32' and False: + source += [ + 'mpivrad.cpp', + '../common/MySqlDatabase.cpp', + '../common/mpi_stats.cpp', + '../common/vmpi_tools_shared.cpp', + '../common/tools_minidump.cpp', +# '../common/scratchpad_helpers.cpp', +# '../../public/scratchpad3d.cpp', + ] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + '../../public/tier3', + '../../public/mathlib' + ] + + defines = [] + + libs = [ + 'tier0', 'tier1', 'tier2', 'tier3', + 'vtf', + 'bitmap', + 'raytrace', + 'mathlib', + 'lzma', + 'vphysics', + 'vstdlib', + ] + + install_path = bld.env.LIBDIR + + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vrad_launcher/stdafx.cpp b/utils/vrad_launcher/stdafx.cpp deleted file mode 100644 index 983b8ba54..000000000 --- a/utils/vrad_launcher/stdafx.cpp +++ /dev/null @@ -1,15 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -// stdafx.cpp : source file that includes just the standard includes -// vrad_launcher.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/utils/vrad_launcher/stdafx.h b/utils/vrad_launcher/stdafx.h deleted file mode 100644 index 36daff0ab..000000000 --- a/utils/vrad_launcher/stdafx.h +++ /dev/null @@ -1,32 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__4A047C84_94D7_4563_A08C_35E52A52AECC__INCLUDED_) -#define AFX_STDAFX_H__4A047C84_94D7_4563_A08C_35E52A52AECC__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include -#include -#include "interface.h" -#include "ivraddll.h" - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__4A047C84_94D7_4563_A08C_35E52A52AECC__INCLUDED_) diff --git a/utils/vrad_launcher/vrad_launcher.cpp b/utils/vrad_launcher/vrad_launcher.cpp index a4d318342..e7a17b0e2 100644 --- a/utils/vrad_launcher/vrad_launcher.cpp +++ b/utils/vrad_launcher/vrad_launcher.cpp @@ -8,12 +8,18 @@ // vrad_launcher.cpp : Defines the entry point for the console application. // -#include "stdafx.h" +#ifdef _WIN32 +#include #include +#else +#include +#endif +#include "ivraddll.h" #include "tier1/strtools.h" +#include "tier1/interface.h" #include "tier0/icommandline.h" - +#ifdef _WIN32 char* GetLastErrorString() { static char err[2048]; @@ -38,6 +44,9 @@ char* GetLastErrorString() return err; } +#else +#define GetLastErrorString dlerror +#endif void MakeFullPath( const char *pIn, char *pOut, int outLen ) @@ -107,7 +116,7 @@ int main(int argc, char* argv[]) // If it didn't load the module above, then use the if ( !pModule ) { - strcpy( dllName, "vrad_dll.dll" ); + strcpy( dllName, "vrad" DLL_EXT_STRING ); pModule = Sys_LoadModule( dllName ); } diff --git a/utils/vrad_launcher/wscript b/utils/vrad_launcher/wscript new file mode 100755 index 000000000..6d1771ab8 --- /dev/null +++ b/utils/vrad_launcher/wscript @@ -0,0 +1,55 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vrad_launcher' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'vrad_launcher.cpp' + ] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'vrad'] + + if bld.env.DEST_OS == 'win32': + libs += ['ADVAPI32', 'WS2_32'] + else: + libs += ['DL', 'LOG'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vvis/flow.cpp b/utils/vvis/flow.cpp index 6e280626f..f2b240b16 100644 --- a/utils/vvis/flow.cpp +++ b/utils/vvis/flow.cpp @@ -6,7 +6,9 @@ // //=============================================================================// #include "vis.h" +#ifdef _WIN32 #include "vmpi.h" +#endif int g_TraceClusterStart = -1; int g_TraceClusterStop = -1; @@ -50,8 +52,9 @@ int c_chop, c_nochop; int active; +#ifdef _WIN32 extern bool g_bVMPIEarlyExit; - +#endif void CheckStack (leaf_t *leaf, threaddata_t *thread) { @@ -485,11 +488,13 @@ void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) long *test, *might, *vis, more; int pnum; +#ifdef _WIN32 // Early-out if we're a VMPI worker that's told to exit. If we don't do this here, then the // worker might spin its wheels for a while on an expensive work unit and not be available to the pool. // This is pretty common in vis. if ( g_bVMPIEarlyExit ) return; +#endif if ( leafnum == g_TraceClusterStop ) { diff --git a/utils/vvis/vvis.cpp b/utils/vvis/vvis.cpp index 42edd0bff..5cf9b0981 100644 --- a/utils/vvis/vvis.cpp +++ b/utils/vvis/vvis.cpp @@ -7,19 +7,21 @@ //=============================================================================// // vis.c +#ifdef _WIN32 #include +#include "vmpi_tools_shared.h" +#include "vmpi.h" +#include "mpivis.h" +#include "tools_minidump.h" +#endif #include "vis.h" #include "threads.h" #include "stdlib.h" #include "pacifier.h" -#include "vmpi.h" -#include "mpivis.h" #include "tier1/strtools.h" #include "collisionutils.h" #include "tier0/icommandline.h" -#include "vmpi_tools_shared.h" #include "ilaunchabledll.h" -#include "tools_minidump.h" #include "loadcmdline.h" #include "byteswap.h" @@ -54,7 +56,9 @@ portal_t *sorted_portals[MAX_MAP_PORTALS*2]; bool g_bUseRadius = false; double g_VisRadius = 4096.0f * 4096.0f; +#ifdef _WIN32 bool g_bLowPriority = false; +#endif //============================================================================= @@ -84,7 +88,7 @@ winding_t *NewWinding (int points) if (points > MAX_POINTS_ON_WINDING) Error ("NewWinding: %i points, max %d", points, MAX_POINTS_ON_WINDING); - size = (int)(&((winding_t *)0)->points[points]); + size = (int)(size_t)(&((winding_t *)0)->points[points]); w = (winding_t*)malloc (size); memset (w, 0, size); @@ -302,11 +306,13 @@ void CalcPortalVis (void) } +#ifdef _WIN32 if (g_bUseMPI) { RunMPIPortalFlow(); } else +#endif { RunThreadsOnIndividual (g_numportals*2, true, PortalFlow); } @@ -315,7 +321,7 @@ void CalcPortalVis (void) void CalcVisTrace (void) { - RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis); + RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis); BuildTracePortals( g_TraceClusterStart ); // NOTE: We only schedule the one-way portals out of the start cluster here // so don't run g_numportals*2 in this case @@ -331,11 +337,13 @@ void CalcVis (void) { int i; +#ifdef _WIN32 if (g_bUseMPI) { RunMPIBasePortalVis(); } else +#endif { RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis); } @@ -413,6 +421,7 @@ void LoadPortals (char *name) FILE *f; +#ifdef _WIN32 // Open the portal file. if ( g_bUseMPI ) { @@ -448,6 +457,7 @@ void LoadPortals (char *name) f = fopen( tempFile, "rSTD" ); // read only, sequential, temporary, delete on close } else +#endif { f = fopen( name, "r" ); } @@ -949,6 +959,7 @@ int ParseCommandLine( int argc, char **argv ) } else if (!Q_stricmp (argv[i],"-tmpin")) strcpy (inbase, "/tmp"); +#ifdef _WIN32 else if( !Q_stricmp( argv[i], "-low" ) ) { g_bLowPriority = true; @@ -957,6 +968,7 @@ int ParseCommandLine( int argc, char **argv ) { EnableFullMinidumps( true ); } +#endif else if ( !Q_stricmp( argv[i], CMDLINEOPTION_NOVCONFIG ) ) { } @@ -968,6 +980,7 @@ int ParseCommandLine( int argc, char **argv ) { // nothing to do here, but don't bail on this option } +#ifdef _WIN32 // NOTE: the -mpi checks must come last here because they allow the previous argument // to be -mpi as well. If it game before something else like -game, then if the previous // argument was -mpi and the current argument was something valid like -game, it would skip it. @@ -980,6 +993,7 @@ int ParseCommandLine( int argc, char **argv ) if ( i == argc - 1 ) break; } +#endif else if (argv[i][0] == '-') { Warning("VBSP: Unknown option \"%s\"\n\n", argv[i]); @@ -1016,8 +1030,10 @@ void PrintUsage( int argc, char **argv ) "\n" " -v (or -verbose): Turn on verbose output (also shows more command\n" " -fast : Only do first quick pass on vis calculations.\n" +#ifdef _WIN32 " -mpi : Use VMPI to distribute computations.\n" " -low : Run as an idle-priority process.\n" +#endif " env_fog_controller specifies one.\n" "\n" " -vproject : Override the VPROJECT environment variable.\n" @@ -1026,14 +1042,18 @@ void PrintUsage( int argc, char **argv ) "Other options:\n" " -novconfig : Don't bring up graphical UI on vproject errors.\n" " -radius_override: Force a vis radius, regardless of whether an\n" +#ifdef _WIN32 " -mpi_pw : Use a password to choose a specific set of VMPI workers.\n" +#endif " -threads : Control the number of threads vbsp uses (defaults to the #\n" " or processors on your machine).\n" " -nosort : Don't sort portals (sorting is an optimization).\n" " -tmpin : Make portals come from \\tmp\\.\n" " -tmpout : Make portals come from \\tmp\\.\n" " -trace : Writes a linefile that traces the vis from one cluster to another for debugging map vis.\n" +#ifdef _WIN32 " -FullMinidumps : Write large minidumps on crash.\n" +#endif " -x360 : Generate Xbox360 version of vsp\n" " -nox360 : Disable generation Xbox360 version of vsp (default)\n" "\n" @@ -1070,7 +1090,7 @@ void PrintUsage( int argc, char **argv ) int RunVVis( int argc, char **argv ) { - char portalfile[1024]; + char portalfile[1024]; char source[1024]; char mapFile[1024]; double start, end; @@ -1109,7 +1129,7 @@ int RunVVis( int argc, char **argv ) start = Plat_FloatTime(); - +#ifdef _WIN32 if (!g_bUseMPI) { // Setup the logfile. @@ -1123,6 +1143,7 @@ int RunVVis( int argc, char **argv ) { SetLowPriority(); } +#endif ThreadSetDefault (); @@ -1187,10 +1208,12 @@ int RunVVis( int argc, char **argv ) { Error("Invalid cluster trace: %d to %d, valid range is 0 to %d\n", g_TraceClusterStart, g_TraceClusterStop, portalclusters-1 ); } +#ifdef _WIN32 if ( g_bUseMPI ) { Warning("Can't compile trace in MPI mode\n"); } +#endif CalcVisTrace (); WritePortalTrace(source); } @@ -1203,7 +1226,9 @@ int RunVVis( int argc, char **argv ) ReleasePakFileLumps(); DeleteCmdLine( argc, argv ); +#ifdef _WIN32 CmdLib_Cleanup(); +#endif return 0; } @@ -1218,6 +1243,7 @@ int main (int argc, char **argv) CommandLine()->CreateCmdLine( argc, argv ); MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f, false, false, false, false ); +#ifdef _WIN32 InstallAllocationFunctions(); InstallSpewFunction(); @@ -1228,6 +1254,7 @@ int main (int argc, char **argv) SetupToolsMinidumpHandler( VMPI_ExceptionFilter ); else SetupDefaultToolsMinidumpHandler(); +#endif return RunVVis( argc, argv ); } diff --git a/utils/vvis/wscript b/utils/vvis/wscript new file mode 100755 index 000000000..1e6d8c18b --- /dev/null +++ b/utils/vvis/wscript @@ -0,0 +1,79 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vvis' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('PROTECTED_THINGS_DISABLE', 1) + return + +def build(bld): + source = [ + 'WaterDist.cpp', + 'flow.cpp', + 'vvis.cpp', + '../common/bsplib.cpp', + '../common/cmdlib.cpp', + '../common/scriplib.cpp', + '../common/filesystem_tools.cpp', + '../common/pacifier.cpp', + '../common/threads.cpp', + '../../public/collisionutils.cpp', + '../../public/filesystem_helpers.cpp', + '../../public/filesystem_init.cpp', + '../../public/loadcmdline.cpp', + '../../public/lumpfiles.cpp', + '../../public/zip_utils.cpp', + '../../filesystem/linux_support.cpp', + ] + + if bld.env.DEST_OS == 'win32': + source += [ + 'mpivis.cpp', + '../common/mpi_stats.cpp', + '../common/MySqlDatabase.cpp', + '../common/tools_minidump.cpp', + '../common/vmpi_tools_shared.cpp', + '../common/scratchpad_helpers.cpp', + '../../public/scratchpad3d.cpp', + ] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + '../../public/tier3', + '../../public/mathlib' + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'tier3', 'mathlib', 'lzma', 'vstdlib'] + + install_path = bld.env.LIBDIR + + bld.shlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/vvis_launcher/vvis_launcher.cpp b/utils/vvis_launcher/vvis_launcher.cpp index edf03d251..ea4ea68f1 100644 --- a/utils/vvis_launcher/vvis_launcher.cpp +++ b/utils/vvis_launcher/vvis_launcher.cpp @@ -8,14 +8,18 @@ // vvis_launcher.cpp : Defines the entry point for the console application. // +#ifdef _WIN32 #include "stdafx.h" #include +#else +#include +#endif +#include "tier1/interface.h" #include "tier1/strtools.h" #include "tier0/icommandline.h" #include "ilaunchabledll.h" - - +#ifdef _WIN32 char* GetLastErrorString() { static char err[2048]; @@ -40,12 +44,15 @@ char* GetLastErrorString() return err; } +#elif defined(POSIX) +#define GetLastErrorString dlerror +#endif int main(int argc, char* argv[]) { CommandLine()->CreateCmdLine( argc, argv ); - const char *pDLLName = "vvis_dll.dll"; + const char *pDLLName = "vvis" DLL_EXT_STRING; CSysModule *pModule = Sys_LoadModule( pDLLName ); if ( !pModule ) diff --git a/utils/vvis_launcher/wscript b/utils/vvis_launcher/wscript new file mode 100755 index 000000000..06948542c --- /dev/null +++ b/utils/vvis_launcher/wscript @@ -0,0 +1,53 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'vvis_launcher' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'vvis_launcher.cpp' + ] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'vvis'] + + if bld.env.DEST_OS != 'win32': + libs += ['DL', 'LOG'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/xbox/xbspinfo/wscript b/utils/xbox/xbspinfo/wscript new file mode 100755 index 000000000..8f39635fe --- /dev/null +++ b/utils/xbox/xbspinfo/wscript @@ -0,0 +1,53 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'xbspinfo' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('DONT_PROTECT_FILEIO_FUNCTIONS', 1) + return + +def build(bld): + source = [ + 'xbspinfo.cpp' + ] + + includes = [ + '.', + '../../common', + '../../../public', + '../../../public/tier0', + '../../../public/tier1', + ] + + defines = [] + + libs = ['tier0', 'tier1', 'tier2', 'tier3', 'lzma', 'mathlib'] + + if bld.env.DEST_OS != 'win32': + libs += ['DL', 'LOG'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/utils/xbox/xbspinfo/xbspinfo.cpp b/utils/xbox/xbspinfo/xbspinfo.cpp index 8a968ff6f..00044426f 100644 --- a/utils/xbox/xbspinfo/xbspinfo.cpp +++ b/utils/xbox/xbspinfo/xbspinfo.cpp @@ -17,7 +17,7 @@ BEGIN_BYTESWAP_DATADESC( lump_t ) DEFINE_FIELD( fileofs, FIELD_INTEGER ), DEFINE_FIELD( filelen, FIELD_INTEGER ), DEFINE_FIELD( version, FIELD_INTEGER ), - DEFINE_ARRAY( fourCC, FIELD_CHARACTER, 4 ), +// DEFINE_ARRAY( fourCC, FIELD_CHARACTER, 4 ), END_BYTESWAP_DATADESC() typedef struct @@ -267,6 +267,7 @@ void DumpInfo( const char *pFilename, void *pBSPFile, int bspSize ) bool LoadBSPFile( const char* pFilename, void **ppBSPBuffer, int *pBSPSize ) { CByteswap byteSwap; + dheader_t *pBSPHeader; *ppBSPBuffer = NULL; *pBSPSize = 0; @@ -298,7 +299,7 @@ bool LoadBSPFile( const char* pFilename, void **ppBSPBuffer, int *pBSPSize ) goto cleanUp; } - dheader_t *pBSPHeader = (dheader_t *)*ppBSPBuffer; + pBSPHeader = (dheader_t *)*ppBSPBuffer; if ( pBSPHeader->ident != IDBSPHEADER ) { @@ -327,7 +328,7 @@ bool LoadBSPFile( const char* pFilename, void **ppBSPBuffer, int *pBSPSize ) goto cleanUp; } - // sucess + // success return true; cleanUp: @@ -427,4 +428,4 @@ int main( int argc, char* argv[] ) } return ( 0 ); -} \ No newline at end of file +} diff --git a/utils/xbox/xbspinfo/xbspinfo.h b/utils/xbox/xbspinfo/xbspinfo.h index 45a31a33c..5c4adce7c 100644 --- a/utils/xbox/xbspinfo/xbspinfo.h +++ b/utils/xbox/xbspinfo/xbspinfo.h @@ -6,22 +6,25 @@ #pragma once +#ifdef _WIN32 #include -#include -#include #include #include +#include +#endif + +#include +#include #include #include #include #include -#include -#include "icommandline.h" +#include "tier0/icommandline.h" #include "tier1/strtools.h" #include "tier1/utlvector.h" #include "tier1/utlbuffer.h" #include "tier1/utlstring.h" +#include "tier1/byteswap.h" #include "datamap.h" -#include "byteswap.h" -#include "../../common/bsplib.h" +#include "bsplib.h" diff --git a/wscript b/wscript index 4690d56de..2e7da2071 100644 --- a/wscript +++ b/wscript @@ -1,5 +1,6 @@ #! /usr/bin/env python # encoding: utf-8 +# vim: noexpandtab # nillerusr from __future__ import print_function @@ -29,8 +30,18 @@ int main() { return (int)FcInit(); } Context.Context.line_just = 55 # should fit for everything on 80x26 projects={ - 'game': [ + 'base': [ 'appframework', + 'filesystem', + 'tier0', + 'tier1', + 'tier2', + 'tier3', + 'mathlib', + 'vstdlib', + 'vpklib', + ], + 'main': [ 'bitmap', 'choreoobjects', 'datacache', @@ -38,7 +49,6 @@ projects={ 'dmxloader', 'engine', 'engine/voice_codecs/minimp3', - 'filesystem', 'game/client', 'game/server', 'gameui', @@ -55,17 +65,12 @@ projects={ 'materialsystem/shaderapidx9', 'materialsystem/shaderlib', 'materialsystem/stdshaders', - 'mathlib', 'particles', 'scenefilecache', 'serverbrowser', 'soundemittersystem', 'studiorender', 'thirdparty/StubSteamAPI', - 'tier0', - 'tier1', - 'tier2', - 'tier3', 'vgui2/matsys_controls', 'vgui2/src', 'vgui2/vgui_controls', @@ -73,24 +78,13 @@ projects={ 'vguimatsurface', 'video', 'vphysics', - 'vpklib', - 'vstdlib', 'vtf', 'utils/vtex', 'unicode', 'video', ], 'tests': [ - 'appframework', - 'tier0', - 'tier1', - 'tier2', - 'tier3', 'unitlib', - 'mathlib', - 'vstdlib', - 'filesystem', - 'vpklib', 'unittests/tier0test', 'unittests/tier1test', 'unittests/tier2test', @@ -99,7 +93,6 @@ projects={ 'utils/unittest' ], 'dedicated': [ - 'appframework', 'bitmap', 'choreoobjects', 'datacache', @@ -114,23 +107,42 @@ projects={ 'ivp/ivp_compact_builder', 'ivp/ivp_physics', 'materialsystem', - 'mathlib', 'particles', 'scenefilecache', 'materialsystem/shaderapiempty', 'materialsystem/shaderlib', 'soundemittersystem', 'studiorender', - 'tier0', - 'tier1', - 'tier2', - 'tier3', 'vphysics', - 'vpklib', - 'vstdlib', 'vtf', 'thirdparty/StubSteamAPI' - ] + ], + 'utils': [ + 'bitmap', + 'vtf', + 'fgdlib', + 'raytrace', + 'vphysics', + 'ivp/havana', + 'ivp/havana/havok/hk_base', + 'ivp/havana/havok/hk_math', + 'ivp/ivp_compact_builder', + 'ivp/ivp_physics', + 'materialsystem', + 'materialsystem/shaderapiempty', + 'materialsystem/shaderlib', + 'utils/vtex', + 'utils/lzma', + 'utils/bsppack', + 'utils/vbspinfo', + 'utils/xbox/xbspinfo', + 'utils/vvis', + 'utils/vvis_launcher', + 'utils/vrad', + 'utils/vrad_launcher', + 'utils/vbsp', + 'utils/vpk', + ], } @Configure.conf @@ -156,38 +168,49 @@ def get_taskgen_count(self): return idx def define_platform(conf): - conf.env.DEDICATED = conf.options.DEDICATED - conf.env.TESTS = conf.options.TESTS - conf.env.TOGLES = conf.options.TOGLES - conf.env.GL = conf.options.GL and not conf.options.TESTS and not conf.options.DEDICATED - conf.env.OPUS = conf.options.OPUS + if conf.options.ALLOW64: + conf.define('PLATFORM_64BITS', 1) + conf.env.projects = ['base'] + conf.env.targets = [] if conf.options.DEDICATED: + conf.env.DEDICATED = True + conf.env.projects += ['dedicated'] conf.options.SDL = False conf.define('DEDICATED', 1) - if conf.options.TESTS: - conf.define('UNITTESTS', 1) - - if conf.env.GL: - conf.env.append_unique('DEFINES', [ - 'DX_TO_GL_ABSTRACTION', - 'GL_GLEXT_PROTOTYPES', - 'BINK_VIDEO' - ]) - - if conf.options.TOGLES: - conf.env.append_unique('DEFINES', ['TOGLES']) + if conf.options.LAUNCHER: + conf.env.projects += ['main'] + if conf.options.GL: + conf.env.GL = True + conf.env.targets += ['togl'] + conf.env.append_unique('DEFINES', [ + 'DX_TO_GL_ABSTRACTION', + 'GL_GLEXT_PROTOTYPES', + 'BINK_VIDEO' + ]) + elif conf.options.TOGLES: + conf.env.TOGLES = True + conf.env.targets += ['togles'] + conf.env.append_unique('DEFINES', ['TOGLES']) + + if conf.options.SDL: + conf.env.SDL = True + conf.define('USE_SDL', 1) if conf.options.TESTS: + conf.env.TESTS = True + conf.env.projects += ['tests'] conf.define('UNITTESTS', 1) - if conf.options.SDL and not conf.options.TESTS: - conf.env.SDL = 1 - conf.define('USE_SDL', 1) + if conf.options.UTILS: + conf.env.projects += ['utils'] - if conf.options.ALLOW64: - conf.define('PLATFORM_64BITS', 1) + if conf.env.DEST_OS == 'win32' and not conf.env.TESTS: + conf.env.targets += ['utils/bzip2'] + if conf.options.OPUS or conf.env.DEST_OS == 'android' and conf.env.LAUNCHER: + conf.env.OPUS = True + conf.env.targets += ['engine/voice_codecs/opus'] if conf.env.DEST_OS == 'linux': conf.define('_GLIBCXX_USE_CXX11_ABI',0) @@ -252,42 +275,55 @@ def options(opt): grp = opt.add_option_group('Common options') grp.add_option('-8', '--64bits', action = 'store_true', dest = 'ALLOW64', default = False, - help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %default]') - - grp.add_option('-d', '--dedicated', action = 'store_true', dest = 'DEDICATED', default = False, - help = 'build dedicated server [default: %default]') - - grp.add_option('--tests', action = 'store_true', dest = 'TESTS', default = False, - help = 'build unit tests [default: %default]') + help = 'allow targetting 64-bit engine [default: %default]') grp.add_option('-D', '--debug-engine', action = 'store_true', dest = 'DEBUG_ENGINE', default = False, help = 'build with -DDEBUG [default: %default]') - grp.add_option('--use-sdl', action = 'store', dest = 'SDL', type = 'int', default = sys.platform != 'win32', - help = 'build engine with SDL [default: %default]') - - grp.add_option('--use-togl', action = 'store', dest = 'GL', type = 'int', default = sys.platform != 'win32', - help = 'build engine with ToGL [default: %default]') + if sys.platform == 'win32': + grp.add_option('--use-sdl', action = 'store_true', dest = 'SDL', default = False, + help = 'build engine with SDL [default: %default]') + grp.add_option('--use-togl', action = 'store_true', dest = 'SDL', default = False, + help = 'build engine with ToGL [default: %default]') + else: + grp.add_option('--no-sdl', action = 'store_false', dest = 'SDL', default = True, + help = 'build engine with SDL [default: %default]') + grp.add_option('--no-togl', action = 'store_false', dest = 'GL', default = True, + help = 'build engine with ToGL [default: %default]') - grp.add_option('--build-games', action = 'store', dest = 'GAMES', type = 'string', default = 'hl2', - help = 'build games [default: %default]') + grp.add_option('--use-togles', action = 'store_true', dest = 'TOGLES', default = False, + help = 'build engine with ToGLES [default: %default]') grp.add_option('--use-ccache', action = 'store_true', dest = 'CCACHE', default = False, help = 'build using ccache [default: %default]') - grp.add_option('--disable-warns', action = 'store_true', dest = 'DISABLE_WARNS', default = False, - help = 'build using ccache [default: %default]') + grp.add_option('--no-warns', action = 'store_true', dest = 'DISABLE_WARNS', default = False, + help = 'build without warnings [default: %default]') - grp.add_option('--togles', action = 'store_true', dest = 'TOGLES', default = False, - help = 'build engine with ToGLES [default: %default]') + grp.add_option('--build-games', action = 'store', dest = 'GAMES', type = 'string', default = 'hl2', + help = 'build games [default: %default]') # TODO(nillerusr): add wscript for opus building - grp.add_option('--enable-opus', action = 'store_true', dest = 'OPUS', default = False, + grp.add_option('--use-opus', action = 'store_true', dest = 'OPUS', default = False, help = 'build engine with Opus voice codec [default: %default]') grp.add_option('--sanitize', action = 'store', dest = 'SANITIZE', default = '', help = 'build with sanitizers [default: %default]') + targ = opt.add_option_group('Targets options') + + targ.add_option('-d', '--use-dedicated', action = 'store_true', dest = 'DEDICATED', default = False, + help = 'build dedicated server [default: %default]') + + targ.add_option('-l', '--no-launcher', action = 'store_false', dest = 'LAUNCHER', default = True, + help = 'build launcher [default: %default]') + + targ.add_option('-t', '--use-tests', action = 'store_true', dest = 'TESTS', default = False, + help = 'build unit tests [default: %default]') + + targ.add_option('-u', '--use-utils', action = 'store_true', dest = 'UTILS', default = False, + help = 'build Valve utilities such as vbsp, vrad, vvis [default: %default]') + opt.load('compiler_optimizations subproject') opt.load('xcompile compiler_cxx compiler_c sdl2 clang_compilation_database strip_on_install_v2 waf_unit_test subproject') @@ -420,17 +456,6 @@ def configure(conf): define_platform(conf) conf.define('GIT_COMMIT_HASH', conf.env.GIT_VERSION) - if conf.env.TOGLES: - projects['game'] += ['togles'] - elif conf.env.GL: - projects['game'] += ['togl'] - - if conf.env.DEST_OS == 'win32': - projects['game'] += ['utils/bzip2'] - projects['dedicated'] += ['utils/bzip2'] - if conf.options.OPUS or conf.env.DEST_OS == 'android': - projects['game'] += ['engine/voice_codecs/opus'] - conf.env.BIT32_MANDATORY = not conf.options.ALLOW64 if conf.env.BIT32_MANDATORY: Logs.info('WARNING: will build engine for 32-bit target') @@ -583,12 +608,8 @@ def configure(conf): conf.env.CC.insert(0, 'ccache') conf.env.CXX.insert(0, 'ccache') - if conf.options.TESTS: - conf.add_subproject(projects['tests']) - elif conf.options.DEDICATED: - conf.add_subproject(projects['dedicated']) - else: - conf.add_subproject(projects['game']) + for proj in conf.env.projects: + conf.add_subproject(projects[proj]) def build(bld): os.environ["CCACHE_DIR"] = os.path.abspath('.ccache/'+bld.env.COMPILER_CC+'/'+bld.env.DEST_OS+'/'+bld.env.DEST_CPU) @@ -598,21 +619,8 @@ def build(bld): sdl_path = os.path.join('lib', bld.env.DEST_OS, bld.env.DEST_CPU, sdl_name) bld.install_files(bld.env.LIBDIR, [sdl_path]) - if bld.env.DEST_OS == 'win32': - projects['game'] += ['utils/bzip2'] - projects['dedicated'] += ['utils/bzip2'] - - if bld.env.OPUS or bld.env.DEST_OS == 'android': - projects['game'] += ['engine/voice_codecs/opus'] - - if bld.env.TESTS: - bld.add_subproject(projects['tests']) - elif bld.env.DEDICATED: - bld.add_subproject(projects['dedicated']) - else: - if bld.env.TOGLES: - projects['game'] += ['togles'] - elif bld.env.GL: - projects['game'] += ['togl'] + for proj in bld.env.projects: + bld.add_subproject(projects[proj]) + for targ in bld.env.targets: + bld.add_subproject(targ) - bld.add_subproject(projects['game']) From 569816e8ed6f46870fd83b24dab2b541ea9d7a35 Mon Sep 17 00:00:00 2001 From: Er2 Date: Tue, 9 May 2023 20:12:03 +0300 Subject: [PATCH 02/11] fix ci --- .github/workflows/build.yml | 10 +++++----- .github/workflows/tests.yml | 4 ++-- scripts/build-android-armv7a.sh | 2 +- scripts/build-macos-amd64.sh | 2 +- scripts/build-ubuntu-amd64.sh | 2 +- scripts/build-ubuntu-i386.sh | 2 +- scripts/tests-macos-amd64.sh | 2 +- scripts/tests-ubuntu-amd64.sh | 2 +- scripts/tests-ubuntu-i386.sh | 2 +- wscript | 19 +++++++++++-------- 10 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 39c8aadd9..222b081e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,7 +60,7 @@ jobs: - name: Build dedicated windows-i386 run: | git submodule init && git submodule update - ./waf.bat configure -T debug -d + ./waf.bat configure -T debug -dl ./waf.bat build build-dedicated-windows-amd64: @@ -71,7 +71,7 @@ jobs: - name: Build dedicated windows-amd64 run: | git submodule init && git submodule update - ./waf.bat configure -T debug -d -8 + ./waf.bat configure -T debug -dl -8 ./waf.bat build build-dedicated-linux-i386: @@ -81,7 +81,7 @@ jobs: - uses: actions/checkout@v2 - name: Build dedicated linux-i386 run: | - scripts/build-ubuntu-i386.sh -d + scripts/build-ubuntu-i386.sh -dl build-dedicated-linux-amd64: runs-on: ubuntu-20.04 @@ -90,7 +90,7 @@ jobs: - uses: actions/checkout@v2 - name: Build dedicated linux-amd64 run: | - scripts/build-ubuntu-amd64.sh -d + scripts/build-ubuntu-amd64.sh -dl build-macos-amd64: runs-on: macos-latest @@ -108,4 +108,4 @@ jobs: - uses: actions/checkout@v2 - name: Build dedicated macos-amd64 run: | - scripts/build-macos-amd64.sh -d + scripts/build-macos-amd64.sh -dl diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d8adc5ab0..9578d1cc7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,7 +38,7 @@ jobs: - name: Run tests windows-i386 run: | git submodule init && git submodule update - ./waf.bat configure -T release --tests --prefix=out/ + ./waf.bat configure -T release -lt --prefix=out/ ./waf.bat install cd out $env:Path = "bin"; @@ -52,7 +52,7 @@ jobs: - name: Run tests windows-amd64 run: | git submodule init && git submodule update - ./waf.bat configure -T release --tests --prefix=out/ -8 + ./waf.bat configure -T release -lt --prefix=out/ -8 ./waf.bat install cd out $env:Path = "bin"; diff --git a/scripts/build-android-armv7a.sh b/scripts/build-android-armv7a.sh index 4c7201ff9..f3e16947d 100755 --- a/scripts/build-android-armv7a.sh +++ b/scripts/build-android-armv7a.sh @@ -5,5 +5,5 @@ wget https://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip unzip android-ndk-r10e-linux-x86_64.zip export ANDROID_NDK_HOME=$PWD/android-ndk-r10e/ export NDK_HOME=$PWD/android-ndk-r10e/ -./waf configure -T debug --android=armeabi-v7a-hard,4.9,21 --togles --disable-warns && +./waf configure -T debug --android=armeabi-v7a-hard,4.9,21 --use-togles --no-warns && ./waf build diff --git a/scripts/build-macos-amd64.sh b/scripts/build-macos-amd64.sh index de0e8cfd1..919c66df7 100755 --- a/scripts/build-macos-amd64.sh +++ b/scripts/build-macos-amd64.sh @@ -4,5 +4,5 @@ git submodule init && git submodule update brew install sdl2 -./waf configure -T debug --64bits --disable-warns $* && +./waf configure -T debug --64bits --no-warns $* && ./waf build diff --git a/scripts/build-ubuntu-amd64.sh b/scripts/build-ubuntu-amd64.sh index e598240dc..ac06c47ae 100755 --- a/scripts/build-ubuntu-amd64.sh +++ b/scripts/build-ubuntu-amd64.sh @@ -4,5 +4,5 @@ git submodule init && git submodule update sudo apt-get update sudo apt-get install -f -y libopenal-dev g++-multilib gcc-multilib libpng-dev libjpeg-dev libfreetype6-dev libfontconfig1-dev libcurl4-gnutls-dev libsdl2-dev zlib1g-dev libbz2-dev libedit-dev -./waf configure -T debug --64bits --disable-warns $* && +./waf configure -T debug --64bits --no-warns $* && ./waf build diff --git a/scripts/build-ubuntu-i386.sh b/scripts/build-ubuntu-i386.sh index c9609cae7..10115469e 100755 --- a/scripts/build-ubuntu-i386.sh +++ b/scripts/build-ubuntu-i386.sh @@ -6,5 +6,5 @@ sudo apt-get update sudo apt-get install -y aptitude sudo aptitude install -y libopenal-dev:i386 g++-multilib gcc-multilib libpng-dev:i386 libjpeg-dev:i386 libfreetype6-dev:i386 libfontconfig1-dev:i386 libcurl4-gnutls-dev:i386 libsdl2-dev:i386 zlib1g-dev:i386 libbz2-dev:i386 libedit-dev:i386 -PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T debug --disable-warns $* && +PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T debug --no-warns $* && ./waf build diff --git a/scripts/tests-macos-amd64.sh b/scripts/tests-macos-amd64.sh index ff4e46b27..ee1d0cfa3 100755 --- a/scripts/tests-macos-amd64.sh +++ b/scripts/tests-macos-amd64.sh @@ -1,7 +1,7 @@ #!/bin/sh git submodule init && git submodule update -./waf configure -T release --sanitize=address,undefined --disable-warns --tests -8 --prefix=out/ $* && +./waf configure -T release --sanitize=address,undefined --no-warns -lt -8 --prefix=out/ $* && ./waf install && cd out && DYLD_LIBRARY_PATH=bin/ ./unittest || exit 1 diff --git a/scripts/tests-ubuntu-amd64.sh b/scripts/tests-ubuntu-amd64.sh index 1cef058e9..6b1aad9e1 100755 --- a/scripts/tests-ubuntu-amd64.sh +++ b/scripts/tests-ubuntu-amd64.sh @@ -4,7 +4,7 @@ git submodule init && git submodule update sudo apt-get update sudo apt-get install -y libbz2-dev -./waf configure -T release --sanitize=address,undefined --disable-warns --tests --prefix=out/ --64bits $* && +./waf configure -T release --sanitize=address,undefined --no-warns -lt --prefix=out/ --64bits $* && ./waf install && cd out && LD_LIBRARY_PATH=bin/ ./unittest diff --git a/scripts/tests-ubuntu-i386.sh b/scripts/tests-ubuntu-i386.sh index f14fc3616..178ed67d5 100755 --- a/scripts/tests-ubuntu-i386.sh +++ b/scripts/tests-ubuntu-i386.sh @@ -5,7 +5,7 @@ sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install -y g++-multilib gcc-multilib libbz2-dev:i386 -PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T release --sanitize=address,undefined --disable-warns --tests --prefix=out/ $* && +PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T release --sanitize=address,undefined --no-warns -lt --prefix=out/ $* && ./waf install && cd out && LD_LIBRARY_PATH=bin/ ./unittest diff --git a/wscript b/wscript index 2e7da2071..2ec9ec506 100644 --- a/wscript +++ b/wscript @@ -181,18 +181,19 @@ def define_platform(conf): if conf.options.LAUNCHER: conf.env.projects += ['main'] - if conf.options.GL: - conf.env.GL = True - conf.env.targets += ['togl'] + conf.env.GL = conf.options.GL or conf.options.TOGLES + if conf.options.TOGLES: + conf.env.TOGLES = True + conf.env.targets += ['togles'] + conf.env.append_unique('DEFINES', ['TOGLES']) + if conf.env.GL: + if not conf.env.TOGLES: + conf.env.targets += ['togl'] conf.env.append_unique('DEFINES', [ 'DX_TO_GL_ABSTRACTION', 'GL_GLEXT_PROTOTYPES', 'BINK_VIDEO' ]) - elif conf.options.TOGLES: - conf.env.TOGLES = True - conf.env.targets += ['togles'] - conf.env.append_unique('DEFINES', ['TOGLES']) if conf.options.SDL: conf.env.SDL = True @@ -283,7 +284,7 @@ def options(opt): if sys.platform == 'win32': grp.add_option('--use-sdl', action = 'store_true', dest = 'SDL', default = False, help = 'build engine with SDL [default: %default]') - grp.add_option('--use-togl', action = 'store_true', dest = 'SDL', default = False, + grp.add_option('--use-togl', action = 'store_true', dest = 'GL', default = False, help = 'build engine with ToGL [default: %default]') else: grp.add_option('--no-sdl', action = 'store_false', dest = 'SDL', default = True, @@ -610,6 +611,8 @@ def configure(conf): for proj in conf.env.projects: conf.add_subproject(projects[proj]) + for targ in conf.env.targets: + conf.add_subproject(targ) def build(bld): os.environ["CCACHE_DIR"] = os.path.abspath('.ccache/'+bld.env.COMPILER_CC+'/'+bld.env.DEST_OS+'/'+bld.env.DEST_CPU) From 88f4cfa22e7f894c6006340dcb6ab54c2e2b9b46 Mon Sep 17 00:00:00 2001 From: Er2 Date: Wed, 10 May 2023 11:26:09 +0300 Subject: [PATCH 03/11] fix header includes --- utils/common/mstristrip.cpp | 2 ++ utils/vvis_launcher/vvis_launcher.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/utils/common/mstristrip.cpp b/utils/common/mstristrip.cpp index ad6ebdc8e..a9be9dd8d 100644 --- a/utils/common/mstristrip.cpp +++ b/utils/common/mstristrip.cpp @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include #include diff --git a/utils/vvis_launcher/vvis_launcher.cpp b/utils/vvis_launcher/vvis_launcher.cpp index ea4ea68f1..ceec54c49 100644 --- a/utils/vvis_launcher/vvis_launcher.cpp +++ b/utils/vvis_launcher/vvis_launcher.cpp @@ -12,6 +12,7 @@ #include "stdafx.h" #include #else +#include #include #endif #include "tier1/interface.h" From 403b060ef9a5db2b0082ed9075f4f17764e29554 Mon Sep 17 00:00:00 2001 From: Er2 Date: Thu, 11 May 2023 21:08:32 +0300 Subject: [PATCH 04/11] WIP studiomdl port --- movieobjects/dmeanimationset.cpp | 4 +- movieobjects/dmeclip.cpp | 6 +- movieobjects/dmefaceset.cpp | 4 +- movieobjects/dmekeyboardinput.cpp | 4 +- movieobjects/dmelog.cpp | 8 + movieobjects/dmemouseinput.cpp | 4 +- movieobjects/dmeparticlesystemdefinition.cpp | 6 +- movieobjects/wscript | 95 +++++ public/appframework/AppFramework.h | 12 +- public/movieobjects/dmeanimationset.h | 1 + public/movieobjects/dmeclip.h | 1 + public/movieobjects/dmelog.h | 8 +- public/movieobjects/dmetimeselection.h | 3 +- public/movieobjects/dmetrackgroup.h | 3 +- utils/studiomdl/bmpread.cpp | 98 ------ utils/studiomdl/dmxsupport.cpp | 3 +- utils/studiomdl/hardwarematrixstate.cpp | 9 +- utils/studiomdl/hardwarevertexcache.cpp | 2 +- utils/studiomdl/optimize.cpp | 13 +- utils/studiomdl/perfstats.cpp | 4 +- utils/studiomdl/studiomdl.cpp | 32 +- utils/studiomdl/studiomdl.h | 4 +- utils/studiomdl/tristrip.cpp | 350 ------------------- utils/studiomdl/write.cpp | 54 +-- utils/studiomdl/wscript | 93 +++++ waf | 2 +- wscript | 17 +- 27 files changed, 302 insertions(+), 538 deletions(-) create mode 100755 movieobjects/wscript delete mode 100644 utils/studiomdl/bmpread.cpp delete mode 100644 utils/studiomdl/tristrip.cpp create mode 100644 utils/studiomdl/wscript diff --git a/movieobjects/dmeanimationset.cpp b/movieobjects/dmeanimationset.cpp index 926de4514..854875089 100644 --- a/movieobjects/dmeanimationset.cpp +++ b/movieobjects/dmeanimationset.cpp @@ -10,7 +10,7 @@ #include "datamodel/dmelementfactoryhelper.h" #include "datamodel/dmehandle.h" #include "phonemeconverter.h" -#include "tier1/utlstringmap.h" +#include "tier1/UtlStringMap.h" #include "tier2/tier2.h" #include "filesystem.h" #include "studio.h" @@ -602,7 +602,7 @@ bool CDmePresetGroup::ExportToTXT( const char *pFileName, CDmeAnimationSet *pAni #ifdef ALIGN4 #undef ALIGN4 #endif // #ifdef ALIGN4 -#define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3) +#define ALIGN4( a ) a = (byte *)((size_t)((byte *)a + 3) & ~ 3) //----------------------------------------------------------------------------- diff --git a/movieobjects/dmeclip.cpp b/movieobjects/dmeclip.cpp index b97c5cbf5..2ce866650 100644 --- a/movieobjects/dmeclip.cpp +++ b/movieobjects/dmeclip.cpp @@ -1025,10 +1025,12 @@ void CDmeFilmClip::OnElementUnserialized( ) // Backward compat conversion // If this is an older file with an overlay attribute, strip it out into materialoverlay CDmAttribute *pOverlayAttribute = GetAttribute( "overlay" ); + CDmAttribute *pOverlayAlphaAttribute; + const char *pName; if ( !pOverlayAttribute ) goto cleanUp; - const char *pName = pOverlayAttribute->GetValueString(); + pName = pOverlayAttribute->GetValueString(); if ( !pName || !pName[0] ) goto cleanUp; @@ -1041,7 +1043,7 @@ void CDmeFilmClip::OnElementUnserialized( ) m_MaterialOverlayEffect->SetOverlayEffect( pName ); // If this is an older file with an overlayalpha attribute, strip it out into materialoverlay - CDmAttribute *pOverlayAlphaAttribute = GetAttribute( "overlayalpha" ); + pOverlayAlphaAttribute = GetAttribute( "overlayalpha" ); if ( pOverlayAlphaAttribute ) { float alpha = pOverlayAlphaAttribute->GetValue(); diff --git a/movieobjects/dmefaceset.cpp b/movieobjects/dmefaceset.cpp index 5fecdfd77..a8aba03cf 100644 --- a/movieobjects/dmefaceset.cpp +++ b/movieobjects/dmefaceset.cpp @@ -6,7 +6,7 @@ #include "movieobjects/dmefaceset.h" #include "movieobjects/dmematerial.h" #include "tier0/dbg.h" -#include "UtlBuffer.h" +#include "utlbuffer.h" #include "datamodel/dmelementfactoryhelper.h" // memdbgon must be the last include file in a .cpp file!!! @@ -184,4 +184,4 @@ int CDmeFaceSet::GetFaceCount() const } return nFaceCount; -} \ No newline at end of file +} diff --git a/movieobjects/dmekeyboardinput.cpp b/movieobjects/dmekeyboardinput.cpp index 0fcea7162..36923f461 100644 --- a/movieobjects/dmekeyboardinput.cpp +++ b/movieobjects/dmekeyboardinput.cpp @@ -8,8 +8,8 @@ #include "movieobjects_interfaces.h" #include "datamodel/dmelementfactoryhelper.h" -#include "vgui/iinput.h" -#include "vgui/keycode.h" +#include "vgui/IInput.h" +#include "vgui/KeyCode.h" #include "tier3/tier3.h" #include "tier0/dbg.h" diff --git a/movieobjects/dmelog.cpp b/movieobjects/dmelog.cpp index 6eb5e5130..1ee66b7e1 100644 --- a/movieobjects/dmelog.cpp +++ b/movieobjects/dmelog.cpp @@ -759,6 +759,7 @@ Quaternion Add( const Quaternion& v1, const Quaternion& v2 ) IMPLEMENT_ABSTRACT_ELEMENT( DmeLogLayer, CDmeLogLayer ); +/* IMPLEMENT_ELEMENT_FACTORY( DmeIntLogLayer, CDmeIntLogLayer ); IMPLEMENT_ELEMENT_FACTORY( DmeFloatLogLayer, CDmeFloatLogLayer ); IMPLEMENT_ELEMENT_FACTORY( DmeBoolLogLayer, CDmeBoolLogLayer ); @@ -770,6 +771,7 @@ IMPLEMENT_ELEMENT_FACTORY( DmeQAngleLogLayer, CDmeQAngleLogLayer ); IMPLEMENT_ELEMENT_FACTORY( DmeQuaternionLogLayer, CDmeQuaternionLogLayer ); IMPLEMENT_ELEMENT_FACTORY( DmeVMatrixLogLayer, CDmeVMatrixLogLayer ); IMPLEMENT_ELEMENT_FACTORY( DmeStringLogLayer, CDmeStringLogLayer ); +*/ //----------------------------------------------------------------------------- // explicit template instantiation @@ -789,6 +791,7 @@ template class CDmeTypedLogLayer; IMPLEMENT_ABSTRACT_ELEMENT( DmeCurveInfo, CDmeCurveInfo ); +/* IMPLEMENT_ELEMENT_FACTORY( DmeIntCurveInfo, CDmeIntCurveInfo ); IMPLEMENT_ELEMENT_FACTORY( DmeFloatCurveInfo, CDmeFloatCurveInfo ); IMPLEMENT_ELEMENT_FACTORY( DmeBoolCurveInfo, CDmeBoolCurveInfo ); @@ -800,6 +803,7 @@ IMPLEMENT_ELEMENT_FACTORY( DmeQAngleCurveInfo, CDmeQAngleCurveInfo ); IMPLEMENT_ELEMENT_FACTORY( DmeQuaternionCurveInfo, CDmeQuaternionCurveInfo ); IMPLEMENT_ELEMENT_FACTORY( DmeVMatrixCurveInfo, CDmeVMatrixCurveInfo ); IMPLEMENT_ELEMENT_FACTORY( DmeStringCurveInfo, CDmeStringCurveInfo ); +*/ //----------------------------------------------------------------------------- // explicit template instantiation @@ -822,6 +826,7 @@ template class CDmeTypedCurveInfo; //----------------------------------------------------------------------------- IMPLEMENT_ABSTRACT_ELEMENT( DmeLog, CDmeLog ); +/* IMPLEMENT_ELEMENT_FACTORY( DmeIntLog, CDmeIntLog ); IMPLEMENT_ELEMENT_FACTORY( DmeFloatLog, CDmeFloatLog ); IMPLEMENT_ELEMENT_FACTORY( DmeBoolLog, CDmeBoolLog ); @@ -833,6 +838,7 @@ IMPLEMENT_ELEMENT_FACTORY( DmeQAngleLog, CDmeQAngleLog ); IMPLEMENT_ELEMENT_FACTORY( DmeQuaternionLog, CDmeQuaternionLog ); IMPLEMENT_ELEMENT_FACTORY( DmeVMatrixLog, CDmeVMatrixLog ); IMPLEMENT_ELEMENT_FACTORY( DmeStringLog, CDmeStringLog ); +*/ //----------------------------------------------------------------------------- @@ -854,6 +860,7 @@ template class CDmeTypedLog; //----------------------------------------------------------------------------- // instantiate and initialize static vars //----------------------------------------------------------------------------- +/* float CDmeIntLog::s_defaultThreshold = 0.0f; float CDmeFloatLog::s_defaultThreshold = 0.0f; float CDmeBoolLog::s_defaultThreshold = 0.0f; @@ -865,6 +872,7 @@ float CDmeQAngleLog::s_defaultThreshold = 0.0f; float CDmeQuaternionLog::s_defaultThreshold = 0.0f; float CDmeVMatrixLog::s_defaultThreshold = 0.0f; float CDmeStringLog::s_defaultThreshold = 0.0f; +*/ void CDmeLogLayer::OnConstruction() diff --git a/movieobjects/dmemouseinput.cpp b/movieobjects/dmemouseinput.cpp index 6215d2a22..8cb570678 100644 --- a/movieobjects/dmemouseinput.cpp +++ b/movieobjects/dmemouseinput.cpp @@ -8,8 +8,8 @@ #include "movieobjects_interfaces.h" #include "datamodel/dmelementfactoryhelper.h" -#include "vgui/iinput.h" -#include "vgui/ipanel.h" +#include "vgui/IInput.h" +#include "vgui/IPanel.h" #include "tier3/tier3.h" #include "tier0/dbg.h" diff --git a/movieobjects/dmeparticlesystemdefinition.cpp b/movieobjects/dmeparticlesystemdefinition.cpp index d279d4482..426d48f9a 100644 --- a/movieobjects/dmeparticlesystemdefinition.cpp +++ b/movieobjects/dmeparticlesystemdefinition.cpp @@ -12,9 +12,9 @@ #include "tier1/utlbuffer.h" #include "tier1/convar.h" #include "particles/particles.h" -#include "dme_controls/attributeintchoicepanel.h" -#include "dme_controls/attributeboolchoicepanel.h" -#include "dme_controls/attributestringchoicepanel.h" +#include "dme_controls/AttributeIntChoicePanel.h" +#include "dme_controls/AttributeBoolChoicePanel.h" +#include "dme_controls/AttributeStringChoicePanel.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/movieobjects/wscript b/movieobjects/wscript new file mode 100755 index 000000000..427ced6cd --- /dev/null +++ b/movieobjects/wscript @@ -0,0 +1,95 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'movieobjects' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + source = [ + 'dmeanimationlist.cpp', + 'dmeanimationset.cpp', + 'dmeattachment.cpp', + 'dmebalancetostereocalculatoroperator.cpp', + 'dmebookmark.cpp', + 'dmecamera.cpp', + 'dmechannel.cpp', + 'dmeclip.cpp', + 'dmecombinationoperator.cpp', + 'dmedag.cpp', + 'dmedccmakefile.cpp', + 'dmeeditortypedictionary.cpp', + 'dmeexpressionoperator.cpp', + 'dmefaceset.cpp', + 'dmegamemodel.cpp', + 'dmegamemodelinput.cpp', + 'dmeinput.cpp', + 'dmejoint.cpp', + 'dmekeyboardinput.cpp', + 'dmelight.cpp', +# 'dmelog.cpp', + 'dmemakefile.cpp', + 'dmemakefileutils.cpp', + 'dmematerial.cpp', + 'dmematerialoverlayfxclip.cpp', + 'dmemdl.cpp', + 'dmemdlmakefile.cpp', +# 'dmemesh.cpp', + 'dmemodel.cpp', + 'dmemorphoperator.cpp', + 'dmemouseinput.cpp', + 'dmeoperator.cpp', + 'dmepackoperators.cpp', + 'dmeparticlesystemdefinition.cpp', + 'dmephonememapping.cpp', + 'dmeselection.cpp', + 'dmeshape.cpp', + 'dmesound.cpp', + 'dmetimeframe.cpp', + 'dmetimeselection.cpp', + 'dmetrack.cpp', + 'dmetrackgroup.cpp', + 'dmetransform.cpp', + 'dmetransforminput.cpp', + 'dmetransformlist.cpp', + 'dmetransformoperator.cpp', + 'dmeunpackoperators.cpp', + 'dmevertexdata.cpp', + 'dmobjserializer.cpp', + 'movieobjects_interfaces.cpp', + '../public/phonemeconverter.cpp', + ] + + includes = [ + '.', + '../public', + '../public/tier0', + '../public/tier1', + ] + + defines = [] + + libs = [] + + bld.stlib( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/public/appframework/AppFramework.h b/public/appframework/AppFramework.h index 4df8a2b85..5d175d195 100644 --- a/public/appframework/AppFramework.h +++ b/public/appframework/AppFramework.h @@ -54,19 +54,11 @@ void AppShutdown( CAppSystemGroup *pAppSystemGroup ); { \ return AppMain( hInstance, hPrevInstance, lpCmdLine, nCmdShow, &_globalVarName ); \ } -#elif defined( OSX ) +#elif defined( POSIX ) #define DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ int main( int argc, char **argv ) \ { \ - extern int ValveCocoaMain( int argc, char **argv, CAppSystemGroup *pAppSystemGroup ); \ - return ValveCocoaMain( argc, argv, &_globalVarName ); \ - } -#elif defined( LINUX ) || defined(PLATFORM_BSD) -#define DEFINE_WINDOWED_APPLICATION_OBJECT_GLOBALVAR( _globalVarName ) \ - int main( int argc, char **argv ) \ - { \ - extern int ValveLinuxWindowedMain( int argc, char **argv, CAppSystemGroup *pAppSystemGroup ); \ - return ValveLinuxWindowedMain( argc, argv, &_globalVarName ); \ + return AppMain( argc, argv, &_globalVarName ); \ } #else #error diff --git a/public/movieobjects/dmeanimationset.h b/public/movieobjects/dmeanimationset.h index ad7678b14..30969a8b8 100644 --- a/public/movieobjects/dmeanimationset.h +++ b/public/movieobjects/dmeanimationset.h @@ -13,6 +13,7 @@ #include "datamodel/dmelement.h" #include "datamodel/dmattribute.h" #include "datamodel/dmattributevar.h" +#include "movieobjects/dmeclip.h" #include "movieobjects/dmephonememapping.h" #include "movieobjects/timeutils.h" #include "movieobjects/proceduralpresets.h" diff --git a/public/movieobjects/dmeclip.h b/public/movieobjects/dmeclip.h index 51cd33799..e6a71cb69 100644 --- a/public/movieobjects/dmeclip.h +++ b/public/movieobjects/dmeclip.h @@ -11,6 +11,7 @@ #endif #include "datamodel/dmelement.h" +#include "datamodel/dmelementfactoryhelper.h" #include "datamodel/dmattribute.h" #include "datamodel/dmattributevar.h" #include "datamodel/dmehandle.h" diff --git a/public/movieobjects/dmelog.h b/public/movieobjects/dmelog.h index a0e85b090..e5f35b3ca 100644 --- a/public/movieobjects/dmelog.h +++ b/public/movieobjects/dmelog.h @@ -404,7 +404,7 @@ abstract_class CDmeLog : public CDmElement template< class T > class CDmeTypedCurveInfo : public CDmeCurveInfo { - DEFINE_ELEMENT( CDmeTypedCurveInfo, CDmeCurveInfo ); +// DEFINE_ELEMENT( CDmeTypedCurveInfo, CDmeCurveInfo ); public: // For "faceposer" style left/right edges, this controls whether interpolators try to mimic faceposer left/right edge behavior @@ -447,7 +447,7 @@ template< class T > class CDmeTypedLog; template< class T > class CDmeTypedLogLayer : public CDmeLogLayer { - DEFINE_ELEMENT( CDmeTypedLogLayer, CDmeLogLayer ); +// DEFINE_ELEMENT( CDmeTypedLogLayer, CDmeLogLayer ); public: virtual void CopyLayer( const CDmeLogLayer *src ); @@ -529,7 +529,7 @@ class CDmeTypedLogLayer : public CDmeLogLayer template< class T > class CDmeTypedLog : public CDmeLog { - DEFINE_ELEMENT( CDmeTypedLog, CDmeLog ); +// DEFINE_ELEMENT( CDmeTypedLog, CDmeLog ); public: @@ -836,7 +836,7 @@ template<> void CDmeTypedLogLayer< Vector >::GetValueUsingCurveInfoSkippingKey( template<> void CDmeTypedLogLayer< Quaternion >::GetValueUsingCurveInfo( DmeTime_t time, Quaternion& out ) const; template<> void CDmeTypedLogLayer< Quaternion >::GetValueUsingCurveInfoSkippingKey( int nKeyToSkip, Quaternion& out ) const; -template void CDmeTypedLogLayer< T >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< T > *output ); +//template void CDmeTypedLogLayer< T >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< T > *output ); template<> void CDmeTypedLogLayer< bool >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< bool > *output ); template<> void CDmeTypedLogLayer< int >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< int > *output ); template<> void CDmeTypedLogLayer< Color >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< Color > *output ); diff --git a/public/movieobjects/dmetimeselection.h b/public/movieobjects/dmetimeselection.h index 5eb1d9387..e533863b3 100644 --- a/public/movieobjects/dmetimeselection.h +++ b/public/movieobjects/dmetimeselection.h @@ -11,11 +11,10 @@ #endif #include "datamodel/dmelement.h" +#include "dme_controls/RecordingState.h" #include "movieobjects/timeutils.h" #include "movieobjects/dmetimeselectiontimes.h" -enum RecordingState_t; - class CDmeTimeSelection : public CDmElement { DEFINE_ELEMENT( CDmeTimeSelection, CDmElement ); diff --git a/public/movieobjects/dmetrackgroup.h b/public/movieobjects/dmetrackgroup.h index 8e029c33d..167a73e3d 100644 --- a/public/movieobjects/dmetrackgroup.h +++ b/public/movieobjects/dmetrackgroup.h @@ -15,6 +15,7 @@ #include "datamodel/dmattribute.h" #include "datamodel/dmattributevar.h" #include "datamodel/dmehandle.h" +#include "movieobjects/dmeclip.h" #include "movieobjects/timeutils.h" @@ -24,8 +25,6 @@ class CDmeClip; class CDmeFilmClip; class CDmeTrack; -enum DmeClipType_t; -enum DmeClipSkipFlag_t; //----------------------------------------------------------------------------- diff --git a/utils/studiomdl/bmpread.cpp b/utils/studiomdl/bmpread.cpp deleted file mode 100644 index 24663fe02..000000000 --- a/utils/studiomdl/bmpread.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// - - -#include -#include - - -int -ReadBmpFile( - char* szFile, - unsigned char** ppbPalette, - unsigned char** ppbBits, - int *pwidth, - int *pheight) - { - int rc = 0; - FILE *pfile = NULL; - BITMAPFILEHEADER bmfh; - BITMAPINFOHEADER bmih; - RGBQUAD rgrgbPalette[256]; - ULONG cbPalBytes; - ULONG cbBmpBits; - BYTE* pbBmpBits; - - // Bogus parameter check - if (!(ppbPalette != NULL && ppbBits != NULL)) - { rc = -1000; goto GetOut; } - - // File exists? - if ((pfile = fopen(szFile, "rb")) == NULL) - { rc = -1; goto GetOut; } - - // Read file header - if (fread(&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1) - { rc = -2; goto GetOut; } - - // Bogus file header check - if (!(bmfh.bfReserved1 == 0 && bmfh.bfReserved2 == 0)) - { rc = -2000; goto GetOut; } - - // Read info header - if (fread(&bmih, sizeof bmih, 1/*count*/, pfile) != 1) - { rc = -3; goto GetOut; } - - // Bogus info header check - if (!(bmih.biSize == sizeof bmih && bmih.biPlanes == 1)) - { rc = -3000; goto GetOut; } - - // Bogus bit depth? Only 8-bit supported. - if (bmih.biBitCount != 8) - { rc = -4; goto GetOut; } - - // Bogus compression? Only non-compressed supported. - if (bmih.biCompression != BI_RGB) - { rc = -5; goto GetOut; } - - // Figure out how many entires are actually in the table - if (bmih.biClrUsed == 0) - { - cbPalBytes = (1 << bmih.biBitCount) * sizeof( RGBQUAD ); - } - else - { - cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD ); - } - - // Read palette (256 entries) - if (fread(rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1) - { rc = -6; goto GetOut; } - - // Read bitmap bits (remainder of file) - cbBmpBits = bmfh.bfSize - ftell(pfile); - pbBmpBits = (BYTE *)malloc(cbBmpBits); - if (fread(pbBmpBits, cbBmpBits, 1/*count*/, pfile) != 1) - { rc = -7; goto GetOut; } - - // Set output parameters - *ppbPalette = (BYTE *)malloc(sizeof rgrgbPalette); - memcpy(*ppbPalette, rgrgbPalette, cbPalBytes); - *ppbBits = pbBmpBits; - - - *pwidth = bmih.biWidth; - *pheight = bmih.biHeight; - - printf("w %d h %d s %d\n",bmih.biWidth, bmih.biHeight, cbBmpBits ); - -GetOut: - if (pfile) fclose(pfile); - return rc; - } - diff --git a/utils/studiomdl/dmxsupport.cpp b/utils/studiomdl/dmxsupport.cpp index 2e83255ed..dcf4bf8a9 100644 --- a/utils/studiomdl/dmxsupport.cpp +++ b/utils/studiomdl/dmxsupport.cpp @@ -1142,6 +1142,7 @@ int Load_DMX( s_source_t *pSource ) CDmeDag *pSkeleton = pRoot->GetValueElement< CDmeDag >( "skeleton" ); CDmeModel *pModel = pRoot->GetValueElement< CDmeModel >( "model" ); CDmeCombinationOperator *pCombinationOperator = pRoot->GetValueElement< CDmeCombinationOperator >( "combinationOperator" ); + CDmeAnimationList *pAnimationList; if ( !pSkeleton ) goto dmxError; @@ -1175,7 +1176,7 @@ int Load_DMX( s_source_t *pSource ) AddCombination( pSource, pCombinationOperator ); } - CDmeAnimationList *pAnimationList = pRoot->GetValueElement< CDmeAnimationList >( "animationList" ); + pAnimationList = pRoot->GetValueElement< CDmeAnimationList >( "animationList" ); if ( pAnimationList ) { LoadAnimations( pSource, pAnimationList, g_currentscale, boneMap ); diff --git a/utils/studiomdl/hardwarematrixstate.cpp b/utils/studiomdl/hardwarematrixstate.cpp index b49430c1b..c524a2d11 100644 --- a/utils/studiomdl/hardwarematrixstate.cpp +++ b/utils/studiomdl/hardwarematrixstate.cpp @@ -5,8 +5,7 @@ // $NoKeywords: $ //=============================================================================// -#include -#include "HardwareMatrixState.h" +#include "hardwarematrixstate.h" #include #include #include @@ -197,7 +196,8 @@ void CHardwareMatrixState::DumpState( void ) return; //#endif - OutputDebugString( "DumpState\n:" ); +#if 0 + Msg( "DumpState:\n" ); for( i = 0; i < m_NumMatrices; i++ ) { if( m_matrixState[i].allocated ) @@ -207,9 +207,10 @@ void CHardwareMatrixState::DumpState( void ) m_matrixState[i].allocated ? "true " : "false", m_matrixState[i].lastUsageID, m_matrixState[i].globalMatrixID ); - OutputDebugString( buf ); + Msg( buf ); } } +#endif } int CHardwareMatrixState::FindHardwareMatrix( int globalMatrixID ) diff --git a/utils/studiomdl/hardwarevertexcache.cpp b/utils/studiomdl/hardwarevertexcache.cpp index 1c5a41c34..7c1d1db35 100644 --- a/utils/studiomdl/hardwarevertexcache.cpp +++ b/utils/studiomdl/hardwarevertexcache.cpp @@ -7,7 +7,7 @@ #include #include -#include "HardwareVertexCache.h" +#include "hardwarevertexcache.h" CHardwareVertexCache::CHardwareVertexCache() { diff --git a/utils/studiomdl/optimize.cpp b/utils/studiomdl/optimize.cpp index 88f6d0f7d..eea9d239c 100644 --- a/utils/studiomdl/optimize.cpp +++ b/utils/studiomdl/optimize.cpp @@ -17,7 +17,7 @@ //#define IGNORE_BONES -#define NVTRISTRIP +//#define NVTRISTRIP #define EMIT_TRILISTS @@ -28,12 +28,11 @@ #include "cmdlib.h" #include "studio.h" #include "studiomdl.h" -#include "HardwareMatrixState.h" -#include "HardwareVertexCache.h" +#include "hardwarematrixstate.h" +#include "hardwarevertexcache.h" #include "optimize.h" -#include -#include -#include "FileBuffer.h" +//#include "nvtristrip.h" +#include "filebuffer.h" #include "tier1/utlvector.h" #include "materialsystem/imaterial.h" #include "tier1/utllinkedlist.h" @@ -352,7 +351,7 @@ class COptimizedModel // Memory optimize the strip data void PostProcessStripGroup( mstudiomodel_t *pStudioModel, mstudiomesh_t *pStudioMesh, StripGroup_t *pStripGroup ); - void COptimizedModel::ZeroNumBones( void ); + void ZeroNumBones( void ); // // Methods associated with writing VTX files diff --git a/utils/studiomdl/perfstats.cpp b/utils/studiomdl/perfstats.cpp index 815ff9803..c2ea6daf2 100644 --- a/utils/studiomdl/perfstats.cpp +++ b/utils/studiomdl/perfstats.cpp @@ -202,8 +202,8 @@ void SpewPerfStats( studiohdr_t *pStudioHdr, const char *pFilename, unsigned int } // studio render will request these through cache interface - pStudioHdr->pVertexBase = (void *)pVvdHdr; - pStudioHdr->pIndexBase = (void *)pVtxHdr; + pStudioHdr->SetVertexBase((void *)pVvdHdr); + pStudioHdr->SetIndexBase((void *)pVtxHdr); g_pStudioRender->LoadModel( pStudioHdr, pVtxHdr, &studioHWData ); diff --git a/utils/studiomdl/studiomdl.cpp b/utils/studiomdl/studiomdl.cpp index 444161768..b5f06db87 100644 --- a/utils/studiomdl/studiomdl.cpp +++ b/utils/studiomdl/studiomdl.cpp @@ -12,22 +12,23 @@ // models/.mdl. // - +#ifdef _WIN32 #pragma warning( disable : 4244 ) #pragma warning( disable : 4237 ) #pragma warning( disable : 4305 ) #include +#include #undef GetCurrentDirectory #include // PathCanonicalize #pragma comment( lib, "shlwapi" ) +#endif #include #include #include #include -#include #include "istudiorender.h" #include "filesystem_tools.h" #include "tier2/fileutils.h" @@ -45,9 +46,9 @@ #include "bspflags.h" #include "tier0/icommandline.h" #include "utldict.h" -#include "tier1/utlsortvector.h" +#include "tier1/UtlSortVector.h" #include "bitvec.h" -#include "appframework/appframework.h" +#include "appframework/AppFramework.h" #include "datamodel/idatamodel.h" #include "materialsystem/materialsystem_config.h" #include "vstdlib/cvar.h" @@ -67,6 +68,10 @@ #include "perfstats.h" #include "worldsize.h" +#ifdef POSIX +#define _stat stat +#endif + bool g_collapse_bones = false; bool g_collapse_bones_aggressive = false; bool g_quiet = false; @@ -195,6 +200,7 @@ void EnsureDependencyFileCheckedIn( const char *pFileName ) if ( g_bNoP4 ) return; +#ifdef _WIN32 char pFullPath[MAX_PATH]; if ( !GetGlobalFilePath( pFileName, pFullPath, sizeof(pFullPath) ) ) { @@ -206,6 +212,7 @@ void EnsureDependencyFileCheckedIn( const char *pFileName ) char bufCanonicalPath[ MAX_PATH ] = {0}; PathCanonicalize( bufCanonicalPath, pFullPath ); CP4AutoAddFile p4_add_dep_file( bufCanonicalPath ); +#endif } void StudioMdl_ScriptLoadedCallback( char const *pFilenameLoaded, char const *pIncludedFromFileName, int nIncludeLineNumber ) @@ -385,15 +392,17 @@ SpewRetval_t MdlSpewOutputFunc( SpewType_t type, char const *pMsg ) { MdlWarning( "%s", pMsg ); } +#if 0 else { return CmdLib_SpewOutputFunc( type, pMsg ); } +#endif return SPEW_CONTINUE; } - +#ifdef _WIN32 #ifndef _DEBUG void MdlHandleCrash( const char *pMessage, bool bAssert ) @@ -471,6 +480,7 @@ void MdlExceptionFilter( unsigned long code ) TerminateProcess( GetCurrentProcess(), 1 ); } +#endif #endif /* @@ -490,7 +500,7 @@ void *kalloc( int num, int size ) nMemSize += 511; void *ptr = malloc( nMemSize ); memset( ptr, 0, nMemSize ); - ptr = (byte *)((int)((byte *)ptr + 511) & ~511); + ptr = (byte *)((size_t)((byte *)ptr + 511) & ~511); return ptr; } @@ -2297,9 +2307,11 @@ int Option_Activity( s_sequence_t *psequence ) int Option_ActivityModifier( s_sequence_t *psequence ) { +#if 0 GetToken(false); V_strcpy_safe( psequence->activitymodifier[ psequence->numactivitymodifiers++ ].name, token ); +#endif return 0; } @@ -8366,7 +8378,7 @@ bool GetGlobalFilePath( const char *pSrc, char *pFullPath, int nMaxLen ) struct _stat buf; int rt = _stat( tmp, &buf ); - if ( rt != -1 && ( buf.st_size > 0 ) && ( ( buf.st_mode & _S_IFDIR ) == 0 ) ) + if ( rt != -1 && ( buf.st_size > 0 ) && ( ( buf.st_mode & S_IFDIR ) == 0 ) ) { Q_strncpy( pFullPath, tmp, nMaxLen ); return true; @@ -8377,7 +8389,7 @@ bool GetGlobalFilePath( const char *pSrc, char *pFullPath, int nMaxLen ) struct _stat buf; int rt = _stat( pFileName, &buf ); - if ( rt != -1 && ( buf.st_size > 0 ) && ( ( buf.st_mode & _S_IFDIR ) == 0 ) ) + if ( rt != -1 && ( buf.st_size > 0 ) && ( ( buf.st_mode & S_IFDIR ) == 0 ) ) { Q_strncpy( pFullPath, pFileName, nMaxLen ); return true; @@ -9463,6 +9475,7 @@ void UsageAndExit() ); } +#ifdef _WIN32 #ifndef _DEBUG LONG __stdcall VExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo ) @@ -9471,6 +9484,7 @@ LONG __stdcall VExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo ) return EXCEPTION_EXECUTE_HANDLER; // (never gets here anyway) } +#endif #endif /* ============== @@ -9545,8 +9559,10 @@ bool CStudioMDLApp::Create() MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); +#ifdef _WIN32 #ifndef _DEBUG SetUnhandledExceptionFilter( VExceptionFilter ); +#endif #endif if ( CommandLine()->ParmCount() == 1 ) diff --git a/utils/studiomdl/studiomdl.h b/utils/studiomdl/studiomdl.h index 413860e87..4df819c03 100644 --- a/utils/studiomdl/studiomdl.h +++ b/utils/studiomdl/studiomdl.h @@ -130,9 +130,9 @@ class CUtlVectorAuto : public CUtlVector< T > template< typename T > inline T& CUtlVectorAuto::operator[]( int i ) { - EnsureCount( i + 1 ); + this->EnsureCount( i + 1 ); Assert( IsValidIndex(i) ); - return Base()[i]; + return this->Base()[i]; } // -------------------------------------------------------------------- diff --git a/utils/studiomdl/tristrip.cpp b/utils/studiomdl/tristrip.cpp deleted file mode 100644 index 2a4283651..000000000 --- a/utils/studiomdl/tristrip.cpp +++ /dev/null @@ -1,350 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// - -// tristrip - convert triangle list into tristrips and fans - -#pragma warning( disable : 4244 ) -#pragma warning( disable : 4237 ) -#pragma warning( disable : 4305 ) - - -#include -#include -#include - -#include "cmdlib.h" -#include "lbmlib.h" -#include "scriplib.h" -#include "mathlib/mathlib.h" -#include "..\..\engine\studio.h" -#include "studiomdl.h" - -int used[MAXSTUDIOTRIANGLES]; - -// the command list holds counts and s/t values that are valid for -// every frame -short commands[MAXSTUDIOTRIANGLES * 13]; -int numcommands; - -// all frames will have their vertexes rearranged and expanded -// so they are in the order expected by the command list - -int allverts, alltris; - -int stripverts[MAXSTUDIOTRIANGLES+2]; -int striptris[MAXSTUDIOTRIANGLES+2]; -int stripcount; - -int neighbortri[MAXSTUDIOTRIANGLES][3]; -int neighboredge[MAXSTUDIOTRIANGLES][3]; - - -s_trianglevert_t (*triangles)[3]; -s_mesh_t *pmesh; - - -void FindNeighbor (int starttri, int startv) -{ - s_trianglevert_t m1, m2; - int j; - s_trianglevert_t *last, *check; - int k; - - // used[starttri] |= (1 << startv); - - last = &triangles[starttri][0]; - - m1 = last[(startv+1)%3]; - m2 = last[(startv+0)%3]; - - for (j=starttri+1, check=&triangles[starttri+1][0] ; jnumtris ; j++, check += 3) - { - if (used[j] == 7) - continue; - for (k=0 ; k<3 ; k++) - { - if (memcmp(&check[k],&m1,sizeof(m1))) - continue; - if (memcmp(&check[ (k+1)%3 ],&m2,sizeof(m2))) - continue; - - neighbortri[starttri][startv] = j; - neighboredge[starttri][startv] = k; - - neighbortri[j][k] = starttri; - neighboredge[j][k] = startv; - - used[starttri] |= (1 << startv); - used[j] |= (1 << k); - return; - } - } -} - - -/* -================ -StripLength -================ -*/ -int StripLength (int starttri, int startv) -{ - int j; - int k; - - used[starttri] = 2; - - stripverts[0] = (startv)%3; - stripverts[1] = (startv+1)%3; - stripverts[2] = (startv+2)%3; - - striptris[0] = starttri; - striptris[1] = starttri; - striptris[2] = starttri; - stripcount = 3; - - while( 1 ) - { - if (stripcount & 1) - { - j = neighbortri[starttri][(startv+1)%3]; - k = neighboredge[starttri][(startv+1)%3]; - } - else - { - j = neighbortri[starttri][(startv+2)%3]; - k = neighboredge[starttri][(startv+2)%3]; - } - if (j == -1 || used[j]) - goto done; - - stripverts[stripcount] = (k+2)%3; - striptris[stripcount] = j; - stripcount++; - - used[j] = 2; - - starttri = j; - startv = k; - } - -done: - - // clear the temp used flags - for (j=0 ; jnumtris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - -/* -=========== -FanLength -=========== -*/ -int FanLength (int starttri, int startv) -{ - int j; - int k; - - used[starttri] = 2; - - stripverts[0] = (startv)%3; - stripverts[1] = (startv+1)%3; - stripverts[2] = (startv+2)%3; - - striptris[0] = starttri; - striptris[1] = starttri; - striptris[2] = starttri; - stripcount = 3; - - while( 1 ) - { - j = neighbortri[starttri][(startv+2)%3]; - k = neighboredge[starttri][(startv+2)%3]; - - if (j == -1 || used[j]) - goto done; - - stripverts[stripcount] = (k+2)%3; - striptris[stripcount] = j; - stripcount++; - - used[j] = 2; - - starttri = j; - startv = k; - } - -done: - - // clear the temp used flags - for (j=0 ; jnumtris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - -/* -================ -BuildTris - -Generate a list of trifans or strips -for the model, which holds for all frames -================ -*/ -int numcommandnodes; - -int BuildTris (s_trianglevert_t (*x)[3], s_mesh_t *y, byte **ppdata ) -{ - int i, j, k, m; - int startv; - int len, bestlen, besttype; - int bestverts[MAXSTUDIOTRIANGLES]; - int besttris[MAXSTUDIOTRIANGLES]; - int peak[MAXSTUDIOTRIANGLES]; - int type; - int total = 0; - long t; - int maxlen; - - triangles = x; - pmesh = y; - - - t = time( NULL ); - - for (i=0 ; inumtris ; i++) - { - neighbortri[i][0] = neighbortri[i][1] = neighbortri[i][2] = -1; - used[i] = 0; - peak[i] = pmesh->numtris; - } - - // printf("finding neighbors\n"); - for (i=0 ; inumtris; i++) - { - for (k = 0; k < 3; k++) - { - if (used[i] & (1 << k)) - continue; - - FindNeighbor( i, k ); - } - // printf("%d", used[i] ); - } - // printf("\n"); - - // - // build tristrips - // - numcommandnodes = 0; - numcommands = 0; - memset (used, 0, sizeof(used)); - - for (i=0 ; inumtris ;) - { - // pick an unused triangle and start the trifan - if (used[i]) - { - i++; - continue; - } - - maxlen = 9999; - bestlen = 0; - m = 0; - for (k = i; k < pmesh->numtris && bestlen < 127; k++) - { - int localpeak = 0; - - if (used[k]) - continue; - - if (peak[k] <= bestlen) - continue; - - m++; - for (type = 0 ; type < 2 ; type++) - { - for (startv =0 ; startv < 3 ; startv++) - { - if (type == 1) - len = FanLength (k, startv); - else - len = StripLength (k, startv); - if (len > 127) - { - // skip these, they are too long to encode - } - else if (len > bestlen) - { - besttype = type; - bestlen = len; - for (j=0 ; j localpeak) - localpeak = len; - } - } - peak[k] = localpeak; - if (localpeak == maxlen) - break; - } - total += (bestlen - 2); - - // printf("%d (%d) %d\n", bestlen, pmesh->numtris - total, i ); - - maxlen = bestlen; - - // mark the tris on the best strip as used - for (j=0 ; jvertindex; - commands[numcommands++] = tri->normindex; - commands[numcommands++] = tri->s; - commands[numcommands++] = tri->t; - } - // printf("%d ", bestlen - 2 ); - numcommandnodes++; - - if (t != time(NULL)) - { - printf("%2d%%\r", (total * 100) / pmesh->numtris ); - t = time(NULL); - } - } - - commands[numcommands++] = 0; // end of list marker - - *ppdata = (byte *)commands; - - // printf("%d %d %d\n", numcommandnodes, numcommands, pmesh->numtris ); - return numcommands * sizeof( short ); -} - diff --git a/utils/studiomdl/write.cpp b/utils/studiomdl/write.cpp index d3867f404..92a880f24 100644 --- a/utils/studiomdl/write.cpp +++ b/utils/studiomdl/write.cpp @@ -10,12 +10,14 @@ // write.c: writes a studio .mdl file // +#ifdef _WIN32 #pragma warning( disable : 4244 ) #pragma warning( disable : 4237 ) #pragma warning( disable : 4305 ) - #include +#endif + #include #include #include @@ -64,11 +66,11 @@ static byte *pBlockStart; #undef ALIGN4 #undef ALIGN16 #undef ALIGN32 -#define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3) -#define ALIGN16( a ) a = (byte *)((int)((byte *)a + 15) & ~ 15) -#define ALIGN32( a ) a = (byte *)((int)((byte *)a + 31) & ~ 31) -#define ALIGN64( a ) a = (byte *)((int)((byte *)a + 63) & ~ 63) -#define ALIGN512( a ) a = (byte *)((int)((byte *)a + 511) & ~ 511) +#define ALIGN4( a ) a = (byte *)((size_t)((byte *)a + 3) & ~ 3) +#define ALIGN16( a ) a = (byte *)((size_t)((byte *)a + 15) & ~ 15) +#define ALIGN32( a ) a = (byte *)((size_t)((byte *)a + 31) & ~ 31) +#define ALIGN64( a ) a = (byte *)((size_t)((byte *)a + 63) & ~ 63) +#define ALIGN512( a ) a = (byte *)((size_t)((byte *)a + 511) & ~ 511) // make sure kalloc aligns to maximum alignment size #define FILEBUFFER (8 * 1024 * 1024) @@ -1736,12 +1738,12 @@ static void WriteBoneTransforms( studiohdr2_t *phdr, mstudiobone_t *pBone ) pLinearBone->numbones = g_numbones; #define WRITE_BONE_BLOCK( type, srcfield, dest, destindex ) \ - type *##dest = (type *)pData; \ - pLinearBone->##destindex = pData - (byte *)pLinearBone; \ - pData += g_numbones * sizeof( *##dest ); \ + type *dest = (type *)pData; \ + pLinearBone->destindex = pData - (byte *)pLinearBone; \ + pData += g_numbones * sizeof( *dest ); \ ALIGN4( pData ); \ for ( int i = 0; i < g_numbones; i++) \ - dest##[i] = pBone[i].##srcfield; + dest[i] = pBone[i].srcfield; WRITE_BONE_BLOCK( int, flags, pFlags, flagsindex ); WRITE_BONE_BLOCK( int, parent, pParent, parentindex ); @@ -1881,7 +1883,7 @@ static void WriteVertices( studiohdr_t *phdr ) // save vertices ALIGN16( pData ); - cur = (int)pData; + cur = (size_t)pData; mstudiovertex_t *pVert = (mstudiovertex_t *)pData; pData += pLodData->numvertices * sizeof( mstudiovertex_t ); for (j = 0; j < pLodData->numvertices; j++) @@ -1908,7 +1910,7 @@ static void WriteVertices( studiohdr_t *phdr ) if (!g_quiet) { - printf( "vertices %7d bytes (%d vertices)\n", (int)(pData - cur), pLodData->numvertices ); + printf( "vertices %7d bytes (%d vertices)\n", (size_t)(pData - cur), pLodData->numvertices ); } } @@ -1925,7 +1927,7 @@ static void WriteVertices( studiohdr_t *phdr ) // save tangent space S ALIGN4( pData ); - cur = (int)pData; + cur = (size_t)pData; Vector4D *ptangents = (Vector4D *)pData; pData += pLodData->numvertices * sizeof( Vector4D ); for (j = 0; j < pLodData->numvertices; j++) @@ -1939,7 +1941,7 @@ static void WriteVertices( studiohdr_t *phdr ) if (!g_quiet) { - printf( "tangents %7d bytes (%d vertices)\n", (int)(pData - cur), pLodData->numvertices ); + printf( "tangents %7d bytes (%d vertices)\n", (size_t)(pData - cur), pLodData->numvertices ); } } @@ -2060,7 +2062,7 @@ static void WriteModel( studiohdr_t *phdr ) mstudiovertanim_t *pvertanim; s_vertanim_t *pvanim; - int cur = (int)pData; + int cur = (size_t)pData; // vertex data is written to external file, offsets kept internal // track expected external base to store proper offsets @@ -2362,9 +2364,9 @@ static void WriteModel( studiohdr_t *phdr ) if( !g_quiet ) { - printf("ik/pose %7d bytes\n", (int)(pData - cur) ); + printf("ik/pose %7d bytes\n", (size_t)(pData - cur) ); } - cur = (int)pData; + cur = (size_t)pData; const float flVertAnimFixedPointScale = ComputeVertAnimFixedPointScale( phdr ); @@ -2424,15 +2426,15 @@ static void WriteModel( studiohdr_t *phdr ) // set expected base offsets to external data ALIGN16( externalVertexIndex ); - pmodel[i].vertexindex = (int)externalVertexIndex; + pmodel[i].vertexindex = (size_t)externalVertexIndex; externalVertexIndex += pmodel[i].numvertices * sizeof(mstudiovertex_t); // set expected base offsets to external data ALIGN4( externalTangentsIndex ); - pmodel[i].tangentsindex = (int)externalTangentsIndex; + pmodel[i].tangentsindex = (size_t)externalTangentsIndex; externalTangentsIndex += pmodel[i].numvertices * sizeof( Vector4D ); - cur = (int)pData; + cur = (size_t)pData; // save eyeballs mstudioeyeball_t *peyeball; @@ -2470,11 +2472,11 @@ static void WriteModel( studiohdr_t *phdr ) if ( !g_quiet ) { - printf("eyeballs %7d bytes (%d eyeballs)\n", (int)(pData - cur), g_model[i]->numeyeballs ); + printf("eyeballs %7d bytes (%d eyeballs)\n", (size_t)(pData - cur), g_model[i]->numeyeballs ); } // move flexes into individual meshes - cur = (int)pData; + cur = (size_t)pData; for (m = 0; m < pmodel[i].nummeshes; m++) { int numflexkeys[MAXSTUDIOFLEXKEYS]; @@ -2581,9 +2583,9 @@ static void WriteModel( studiohdr_t *phdr ) if( !g_quiet ) { - printf("flexes %7d bytes (%d flexes)\n", (int)(pData - cur), g_numflexkeys ); + printf("flexes %7d bytes (%d flexes)\n", (size_t)(pData - cur), g_numflexkeys ); } - cur = (int)pData; + cur = (size_t)pData; } @@ -3188,7 +3190,7 @@ typedef struct lodMeshInfo_t lodMeshInfo; } vertexPool_t; -#define ALIGN(b,s) (((unsigned int)(b)+(s)-1)&~((s)-1)) +#define ALIGN(b,s) (((size_t)(b)+(s)-1)&~((s)-1)) //----------------------------------------------------------------------------- // FindVertexOffsets @@ -4583,4 +4585,4 @@ void WriteAllSwappedFiles( const char *filename ) Q_strcat( outname, ".360.mdl", sizeof( outname ) ); WriteSwappedFile( srcname, outname, StudioByteSwap::ByteswapMDL ); -} \ No newline at end of file +} diff --git a/utils/studiomdl/wscript b/utils/studiomdl/wscript new file mode 100644 index 000000000..c8d10d353 --- /dev/null +++ b/utils/studiomdl/wscript @@ -0,0 +1,93 @@ +#! /usr/bin/env python +# encoding: utf-8 +# vim: noexpandtab + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'studiomdl' + +def options(opt): + # stub + return + +def configure(conf): + conf.define('PROTECTED_THINGS_DISABLE', 1) + return + +def build(bld): + source = [ + 'UnifyLODs.cpp', + 'checkuv.cpp', + 'collisionmodel.cpp', + 'dmxsupport.cpp', + 'hardwarematrixstate.cpp', + 'hardwarevertexcache.cpp', + 'mrmsupport.cpp', + 'objsupport.cpp', + 'optimize.cpp', + 'perfstats.cpp', + 'simplify.cpp', + 'studiomdl.cpp', + 'v1support.cpp', + 'write.cpp', + '../common/cmdlib.cpp', + '../common/filesystem_tools.cpp', + '../common/physdll.cpp', + '../common/scriplib.cpp', + '../../filesystem/linux_support.cpp', + '../../public/filesystem_helpers.cpp', + '../../public/filesystem_init.cpp', + '../../public/bone_setup.cpp', + '../../public/collisionutils.cpp', + '../../public/interpolatortypes.cpp', + '../../public/mdlobjects/mdlobjects.cpp', + '../../public/movieobjects/movieobjects_compiletools.cpp', + '../../public/studio.cpp', + '../../common/studiobyteswap.cpp', + ] + + includes = [ + '.', + '../common', + '../../public', + '../../public/tier0', + '../../public/tier1', + '../../public/tier2', + '../../public/tier3', + '../../public/vstdlib', + ] + + defines = [] + + libs = [ + 'tier0', 'tier1', 'tier2', 'tier3', + 'appframework', + 'datamodel', + 'dmserializers', + 'mathlib', + 'mdlobjects', + 'movieobjects', +# 'nvtristrip', + 'vstdlib', + ] + + if bld.env.DEST_OS == 'win32': + libs += ['USER32'] + + install_path = bld.env.BINDIR + + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/waf b/waf index b2f4c6f49..f754d112d 100755 --- a/waf +++ b/waf @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # encoding: latin-1 # Thomas Nagy, 2005-2018 # diff --git a/wscript b/wscript index 2ec9ec506..ddf8b9f3c 100644 --- a/wscript +++ b/wscript @@ -123,6 +123,8 @@ projects={ 'fgdlib', 'raytrace', 'vphysics', + 'movieobjects', +# 'hammer_launcher', 'ivp/havana', 'ivp/havana/havok/hk_base', 'ivp/havana/havok/hk_math', @@ -131,17 +133,18 @@ projects={ 'materialsystem', 'materialsystem/shaderapiempty', 'materialsystem/shaderlib', - 'utils/vtex', - 'utils/lzma', 'utils/bsppack', + 'utils/lzma', +# 'utils/studiomdl', + 'utils/vbsp', 'utils/vbspinfo', - 'utils/xbox/xbspinfo', - 'utils/vvis', - 'utils/vvis_launcher', + 'utils/vpk', 'utils/vrad', 'utils/vrad_launcher', - 'utils/vbsp', - 'utils/vpk', + 'utils/vtex', + 'utils/vvis', + 'utils/vvis_launcher', + 'utils/xbox/xbspinfo', ], } From faa452222e1a99b125eb57f11bc52ae2685feb6f Mon Sep 17 00:00:00 2001 From: Er2 Date: Fri, 12 May 2023 21:10:58 +0300 Subject: [PATCH 05/11] some things --- hammer_launcher/main.cpp | 25 +- hammer_launcher/wscript | 49 ++ tier0/dbg.cpp | 2 +- tier0/wscript | 2 + utils/common/utilmatlib.cpp | 2 +- utils/vbsp/disp_ivp.cpp | 346 ++++++++ utils/vbsp/disp_vbsp.h | 2 + utils/vbsp/ivp.cpp | 1652 +++++++++++++++++++++++++++++++++++ utils/vbsp/ivp.h | 75 ++ utils/vbsp/writebsp.cpp | 4 +- utils/vbsp/wscript | 2 + wscript | 33 +- 12 files changed, 2166 insertions(+), 28 deletions(-) create mode 100644 hammer_launcher/wscript create mode 100644 utils/vbsp/disp_ivp.cpp create mode 100644 utils/vbsp/ivp.cpp create mode 100644 utils/vbsp/ivp.h diff --git a/hammer_launcher/main.cpp b/hammer_launcher/main.cpp index 72d36343e..7bd93613b 100644 --- a/hammer_launcher/main.cpp +++ b/hammer_launcher/main.cpp @@ -4,10 +4,8 @@ // //===========================================================================// -#include -#include #include "appframework/AppFramework.h" -#include "ihammer.h" +#include "IHammer.h" #include "tier0/dbg.h" #include "vstdlib/cvar.h" #include "filesystem.h" @@ -17,12 +15,21 @@ #include "datacache/idatacache.h" #include "datacache/imdlcache.h" #include "vphysics_interface.h" -#include "vgui/ivgui.h" +#include "vgui/IVGui.h" #include "vgui/ISurface.h" #include "inputsystem/iinputsystem.h" #include "tier0/icommandline.h" #include "p4lib/ip4.h" +#ifdef USE_SDL +# include +# include +# ifndef _WIN32 +# define MB_OK 0 +# define MB_ICONSTOP 0 +# endif +#endif + //----------------------------------------------------------------------------- // Global systems //----------------------------------------------------------------------------- @@ -129,6 +136,16 @@ void CHammerApp::Destroy() } +#if defined( USE_SDL ) && !defined( _WIN32 ) + +int MessageBox( HWND hWnd, const char *message, const char *header, unsigned uType ) +{ + SDL_ShowSimpleMessageBox( 0, header, message, GetAssertDialogParent() ); + return 0; +} + +#endif + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- SpewRetval_t HammerSpewFunc( SpewType_t type, tchar const *pMsg ) diff --git a/hammer_launcher/wscript b/hammer_launcher/wscript new file mode 100644 index 000000000..b73e6b0dd --- /dev/null +++ b/hammer_launcher/wscript @@ -0,0 +1,49 @@ +#! /usr/bin/env python +# encoding: utf-8 + +from waflib import Utils +import os + +top = '.' +PROJECT_NAME = 'hammer_launcher' + +def options(opt): + # stub + return + +def configure(conf): + return + +def build(bld): + if bld.env.DEST_OS == 'android': + return + + source = ['main.cpp'] + includes = [ + '../public', + '../public/tier0', + '../public/tier1', + ] + bld.env.INCLUDES_SDL2 + defines = [] + libs = ['tier0', 'appframework', 'tier1', 'vstdlib', 'SDL2'] + + if bld.env.DEST_OS != 'win32': + libs += [ 'DL', 'LOG' ] + else: + libs += ['USER32', 'SHELL32'] + source += ['hammer_launcher.rc'] + + install_path = bld.env.BINDIR + bld( + source = source, + target = PROJECT_NAME, + name = PROJECT_NAME, + features = 'c cxx cxxprogram', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/tier0/dbg.cpp b/tier0/dbg.cpp index 84da04717..c2a83fca1 100644 --- a/tier0/dbg.cpp +++ b/tier0/dbg.cpp @@ -112,7 +112,7 @@ void CDbgLogger::Init(const char *logfile) #ifdef GIT_COMMIT_HASH fprintf(file, ">>> Engine(arch:%s commit:" GIT_COMMIT_HASH ") started at %s\n", GetProcessorArchName(), szTime); #else - fprintf(file, ">>> Engine(arch:%s) started at %s\n", GetProcessorArchName(), szTime); + fprintf(file, ">>> Engine(arch:%s version:" REL_VERSION ") started at %s\n", GetProcessorArchName(), szTime); #endif #ifdef GNUC diff --git a/tier0/wscript b/tier0/wscript index b02c60bf8..7604b74bb 100755 --- a/tier0/wscript +++ b/tier0/wscript @@ -16,6 +16,8 @@ def configure(conf): conf.define('WAF_LDFLAGS', conf.env.LINKFLAGS) conf.define('TIER0_DLL_EXPORT',1) # conf.define('NO_HOOK_MALLOC',1) + conf.define('GIT_COMMIT_HASH', conf.env.GIT_VERSION) + conf.define('REL_VERSION', conf.env.REL_VERSION) def build(bld): source = [ diff --git a/utils/common/utilmatlib.cpp b/utils/common/utilmatlib.cpp index c2e4babff..b2ae70b88 100644 --- a/utils/common/utilmatlib.cpp +++ b/utils/common/utilmatlib.cpp @@ -49,7 +49,7 @@ void LoadMaterialSystemInterface( CreateInterfaceFn fileSystemFactory ) if (!g_pMaterialSystem->Init( "shaderapiempty" DLL_EXT_STRING, 0, fileSystemFactory )) { - Error( "Could not start the empty shader (shaderapiempty)!" ); + Error( "Could not start the empty shader (shaderapiempty)!\n" ); } } diff --git a/utils/vbsp/disp_ivp.cpp b/utils/vbsp/disp_ivp.cpp new file mode 100644 index 000000000..ec333fb6b --- /dev/null +++ b/utils/vbsp/disp_ivp.cpp @@ -0,0 +1,346 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#include "vbsp.h" +#include "disp_vbsp.h" +#include "builddisp.h" +#include "disp_common.h" +#include "ivp.h" +#include "disp_vbsp.h" +#include "vphysics_interface.h" +#include "vphysics/virtualmesh.h" +#include "utlrbtree.h" +#include "tier1/utlbuffer.h" +#include "materialpatch.h" + +struct disp_grid_t +{ + int gridIndex; + CUtlVector dispList; +}; + +static CUtlVector gDispGridList; + + + +disp_grid_t &FindOrInsertGrid( int gridIndex ) +{ + // linear search is slow, but only a few grids will be present + for ( int i = gDispGridList.Count()-1; i >= 0; i-- ) + { + if ( gDispGridList[i].gridIndex == gridIndex ) + { + return gDispGridList[i]; + } + } + int index = gDispGridList.AddToTail(); + gDispGridList[index].gridIndex = gridIndex; + + // must be empty + Assert( gDispGridList[index].dispList.Count() == 0 ); + + return gDispGridList[index]; +} + +// UNDONE: Tune these or adapt them to map size or triangle count? +#define DISP_GRID_SIZEX 4096 +#define DISP_GRID_SIZEY 4096 +#define DISP_GRID_SIZEZ 8192 + +int Disp_GridIndex( CCoreDispInfo *pDispInfo ) +{ + // quick hash the center into the grid and put the whole terrain in that grid + Vector mins, maxs; + pDispInfo->GetNode(0)->GetBoundingBox( mins, maxs ); + Vector center; + center = 0.5 * (mins + maxs); + // make sure it's positive + center += Vector(MAX_COORD_INTEGER,MAX_COORD_INTEGER,MAX_COORD_INTEGER); + int gridX = center.x / DISP_GRID_SIZEX; + int gridY = center.y / DISP_GRID_SIZEY; + int gridZ = center.z / DISP_GRID_SIZEZ; + + gridX &= 0xFF; + gridY &= 0xFF; + gridZ &= 0xFF; + return MAKEID( gridX, gridY, gridZ, 0 ); +} + +void AddToGrid( int gridIndex, int dispIndex ) +{ + disp_grid_t &grid = FindOrInsertGrid( gridIndex ); + grid.dispList.AddToTail( dispIndex ); +} + +MaterialSystemMaterial_t GetMatIDFromDisp( mapdispinfo_t *pMapDisp ) +{ + texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo]; + dtexdata_t *pTexData = GetTexData( pTexInfo->texdata ); + MaterialSystemMaterial_t matID = FindOriginalMaterial( TexDataStringTable_GetString( pTexData->nameStringTableID ), NULL, true ); + return matID; +} + +// adds all displacement faces as a series of convex objects +// UNDONE: Only add the displacements for this model? +void Disp_AddCollisionModels( CUtlVector &collisionList, dmodel_t *pModel, int contentsMask) +{ + int dispIndex; + + // Add each displacement to the grid hash + for ( dispIndex = 0; dispIndex < g_CoreDispInfos.Count(); dispIndex++ ) + { + CCoreDispInfo *pDispInfo = g_CoreDispInfos[ dispIndex ]; + mapdispinfo_t *pMapDisp = &mapdispinfo[ dispIndex ]; + + // not solid for this pass + if ( !(pMapDisp->contents & contentsMask) ) + continue; + + int gridIndex = Disp_GridIndex( pDispInfo ); + AddToGrid( gridIndex, dispIndex ); + } + + // now make a polysoup for the terrain in each grid + for ( int grid = 0; grid < gDispGridList.Count(); grid++ ) + { + int triCount = 0; + CPhysPolysoup *pTerrainPhysics = physcollision->PolysoupCreate(); + + // iterate the displacements in this grid + for ( int listIndex = 0; listIndex < gDispGridList[grid].dispList.Count(); listIndex++ ) + { + dispIndex = gDispGridList[grid].dispList[listIndex]; + CCoreDispInfo *pDispInfo = g_CoreDispInfos[ dispIndex ]; + mapdispinfo_t *pMapDisp = &mapdispinfo[ dispIndex ]; + + // Get the material id. + MaterialSystemMaterial_t matID = GetMatIDFromDisp( pMapDisp ); + + // Build a triangle list. This shares the tesselation code with the engine. + CUtlVector indices; + CVBSPTesselateHelper helper; + helper.m_pIndices = &indices; + helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base(); + helper.m_pPowerInfo = pDispInfo->GetPowerInfo(); + + ::TesselateDisplacement( &helper ); + + Assert( indices.Count() > 0 ); + Assert( indices.Count() % 3 == 0 ); // Make sure indices are a multiple of 3. + int nTriCount = indices.Count() / 3; + triCount += nTriCount; + if ( triCount >= 65536 ) + { + // don't put more than 64K tris in any single collision model + CPhysCollide *pCollide = physcollision->ConvertPolysoupToCollide( pTerrainPhysics, false ); + if ( pCollide ) + { + collisionList.AddToTail( new CPhysCollisionEntryStaticMesh( pCollide, NULL ) ); + } + // Throw this polysoup away and start over for the remaining triangles + physcollision->PolysoupDestroy( pTerrainPhysics ); + pTerrainPhysics = physcollision->PolysoupCreate(); + triCount = nTriCount; + } + Vector tmpVerts[3]; + for ( int iTri = 0; iTri < nTriCount; ++iTri ) + { + float flAlphaTotal = 0.0f; + for ( int iTriVert = 0; iTriVert < 3; ++iTriVert ) + { + pDispInfo->GetVert( indices[iTri*3+iTriVert], tmpVerts[iTriVert] ); + flAlphaTotal += pDispInfo->GetAlpha( indices[iTri*3+iTriVert] ); + } + + int nProp = g_SurfaceProperties[texinfo[pMapDisp->face.texinfo].texdata]; + if ( flAlphaTotal > DISP_ALPHA_PROP_DELTA ) + { + int nProp2 = GetSurfaceProperties2( matID, "surfaceprop2" ); + if ( nProp2 != -1 ) + { + nProp = nProp2; + } + } + int nMaterialIndex = RemapWorldMaterial( nProp ); + physcollision->PolysoupAddTriangle( pTerrainPhysics, tmpVerts[0], tmpVerts[1], tmpVerts[2], nMaterialIndex ); + } + } + + // convert the whole grid's polysoup to a collide and store in the collision list + CPhysCollide *pCollide = physcollision->ConvertPolysoupToCollide( pTerrainPhysics, false ); + if ( pCollide ) + { + collisionList.AddToTail( new CPhysCollisionEntryStaticMesh( pCollide, NULL ) ); + } + // now that we have the collide, we're done with the soup + physcollision->PolysoupDestroy( pTerrainPhysics ); + } +} + + +class CDispMeshEvent : public IVirtualMeshEvent +{ +public: + CDispMeshEvent( unsigned short *pIndices, int indexCount, CCoreDispInfo *pDispInfo ); + virtual void GetVirtualMesh( void *userData, virtualmeshlist_t *pList ); + virtual void GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs ); + virtual void GetTrianglesInSphere( void *userData, const Vector ¢er, float radius, virtualmeshtrianglelist_t *pList ); + + CUtlVector m_verts; + unsigned short *m_pIndices; + int m_indexCount; +}; + +CDispMeshEvent::CDispMeshEvent( unsigned short *pIndices, int indexCount, CCoreDispInfo *pDispInfo ) +{ + m_pIndices = pIndices; + m_indexCount = indexCount; + int maxIndex = 0; + for ( int i = 0; i < indexCount; i++ ) + { + if ( pIndices[i] > maxIndex ) + { + maxIndex = pIndices[i]; + } + } + for ( int i = 0; i < indexCount/2; i++ ) + { + V_swap( pIndices[i], pIndices[(indexCount-i)-1] ); + } + int count = maxIndex + 1; + m_verts.SetCount( count ); + for ( int i = 0; i < count; i++ ) + { + m_verts[i] = pDispInfo->GetVert(i); + } +} + +void CDispMeshEvent::GetVirtualMesh( void *userData, virtualmeshlist_t *pList ) +{ + Assert(userData==((void *)this)); + pList->pVerts = m_verts.Base(); + pList->indexCount = m_indexCount; + pList->triangleCount = m_indexCount/3; + pList->vertexCount = m_verts.Count(); + pList->surfacePropsIndex = 0; // doesn't matter here, reset at runtime + pList->pHull = NULL; + int indexMax = ARRAYSIZE(pList->indices); + int indexCount = min(m_indexCount, indexMax); + Assert(m_indexCount < indexMax); + Q_memcpy( pList->indices, m_pIndices, sizeof(*m_pIndices) * indexCount ); +} + +void CDispMeshEvent::GetWorldspaceBounds( void *userData, Vector *pMins, Vector *pMaxs ) +{ + Assert(userData==((void *)this)); + ClearBounds( *pMins, *pMaxs ); + for ( int i = 0; i < m_verts.Count(); i++ ) + { + AddPointToBounds( m_verts[i], *pMins, *pMaxs ); + } +} + +void CDispMeshEvent::GetTrianglesInSphere( void *userData, const Vector ¢er, float radius, virtualmeshtrianglelist_t *pList ) +{ + Assert(userData==((void *)this)); + pList->triangleCount = m_indexCount/3; + int indexMax = ARRAYSIZE(pList->triangleIndices); + int indexCount = min(m_indexCount, indexMax); + Assert(m_indexCount < MAX_VIRTUAL_TRIANGLES*3); + Q_memcpy( pList->triangleIndices, m_pIndices, sizeof(*m_pIndices) * indexCount ); +} + +void Disp_BuildVirtualMesh( int contentsMask ) +{ + CUtlVector virtualMeshes; + virtualMeshes.EnsureCount( g_CoreDispInfos.Count() ); + for ( int i = 0; i < g_CoreDispInfos.Count(); i++ ) + { + CCoreDispInfo *pDispInfo = g_CoreDispInfos[ i ]; + mapdispinfo_t *pMapDisp = &mapdispinfo[ i ]; + + virtualMeshes[i] = NULL; + // not solid for this pass + if ( !(pMapDisp->contents & contentsMask) ) + continue; + + // Build a triangle list. This shares the tesselation code with the engine. + CUtlVector indices; + CVBSPTesselateHelper helper; + helper.m_pIndices = &indices; + helper.m_pActiveVerts = pDispInfo->GetAllowedVerts().Base(); + helper.m_pPowerInfo = pDispInfo->GetPowerInfo(); + + ::TesselateDisplacement( &helper ); + + // validate the collision data + if ( 1 ) + { + int triCount = indices.Count() / 3; + for ( int j = 0; j < triCount; j++ ) + { + int index = j * 3; + Vector v0 = pDispInfo->GetVert( indices[index+0] ); + Vector v1 = pDispInfo->GetVert( indices[index+1] ); + Vector v2 = pDispInfo->GetVert( indices[index+2] ); + if ( v0 == v1 || v1 == v2 || v2 == v0 ) + { + Warning( "Displacement %d has bad geometry near %.2f %.2f %.2f\n", i, v0.x, v0.y, v0.z ); + texinfo_t *pTexInfo = &texinfo[pMapDisp->face.texinfo]; + dtexdata_t *pTexData = GetTexData( pTexInfo->texdata ); + const char *pMatName = TexDataStringTable_GetString( pTexData->nameStringTableID ); + + Error( "Can't compile displacement physics, exiting. Texture is %s\n", pMatName ); + } + } + + } + CDispMeshEvent meshHandler( indices.Base(), indices.Count(), pDispInfo ); + virtualmeshparams_t params; + params.buildOuterHull = true; + params.pMeshEventHandler = &meshHandler; + params.userData = &meshHandler; + virtualMeshes[i] = physcollision->CreateVirtualMesh( params ); + } + unsigned int totalSize = 0; + CUtlBuffer buf; + dphysdisp_t header; + header.numDisplacements = g_CoreDispInfos.Count(); + buf.PutObjects( &header ); + + CUtlVector dispBuf; + for ( int i = 0; i < header.numDisplacements; i++ ) + { + if ( virtualMeshes[i] ) + { + unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] ); + totalSize += testSize; + buf.PutShort( testSize ); + } + else + { + buf.PutShort( -1 ); + } + } + for ( int i = 0; i < header.numDisplacements; i++ ) + { + if ( virtualMeshes[i] ) + { + unsigned int testSize = physcollision->CollideSize( virtualMeshes[i] ); + dispBuf.RemoveAll(); + dispBuf.EnsureCount(testSize); + + unsigned int outSize = physcollision->CollideWrite( dispBuf.Base(), virtualMeshes[i], false ); + Assert( outSize == testSize ); + buf.Put( dispBuf.Base(), outSize ); + } + } + g_PhysDispSize = totalSize + sizeof(dphysdisp_t) + (sizeof(unsigned short) * header.numDisplacements); + Assert( buf.TellMaxPut() == g_PhysDispSize ); + g_PhysDispSize = buf.TellMaxPut(); + g_pPhysDisp = new byte[g_PhysDispSize]; + Q_memcpy( g_pPhysDisp, buf.Base(), g_PhysDispSize ); +} + diff --git a/utils/vbsp/disp_vbsp.h b/utils/vbsp/disp_vbsp.h index d0e5ea5f2..1c6fee4b7 100644 --- a/utils/vbsp/disp_vbsp.h +++ b/utils/vbsp/disp_vbsp.h @@ -67,4 +67,6 @@ bool HasDispInfo( mapbrush_t *pBrush ); // Computes the bounds for a disp info void ComputeDispInfoBounds( int dispinfo, Vector& mins, Vector& maxs ); +extern void Disp_AddCollisionModels( CUtlVector &collisionList, dmodel_t *pModel, int contentsMask ); +extern void Disp_BuildVirtualMesh( int contentsMask ); #endif // VBSP_DISPINFO_H diff --git a/utils/vbsp/ivp.cpp b/utils/vbsp/ivp.cpp new file mode 100644 index 000000000..7128d4bf7 --- /dev/null +++ b/utils/vbsp/ivp.cpp @@ -0,0 +1,1652 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include +#include "mathlib/vector.h" +#include "bspfile.h" +#include "bsplib.h" +#include "cmdlib.h" +#include "physdll.h" +#include "utlvector.h" +#include "vbsp.h" +#include "phyfile.h" +#include +#include "KeyValues.h" +#include "utlbuffer.h" +#include "utlsymbol.h" +#include "utlrbtree.h" +#include "ivp.h" +#include "disp_vbsp.h" +#include "materialpatch.h" +#include "bitvec.h" +#include "tier3/tier3.h" + +// bit per leaf +typedef CBitVec leafbitarray_t; + +// parameters for conversion to vphysics +#define NO_SHRINK 0.0f +// NOTE: vphysics maintains a minimum separation radius between objects +// This radius is set to 0.25, but it's symmetric. So shrinking potentially moveable +// brushes by 0.5 in every direction ensures that these brushes can be constructed +// touching the world, and constrained in place without collisions or friction +// UNDONE: Add a key to disable this shrinking if necessary +#define VPHYSICS_SHRINK (0.5f) // shrink BSP brushes by this much for collision +#define VPHYSICS_MERGE 0.01f // merge verts closer than this + +void EmitPhysCollision(); + +IPhysicsCollision *physcollision = NULL; +extern IPhysicsSurfaceProps *physprops; + +// a list of all of the materials in the world model +static CUtlVector s_WorldPropList; + +//----------------------------------------------------------------------------- +// Purpose: Write key/value pairs out to a memory buffer +//----------------------------------------------------------------------------- +CTextBuffer::CTextBuffer( void ) +{ +} +CTextBuffer::~CTextBuffer( void ) +{ +} + +void CTextBuffer::WriteText( const char *pText ) +{ + int len = strlen( pText ); + CopyData( pText, len ); +} + +void CTextBuffer::WriteIntKey( const char *pKeyName, int outputData ) +{ + char tmp[1024]; + + // FAIL! + if ( strlen(pKeyName) > 1000 ) + { + Msg("Error writing collision data %s\n", pKeyName ); + return; + } + sprintf( tmp, "\"%s\" \"%d\"\n", pKeyName, outputData ); + CopyData( tmp, strlen(tmp) ); +} + +void CTextBuffer::WriteStringKey( const char *pKeyName, const char *outputData ) +{ + CopyStringQuotes( pKeyName ); + CopyData( " ", 1 ); + CopyStringQuotes( outputData ); + CopyData( "\n", 1 ); +} + +void CTextBuffer::WriteFloatKey( const char *pKeyName, float outputData ) +{ + char tmp[1024]; + + // FAIL! + if ( strlen(pKeyName) > 1000 ) + { + Msg("Error writing collision data %s\n", pKeyName ); + return; + } + sprintf( tmp, "\"%s\" \"%f\"\n", pKeyName, outputData ); + CopyData( tmp, strlen(tmp) ); +} + +void CTextBuffer::WriteFloatArrayKey( const char *pKeyName, const float *outputData, int count ) +{ + char tmp[1024]; + + // FAIL! + if ( strlen(pKeyName) > 1000 ) + { + Msg("Error writing collision data %s\n", pKeyName ); + return; + } + sprintf( tmp, "\"%s\" \"", pKeyName ); + for ( int i = 0; i < count; i++ ) + { + char buf[80]; + + sprintf( buf, "%f ", outputData[i] ); + strcat( tmp, buf ); + } + strcat( tmp, "\"\n" ); + + CopyData( tmp, strlen(tmp) ); +} + +void CTextBuffer::CopyStringQuotes( const char *pString ) +{ + CopyData( "\"", 1 ); + CopyData( pString, strlen(pString) ); + CopyData( "\"", 1 ); +} + +void CTextBuffer::Terminate( void ) +{ + CopyData( "\0", 1 ); +} + +void CTextBuffer::CopyData( const char *pData, int len ) +{ + int offset = m_buffer.AddMultipleToTail( len ); + memcpy( m_buffer.Base() + offset, pData, len ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Writes a glview text file containing the collision surface in question +// Input : *pCollide - +// *pFilename - +//----------------------------------------------------------------------------- +void DumpCollideToGlView( CPhysCollide *pCollide, const char *pFilename ) +{ + if ( !pCollide ) + return; + + Msg("Writing %s...\n", pFilename ); + Vector *outVerts; + int vertCount = physcollision->CreateDebugMesh( pCollide, &outVerts ); + FILE *fp = fopen( pFilename, "w" ); + int triCount = vertCount / 3; + int vert = 0; + for ( int i = 0; i < triCount; i++ ) + { + fprintf( fp, "3\n" ); + fprintf( fp, "%6.3f %6.3f %6.3f 1 0 0\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z ); + vert++; + fprintf( fp, "%6.3f %6.3f %6.3f 0 1 0\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z ); + vert++; + fprintf( fp, "%6.3f %6.3f %6.3f 0 0 1\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z ); + vert++; + } + fclose( fp ); + physcollision->DestroyDebugMesh( vertCount, outVerts ); +} + + +void DumpCollideToPHY( CPhysCollide *pCollide, CTextBuffer *text, const char *pFilename ) +{ + Msg("Writing %s...\n", pFilename ); + FILE *fp = fopen( pFilename, "wb" ); + phyheader_t header; + header.size = sizeof(header); + header.id = 0; + header.checkSum = 0; + header.solidCount = 1; + fwrite( &header, sizeof(header), 1, fp ); + int size = physcollision->CollideSize( pCollide ); + fwrite( &size, sizeof(int), 1, fp ); + + char *buf = (char *)malloc( size ); + physcollision->CollideWrite( buf, pCollide ); + fwrite( buf, size, 1, fp ); + + fwrite( text->GetData(), text->GetSize(), 1, fp ); + fclose( fp ); + free( buf ); +} + +CPhysCollisionEntry::CPhysCollisionEntry( CPhysCollide *pCollide ) +{ + m_pCollide = pCollide; +} + +unsigned int CPhysCollisionEntry::GetCollisionBinarySize() +{ + return physcollision->CollideSize( m_pCollide ); +} + +unsigned int CPhysCollisionEntry::WriteCollisionBinary( char *pDest ) +{ + return physcollision->CollideWrite( pDest, m_pCollide ); +} + +void CPhysCollisionEntry::DumpCollideFileName( const char *pName, int modelIndex, CTextBuffer *pTextBuffer ) +{ + char tmp[128]; + sprintf( tmp, "%s%03d.phy", pName, modelIndex ); + DumpCollideToPHY( m_pCollide, pTextBuffer, tmp ); + sprintf( tmp, "%s%03d.txt", pName, modelIndex ); + DumpCollideToGlView( m_pCollide, tmp ); +} + + +class CPhysCollisionEntrySolid : public CPhysCollisionEntry +{ +public: + CPhysCollisionEntrySolid( CPhysCollide *pCollide, const char *pMaterialName, float mass ); + + virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + +private: + float m_volume; + float m_mass; + const char *m_pMaterial; +}; + + +CPhysCollisionEntrySolid::CPhysCollisionEntrySolid( CPhysCollide *pCollide, const char *pMaterialName, float mass ) + : CPhysCollisionEntry( pCollide ) +{ + m_volume = physcollision->CollideVolume( m_pCollide ); + m_mass = mass; + m_pMaterial = pMaterialName; +} + +void CPhysCollisionEntrySolid::DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + DumpCollideFileName( "collide", modelIndex, pTextBuffer ); +} + +void CPhysCollisionEntrySolid::WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + pTextBuffer->WriteText( "solid {\n" ); + pTextBuffer->WriteIntKey( "index", collideIndex ); + pTextBuffer->WriteFloatKey( "mass", m_mass ); + if ( m_pMaterial ) + { + pTextBuffer->WriteStringKey( "surfaceprop", m_pMaterial ); + } + if ( m_volume != 0.f ) + { + pTextBuffer->WriteFloatKey( "volume", m_volume ); + } + pTextBuffer->WriteText( "}\n" ); +} + + +class CPhysCollisionEntryStaticSolid : public CPhysCollisionEntry +{ +public: + CPhysCollisionEntryStaticSolid ( CPhysCollide *pCollide, int contentsMask ); + + virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + +private: + int m_contentsMask; +}; + + +CPhysCollisionEntryStaticSolid ::CPhysCollisionEntryStaticSolid ( CPhysCollide *pCollide, int contentsMask ) + : CPhysCollisionEntry( pCollide ), m_contentsMask(contentsMask) +{ +} + +void CPhysCollisionEntryStaticSolid::DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + char tmp[128]; + sprintf( tmp, "static%02d", modelIndex ); + DumpCollideFileName( tmp, collideIndex, pTextBuffer ); +} + +void CPhysCollisionEntryStaticSolid::WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + pTextBuffer->WriteText( "staticsolid {\n" ); + pTextBuffer->WriteIntKey( "index", collideIndex ); + pTextBuffer->WriteIntKey( "contents", m_contentsMask ); + pTextBuffer->WriteText( "}\n" ); +} + +CPhysCollisionEntryStaticMesh::CPhysCollisionEntryStaticMesh( CPhysCollide *pCollide, const char *pMaterialName ) + : CPhysCollisionEntry( pCollide ) +{ + m_pMaterial = pMaterialName; +} + +void CPhysCollisionEntryStaticMesh::DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + char tmp[128]; + sprintf( tmp, "mesh%02d", modelIndex ); + DumpCollideFileName( tmp, collideIndex, pTextBuffer ); +} + +void CPhysCollisionEntryStaticMesh::WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + pTextBuffer->WriteText( "staticsolid {\n" ); + pTextBuffer->WriteIntKey( "index", collideIndex ); + pTextBuffer->WriteText( "}\n" ); +} + +class CPhysCollisionEntryFluid : public CPhysCollisionEntry +{ +public: + ~CPhysCollisionEntryFluid(); + CPhysCollisionEntryFluid( CPhysCollide *pCollide, const char *pSurfaceProp, float damping, const Vector &normal, float dist, int nContents ); + + virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + +private: + char *m_pSurfaceProp; + float m_damping; + Vector m_surfaceNormal; + float m_surfaceDist; + int m_contentsMask; +}; + + +CPhysCollisionEntryFluid::CPhysCollisionEntryFluid( CPhysCollide *pCollide, const char *pSurfaceProp, float damping, const Vector &normal, float dist, int nContents ) + : CPhysCollisionEntry( pCollide ) +{ + m_surfaceNormal = normal; + m_surfaceDist = dist; + m_pSurfaceProp = new char[strlen(pSurfaceProp)+1]; + strcpy( m_pSurfaceProp, pSurfaceProp ); + m_damping = damping; + m_contentsMask = nContents; +} + +CPhysCollisionEntryFluid::~CPhysCollisionEntryFluid() +{ + delete[] m_pSurfaceProp; +} + +void CPhysCollisionEntryFluid::DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + char tmp[128]; + sprintf( tmp, "water%02d", modelIndex ); + DumpCollideFileName( tmp, collideIndex, pTextBuffer ); +} + +void CPhysCollisionEntryFluid::WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) +{ + pTextBuffer->WriteText( "fluid {\n" ); + pTextBuffer->WriteIntKey( "index", collideIndex ); + pTextBuffer->WriteStringKey( "surfaceprop", m_pSurfaceProp ); // write out water material + pTextBuffer->WriteFloatKey( "damping", m_damping ); // write out water damping + pTextBuffer->WriteIntKey( "contents", m_contentsMask ); // write out water contents + float array[4]; + m_surfaceNormal.CopyToArray( array ); + array[3] = m_surfaceDist; + pTextBuffer->WriteFloatArrayKey( "surfaceplane", array, 4 ); // write out water surface plane + pTextBuffer->WriteFloatArrayKey( "currentvelocity", vec3_origin.Base(), 3 ); // write out water velocity + pTextBuffer->WriteText( "}\n" ); +} + +// Get an index into the prop list of this prop (add it if necessary) +static int PropIndex( CUtlVector &propList, int propIndex ) +{ + for ( int i = 0; i < propList.Count(); i++ ) + { + if ( propList[i] == propIndex ) + return i+1; + } + + if ( propList.Count() < 126 ) + { + return propList.AddToTail( propIndex )+1; + } + + return 0; +} + +int RemapWorldMaterial( int materialIndexIn ) +{ + return PropIndex( s_WorldPropList, materialIndexIn ); +} + +typedef struct +{ + float normal[3]; + float dist; +} listplane_t; + +static void AddListPlane( CUtlVector *list, float x, float y, float z, float d ) +{ + listplane_t plane; + plane.normal[0] = x; + plane.normal[1] = y; + plane.normal[2] = z; + plane.dist = d; + + list->AddToTail( plane ); +} + +class CPlaneList +{ +public: + + CPlaneList( float shrink, float merge ); + ~CPlaneList( void ); + + void AddConvex( CPhysConvex *pConvex ); + + // add the brushes to the model + int AddBrushes( void ); + + // Adds a single brush as a convex object + void ReferenceBrush( int brushnumber ); + bool IsBrushReferenced( int brushnumber ); + + void ReferenceLeaf( int leafIndex ); + bool IsLeafReferenced( int leafIndex ); + int GetFirstBrushSide(); + +private: + + CPhysConvex *BuildConvexForBrush( int brushnumber, float shrink, CPhysCollide *pCollideTest, float shrinkMinimum ); + +public: + CUtlVector m_convex; + + CUtlVector m_leafList; + int m_contentsMask; + + float m_shrink; + float m_merge; + bool *m_brushAdded; + float m_totalVolume; +}; + +CPlaneList::CPlaneList( float shrink, float merge ) +{ + m_shrink = shrink; + m_merge = merge; + m_contentsMask = MASK_SOLID; + m_brushAdded = new bool[numbrushes]; + memset( m_brushAdded, 0, sizeof(bool) * numbrushes ); + m_totalVolume = 0; + m_leafList.Purge(); +} + + +CPlaneList::~CPlaneList( void ) +{ + delete[] m_brushAdded; +} + + +void CPlaneList::AddConvex( CPhysConvex *pConvex ) +{ + if ( pConvex ) + { + m_totalVolume += physcollision->ConvexVolume( pConvex ); + m_convex.AddToTail( pConvex ); + } +} + +// Adds a single brush as a convex object +void CPlaneList::ReferenceBrush( int brushnumber ) +{ + if ( !(dbrushes[brushnumber].contents & m_contentsMask) ) + return; + + m_brushAdded[brushnumber] = true; + +} + + +bool CPlaneList::IsBrushReferenced( int brushnumber ) +{ + return m_brushAdded[brushnumber]; +} + +CPhysConvex *CPlaneList::BuildConvexForBrush( int brushnumber, float shrink, CPhysCollide *pCollideTest, float shrinkMinimum ) +{ + CUtlVector temp( 0, 32 ); + + for ( int i = 0; i < dbrushes[brushnumber].numsides; i++ ) + { + dbrushside_t *pside = dbrushsides + i + dbrushes[brushnumber].firstside; + if ( pside->bevel ) + continue; + + dplane_t *pplane = dplanes + pside->planenum; + float shrinkThisPlane = shrink; + + if ( i < g_MainMap->mapbrushes[brushnumber].numsides ) + { + if ( !g_MainMap->mapbrushes[brushnumber].original_sides[i].visible ) + { + // don't shrink brush sides with no visible components. + // this produces something closer to the ideal shrink than simply shrinking all planes + shrinkThisPlane = 0; + } + } + // Make sure shrinking won't swallow geometry along this axis. + if ( pCollideTest && shrinkThisPlane != 0 ) + { + Vector start = physcollision->CollideGetExtent( pCollideTest, vec3_origin, vec3_angle, pplane->normal ); + Vector end = physcollision->CollideGetExtent( pCollideTest, vec3_origin, vec3_angle, -pplane->normal ); + float thick = DotProduct( (end-start), pplane->normal ); + // NOTE: The object must be at least "shrinkMinimum" inches wide on each axis + if ( fabs(thick) < shrinkMinimum ) + { +#if _DEBUG + Warning("Can't shrink brush %d, plane %d (%.2f, %.2f, %.2f)\n", brushnumber, pside->planenum, pplane->normal[0], pplane->normal[1], pplane->normal[2] ); +#endif + shrinkThisPlane = 0; + } + } + AddListPlane( &temp, pplane->normal[0], pplane->normal[1], pplane->normal[2], pplane->dist - shrinkThisPlane ); + } + return physcollision->ConvexFromPlanes( (float *)temp.Base(), temp.Count(), m_merge ); +} + +int CPlaneList::AddBrushes( void ) +{ + int count = 0; + for ( int brushnumber = 0; brushnumber < numbrushes; brushnumber++ ) + { + if ( IsBrushReferenced(brushnumber) ) + { + CPhysConvex *pBrushConvex = NULL; + if ( m_shrink != 0 ) + { + // Make sure shrinking won't swallow this brush. + CPhysConvex *pConvex = BuildConvexForBrush( brushnumber, 0, NULL, 0 ); + CPhysCollide *pUnshrunkCollide = physcollision->ConvertConvexToCollide( &pConvex, 1 ); + pBrushConvex = BuildConvexForBrush( brushnumber, m_shrink, pUnshrunkCollide, m_shrink * 3 ); + physcollision->DestroyCollide( pUnshrunkCollide ); + } + else + { + pBrushConvex = BuildConvexForBrush( brushnumber, m_shrink, NULL, 1.0 ); + } + + if ( pBrushConvex ) + { + count++; + physcollision->SetConvexGameData( pBrushConvex, brushnumber ); + AddConvex( pBrushConvex ); + } + } + } + return count; +} + + +int CPlaneList::GetFirstBrushSide() +{ + for ( int brushnumber = 0; brushnumber < numbrushes; brushnumber++ ) + { + if ( IsBrushReferenced(brushnumber) ) + { + for ( int i = 0; i < dbrushes[brushnumber].numsides; i++ ) + { + int sideIndex = i + dbrushes[brushnumber].firstside; + dbrushside_t *pside = dbrushsides + sideIndex; + if ( pside->bevel ) + continue; + return sideIndex; + } + } + } + return 0; +} + +// UNDONE: Try using this kind of algorithm if we run into precision problems. +// NOTE: ConvexFromPlanes will be doing a bunch of matrix inversions that can suffer +// if plane normals are too close to each other... +#if 0 +void CPlaneList::AddBrushes( void ) +{ + CUtlVector temp; + for ( int brushnumber = 0; brushnumber < numbrushes; brushnumber++ ) + { + if ( IsBrushReferenced(brushnumber) ) + { + CUtlVector windings; + + for ( int i = 0; i < dbrushes[brushnumber].numsides; i++ ) + { + dbrushside_t *pside = dbrushsides + i + dbrushes[brushnumber].firstside; + if (pside->bevel) + continue; + dplane_t *pplane = dplanes + pside->planenum; + winding_t *w = BaseWindingForPlane( pplane->normal, pplane->dist - m_shrink ); + for ( int j = 0; j < dbrushes[brushnumber].numsides && w; j++ ) + { + if (i == j) + continue; + dbrushside_t *pClipSide = dbrushsides + j + dbrushes[brushnumber].firstside; + if (pClipSide->bevel) + continue; + dplane_t *pClipPlane = dplanes + pClipSide->planenum; + ChopWindingInPlace (&w, -pClipPlane->normal, -pClipPlane->dist+m_shrink, 0); //CLIP_EPSILON); + } + if ( w ) + { + windings.AddToTail( w ); + } + } + + CUtlVector vertList; + for ( int p = 0; p < windings.Count(); p++ ) + { + for ( int v = 0; v < windings[p]->numpoints; v++ ) + { + vertList.AddToTail( windings[p]->p + v ); + } + } + CPhysConvex *pConvex = physcollision->ConvexFromVerts( vertList.Base(), vertList.Count() ); + if ( pConvex ) + { + physcollision->SetConvexGameData( pConvex, brushnumber ); + AddConvex( pConvex ); + } + temp.RemoveAll(); + } + } +} +#endif + +// If I have a list of leaves, make sure this leaf is in it. +// Otherwise, process all leaves +bool CPlaneList::IsLeafReferenced( int leafIndex ) +{ + if ( !m_leafList.Count() ) + return true; + + for ( int i = 0; i < m_leafList.Count(); i++ ) + { + if ( m_leafList[i] == leafIndex ) + return true; + } + + return false; +} + +// Add a leaf to my list of interesting leaves +void CPlaneList::ReferenceLeaf( int leafIndex ) +{ + m_leafList.AddToTail( leafIndex ); +} + +static void VisitLeaves_r( CPlaneList &planes, int node ) +{ + if ( node < 0 ) + { + int leafIndex = -1 - node; + if ( planes.IsLeafReferenced(leafIndex) ) + { + int i; + + // Add the solids in the "empty" leaf + for ( i = 0; i < dleafs[leafIndex].numleafbrushes; i++ ) + { + int brushIndex = dleafbrushes[dleafs[leafIndex].firstleafbrush + i]; + planes.ReferenceBrush( brushIndex ); + } + } + } + else + { + dnode_t *pnode = dnodes + node; + + VisitLeaves_r( planes, pnode->children[0] ); + VisitLeaves_r( planes, pnode->children[1] ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +struct waterleaf_t +{ + Vector surfaceNormal; + float surfaceDist; + float minZ; + bool hasSurface; + int waterLeafIndex;// this is the submerged leaf + int planenum; //UNDONE: REMOVE + int surfaceTexInfo; // if hasSurface == true, this is the texinfo index for the water material + int outsideLeafIndex;// this is the leaf on the other side of the water surface + node_t *pNode; +}; + + + +// returns true if newleaf should appear before currentleaf in the list +static bool IsLowerLeaf( const waterleaf_t &newleaf, const waterleaf_t ¤tleaf ) +{ + if ( newleaf.hasSurface && currentleaf.hasSurface ) + { + // the one with the upmost pointing z goes first + if ( currentleaf.surfaceNormal.z > newleaf.surfaceNormal.z ) + return false; + + if ( fabs(currentleaf.surfaceNormal.z - newleaf.surfaceNormal.z) < 0.01 ) + { + if ( newleaf.surfaceDist < currentleaf.surfaceDist ) + return true; + } + return true; + } + else if ( newleaf.hasSurface ) // the leaf with a surface always goes first + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Water surfaces are stored in an RB tree and the tree is used to +// create one-off .vmt files embedded in the .bsp for each surface so that the +// water depth effect occurs on a per-water surface level. +//----------------------------------------------------------------------------- +struct WaterTexInfo +{ + // The mangled new .vmt name ( materials/levelename/oldmaterial_depth_xxx ) where xxx is + // the water depth (as an integer ) + CUtlSymbol m_FullName; + + // The original .vmt name + CUtlSymbol m_MaterialName; + + // The depth of the water this texinfo refers to + int m_nWaterDepth; + + // The texinfo id + int m_nTexInfo; + + // The subdivision size for the water surface +// float m_SubdivSize; +}; + +//----------------------------------------------------------------------------- +// Purpose: Helper for RB tree operations ( we compare full mangled names ) +// Input : src1 - +// src2 - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool WaterLessFunc( WaterTexInfo const& src1, WaterTexInfo const& src2 ) +{ + return src1.m_FullName < src2.m_FullName; +} + +//----------------------------------------------------------------------------- +// Purpose: A growable RB tree of water surfaces +//----------------------------------------------------------------------------- +static CUtlRBTree< WaterTexInfo, int > g_WaterTexInfos( 0, 32, WaterLessFunc ); + +#if 0 +float GetSubdivSizeForFogVolume( int fogVolumeID ) +{ + Assert( fogVolumeID >= 0 && fogVolumeID < g_WaterTexInfos.Count() ); + return g_WaterTexInfos[fogVolumeID].m_SubdivSize; +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *mapname - +// *materialname - +// waterdepth - +// *fullname - +//----------------------------------------------------------------------------- +void GetWaterTextureName( char const *mapname, char const *materialname, int waterdepth, char *fullname ) +{ + char temp[ 512 ]; + + // Construct the full name (prepend mapname to reduce name collisions) + sprintf( temp, "maps/%s/%s_depth_%i", mapname, materialname, (int)waterdepth ); + + // Make sure it's lower case + strlwr( temp ); + + strcpy( fullname, temp ); +} + +//----------------------------------------------------------------------------- +// Purpose: Called to write procedural materials in the rb tree to the embedded +// pak file for this .bsp +//----------------------------------------------------------------------------- +void EmitWaterMaterialFile( WaterTexInfo *wti ) +{ + char waterTextureName[512]; + if ( !wti ) + { + return; + } + + GetWaterTextureName( mapbase, wti->m_MaterialName.String(), ( int )wti->m_nWaterDepth, waterTextureName ); + + // Convert to string + char szDepth[ 32 ]; + sprintf( szDepth, "%i", wti->m_nWaterDepth ); + CreateMaterialPatch( wti->m_MaterialName.String(), waterTextureName, "$waterdepth", szDepth, PATCH_INSERT ); +} + +//----------------------------------------------------------------------------- +// Purpose: Takes the texinfo_t referenced by the .vmt and the computed depth for the +// surface and looks up or creates a texdata/texinfo for the mangled one-off water .vmt file +// Input : *pBaseInfo - +// depth - +// Output : int +//----------------------------------------------------------------------------- +int FindOrCreateWaterTexInfo( texinfo_t *pBaseInfo, float depth ) +{ + char fullname[ 512 ]; + char materialname[ 512 ]; + + // Get the base texture/material name + char const *name = TexDataStringTable_GetString( GetTexData( pBaseInfo->texdata )->nameStringTableID ); + + GetWaterTextureName( mapbase, name, (int)depth, fullname ); + + // See if we already have an entry for this depth + WaterTexInfo lookup; + lookup.m_FullName = fullname; + int idx = g_WaterTexInfos.Find( lookup ); + + // If so, return the existing entry texinfo index + if ( idx != g_WaterTexInfos.InvalidIndex() ) + { + return g_WaterTexInfos[ idx ].m_nTexInfo; + } + + // Otherwise, fill in the rest of the data + lookup.m_nWaterDepth = (int)depth; + // Remember the current material name + sprintf( materialname, "%s", name ); + strlwr( materialname ); + lookup.m_MaterialName = materialname; + + texinfo_t ti; + // Make a copy + ti = *pBaseInfo; + // Create a texdata that is based on the underlying existing entry + ti.texdata = FindAliasedTexData( fullname, GetTexData( pBaseInfo->texdata ) ); + + // Find or create a new index + lookup.m_nTexInfo = FindOrCreateTexInfo( ti ); + + // Add the new texinfo to the RB tree + idx = g_WaterTexInfos.Insert( lookup ); + + // Msg( "created texinfo for %s\n", lookup.m_FullName.String() ); + + // Go ahead and create the new vmt file. + EmitWaterMaterialFile( &g_WaterTexInfos[idx] ); + + // Return the new texinfo + return g_WaterTexInfos[ idx ].m_nTexInfo; +} + +extern node_t *dfacenodes[MAX_MAP_FACES]; +static void WriteFogVolumeIDs( dmodel_t *pModel ) +{ + int i; + + // write fog volume ID to each face in this model + for( i = pModel->firstface; i < pModel->firstface + pModel->numfaces; i++ ) + { + dface_t *pFace = &dfaces[i]; + node_t *pFaceNode = dfacenodes[i]; + texinfo_t *pTexInfo = &texinfo[pFace->texinfo]; + pFace->surfaceFogVolumeID = -1; + if ( pFaceNode ) + { + if ( (pTexInfo->flags & SURF_WARP ) && pFaceNode->planenum == PLANENUM_LEAF && pFaceNode->diskId >= 0 ) + { + pFace->surfaceFogVolumeID = dleafs[pFaceNode->diskId].leafWaterDataID; + dleafwaterdata_t *pLeafWaterData = &dleafwaterdata[pFace->surfaceFogVolumeID]; + + // HACKHACK: Should probably mark these faces as water bottom or "bottommaterial" faces. + // HACKHACK: Use a heuristic, if it points up, it's the water top. + if ( dplanes[pFace->planenum].normal.z > 0 ) + { + pFace->texinfo = pLeafWaterData->surfaceTexInfoID; + } + } + else + { + // missed this face somehow? + Assert( !(pTexInfo->flags & SURF_WARP ) ); + } + + } + } +} + + +static bool PortalCrossesWater( waterleaf_t &baseleaf, portal_t *portal ) +{ + if ( baseleaf.hasSurface ) + { + int side = WindingOnPlaneSide( portal->winding, baseleaf.surfaceNormal, baseleaf.surfaceDist ); + if ( side == SIDE_CROSS || side == SIDE_FRONT ) + return true; + } + + return false; +} + + +static int FindOrCreateLeafWaterData( float surfaceZ, float minZ, int surfaceTexInfoID ) +{ + int i; + for( i = 0; i < numleafwaterdata; i++ ) + { + dleafwaterdata_t *pLeafWaterData = &dleafwaterdata[i]; + if( pLeafWaterData->surfaceZ == surfaceZ && + pLeafWaterData->minZ == minZ && + pLeafWaterData->surfaceTexInfoID == surfaceTexInfoID ) + { + return i; + } + } + dleafwaterdata_t *pLeafWaterData = &dleafwaterdata[numleafwaterdata]; + pLeafWaterData->surfaceZ = surfaceZ; + pLeafWaterData->minZ = minZ; + pLeafWaterData->surfaceTexInfoID = surfaceTexInfoID; + numleafwaterdata++; + return numleafwaterdata - 1; +} + + +// Enumerate all leaves under node with contents in contentsMask and add them to list +void EnumLeaves_r( CUtlVector &list, node_t *node, int contentsMask ) +{ + if ( node->planenum != PLANENUM_LEAF ) + { + EnumLeaves_r( list, node->children[0], contentsMask ); + EnumLeaves_r( list, node->children[1], contentsMask ); + return; + } + + if ( !(node->contents & contentsMask) ) + return; + + + // has the contents, put it in the list + list.AddToTail( node ); +} + + +// Builds a waterleaf_t for the given leaf +static void BuildWaterLeaf( node_t *pLeafIn, waterleaf_t &waterLeafOut ) +{ + waterLeafOut.pNode = pLeafIn; + waterLeafOut.waterLeafIndex = pLeafIn->diskId; + waterLeafOut.outsideLeafIndex = -1; + waterLeafOut.hasSurface = false; + waterLeafOut.surfaceDist = MAX_COORD_INTEGER; + waterLeafOut.surfaceNormal.Init( 0.f, 0.f, 1.f ); + waterLeafOut.planenum = -1; + waterLeafOut.surfaceTexInfo = -1; + waterLeafOut.minZ = MAX_COORD_INTEGER; + + // search the list of portals out of this leaf for one that leaves water + // If you find one, this leaf has a surface, so fill out the surface data + int oppositeNodeIndex = 0; + for (portal_t *p = pLeafIn->portals ; p ; p = p->next[!oppositeNodeIndex]) + { + oppositeNodeIndex = (p->nodes[0] == pLeafIn) ? 1 : 0; + + // not visible, can't be the portals we're looking for... + if ( !p->side ) + continue; + + // See if this portal crosses into air + node_t *pOpposite = p->nodes[oppositeNodeIndex]; + if ( !(pOpposite->contents & MASK_WATER) && !(pOpposite->contents & MASK_SOLID) ) + { + // it does, there must be a surface here + plane_t *plane = &g_MainMap->mapplanes[p->side->planenum]; + if ( waterLeafOut.hasSurface ) + { + // Sort to find the most upward facing normal (skips sides) + if ( waterLeafOut.surfaceNormal.z > plane->normal.z ) + continue; + if ( (waterLeafOut.surfaceNormal.z == plane->normal.z) && waterLeafOut.surfaceDist >= plane->dist ) + continue; + } + // water surface needs to point at least somewhat up, this is + // probably a map error + if ( plane->normal.z <= 0 ) + continue; + waterLeafOut.surfaceDist = plane->dist; + waterLeafOut.surfaceNormal = plane->normal; + waterLeafOut.hasSurface = true; + waterLeafOut.outsideLeafIndex = p->nodes[oppositeNodeIndex]->diskId; + waterLeafOut.surfaceTexInfo = p->side->texinfo; + } + } +} + + +static void InsertSortWaterLeaf( CUtlVector &list, const waterleaf_t &leafInsert ) +{ + // insertion sort the leaf (lowest leaves go first) + // leaves that aren't actually on the surface of the water will have leaf.hasSurface == false. + for ( int i = 0; i < list.Count(); i++ ) + { + if ( IsLowerLeaf( leafInsert, list[i] ) ) + { + list.InsertBefore( i, leafInsert ); + return; + } + } + + // must the highest one, so stick it at the end. + list.AddToTail( leafInsert ); +} + + +// Flood fill the tree, finding neighboring water volumes and connecting them to this list +// Cut groups that try to cross the surface. +// Mark leaves that are in a group as "visited" so they won't be chosen by subsequent fills +static void Flood_FindConnectedWaterVolumes_r( CUtlVector &list, node_t *pLeaf, waterleaf_t &baseleaf, leafbitarray_t &visited ) +{ + // already visited, or not the same water contents + if ( pLeaf->diskId < 0 || visited.Get(pLeaf->diskId) || !(pLeaf->contents & (baseleaf.pNode->contents & MASK_WATER) ) ) + return; + + int oppositeNodeIndex = 0; + for (portal_t *p = pLeaf->portals ; p ; p = p->next[!oppositeNodeIndex]) + { + oppositeNodeIndex = (p->nodes[0] == pLeaf) ? 1 : 0; + + // If any portal crosses the water surface, don't flow through this leaf + if ( PortalCrossesWater( baseleaf, p ) ) + return; + } + + visited.Set( pLeaf->diskId ); + list.AddToTail( pLeaf ); + + baseleaf.minZ = MIN( pLeaf->mins.z, baseleaf.minZ ); + + for (portal_t *p = pLeaf->portals ; p ; p = p->next[!oppositeNodeIndex]) + { + oppositeNodeIndex = (p->nodes[0] == pLeaf) ? 1 : 0; + + Flood_FindConnectedWaterVolumes_r( list, p->nodes[oppositeNodeIndex], baseleaf, visited ); + } +} + +// UNDONE: This is a bit of a hack to avoid crashing when we can't find an +// appropriate texinfo for a water model (to get physics properties) +int FirstWaterTexinfo( bspbrush_t *brushlist, int contents ) +{ + while (brushlist) + { + if ( brushlist->original->contents & contents ) + { + for ( int i = 0; i < brushlist->original->numsides; i++ ) + { + if ( brushlist->original->original_sides[i].contents & contents ) + { + return brushlist->original->original_sides[i].texinfo; + } + } + } + brushlist = brushlist->next; + } + + Assert(0); + return 0; +} + +// This is a list of water data that will be turned into physics models +struct watermodel_t +{ + int modelIndex; + int contents; + waterleaf_t waterLeafData; + int depthTexinfo; + int firstWaterLeafIndex; + int waterLeafCount; + int fogVolumeIndex; +}; + +static CUtlVector g_WaterModels; +static CUtlVector g_WaterLeafList; + +// Creates a list of watermodel_t for later processing by EmitPhysCollision +void EmitWaterVolumesForBSP( dmodel_t *pModel, node_t *node ) +{ + CUtlVector leafListAnyWater; + // build the list of all leaves containing water + EnumLeaves_r( leafListAnyWater, node, MASK_WATER ); + + // make a sorted list to flood fill + CUtlVector list; + + int i; + for ( i = 0; i < leafListAnyWater.Count(); i++ ) + { + waterleaf_t waterLeaf; + BuildWaterLeaf( leafListAnyWater[i], waterLeaf ); + InsertSortWaterLeaf( list, waterLeaf ); + } + + leafbitarray_t visited; + CUtlVector waterAreaList; + for ( i = 0; i < list.Count(); i++ ) + { + Flood_FindConnectedWaterVolumes_r( waterAreaList, list[i].pNode, list[i], visited ); + + // did we find a list of leaves connected to this one? + // remember the list is sorted, so this one may have been attached to a previous + // leaf. So it could have nothing hanging off of it. + if ( waterAreaList.Count() ) + { + // yes, emit a watermodel + watermodel_t tmp; + tmp.modelIndex = nummodels; + tmp.contents = list[i].pNode->contents; + tmp.waterLeafData = list[i]; + tmp.firstWaterLeafIndex = g_WaterLeafList.Count(); + tmp.waterLeafCount = waterAreaList.Count(); + + float waterDepth = tmp.waterLeafData.surfaceDist - tmp.waterLeafData.minZ; + if ( tmp.waterLeafData.surfaceTexInfo < 0 ) + { + // the map has probably leaked in this case, but output something anyway. + Assert(list[i].pNode->planenum == PLANENUM_LEAF); + tmp.waterLeafData.surfaceTexInfo = FirstWaterTexinfo( list[i].pNode->brushlist, tmp.contents ); + } + tmp.depthTexinfo = FindOrCreateWaterTexInfo( &texinfo[ tmp.waterLeafData.surfaceTexInfo ], waterDepth ); + tmp.fogVolumeIndex = FindOrCreateLeafWaterData( tmp.waterLeafData.surfaceDist, tmp.waterLeafData.minZ, tmp.waterLeafData.surfaceTexInfo ); + + for ( int j = 0; j < waterAreaList.Count(); j++ ) + { + g_WaterLeafList.AddToTail( waterAreaList[j]->diskId ); + } + waterAreaList.RemoveAll(); + g_WaterModels.AddToTail( tmp ); + } + } + + WriteFogVolumeIDs( pModel ); +} + + +static void ConvertWaterModelToPhysCollide( CUtlVector &collisionList, int modelIndex, + float shrinkSize, float mergeTolerance ) +{ + dmodel_t *pModel = dmodels + modelIndex; + + for ( int i = 0; i < g_WaterModels.Count(); i++ ) + { + watermodel_t &waterModel = g_WaterModels[i]; + if ( waterModel.modelIndex != modelIndex ) + continue; + + CPlaneList planes( shrinkSize, mergeTolerance ); + int firstLeaf = waterModel.firstWaterLeafIndex; + planes.m_contentsMask = waterModel.contents; + + // push all of the leaves into the collision list + for ( int j = 0; j < waterModel.waterLeafCount; j++ ) + { + int leafIndex = g_WaterLeafList[firstLeaf + j]; + + dleaf_t *pLeaf = dleafs + leafIndex; + // fixup waterdata + pLeaf->leafWaterDataID = waterModel.fogVolumeIndex; + planes.ReferenceLeaf( leafIndex ); + } + + // visit the referenced leaves that belong to this model + VisitLeaves_r( planes, pModel->headnode ); + + // Now add the brushes from those leaves as convex + + // BUGBUG: NOTE: If your map has a brush that crosses the surface, it will be added to two water + // volumes. This only happens with connected water volumes with multiple surface heights + // UNDONE: Right now map makers must cut such brushes. It could be automatically cut by adding the + // surface plane to the list for each brush before calling ConvexFromPlanes() + planes.AddBrushes(); + + int count = planes.m_convex.Count(); + if ( !count ) + continue; + + // Save off the plane of the surface for this group as well as the collision model + // for all convex objects in the group. + CPhysCollide *pCollide = physcollision->ConvertConvexToCollide( planes.m_convex.Base(), count ); + if ( pCollide ) + { + int waterSurfaceTexInfoID = -1; + // use defaults + const char *pSurfaceProp = "water"; + float damping = 0.01; + if ( waterSurfaceTexInfoID >= 0 ) + { + // material override + int texdata = texinfo[waterSurfaceTexInfoID].texdata; + int prop = g_SurfaceProperties[texdata]; + pSurfaceProp = physprops->GetPropName( prop ); + } + + if ( !waterModel.waterLeafData.hasSurface ) + { + waterModel.waterLeafData.surfaceNormal.Init( 0,0,1 ); + Vector top = physcollision->CollideGetExtent( pCollide, vec3_origin, vec3_angle, waterModel.waterLeafData.surfaceNormal ); + waterModel.waterLeafData.surfaceDist = top.z; + } + CPhysCollisionEntryFluid *pCollisionEntryFuild = new CPhysCollisionEntryFluid( pCollide, + pSurfaceProp, damping, waterModel.waterLeafData.surfaceNormal, waterModel.waterLeafData.surfaceDist, waterModel.contents ); + collisionList.AddToTail( pCollisionEntryFuild ); + } + } +} + +// compute a normal for a triangle of the given three points (points are clockwise, normal points out) +static Vector TriangleNormal( const Vector &p0, const Vector &p1, const Vector &p2 ) +{ + Vector e0 = p1 - p0; + Vector e1 = p2 - p0; + Vector normal = CrossProduct( e1, e0 ); + VectorNormalize( normal ); + + return normal; +} + + +// find the side of the brush with the normal closest to the given normal +static dbrushside_t *FindBrushSide( int brushIndex, const Vector &normal ) +{ + dbrush_t *pbrush = &dbrushes[brushIndex]; + dbrushside_t *out = NULL; + float best = -1.f; + + for ( int i = 0; i < pbrush->numsides; i++ ) + { + dbrushside_t *pside = dbrushsides + i + pbrush->firstside; + dplane_t *pplane = dplanes + pside->planenum; + float dot = DotProduct( normal, pplane->normal ); + if ( dot > best ) + { + best = dot; + out = pside; + } + } + + return out; +} + + + +static void ConvertWorldBrushesToPhysCollide( CUtlVector &collisionList, float shrinkSize, float mergeTolerance, int contentsMask ) +{ + CPlaneList planes( shrinkSize, mergeTolerance ); + + planes.m_contentsMask = contentsMask; + + VisitLeaves_r( planes, dmodels[0].headnode ); + planes.AddBrushes(); + + int count = planes.m_convex.Count(); + if ( count ) + { + CPhysCollide *pCollide = physcollision->ConvertConvexToCollide( planes.m_convex.Base(), count ); + + ICollisionQuery *pQuery = physcollision->CreateQueryModel( pCollide ); + int convex = pQuery->ConvexCount(); + for ( int i = 0; i < convex; i++ ) + { + int triCount = pQuery->TriangleCount( i ); + int brushIndex = pQuery->GetGameData( i ); + + Vector points[3]; + for ( int j = 0; j < triCount; j++ ) + { + pQuery->GetTriangleVerts( i, j, points ); + Vector normal = TriangleNormal( points[0], points[1], points[2] ); + dbrushside_t *pside = FindBrushSide( brushIndex, normal ); + if ( pside->texinfo != TEXINFO_NODE ) + { + int prop = g_SurfaceProperties[texinfo[pside->texinfo].texdata]; + pQuery->SetTriangleMaterialIndex( i, j, RemapWorldMaterial( prop ) ); + } + } + } + physcollision->DestroyQueryModel( pQuery ); + pQuery = NULL; + + collisionList.AddToTail( new CPhysCollisionEntryStaticSolid( pCollide, contentsMask ) ); + } +} + +// adds any world, terrain, and water collision models to the collision list +static void BuildWorldPhysModel( CUtlVector &collisionList, float shrinkSize, float mergeTolerance ) +{ + ConvertWorldBrushesToPhysCollide( collisionList, shrinkSize, mergeTolerance, MASK_SOLID & (~CONTENTS_GRATE) ); + ConvertWorldBrushesToPhysCollide( collisionList, shrinkSize, mergeTolerance, CONTENTS_GRATE ); + ConvertWorldBrushesToPhysCollide( collisionList, shrinkSize, mergeTolerance, CONTENTS_PLAYERCLIP ); + ConvertWorldBrushesToPhysCollide( collisionList, shrinkSize, mergeTolerance, CONTENTS_MONSTERCLIP ); + + // if there's terrain, save it off as a static mesh/polysoup + if ( g_bNoVirtualMesh || !physcollision->SupportsVirtualMesh() ) + { + Disp_AddCollisionModels( collisionList, &dmodels[0], MASK_SOLID ); + } + else + { + Disp_BuildVirtualMesh( MASK_SOLID ); + } + ConvertWaterModelToPhysCollide( collisionList, 0, shrinkSize, mergeTolerance ); +} + + +// adds a collision entry for this brush model +static void ConvertModelToPhysCollide( CUtlVector &collisionList, int modelIndex, int contents, float shrinkSize, float mergeTolerance ) +{ + int i; + CPlaneList planes( shrinkSize, mergeTolerance ); + + planes.m_contentsMask = contents; + + dmodel_t *pModel = dmodels + modelIndex; + VisitLeaves_r( planes, pModel->headnode ); + planes.AddBrushes(); + int count = planes.m_convex.Count(); + convertconvexparams_t params; + params.Defaults(); + params.buildOuterConvexHull = count > 1 ? true : false; + params.buildDragAxisAreas = true; + Vector size = pModel->maxs - pModel->mins; + + float minSurfaceArea = -1.0f; + for ( i = 0; i < 3; i++ ) + { + int other = (i+1)%3; + int cross = (i+2)%3; + float surfaceArea = size[other] * size[cross]; + if ( minSurfaceArea < 0 || surfaceArea < minSurfaceArea ) + { + minSurfaceArea = surfaceArea; + } + } + // this can be really slow with super-large models and a low error tolerance + // Basically you get a ray cast through each square of epsilon surface area on each OBB side + // So compute it for 1% error (on the smallest side, less on larger sides) + params.dragAreaEpsilon = clamp( minSurfaceArea * 1e-2f, 1.0f, 1024.0f ); + CPhysCollide *pCollide = physcollision->ConvertConvexToCollideParams( planes.m_convex.Base(), count, params ); + + if ( !pCollide ) + return; + + struct + { + int prop; + float area; + } proplist[256]; + int numprops = 1; + + proplist[0].prop = -1; + proplist[0].area = 1; + // compute the array of props on the surface of this model + + // NODRAW brushes no longer have any faces + if ( !dmodels[modelIndex].numfaces ) + { + int sideIndex = planes.GetFirstBrushSide(); + int texdata = texinfo[dbrushsides[sideIndex].texinfo].texdata; + int prop = g_SurfaceProperties[texdata]; + proplist[numprops].prop = prop; + proplist[numprops].area = 2; + numprops++; + } + + for ( i = 0; i < dmodels[modelIndex].numfaces; i++ ) + { + dface_t *face = dfaces + i + dmodels[modelIndex].firstface; + int texdata = texinfo[face->texinfo].texdata; + int prop = g_SurfaceProperties[texdata]; + int j; + for ( j = 0; j < numprops; j++ ) + { + if ( proplist[j].prop == prop ) + { + proplist[j].area += face->area; + break; + } + } + + if ( (!numprops || j >= numprops) && numprops < ARRAYSIZE(proplist) ) + { + proplist[numprops].prop = prop; + proplist[numprops].area = face->area; + numprops++; + } + } + + + // choose the prop with the most surface area + int maxIndex = -1; + float maxArea = 0; + float totalArea = 0; + + for ( i = 0; i < numprops; i++ ) + { + if ( proplist[i].area > maxArea ) + { + maxIndex = i; + maxArea = proplist[i].area; + } + // add up the total surface area + totalArea += proplist[i].area; + } + + float mass = 1.0f; + const char *pMaterial = "default"; + if ( maxIndex >= 0 ) + { + int prop = proplist[maxIndex].prop; + + // use default if this material has no prop + if ( prop < 0 ) + prop = 0; + + pMaterial = physprops->GetPropName( prop ); + float density, thickness; + physprops->GetPhysicsProperties( prop, &density, &thickness, NULL, NULL ); + + // if this is a "shell" material (it is hollow and encloses some empty space) + // compute the mass with a constant surface thickness + if ( thickness != 0 ) + { + mass = totalArea * thickness * density * CUBIC_METERS_PER_CUBIC_INCH; + } + else + { + // material is completely solid, compute total mass as if constant density throughout. + mass = planes.m_totalVolume * density * CUBIC_METERS_PER_CUBIC_INCH; + } + } + + // Clamp mass to 100,000 kg + if ( mass > VPHYSICS_MAX_MASS ) + { + mass = VPHYSICS_MAX_MASS; + } + + collisionList.AddToTail( new CPhysCollisionEntrySolid( pCollide, pMaterial, mass ) ); +} + +static void ClearLeafWaterData( void ) +{ + int i; + + for( i = 0; i < numleafs; i++ ) + { + dleafs[i].leafWaterDataID = -1; + dleafs[i].contents &= ~CONTENTS_TESTFOGVOLUME; + } +} + + +// This is the only public entry to this file. +// The global data touched in the file is: +// from bsplib.h: +// g_pPhysCollide : This is an output from this file. +// g_PhysCollideSize : This is set in this file. +// g_numdispinfo : This is an input to this file. +// g_dispinfo : This is an input to this file. +// numnodewaterdata : This is an output from this file. +// dleafwaterdata : This is an output from this file. +// from vbsp.h: +// g_SurfaceProperties : This is an input to this file. +void EmitPhysCollision() +{ + ClearLeafWaterData(); + + CreateInterfaceFn physicsFactory = GetPhysicsFactory(); + if ( physicsFactory ) + { + physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL ); + } + + if ( !physcollision ) + { + Warning("!!! WARNING: Can't build collision data!\n" ); + return; + } + + CUtlVector collisionList[MAX_MAP_MODELS]; + CTextBuffer *pTextBuffer[MAX_MAP_MODELS]; + + int physModelCount = 0, totalSize = 0; + + int start = Plat_FloatTime(); + + Msg("Building Physics collision data...\n" ); + + int i, j; + for ( i = 0; i < nummodels; i++ ) + { + // Build a list of collision models for this brush model section + if ( i == 0 ) + { + // world is the only model that processes water separately. + // other brushes are assumed to be completely solid or completely liquid + BuildWorldPhysModel( collisionList[i], NO_SHRINK, VPHYSICS_MERGE); + } + else + { + ConvertModelToPhysCollide( collisionList[i], i, MASK_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|MASK_WATER, VPHYSICS_SHRINK, VPHYSICS_MERGE ); + } + + pTextBuffer[i] = NULL; + if ( !collisionList[i].Count() ) + continue; + + // if we've got collision models, write their script for processing in the game + pTextBuffer[i] = new CTextBuffer; + for ( j = 0; j < collisionList[i].Count(); j++ ) + { + // dump a text file for visualization + if ( dumpcollide ) + { + collisionList[i][j]->DumpCollide( pTextBuffer[i], i, j ); + } + // each model knows how to write its script + collisionList[i][j]->WriteToTextBuffer( pTextBuffer[i], i, j ); + // total up the binary section's size + totalSize += collisionList[i][j]->GetCollisionBinarySize() + sizeof(int); + } + + // These sections only appear in the world's collision text + if ( i == 0 ) + { + if ( !g_bNoVirtualMesh && physcollision->SupportsVirtualMesh() ) + { + pTextBuffer[i]->WriteText("virtualterrain {}\n"); + } + if ( s_WorldPropList.Count() ) + { + pTextBuffer[i]->WriteText( "materialtable {\n" ); + for ( j = 0; j < s_WorldPropList.Count(); j++ ) + { + int propIndex = s_WorldPropList[j]; + if ( propIndex < 0 ) + { + pTextBuffer[i]->WriteIntKey( "default", j+1 ); + } + else + { + pTextBuffer[i]->WriteIntKey( physprops->GetPropName( propIndex ), j+1 ); + } + } + pTextBuffer[i]->WriteText( "}\n" ); + } + } + + pTextBuffer[i]->Terminate(); + + // total lump size includes the text buffers (scripts) + totalSize += pTextBuffer[i]->GetSize(); + + physModelCount++; + } + + // add one for tail of list marker + physModelCount++; + + // DWORD align the lump because AddLump assumes that it is DWORD aligned. + byte *ptr ; + g_PhysCollideSize = totalSize + (physModelCount * sizeof(dphysmodel_t)); + g_pPhysCollide = (byte *)malloc(( g_PhysCollideSize + 3 ) & ~3 ); + memset( g_pPhysCollide, 0, g_PhysCollideSize ); + ptr = g_pPhysCollide; + + for ( i = 0; i < nummodels; i++ ) + { + if ( pTextBuffer[i] ) + { + int j; + + dphysmodel_t model; + + model.modelIndex = i; + model.solidCount = collisionList[i].Count(); + model.dataSize = sizeof(int) * model.solidCount; + + for ( j = 0; j < model.solidCount; j++ ) + { + model.dataSize += collisionList[i][j]->GetCollisionBinarySize(); + } + model.keydataSize = pTextBuffer[i]->GetSize(); + + // store the header + memcpy( ptr, &model, sizeof(model) ); + ptr += sizeof(model); + + for ( j = 0; j < model.solidCount; j++ ) + { + int collideSize = collisionList[i][j]->GetCollisionBinarySize(); + + // write size + memcpy( ptr, &collideSize, sizeof(int) ); + ptr += sizeof(int); + + // now write the collision model + collisionList[i][j]->WriteCollisionBinary( reinterpret_cast(ptr) ); + ptr += collideSize; + } + + memcpy( ptr, pTextBuffer[i]->GetData(), pTextBuffer[i]->GetSize() ); + ptr += pTextBuffer[i]->GetSize(); + } + + delete pTextBuffer[i]; + } + + dphysmodel_t model; + + // Mark end of list + model.modelIndex = -1; + model.dataSize = -1; + model.keydataSize = 0; + model.solidCount = 0; + memcpy( ptr, &model, sizeof(model) ); + ptr += sizeof(model); + Assert( (ptr-g_pPhysCollide) == g_PhysCollideSize); + Msg("done (%d) (%d bytes)\n", (int)(Plat_FloatTime() - start), g_PhysCollideSize ); + + // UNDONE: Collision models (collisionList) memory leak! +} diff --git a/utils/vbsp/ivp.h b/utils/vbsp/ivp.h new file mode 100644 index 000000000..88598f5ab --- /dev/null +++ b/utils/vbsp/ivp.h @@ -0,0 +1,75 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IVP_H +#define IVP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +class CPhysCollide; +class CTextBuffer; +class IPhysicsCollision; +extern IPhysicsCollision *physcollision; + +// a list of all of the materials in the world model +extern int RemapWorldMaterial( int materialIndexIn ); + +class CPhysCollisionEntry +{ +public: + CPhysCollisionEntry( CPhysCollide *pCollide ); + + virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) = 0; + virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ) = 0; + + unsigned int GetCollisionBinarySize(); + unsigned int WriteCollisionBinary( char *pDest ); + +protected: + void DumpCollideFileName( const char *pName, int modelIndex, CTextBuffer *pTextBuffer ); + +protected: + CPhysCollide *m_pCollide; +}; + +class CPhysCollisionEntryStaticMesh : public CPhysCollisionEntry +{ +public: + CPhysCollisionEntryStaticMesh( CPhysCollide *pCollide, const char *pMaterialName ); + + virtual void WriteToTextBuffer( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + virtual void DumpCollide( CTextBuffer *pTextBuffer, int modelIndex, int collideIndex ); + +private: + const char *m_pMaterial; +}; + + +class CTextBuffer +{ +public: + CTextBuffer( void ); + ~CTextBuffer( void ); + inline int GetSize( void ) { return m_buffer.Count(); } + inline char *GetData( void ) { return m_buffer.Base(); } + + void WriteText( const char *pText ); + void WriteIntKey( const char *pKeyName, int outputData ); + void WriteStringKey( const char *pKeyName, const char *outputData ); + void WriteFloatKey( const char *pKeyName, float outputData ); + void WriteFloatArrayKey( const char *pKeyName, const float *outputData, int count ); + + void CopyStringQuotes( const char *pString ); + void Terminate( void ); +private: + void CopyData( const char *pData, int len ); + CUtlVector m_buffer; +}; + +#endif // IVP_H diff --git a/utils/vbsp/writebsp.cpp b/utils/vbsp/writebsp.cpp index 687bbbf74..005990d64 100644 --- a/utils/vbsp/writebsp.cpp +++ b/utils/vbsp/writebsp.cpp @@ -931,7 +931,7 @@ void WriteBSP (node_t *headnode, face_t *pLeafFaceList ) } } -// EmitWaterVolumesForBSP( &dmodels[nummodels], headnode ); + EmitWaterVolumesForBSP( &dmodels[nummodels], headnode ); qprintf ("%5i nodes with faces\n", c_facenodes); qprintf ("%5i nodes without faces\n", c_nofaces); qprintf ("%5i faces\n", numfaces-oldfaces); @@ -1257,7 +1257,7 @@ void EndBSPFile (void) OverlayTransition_EmitOverlayFaces(); // phys collision needs dispinfo to operate (needs to generate phys collision for displacement surfs) -// EmitPhysCollision(); + EmitPhysCollision(); // We can't calculate this properly until vvis (since we need vis to do this), so we set // to zero everywhere by default. diff --git a/utils/vbsp/wscript b/utils/vbsp/wscript index bb5334740..cefff4e13 100755 --- a/utils/vbsp/wscript +++ b/utils/vbsp/wscript @@ -24,8 +24,10 @@ def build(bld): 'detail.cpp', 'detailobjects.cpp', 'disp_vbsp.cpp', + 'disp_ivp.cpp', 'faces.cpp', 'glfile.cpp', + 'ivp.cpp', 'leakfile.cpp', 'map.cpp', 'manifest.cpp', diff --git a/wscript b/wscript index ddf8b9f3c..ababfe848 100644 --- a/wscript +++ b/wscript @@ -8,7 +8,7 @@ from waflib import Logs, Context, Configure import sys import os -VERSION = '1.0' +VERSION = '1.17' APPNAME = 'source-engine' top = '.' @@ -174,29 +174,26 @@ def define_platform(conf): if conf.options.ALLOW64: conf.define('PLATFORM_64BITS', 1) - conf.env.projects = ['base'] - conf.env.targets = [] + conf.env.targets = projects['base'] if conf.options.DEDICATED: conf.env.DEDICATED = True - conf.env.projects += ['dedicated'] + conf.env.targets += projects['dedicated'] conf.options.SDL = False conf.define('DEDICATED', 1) if conf.options.LAUNCHER: - conf.env.projects += ['main'] + conf.env.targets += projects['main'] conf.env.GL = conf.options.GL or conf.options.TOGLES if conf.options.TOGLES: conf.env.TOGLES = True - conf.env.targets += ['togles'] conf.env.append_unique('DEFINES', ['TOGLES']) if conf.env.GL: - if not conf.env.TOGLES: - conf.env.targets += ['togl'] conf.env.append_unique('DEFINES', [ 'DX_TO_GL_ABSTRACTION', 'GL_GLEXT_PROTOTYPES', 'BINK_VIDEO' ]) + conf.env.targets += ['togles' if conf.env.TOGLES else 'togl'] if conf.options.SDL: conf.env.SDL = True @@ -204,11 +201,11 @@ def define_platform(conf): if conf.options.TESTS: conf.env.TESTS = True - conf.env.projects += ['tests'] + conf.env.targets += projects['tests'] conf.define('UNITTESTS', 1) if conf.options.UTILS: - conf.env.projects += ['utils'] + conf.env.targets += projects['utils'] if conf.env.DEST_OS == 'win32' and not conf.env.TESTS: conf.env.targets += ['utils/bzip2'] @@ -458,7 +455,8 @@ def configure(conf): conf.load('mm_hook') define_platform(conf) - conf.define('GIT_COMMIT_HASH', conf.env.GIT_VERSION) + conf.env.targets = set(conf.env.targets) + conf.env.REL_VERSION = VERSION conf.env.BIT32_MANDATORY = not conf.options.ALLOW64 if conf.env.BIT32_MANDATORY: @@ -612,21 +610,16 @@ def configure(conf): conf.env.CC.insert(0, 'ccache') conf.env.CXX.insert(0, 'ccache') - for proj in conf.env.projects: - conf.add_subproject(projects[proj]) - for targ in conf.env.targets: - conf.add_subproject(targ) + conf.add_subproject(conf.env.targets) def build(bld): - os.environ["CCACHE_DIR"] = os.path.abspath('.ccache/'+bld.env.COMPILER_CC+'/'+bld.env.DEST_OS+'/'+bld.env.DEST_CPU) + if not os.environ.get('CCACHE_DIR'): + os.environ['CCACHE_DIR'] = os.path.abspath('.ccache/'+bld.env.COMPILER_CC+'/'+bld.env.DEST_OS+'/'+bld.env.DEST_CPU) if bld.env.DEST_OS in ['win32', 'android']: sdl_name = 'SDL2.dll' if bld.env.DEST_OS == 'win32' else 'libSDL2.so' sdl_path = os.path.join('lib', bld.env.DEST_OS, bld.env.DEST_CPU, sdl_name) bld.install_files(bld.env.LIBDIR, [sdl_path]) - for proj in bld.env.projects: - bld.add_subproject(projects[proj]) - for targ in bld.env.targets: - bld.add_subproject(targ) + bld.add_subproject(bld.env.targets) From 8241777248be09cf3c1651149e66448222c0632d Mon Sep 17 00:00:00 2001 From: Er2 Date: Fri, 12 May 2023 21:13:27 +0300 Subject: [PATCH 06/11] lol --- utils/vrad/wscript | 1 - wscript | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/vrad/wscript b/utils/vrad/wscript index a3b85479e..7b6779a53 100755 --- a/utils/vrad/wscript +++ b/utils/vrad/wscript @@ -13,7 +13,6 @@ def options(opt): return def configure(conf): - conf.define('PROTECTED_THINGS_DISABLE', 1) conf.define('VRAD', 1) conf.define('MAX_TOOL_THREADS', 1) conf.define('THREADINDEX_MAIN', 0) diff --git a/wscript b/wscript index ababfe848..a1d448e68 100644 --- a/wscript +++ b/wscript @@ -455,7 +455,7 @@ def configure(conf): conf.load('mm_hook') define_platform(conf) - conf.env.targets = set(conf.env.targets) + conf.env.targets = list(set(conf.env.targets)) conf.env.REL_VERSION = VERSION conf.env.BIT32_MANDATORY = not conf.options.ALLOW64 From d4ca49ff1ac67111c095a27d8bd144df8a7ac431 Mon Sep 17 00:00:00 2001 From: Er2 Date: Sat, 13 May 2023 21:11:15 +0300 Subject: [PATCH 07/11] use vrad from kisak strike and fix wscript --- .github/workflows/build.yml | 10 +- materialsystem/cmaterialsystem.cpp | 2 +- utils/common/cmdlib.cpp | 2 +- utils/common/filesystem_tools.cpp | 2 + utils/vbsp/writebsp.cpp | 2 +- utils/vrad/leaf_ambient_lighting.cpp | 6 +- utils/vrad/lightmap.cpp | 717 +++++++-- utils/vrad/lightmap.h | 5 + utils/vrad/mpivrad.cpp | 12 +- utils/vrad/mpivrad.h | 3 - utils/vrad/radial.cpp | 20 +- utils/vrad/trace.cpp | 177 ++- utils/vrad/vismat.cpp | 39 +- utils/vrad/vrad.cpp | 347 +++-- utils/vrad/vrad.h | 55 +- utils/vrad/vrad_dispcoll.cpp | 19 +- utils/vrad/vraddetailprops.cpp | 405 ++++- utils/vrad/vraddisps.cpp | 69 +- utils/vrad/vradstaticprops.cpp | 2053 ++++++++++++++------------ wscript | 4 +- 20 files changed, 2619 insertions(+), 1330 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 222b081e1..660986132 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - name: Build linux-i386 run: | - scripts/build-ubuntu-i386.sh + scripts/build-ubuntu-i386.sh -u build-linux-amd64: runs-on: ubuntu-20.04 @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v2 - name: Build linux-amd64 run: | - scripts/build-ubuntu-amd64.sh + scripts/build-ubuntu-amd64.sh -u build-android-armv7a: runs-on: ubuntu-20.04 @@ -38,7 +38,7 @@ jobs: - name: Build windows-i386 run: | git submodule init && git submodule update - ./waf.bat configure -T debug + ./waf.bat configure -T debug -u ./waf.bat build build-windows-amd64: @@ -49,7 +49,7 @@ jobs: - name: Build windows-amd64 run: | git submodule init && git submodule update - ./waf.bat configure -T debug -8 + ./waf.bat configure -T debug -8 -u ./waf.bat build build-dedicated-windows-i386: @@ -99,7 +99,7 @@ jobs: - uses: actions/checkout@v2 - name: Build macos-amd64 run: | - scripts/build-macos-amd64.sh + scripts/build-macos-amd64.sh -u build-dedicated-macos-amd64: runs-on: macos-latest diff --git a/materialsystem/cmaterialsystem.cpp b/materialsystem/cmaterialsystem.cpp index e7870712f..75676b3c5 100644 --- a/materialsystem/cmaterialsystem.cpp +++ b/materialsystem/cmaterialsystem.cpp @@ -672,7 +672,7 @@ bool CMaterialSystem::Connect( CreateInterfaceFn factory ) g_pLauncherMgr = (ILauncherMgr *)factory( "SDLMgrInterface001" /*SDL_MGR_INTERFACE_VERSION*/, NULL ); if ( !g_pLauncherMgr ) { - return false; + Warning("Cannot connect SDL!\n"); } #endif // USE_SDL #endif // !DEDICATED diff --git a/utils/common/cmdlib.cpp b/utils/common/cmdlib.cpp index 5ab2267a4..103f170e2 100644 --- a/utils/common/cmdlib.cpp +++ b/utils/common/cmdlib.cpp @@ -803,7 +803,7 @@ FileHandle_t SafeOpenRead( const char *filename ) void SafeRead( FileHandle_t f, void *buffer, int count) { if ( g_pFileSystem->Read (buffer, count, f) != (size_t)count) - Error ("File read failure"); + Error ("File read failure\n"); } diff --git a/utils/common/filesystem_tools.cpp b/utils/common/filesystem_tools.cpp index 9401c4ad6..a06dc33cb 100644 --- a/utils/common/filesystem_tools.cpp +++ b/utils/common/filesystem_tools.cpp @@ -62,7 +62,9 @@ void FileSystem_SetupStandardDirectories( const char *pFilename, const char *pGa Q_MakeAbsolutePath( qdir, sizeof( qdir ), pFilename, NULL ); Q_StripFilename( qdir ); +#ifdef _WIN32 // lol Q_strlower( qdir ); +#endif if ( qdir[0] != 0 ) { Q_AppendSlash( qdir, sizeof( qdir ) ); diff --git a/utils/vbsp/writebsp.cpp b/utils/vbsp/writebsp.cpp index 005990d64..bb7d0216d 100644 --- a/utils/vbsp/writebsp.cpp +++ b/utils/vbsp/writebsp.cpp @@ -966,7 +966,7 @@ void SetModelNumbers (void) } else { - sprintf (value, ""); + value[0] = '\0'; } SetKeyValue (&entities[i], "model", value); } diff --git a/utils/vrad/leaf_ambient_lighting.cpp b/utils/vrad/leaf_ambient_lighting.cpp index 507e0a511..502014f97 100644 --- a/utils/vrad/leaf_ambient_lighting.cpp +++ b/utils/vrad/leaf_ambient_lighting.cpp @@ -193,8 +193,8 @@ bool IsLeafAmbientSurfaceLight( dworldlight_t *wl ) if ( wl->style != 0 ) return false; - float intensity = MAX( wl->intensity[0], wl->intensity[1] ); - intensity = MAX( intensity, wl->intensity[2] ); + float intensity = max( wl->intensity[0], wl->intensity[1] ); + intensity = max( intensity, wl->intensity[2] ); return (intensity * g_flWorldLightMinEmitSurfaceDistanceRatio) < g_flWorldLightMinEmitSurface; } @@ -650,7 +650,7 @@ void ComputePerLeafAmbientLighting() { // Distribute the work among the workers. VMPI_SetCurrentStage( "ComputeLeafAmbientLighting" ); - DistributeWork( numleafs, VMPI_DISTRIBUTEWORK_PACKETID, VMPI_ProcessLeafAmbient, VMPI_ReceiveLeafAmbientResults ); + DistributeWork( numleafs, VMPI_ProcessLeafAmbient, VMPI_ReceiveLeafAmbientResults ); } else #endif diff --git a/utils/vrad/lightmap.cpp b/utils/vrad/lightmap.cpp index 661012626..ebb873455 100644 --- a/utils/vrad/lightmap.cpp +++ b/utils/vrad/lightmap.cpp @@ -33,6 +33,120 @@ enum #define SMOOTHING_GROUP_HARD_EDGE 0xff000000 +//==========================================================================// +// Ambient occlusion +//==========================================================================// +bool g_bNoSoften = false; +bool g_bNoAO = false; + +float CalculateAmbientOcclusion( Vector *pPosition, Vector *pNormal ) +{ + // Just call through to the simd version of this function + FourVectors position4; + position4.DuplicateVector( *pPosition ); + + FourVectors normal4; + position4.DuplicateVector( *pNormal ); + + fltx4 ao = CalculateAmbientOcclusion4( position4, normal4, -1 ); + + return SubFloat( ao, 0 ); +} + +inline FourVectors Mul( const FourVectors &a, const fltx4 &b ) +{ + FourVectors ret; + ret.x = MulSIMD( a.x, b ); + ret.y = MulSIMD( a.y, b ); + ret.z = MulSIMD( a.z, b ); + return ret; +} +inline FourVectors operator+( const FourVectors &a, const FourVectors &b ) +{ + FourVectors ret; + ret.x = AddSIMD( a.x, b.x ); + ret.y = AddSIMD( a.y, b.y ); + ret.z = AddSIMD( a.z, b.z ); + return ret; +} +inline FourVectors operator-(const FourVectors &a, const FourVectors &b) +{ + FourVectors ret; + ret.x=SubSIMD(a.x,b.x); + ret.y=SubSIMD(a.y,b.y); + ret.z=SubSIMD(a.z,b.z); + return ret; +} + +fltx4 CalculateAmbientOcclusion4( const FourVectors &position4, const FourVectors &normal4, int static_prop_index_to_ignore ) +{ + if ( g_bNoAO ) + { + return Four_Ones; + } + + DirectionalSampler_t sampler; + int nSamples = 32; + if ( do_fast ) + { + nSamples /= 2; + } + + fltx4 totalVisible = Four_Zeros; + fltx4 totalPossibleVisible = Four_Zeros; + for ( int i = 0; i < nSamples; i++ ) + { + FourVectors rayStart = position4; + rayStart += normal4; + + // Ray direction on the sphere + FourVectors rayDirection; + rayDirection.DuplicateVector( sampler.NextValue() ); + + // Mirror ray along normal so all rays are on the hemisphere defined by the normal + fltx4 rayDotN = rayDirection * normal4; // dot product + fltx4 absRayDotN = fabs( rayDotN ); + rayDirection = rayDirection - Mul( normal4, rayDotN ) + Mul( normal4, absRayDotN ); + + // Set length of ray + FourVectors rayEnd = rayDirection; + rayEnd *= 36.0f; + rayEnd += rayStart; + + // Raytrace for visibility function + fltx4 fractionVisible = Four_Ones; + TestLine_IgnoreSky( rayStart, rayEnd, &fractionVisible, static_prop_index_to_ignore ); + totalVisible = AddSIMD( totalVisible, MulSIMD( fractionVisible, absRayDotN ) ); + totalPossibleVisible = AddSIMD( totalPossibleVisible, absRayDotN ); + } + + fltx4 ao = DivSIMD( totalVisible, totalPossibleVisible ); + ao = MulSIMD( ao, ao ); // Square ao term - This is an artistic choice by the CS:GO team + return ao; +} + +//==========================================================================// +// Give surfaces a softer look instead of the harsher linear N.L look +//==========================================================================// +float SoftenCosineTerm( float flDot ) +{ + if ( g_bNoSoften ) + return flDot; + + flDot = MAX( flDot, 0.0f ); + return ( flDot + ( flDot * flDot ) ) * 0.5f; // This is cheaper than an exponent in shader code +} + +fltx4 SoftenCosineTerm( fltx4 dots ) +{ + if ( g_bNoSoften ) + return dots; + + dots = MaxSIMD( dots, Four_Zeros ); + fltx4 dotsSquared = MulSIMD( dots, dots ); + return MulSIMD( AddSIMD( dots, dotsSquared ), Four_PointFives ); +} + //==========================================================================// // CNormalList. //==========================================================================// @@ -98,7 +212,7 @@ int CNormalList::FindOrAddNormal( Vector const &vNormal ) // Look for a matching vector in there. CUtlVector *pGridElement = &m_NormalGrid[gi[0]][gi[1]][gi[2]]; - for( int i=0; i < pGridElement->Size(); i++ ) + for( int i=0; i < pGridElement->Count(); i++ ) { int iNormal = pGridElement->Element(i); @@ -109,7 +223,7 @@ int CNormalList::FindOrAddNormal( Vector const &vNormal ) } // Ok, add a new one. - pGridElement->AddToTail( m_Normals.Size() ); + pGridElement->AddToTail( m_Normals.Count() ); return m_Normals.AddToTail( vNormal ); } @@ -364,14 +478,14 @@ void SaveVertexNormals( void ) } } - if( normalList.m_Normals.Size() > MAX_MAP_VERTNORMALS ) + if( normalList.m_Normals.Count() > MAX_MAP_VERTNORMALS ) { Error( "g_numvertnormals > MAX_MAP_VERTNORMALS" ); } // Copy the list of unique vert normals into g_vertnormals. - g_numvertnormals = normalList.m_Normals.Size(); - memcpy( g_vertnormals, normalList.m_Normals.Base(), sizeof(g_vertnormals[0]) * normalList.m_Normals.Size() ); + g_numvertnormals = normalList.m_Normals.Count(); + memcpy( g_vertnormals, normalList.m_Normals.Base(), sizeof(g_vertnormals[0]) * normalList.m_Normals.Count() ); } /* @@ -410,7 +524,7 @@ void ErrorLightInfo(const char *s, lightinfo_t *l) // else { - Warning("%s at (degenerate face)\n\tmaterial=%s\n", s, TexDataStringTable_GetString( dtexdata[tex->texdata].nameStringTableID )); + Warning("%s at (degenerate face)\n\tmaterial=%s\n", TexDataStringTable_GetString( dtexdata[tex->texdata].nameStringTableID )); } } @@ -1130,8 +1244,22 @@ static void ParseLightGeneric( entity_t *e, directlight_t *dl ) Vector dest; dl->light.style = (int)FloatForKey (e, "style"); - - // get intenfsity + dl->m_bSkyLightIsDirectionalLight = false; + + if( (int)FloatForKeyWithDefault(e, "_castentityshadow", 1.0f ) != 0 ) + { + dl->light.flags |= DWL_FLAGS_CASTENTITYSHADOWS; + } + else + { + dl->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS; + } + + Vector shadowOffset( 0.0f, 0.0f, 0.0f ); + GetVectorForKey (e, "_shadoworiginoffset", shadowOffset ); + dl->light.shadow_cast_offset = shadowOffset; + + // get intensity if( g_bHDR && LightForKey( e, "_lightHDR", dl->light.intensity ) ) { } @@ -1172,90 +1300,102 @@ static void ParseLightGeneric( entity_t *e, directlight_t *dl ) static void SetLightFalloffParams( entity_t * e, directlight_t * dl ) { - float d50=FloatForKey( e, "_fifty_percent_distance" ); dl->m_flStartFadeDistance = 0; dl->m_flEndFadeDistance = - 1; dl->m_flCapDist = 1.0e22; - if ( d50 ) + if ( g_bFiniteFalloffModel ) { float d0 = FloatForKey( e, "_zero_percent_distance" ); - if ( d0 < d50 ) - { - Warning( "light has _fifty_percent_distance of %f but _zero_percent_distance of %f\n", d50, d0); - d0 = 2.0 * d50; - } - float a = 0, b = 1, c = 0; - if ( ! SolveInverseQuadraticMonotonic( 0, 1.0, d50, 2.0, d0, 256.0, a, b, c )) + dl->light.constant_attn = 1.0; + dl->light.linear_attn = 0; //-2.0 * ( 1.0 / d0 ); + dl->light.quadratic_attn = -1.0 / ( d0 * d0 ); +// for(float d=0;d<200;d+=20) +// printf("at %f, %f\n",d,1.0+d*d*dl->light.quadratic_attn ); + } + else + { + float d50=FloatForKey( e, "_fifty_percent_distance" ); + if ( d50 ) { - Warning( "can't solve quadratic for light %f %f\n", d50, d0 ); - } - // it it possible that the parameters couldn't be used because of enforing monoticity. If so, rescale so at - // least the 50 percent value is right + float d0 = FloatForKey( e, "_zero_percent_distance" ); + if ( d0 < d50 ) + { + Warning( "light has _fifty_percent_distance of %f but _zero_percent_distance of %f\n", d50, d0); + d0 = 2.0 * d50; + } + float a = 0, b = 1, c = 0; + if ( ! SolveInverseQuadraticMonotonic( 0, 1.0, d50, 2.0, d0, 256.0, a, b, c )) + { + Warning( "can't solve quadratic for light %f %f\n", d50, d0 ); + } + // it it possible that the parameters couldn't be used because of enforing monoticity. If so, rescale so at + // least the 50 percent value is right // printf("50 percent=%f 0 percent=%f\n",d50,d0); // printf("a=%f b=%f c=%f\n",a,b,c); - float v50 = c + d50 * ( b + d50 * a ); - float scale = 2.0 / v50; - a *= scale; - b *= scale; - c *= scale; + float v50 = c + d50 * ( b + d50 * a ); + float scale = 2.0 / v50; + a *= scale; + b *= scale; + c *= scale; // printf("scaled=%f a=%f b=%f c=%f\n",scale,a,b,c); -// for(float d=0;d<1000;d+=20) +// for(float d=0;d<200;d+=20) // printf("at %f, %f\n",d,1.0/(c+d*(b+d*a))); - dl->light.quadratic_attn = a; - dl->light.linear_attn = b; - dl->light.constant_attn = c; + dl->light.quadratic_attn = a; + dl->light.linear_attn = b; + dl->light.constant_attn = c; - if ( IntForKey(e, "_hardfalloff" ) ) - { - dl->m_flEndFadeDistance = d0; - dl->m_flStartFadeDistance = 0.75 * d0 + 0.25 * d50; // start fading 3/4 way between 50 and 0. could allow adjust - } - else - { - // now, we will find the point at which the 1/x term reaches its maximum value, and - // prevent the light from going past there. If a user specifes an extreme falloff, the - // quadratic will start making the light brighter at some distance. We handle this by - // fading it from the minimum brightess point down to zero at 10x the minimum distance - if ( fabs( a ) > 0. ) + if ( IntForKey(e, "_hardfalloff" ) ) + { + dl->m_flEndFadeDistance = d0; + dl->m_flStartFadeDistance = 0.75 * d0 + 0.25 * d50; // start fading 3/4 way between 50 and 0. could allow adjust + } + else { - float flMax = b / ( - 2.0 * a ); // where f' = 0 - if ( flMax > 0.0 ) + // now, we will find the point at which the 1/x term reaches its maximum value, and + // prevent the light from going past there. If a user specifes an extreme falloff, the + // quadratic will start making the light brighter at some distance. We handle this by + // fading it from the minimum brightess point down to zero at 10x the minimum distance + if ( fabs( a ) > 0. ) { - dl->m_flCapDist = flMax; - dl->m_flStartFadeDistance = flMax; - dl->m_flEndFadeDistance = 10.0 * flMax; + float flMax = b / ( - 2.0 * a ); // where f' = 0 + if ( flMax > 0.0 ) + { + dl->m_flCapDist = flMax; + dl->m_flStartFadeDistance = flMax; + dl->m_flEndFadeDistance = 10.0 * flMax; + } } } } - } - else - { - dl->light.constant_attn = FloatForKey (e, "_constant_attn" ); - dl->light.linear_attn = FloatForKey (e, "_linear_attn" ); - dl->light.quadratic_attn = FloatForKey (e, "_quadratic_attn" ); + else + { + dl->light.constant_attn = FloatForKey (e, "_constant_attn" ); + dl->light.linear_attn = FloatForKey (e, "_linear_attn" ); + dl->light.quadratic_attn = FloatForKey (e, "_quadratic_attn" ); - dl->light.radius = FloatForKey (e, "_distance"); + dl->light.radius = FloatForKey (e, "_distance"); - // clamp values to >= 0 - if ( dl->light.constant_attn < EQUAL_EPSILON ) - dl->light.constant_attn = 0; + // clamp values to >= 0 + if ( dl->light.constant_attn < EQUAL_EPSILON ) + dl->light.constant_attn = 0; - if ( dl->light.linear_attn < EQUAL_EPSILON ) - dl->light.linear_attn = 0; + if ( dl->light.linear_attn < EQUAL_EPSILON ) + dl->light.linear_attn = 0; - if ( dl->light.quadratic_attn < EQUAL_EPSILON ) - dl->light.quadratic_attn = 0; + if ( dl->light.quadratic_attn < EQUAL_EPSILON ) + dl->light.quadratic_attn = 0; - if ( dl->light.constant_attn < EQUAL_EPSILON && dl->light.linear_attn < EQUAL_EPSILON && dl->light.quadratic_attn < EQUAL_EPSILON ) - dl->light.constant_attn = 1; + if ( dl->light.constant_attn < EQUAL_EPSILON && dl->light.linear_attn < EQUAL_EPSILON && dl->light.quadratic_attn < EQUAL_EPSILON ) + dl->light.constant_attn = 1; - // scale intensity for unit 100 distance - float ratio = ( dl->light.constant_attn + 100 * dl->light.linear_attn + 100 * 100 * dl->light.quadratic_attn ); - if ( ratio > 0 ) - { - VectorScale( dl->light.intensity, ratio, dl->light.intensity ); + // scale intensity for unit 100 distance + float ratio = ( dl->light.constant_attn + 100 * dl->light.linear_attn + 100 * 100 * dl->light.quadratic_attn ); + if ( ratio > 0 ) + { + VectorScale( dl->light.intensity, ratio, dl->light.intensity ); + } } } } @@ -1329,8 +1469,8 @@ bool CanLeafTraceToSky( int iLeaf ) for ( int j = 0; j < NUMVERTEXNORMALS; j+=4 ) { // search back to see if we can hit a sky brush - delta.LoadAndSwizzle( g_anorms[j], g_anorms[MIN( j+1, NUMVERTEXNORMALS-1 )], - g_anorms[MIN( j+2, NUMVERTEXNORMALS-1 )], g_anorms[MIN( j+3, NUMVERTEXNORMALS-1 )] ); + delta.LoadAndSwizzle( g_anorms[j], g_anorms[min( j+1, NUMVERTEXNORMALS-1 )], + g_anorms[min( j+2, NUMVERTEXNORMALS-1 )], g_anorms[min( j+3, NUMVERTEXNORMALS-1 )] ); delta *= -MAX_TRACE_LENGTH; delta += center4; @@ -1343,8 +1483,10 @@ bool CanLeafTraceToSky( int iLeaf ) return false; } -void BuildVisForLightEnvironment( void ) +void BuildVisForLightEnvironment( int nNumLights, directlight_t** pLights ) { + // FIXME: The work in this function is executed redundantly for multiple emit_skylight lights. + // Create the vis. for ( int iLeaf = 0; iLeaf < numleafs; ++iLeaf ) { @@ -1365,8 +1507,11 @@ void BuildVisForLightEnvironment( void ) { dleafs[iLeaf].flags |= LEAF_FLAGS_SKY; } - MergeDLightVis( gSkyLight, dleafs[iLeaf].cluster ); - MergeDLightVis( gAmbient, dleafs[iLeaf].cluster ); + + for ( int iLight = 0; iLight < nNumLights; ++iLight ) + { + MergeDLightVis( pLights[iLight], dleafs[iLeaf].cluster ); + } break; } } @@ -1482,15 +1627,17 @@ static void ParseLightEnvironment( entity_t* e, directlight_t* dl ) ParseLightGeneric( e, dl ); - char *angle_str=ValueForKeyWithDefault( e, "SunSpreadAngle" ); - if (angle_str) - { - g_SunAngularExtent=atof(angle_str); - g_SunAngularExtent=sin((M_PI/180.0)*g_SunAngularExtent); - printf("sun extent from map=%f\n",g_SunAngularExtent); - } if ( !gSkyLight ) { + char *angle_str=ValueForKeyWithDefault( e, "SunSpreadAngle" ); + if (angle_str) + { + g_SunAngularExtent=atof(angle_str); + g_SunAngularExtent=sin((M_PI/180.0)*g_SunAngularExtent); + dl->m_flSkyLightSunAngularExtent = g_SunAngularExtent; + printf("sun extent from map=%f\n",g_SunAngularExtent); + } + // Sky light. gSkyLight = dl; dl->light.type = emit_skylight; @@ -1513,7 +1660,12 @@ static void ParseLightEnvironment( entity_t* e, directlight_t* dl ) gAmbient->light.intensity ); } - BuildVisForLightEnvironment(); + // skylight and ambient light never cast entity shadows + gSkyLight->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS; + gAmbient->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS; + + directlight_t* lights[] = { gSkyLight, gAmbient }; + BuildVisForLightEnvironment( 2, lights ); // Add sky and sky ambient lights to the list. AddDLightToActiveList( gSkyLight ); @@ -1521,6 +1673,33 @@ static void ParseLightEnvironment( entity_t* e, directlight_t* dl ) } } +static void ParseLightDirectional( entity_t* e, directlight_t* dl ) +{ + Vector dest; + GetVectorForKey (e, "origin", dest ); + dl = AllocDLight( dest, true ); + + ParseLightGeneric( e, dl ); + + char *angle_str=ValueForKeyWithDefault( e, "SunSpreadAngle" ); + if (angle_str) + { + dl->m_flSkyLightSunAngularExtent = atof(angle_str); + dl->m_flSkyLightSunAngularExtent = sin((M_PI/180.0)*dl->m_flSkyLightSunAngularExtent); + } + + dl->light.type = emit_skylight; + // For the engine, emit_skylight is the type we want. + // Set an additional flag identifying this as "not the global skylight" for vrad. This will cause it to use the angular extent associated with this light + // instead of the global one. + dl->m_bSkyLightIsDirectionalLight = true; + + // directional lights never cast entity shadows + dl->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS; + + BuildVisForLightEnvironment( 1, &dl ); +} + static void ParseLightPoint( entity_t* e, directlight_t* dl ) { Vector dest; @@ -1573,6 +1752,8 @@ void CreateDirectLights (void) dl = AllocDLight( p->origin, true ); dl->light.type = emit_surface; + dl->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS; + VectorCopy (p->normal, dl->light.normal); Assert( VectorLength( p->normal ) > 1.0e-20 ); // scale intensity by number of texture instances @@ -1605,6 +1786,10 @@ void CreateDirectLights (void) { ParseLightEnvironment( e, dl ); } + else if (!strcmp(name, "light_directional")) + { + ParseLightDirectional( e, dl ); + } else if (!strcmp(name, "light")) { ParseLightPoint( e, dl ); @@ -1648,6 +1833,7 @@ void ExportDirectLightsToWorldLights() // FIXME: why does vrad want 0 to 255 and not 0 to 1?? VectorScale( dl->light.intensity, (1.0 / 255.0), wl->intensity ); VectorCopy( dl->light.normal, wl->normal ); + VectorCopy( dl->light.shadow_cast_offset, wl->shadow_cast_offset ); wl->stopdot = dl->light.stopdot; wl->stopdot2 = dl->light.stopdot2; wl->exponent = dl->light.exponent; @@ -1655,7 +1841,7 @@ void ExportDirectLightsToWorldLights() wl->constant_attn = dl->light.constant_attn; wl->linear_attn = dl->light.linear_attn; wl->quadratic_attn = dl->light.quadratic_attn; - wl->flags = 0; + wl->flags = dl->light.flags; } } @@ -1668,7 +1854,7 @@ void ExportDirectLightsToWorldLights() #define CONSTANT_DOT (.7/2) -#define NSAMPLES_SUN_AREA_LIGHT 30 // number of samples to take for an +#define NSAMPLES_SUN_AREA_LIGHT 300 // number of samples to take for an // non-point sun light // Helper function - gathers light from sun (emit_skylight) @@ -1679,21 +1865,29 @@ void GatherSampleSkyLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, i { bool bIgnoreNormals = ( nLFlags & GATHERLFLAGS_IGNORE_NORMALS ) != 0; bool force_fast = ( nLFlags & GATHERLFLAGS_FORCE_FAST ) != 0; - fltx4 dot; + float fSunAngularExtent = g_SunAngularExtent; + if ( dl->m_bSkyLightIsDirectionalLight ) + { + fSunAngularExtent = dl->m_flSkyLightSunAngularExtent; + } + if ( bIgnoreNormals ) dot = ReplicateX4( CONSTANT_DOT ); else dot = NegSIMD( pNormals[0] * dl->light.normal ); dot = MaxSIMD( dot, Four_Zeros ); + + dot = SoftenCosineTerm( dot ); + int zeroMask = TestSignSIMD ( CmpEqSIMD( dot, Four_Zeros ) ); if (zeroMask == 0xF) return; int nsamples = 1; - if ( g_SunAngularExtent > 0.0f ) + if ( fSunAngularExtent > 0.0f ) { nsamples = NSAMPLES_SUN_AREA_LIGHT; if ( do_fast || force_fast ) @@ -1715,7 +1909,7 @@ void GatherSampleSkyLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, i { // jitter light source location Vector ofs = sampler.NextValue(); - ofs *= MAX_TRACE_LENGTH * g_SunAngularExtent; + ofs *= MAX_TRACE_LENGTH * fSunAngularExtent; delta += ofs; } FourVectors delta4; @@ -1728,17 +1922,25 @@ void GatherSampleSkyLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, i } fltx4 seeAmount = MulSIMD ( totalFractionVisible, ReplicateX4 ( 1.0f / nsamples ) ); + out.m_flDot[0] = MulSIMD ( dot, seeAmount ); out.m_flFalloff = Four_Ones; - out.m_flSunAmount = MulSIMD ( seeAmount, ReplicateX4( 10000.0f ) ); + out.m_flSunAmount[0] = MulSIMD( out.m_flDot[0], out.m_flFalloff ); + for ( int i = 1; i < normalCount; i++ ) { if ( bIgnoreNormals ) - out.m_flDot[i] = ReplicateX4 ( CONSTANT_DOT ); + { + out.m_flDot[i] = ReplicateX4( CONSTANT_DOT ); + out.m_flSunAmount[i] = Four_Zeros; + } else { out.m_flDot[i] = NegSIMD( pNormals[i] * dl->light.normal ); + out.m_flDot[i] = MaxSIMD( out.m_flDot[i], Four_Zeros ); + out.m_flDot[i] = SoftenCosineTerm( out.m_flDot[i] ); out.m_flDot[i] = MulSIMD( out.m_flDot[i], seeAmount ); + out.m_flSunAmount[i] = MulSIMD( out.m_flDot[i], out.m_flFalloff ); } } } @@ -1781,6 +1983,8 @@ void GatherSampleAmbientSkySSE( SSE_sampleLightOutput_t &out, directlight_t *dl, else dots[0] = NegSIMD( pNormals[0] * anorm ); + dots[0] = SoftenCosineTerm( dots[0] ); + fltx4 validity = CmpGtSIMD( dots[0], ReplicateX4( EQUAL_EPSILON ) ); // No possibility of anybody getting lit @@ -1797,6 +2001,9 @@ void GatherSampleAmbientSkySSE( SSE_sampleLightOutput_t &out, directlight_t *dl, dots[i] = ReplicateX4( CONSTANT_DOT ); else dots[i] = NegSIMD( pNormals[i] * anorm ); + + dots[i] = SoftenCosineTerm( dots[i] ); + fltx4 validity2 = CmpGtSIMD( dots[i], ReplicateX4 ( EQUAL_EPSILON ) ); dots[i] = AndSIMD( validity2, dots[i] ); possibleHitCount[i] = AddSIMD( AndSIMD( AndSIMD( validity, validity2 ), Four_Ones ), possibleHitCount[i] ); @@ -1830,8 +2037,8 @@ void GatherSampleAmbientSkySSE( SSE_sampleLightOutput_t &out, directlight_t *dl, out.m_flDot[i] = MulSIMD( factor, sumdot ); out.m_flDot[i] = ReciprocalSIMD( out.m_flDot[i] ); out.m_flDot[i] = MulSIMD( ambient_intensity[i], out.m_flDot[i] ); + out.m_flSunAmount[i] = Four_Zeros; } - } // Helper function - gathers light from area lights, spot lights, and point lights @@ -1865,6 +2072,8 @@ void GatherSampleStandardLightSSE( SSE_sampleLightOutput_t &out, directlight_t * dot = delta * pNormals[0]; dot = MaxSIMD( Four_Zeros, dot ); + dot = SoftenCosineTerm( dot ); + // Affix dot to zero if past fade distz bool bHasHardFalloff = ( dl->m_flEndFadeDistance > dl->m_flStartFadeDistance ); if ( bHasHardFalloff ) @@ -1893,7 +2102,14 @@ void GatherSampleStandardLightSSE( SSE_sampleLightOutput_t &out, directlight_t * out.m_flFalloff = MulSIMD( out.m_flFalloff, quadratic ); out.m_flFalloff = AddSIMD( out.m_flFalloff, MulSIMD( linear, falloffEvalDist ) ); out.m_flFalloff = AddSIMD( out.m_flFalloff, constant ); - out.m_flFalloff = ReciprocalSIMD( out.m_flFalloff ); + if ( g_bFiniteFalloffModel ) + { + out.m_flFalloff = MaxSIMD( Four_Zeros, out.m_flFalloff ); + } + else + { + out.m_flFalloff = ReciprocalSIMD( out.m_flFalloff ); + } break; case emit_surface: @@ -1932,7 +2148,14 @@ void GatherSampleStandardLightSSE( SSE_sampleLightOutput_t &out, directlight_t * out.m_flFalloff = MulSIMD( out.m_flFalloff, quadratic ); out.m_flFalloff = AddSIMD( out.m_flFalloff, MulSIMD( linear, falloffEvalDist ) ); out.m_flFalloff = AddSIMD( out.m_flFalloff, constant ); - out.m_flFalloff = ReciprocalSIMD( out.m_flFalloff ); + if ( g_bFiniteFalloffModel ) + { + out.m_flFalloff = MaxSIMD( Four_Zeros, out.m_flFalloff ); + } + else + { + out.m_flFalloff = ReciprocalSIMD( out.m_flFalloff ); + } out.m_flFalloff = MulSIMD( out.m_flFalloff, dot2 ); // outside the inner cone @@ -1978,20 +2201,27 @@ void GatherSampleStandardLightSSE( SSE_sampleLightOutput_t &out, directlight_t * out.m_flFalloff = MulSIMD( mult, out.m_flFalloff ); } - // Raytrace for visibility function - fltx4 fractionVisible = Four_Ones; - TestLine( pos, src, &fractionVisible, static_prop_index_to_ignore); - dot = MulSIMD( fractionVisible, dot ); - out.m_flDot[0] = dot; + if ( !( nLFlags & GATHERLFLAGS_NO_OCCLUSION ) ) + { + // Raytrace for visibility function + fltx4 fractionVisible = Four_Ones; + TestLine( pos, src, &fractionVisible, static_prop_index_to_ignore); + dot = MulSIMD( fractionVisible, dot ); + } + out.m_flDot[0] = dot; for ( int i = 1; i < normalCount; i++ ) { if ( bIgnoreNormals ) - out.m_flDot[i] = ReplicateX4( (float) CONSTANT_DOT ); + { + out.m_flDot[i] = ReplicateX4( (float)CONSTANT_DOT ); + out.m_flSunAmount[i] = Four_Zeros; + } else { out.m_flDot[i] = pNormals[i] * delta; out.m_flDot[i] = MaxSIMD( Four_Zeros, out.m_flDot[i] ); + out.m_flSunAmount[i] = Four_Zeros; } } } @@ -2009,9 +2239,11 @@ void GatherSampleLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int float flEpsilon ) { for ( int b = 0; b < normalCount; b++ ) + { out.m_flDot[b] = Four_Zeros; + out.m_flSunAmount[b] = Four_Zeros; + } out.m_flFalloff = Four_Zeros; - out.m_flSunAmount = Four_Zeros; Assert( normalCount <= (NUM_BUMP_VECTS+1) ); // skylights work fundamentally differently than normal lights @@ -2036,18 +2268,40 @@ void GatherSampleLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int return; } + // Ambient occlusion for the 4 sample positions & normals + fltx4 ao = Four_Ones; + bool bIgnoreNormals = (nLFlags & GATHERLFLAGS_IGNORE_NORMALS) != 0; + if ( !bIgnoreNormals ) // Don't calculate ambient occlusion for objects that ignore normals for gathering light + { + if ( nLFlags & GATHERLFLAGS_STATICPROP ) + { + // for static props we want the sun amount for the basis normals to be mutliplied by the ao of the main vertex normal only. + // lightmaps using this path do not send basis normals here, we do so for static props to take advantage of the SIMD optimisation this path provides. + ao = CalculateAmbientOcclusion4( pos, *pNormals, static_prop_index_to_ignore ); + fltx4 ao0 = SplatXSIMD( ao ); + ao = ao0; + } + else + { + ao = CalculateAmbientOcclusion4( pos, *pNormals, static_prop_index_to_ignore ); + } + } + // NOTE: Notice here that if the light is on the back side of the face // (tested by checking the dot product of the face normal and the light position) // we don't want it to contribute to *any* of the bumped lightmaps. It glows // in disturbing ways if we don't do this. out.m_flDot[0] = MaxSIMD ( out.m_flDot[0], Four_Zeros ); fltx4 notZero = CmpGtSIMD( out.m_flDot[0], Four_Zeros ); + out.m_flDot[0] = MulSIMD( out.m_flDot[0], ao ); + out.m_flSunAmount[0] = MulSIMD( out.m_flSunAmount[0], ao ); for ( int n = 1; n < normalCount; n++ ) { out.m_flDot[n] = MaxSIMD( out.m_flDot[n], Four_Zeros ); out.m_flDot[n] = AndSIMD( out.m_flDot[n], notZero ); + out.m_flDot[n] = MulSIMD( out.m_flDot[n], ao ); + out.m_flSunAmount[n] = MulSIMD( out.m_flSunAmount[n], ao ); } - } /* @@ -2438,7 +2692,6 @@ static int FindOrAllocateLightstyleSamples( dface_t* f, facelight_t *fl, int lig //----------------------------------------------------------------------------- static void ComputeIlluminationPointAndNormalsSSE( lightinfo_t const& l, FourVectors const &pos, FourVectors const &norm, SSE_SampleInfo_t* pInfo, int numSamples ) { - Vector v[4]; pInfo->m_Points = pos; @@ -2487,6 +2740,44 @@ static void ComputeIlluminationPointAndNormalsSSE( lightinfo_t const& l, FourVec pInfo->m_Clusters[i] = ClusterFromPoint( pos.Vec( i ) ); } +//----------------------------------------------------------------------------- +// Compute the illumination point + normal for the sample on a displacement +// (see ComputeIlluminationPointAndNormalsSSE above) +//----------------------------------------------------------------------------- +static void ComputeIlluminationPointAndNormalsForDisp( lightinfo_t const& l, FourVectors &pos, FourVectors &norm, SSE_SampleInfo_t* pInfo ) +{ + pInfo->m_PointNormals[ 0 ] = norm; + + if ( pInfo->m_NormalCount > 1 ) + { + Vector bv[ 4 ][ NUM_BUMP_VECTS ]; + for ( int j = 0; j < 4; j++ ) + { + // TODO: using Vec may slow things down a bit + GetBumpNormals( pInfo->m_pTexInfo->textureVecsTexelsPerWorldUnits[ 0 ], + pInfo->m_pTexInfo->textureVecsTexelsPerWorldUnits[ 1 ], + l.facenormal, norm.Vec( j ), bv[ j ] ); + } + for ( int b = 0; b < NUM_BUMP_VECTS; b++ ) + { + pInfo->m_PointNormals[ b + 1 ].LoadAndSwizzle( bv[ 0 ][ b ], bv[ 1 ][ b ], bv[ 2 ][ b ], bv[ 3 ][ b ] ); + } + } + + pInfo->m_Points = pos; + + // FIXME: move sample point off the surface a bit, this is done so that + // light sampling will not be affected by a bug where raycasts will + // intersect with the face being lit. We really should just have that + // logic in GatherSampleLight + FourVectors faceNormal = norm; + pInfo->m_Points += faceNormal; + + // TODO: this may slow things down a bit ( using Vec ) + for ( int j = 0; j < 4; j++ ) + pInfo->m_Clusters[ j ] = ClusterFromPoint( pos.Vec( j ) ); +} + //----------------------------------------------------------------------------- // Iterates over all lights and computes lighting at up to 4 sample points //----------------------------------------------------------------------------- @@ -2536,11 +2827,7 @@ static void GatherSampleLightAt4Points( SSE_SampleInfo_t& info, int sampleIdx, i if (info.m_WarnFace != info.m_FaceNum) { Warning ("\nWARNING: Too many light styles on a face at (%f, %f, %f)\n", -#ifdef VRAD_SSE - info.m_Points.x.m128_f32[0], info.m_Points.y.m128_f32[0], info.m_Points.z.m128_f32[0] ); -#else info.m_Points.x[0], info.m_Points.y[0], info.m_Points.z[0] ); -#endif info.m_WarnFace = info.m_FaceNum; } continue; @@ -2564,7 +2851,7 @@ static void GatherSampleLightAt4Points( SSE_SampleInfo_t& info, int sampleIdx, i { for ( int i = 0; i < numSamples; i++ ) { - pLightmaps[n][sampleIdx + i].AddLight( SubFloat( fxdot[n], i ), dl->light.intensity, SubFloat( out.m_flSunAmount, i ) ); + pLightmaps[n][sampleIdx + i].AddLight( SubFloat( fxdot[n], i ), dl->light.intensity, SubFloat( out.m_flSunAmount[n], i ) ); } } } @@ -2638,16 +2925,16 @@ static void ResampleLightAt4Points( SSE_SampleInfo_t& info, int lightStyleIndex, { for( int n = 0; n < info.m_NormalCount; ++n ) { - pLightmap[i][n].AddLight( SubFloat( fxdot[n], i ), dl->light.intensity, SubFloat( out.m_flSunAmount, i ) ); + pLightmap[i][n].AddLight( SubFloat( fxdot[n], i ), dl->light.intensity, SubFloat( out.m_flSunAmount[n], i ) ); } } } } -bool PointsInWinding ( FourVectors const & point, winding_t *w, int &invalidBits ) +bool PointsInWinding( FourVectors const & point, winding_t *w, int &invalidBits ) { FourVectors edge, toPt, cross, testCross, p0, p1; - fltx4 invalidMask; + fltx4 invalidMask = Four_Zeros; // // get the first normal to test @@ -2659,9 +2946,11 @@ bool PointsInWinding ( FourVectors const & point, winding_t *w, int &invalidBits edge = p1; edge -= p0; testCross = edge ^ toPt; - testCross.VectorNormalizeFast(); + // safer against /0 - testCross.VectorNormalizeFast(); + fltx4 mag_sq = testCross * testCross; + testCross *= ReciprocalSqrtEstSaturateSIMD( mag_sq ); - for( int ndxPt = 1; ndxPt < w->numpoints; ndxPt++ ) + for ( int ndxPt = 1; ndxPt < w->numpoints; ndxPt++ ) { p0.DuplicateVector( w->p[ndxPt] ); p1.DuplicateVector( w->p[(ndxPt+1)%w->numpoints] ); @@ -2670,7 +2959,9 @@ bool PointsInWinding ( FourVectors const & point, winding_t *w, int &invalidBits edge = p1; edge -= p0; cross = edge ^ toPt; - cross.VectorNormalizeFast(); + // safer against /0 - cross.VectorNormalizeFast(); + mag_sq = cross * cross; + cross *= ReciprocalSqrtEstSaturateSIMD( mag_sq ); fltx4 dot = cross * testCross; invalidMask = OrSIMD( invalidMask, CmpLtSIMD( dot, Four_Zeros ) ); @@ -2698,8 +2989,9 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, // Some parameters related to supersampling float sampleWidth = ( flags & NON_AMBIENT_ONLY ) ? 4 : 2; + float cscale = 1.0f / sampleWidth; - float csshift = -((sampleWidth - 1) * cscale) / 2.0; + float csshift = -( ( sampleWidth - 1 ) * cscale ) / 2.0; // Clear out the light values for (int i = 0; i < info.m_NormalCount; ++i ) @@ -2712,12 +3004,35 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, FourVectors superSampleLightCoord; FourVectors superSamplePosition; + superSamplePosition.DuplicateVector( sample.pos ); + + Vector wsError; + FourVectors superSampleWorldSpaceError; + + float stepU = 0.0f; + float stepV = 0.0f; + if ( info.m_IsDispFace ) + { + // compensate for error when transforming back to worldspace (only enabled for displacements) + Vector toWorld; + LuxelSpaceToWorld( &l, temp.x, temp.y, toWorld ); + VectorSubtract( sample.pos, toWorld, wsError ); + superSampleWorldSpaceError.DuplicateVector( wsError ); + + // lightmap size + int width = l.face->m_LightmapTextureSizeInLuxels[ 0 ] + 1; + int height = l.face->m_LightmapTextureSizeInLuxels[ 1 ] + 1; + + // calculate the steps in uv space + stepU = 1.0f / (float)width; + stepV = 1.0f / (float)height; + } if ( flags & NON_AMBIENT_ONLY ) { float aRow[4]; for ( int coord = 0; coord < 4; ++coord ) - aRow[coord] = csshift + coord * cscale; + aRow[ coord ] = csshift + coord * cscale; fltx4 sseRow = LoadUnalignedSIMD( aRow ); for (int s = 0; s < 4; ++s) @@ -2732,6 +3047,29 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, // Figure out where the supersample exists in the world, and make sure // it lies within the sample winding LuxelSpaceToWorld( &l, superSampleLightCoord[0], superSampleLightCoord[1], superSamplePosition ); + + if ( info.m_IsDispFace ) + { + // Fix up error from world to luxel and back again + superSamplePosition += superSampleWorldSpaceError; + + // Find pos and norm for disp from uv supersample offsets + Vector vDispP[4], vDispN[4]; + for ( int i = 0; i < 4; i++ ) + { + vDispP[ i ] = superSamplePosition.Vec( i ); + Vector2D uv; + + uv.x = sample.coord[0] + ( aRow[ s ] * stepU ); + uv.y = sample.coord[1] + ( aRow[ i ] * stepV ); + + StaticDispMgr()->GetDispSurfPointAndNormalFromUV( info.m_FaceNum, vDispP[ i ], vDispN[ i ], uv, false ); + } + superSamplePosition = FourVectors( vDispP[ 0 ], vDispP[ 1 ], vDispP[ 2 ], vDispP[ 3 ] ); + superSampleNormal = FourVectors( vDispN[ 0 ], vDispN[ 1 ], vDispN[ 2 ], vDispN[ 3 ] ); + + ComputeIlluminationPointAndNormalsForDisp( l, superSamplePosition, superSampleNormal, &info ); + } // A winding should exist only if the sample wasn't a uniform luxel, or if g_bDumpPatches is true. int invalidBits = 0; @@ -2740,7 +3078,8 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, // Compute the super-sample illumination point and normal // We're assuming the flat normal is the same for all supersamples - ComputeIlluminationPointAndNormalsSSE( l, superSamplePosition, superSampleNormal, &info, 4 ); + if ( !info.m_IsDispFace ) + ComputeIlluminationPointAndNormalsSSE( l, superSamplePosition, superSampleNormal, &info, 4 ); // Resample the non-ambient light at this point... LightingValue_t result[4][NUM_BUMP_VECTS+1]; @@ -2753,7 +3092,7 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, { for ( int n = 0; n < info.m_NormalCount; ++n ) { - pLight[n].AddLight( result[i][n] ); + pLight[ n ].AddLight( result[ i ][ n ] ); } ++subsampleCount; } @@ -2770,11 +3109,36 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, LuxelSpaceToWorld( &l, superSampleLightCoord[0], superSampleLightCoord[1], superSamplePosition ); + if ( info.m_IsDispFace ) + { + // Fix up error from world to luxel and back again + superSamplePosition += superSampleWorldSpaceError; + + // Find pos and norm for disp from uv supersample offsets + Vector vDispP[ 4 ], vDispN[ 4 ]; + for ( int i = 0; i < 4; i++ ) + { + vDispP[ i ] = superSamplePosition.Vec( i ); + Vector uvOffsets = superSampleOffsets.Vec( i ); + Vector2D uv; + + uv.x = sample.coord[ 0 ] + ( uvOffsets.x * stepU ); + uv.y = sample.coord[ 1 ] + ( uvOffsets.y * stepV ); + + StaticDispMgr()->GetDispSurfPointAndNormalFromUV( info.m_FaceNum, vDispP[ i ], vDispN[ i ], uv, false ); + } + superSamplePosition = FourVectors( vDispP[ 0 ], vDispP[ 1 ], vDispP[ 2 ], vDispP[ 3 ] ); + superSampleNormal = FourVectors( vDispN[ 0 ], vDispN[ 1 ], vDispN[ 2 ], vDispN[ 3 ] ); + + ComputeIlluminationPointAndNormalsForDisp( l, superSamplePosition, superSampleNormal, &info ); + } + int invalidBits = 0; if ( sample.w && !PointsInWinding( superSamplePosition, sample.w, invalidBits ) ) return 0; - ComputeIlluminationPointAndNormalsSSE( l, superSamplePosition, superSampleNormal, &info, 4 ); + if ( !info.m_IsDispFace ) + ComputeIlluminationPointAndNormalsSSE( l, superSamplePosition, superSampleNormal, &info, 4 ); LightingValue_t result[4][NUM_BUMP_VECTS+1]; ResampleLightAt4Points( info, lightStyleIndex, AMBIENT_ONLY, result ); @@ -2786,7 +3150,7 @@ static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info, { for ( int n = 0; n < info.m_NormalCount; ++n ) { - pLight[n].AddLight( result[i][n] ); + pLight[ n ].AddLight( result[ i ][ n ] ); } ++subsampleCount; } @@ -2951,17 +3315,16 @@ static void BuildSupersampleFaceLights( lightinfo_t& l, SSE_SampleInfo_t& info, if ( ambientSupersampleCount > 0 && directSupersampleCount > 0 ) { // Add the ambient + directional terms together, stick it back into the lightmap - for (int n = 0; n < info.m_NormalCount; ++n) + for ( int n = 0; n < info.m_NormalCount; ++n ) { - ppLightSamples[n][i].Zero(); - ppLightSamples[n][i].AddWeighted( pDirectLight[n],1.0f / directSupersampleCount ); - ppLightSamples[n][i].AddWeighted( pAmbientLight[n], 1.0f / ambientSupersampleCount ); + ppLightSamples[ n ][ i ].Zero(); + ppLightSamples[ n ][ i ].AddWeighted( pDirectLight[ n ], 1.0f / directSupersampleCount ); + ppLightSamples[ n ][ i ].AddWeighted( pAmbientLight[ n ], 1.0f / ambientSupersampleCount ); } // Recompute the luxel intensity based on the supersampling ComputeLuxelIntensity( info, i, ppLightSamples, pSampleIntensity ); } - } // We've finished another pass @@ -3125,12 +3488,12 @@ void BuildFacelights (int iThread, int facenum) int nSample = 4 * grp; sample_t *sample = sampleInfo.m_pFaceLight->sample + nSample; - int numSamples = MIN ( 4, sampleInfo.m_pFaceLight->numsamples - nSample ); + int numSamples = min ( 4, sampleInfo.m_pFaceLight->numsamples - nSample ); FourVectors positions; FourVectors normals; - for ( int i = 0; i < 4; i++ ) + for ( i = 0; i < 4; i++ ) { v[i] = ( i < numSamples ) ? sample[i].pos : sample[numSamples - 1].pos; n[i] = ( i < numSamples ) ? sample[i].normal : sample[numSamples - 1].normal; @@ -3143,7 +3506,7 @@ void BuildFacelights (int iThread, int facenum) // Fixup sample normals in case of smooth faces if ( !l.isflat ) { - for ( int i = 0; i < numSamples; i++ ) + for ( i = 0; i < numSamples; i++ ) sample[i].normal = sampleInfo.m_PointNormals[0].Vec( i ); } @@ -3166,8 +3529,9 @@ void BuildFacelights (int iThread, int facenum) return; } - // get rid of the -extra functionality on displacement surfaces - if (do_extra && !sampleInfo.m_IsDispFace) + // Enabling supersampling for displacements (previous revision always disabled do_extra for disp) + // improves continuity significantly between disp and brush surfaces, especially when using high frequency alpha shadow materials + if ( do_extra ) { // For each lightstyle, perform a supersampling pass for ( i = 0; i < MAXLIGHTMAPS; ++i ) @@ -3363,6 +3727,59 @@ void BuildPatchLights( int facenum ) } +void BuildStaticPropPatchlights( int iThread, int nPatch ) +{ + if ( g_Patches[ nPatch ].faceNumber >= 0 ) + { + // Not a static prop patch + return; + } + CPatch &patch = g_Patches[ nPatch ]; + + // Random sample locations + Vector vecOrigin = patch.winding->p[ 0 ]; + Vector vecU = patch.winding->p[ 2 ] - patch.winding->p[ 0 ]; + Vector vecV = patch.winding->p[ 1 ] - patch.winding->p[ 0 ]; + int nSampleCount = Max( 1, int( patch.area / 16.0f ) ); + float flSampleArea = patch.area / float( nSampleCount ); + float flSampleFrac = 1.0f / float( nSampleCount ); + sample_t *pSamples = new sample_t[ nSampleCount ]; + memset( pSamples, 0, sizeof( sample_t )*nSampleCount ); + for ( int i = 0; i < nSampleCount; i++ ) + { + // Shitty. Should be jittered instead or some other better distribution over the triangle. + float flU = RandomFloat(); + float flV = RandomFloat(); + if ( flU + flV > 1.0f ) + { + flU = 1.0f - flU; + flV = 1.0f - flV; + std::swap( flU, flV ); + } + pSamples[ i ].pos = vecOrigin + flU * vecU + flV * vecV; + pSamples[ i ].normal = patch.normal; + pSamples[ i ].area = flSampleArea; + } + + Vector directColor( 0.0f, 0.0f, 0.0f ); + float flSunAmount = 0.0f; + + // sample the lights at each sample location + for ( int i = 0; i < nSampleCount; i++ ) + { + sample_t *sample = pSamples + i; + + directColor.Init( 0.0f, 0.0f, 0.0f ); + flSunAmount = 0.0f; + ComputeDirectLightingAtPoint( sample->pos, &sample->normal, &directColor, &flSunAmount, 1, false, iThread, -1, 0 ); + directColor *= g_flStaticPropBounceBoost; + patch.totallight.light[ 0 ] += directColor * flSampleFrac; + patch.directlight += directColor * flSampleFrac; + } + + delete[] pSamples; +} + /* ============= PrecompLightmapOffsets @@ -3417,7 +3834,10 @@ void PrecompLightmapOffsets() { lightdatasize += nLuxels * 4 * lightstyles; } - } + + // Add room for additional light data here that will be packed into lightmap alpha + lightdatasize += nLuxels * 4 * lightstyles; + } // The incremental lighting code needs us to preserve the contents of dlightdata // since it only recomposites lighting for faces that have lights that touch them. @@ -3556,51 +3976,30 @@ static void LinearToBumpedLightmap( // Convert a RGBExp32 to a RGBA8888 // This matches the engine's conversion, so the lighting result is consistent. //----------------------------------------------------------------------------- -void ConvertRGBExp32ToRGBA8888( const ColorRGBExp32 *pSrc, unsigned char *pDst, Vector* _optOutLinear ) +void ConvertRGBExp32ToRGBA8888( const ColorRGBExp32 *pSrc, unsigned char *pDst ) { Vector linearColor; + Vector vertexColor; // convert from ColorRGBExp32 to linear space linearColor[0] = TexLightToLinear( ((ColorRGBExp32 *)pSrc)->r, ((ColorRGBExp32 *)pSrc)->exponent ); linearColor[1] = TexLightToLinear( ((ColorRGBExp32 *)pSrc)->g, ((ColorRGBExp32 *)pSrc)->exponent ); linearColor[2] = TexLightToLinear( ((ColorRGBExp32 *)pSrc)->b, ((ColorRGBExp32 *)pSrc)->exponent ); - ConvertLinearToRGBA8888( &linearColor, pDst ); - if ( _optOutLinear ) - *_optOutLinear = linearColor; -} - -//----------------------------------------------------------------------------- -// Converts a RGBExp32 to a linear color value. -//----------------------------------------------------------------------------- -void ConvertRGBExp32ToLinear(const ColorRGBExp32 *pSrc, Vector* pDst) -{ - - (*pDst)[0] = TexLightToLinear(((ColorRGBExp32 *)pSrc)->r, ((ColorRGBExp32 *)pSrc)->exponent); - (*pDst)[1] = TexLightToLinear(((ColorRGBExp32 *)pSrc)->g, ((ColorRGBExp32 *)pSrc)->exponent); - (*pDst)[2] = TexLightToLinear(((ColorRGBExp32 *)pSrc)->b, ((ColorRGBExp32 *)pSrc)->exponent); -} - -//----------------------------------------------------------------------------- -// Converts a linear color value (suitable for combining linearly) to an RBGA8888 value expected by the engine. -//----------------------------------------------------------------------------- -void ConvertLinearToRGBA8888(const Vector *pSrcLinear, unsigned char *pDst) -{ - Vector vertexColor; - // convert from linear space to lightmap space // cannot use mathlib routine directly because it doesn't match // the colorspace version found in the engine, which *is* the same sequence here - vertexColor[0] = LinearToVertexLight((*pSrcLinear)[0]); - vertexColor[1] = LinearToVertexLight((*pSrcLinear)[1]); - vertexColor[2] = LinearToVertexLight((*pSrcLinear)[2]); + vertexColor[0] = LinearToVertexLight( linearColor[0] ); + vertexColor[1] = LinearToVertexLight( linearColor[1] ); + vertexColor[2] = LinearToVertexLight( linearColor[2] ); // this is really a color normalization with a floor - ColorClamp(vertexColor); + ColorClamp( vertexColor ); // final [0..255] scale - pDst[0] = RoundFloatToByte(vertexColor[0] * 255.0f); - pDst[1] = RoundFloatToByte(vertexColor[1] * 255.0f); - pDst[2] = RoundFloatToByte(vertexColor[2] * 255.0f); + pDst[0] = RoundFloatToByte( vertexColor[0] * 255.0f ); + pDst[1] = RoundFloatToByte( vertexColor[1] * 255.0f ); + pDst[2] = RoundFloatToByte( vertexColor[2] * 255.0f ); pDst[3] = 255; } + diff --git a/utils/vrad/lightmap.h b/utils/vrad/lightmap.h index a4c698daf..42e732e15 100644 --- a/utils/vrad/lightmap.h +++ b/utils/vrad/lightmap.h @@ -137,5 +137,10 @@ void FreeDLights(); void ExportDirectLightsToWorldLights(); +float CalculateAmbientOcclusion( Vector *pPosition, Vector *pNormal ); +fltx4 CalculateAmbientOcclusion4( const FourVectors &position4, const FourVectors &normal4, int static_prop_index_to_ignore ); + +float SoftenCosineTerm( float flDot ); +fltx4 SoftenCosineTerm( fltx4 dots ); #endif // LIGHTMAP_H diff --git a/utils/vrad/mpivrad.cpp b/utils/vrad/mpivrad.cpp index 5b7bfc03e..1a081cda3 100644 --- a/utils/vrad/mpivrad.cpp +++ b/utils/vrad/mpivrad.cpp @@ -29,7 +29,7 @@ #include "mpi_stats.h" #include "vmpi_distribute_work.h" #include "vmpi_tools_shared.h" - +#include "tier0/fasttimer.h" @@ -60,9 +60,13 @@ bool VRAD_DispatchFn( MessageBuffer *pBuf, int iSource, int iPacketID ) } } CDispatchReg g_VRADDispatchReg( VMPI_VRAD_PACKET_ID, VRAD_DispatchFn ); // register to handle the messages we want -CDispatchReg g_DistributeWorkReg( VMPI_DISTRIBUTEWORK_PACKETID, DistributeWorkDispatch ); +VMPI_REGISTER_PACKET_ID( VMPI_VRAD_PACKET_ID ) +VMPI_REGISTER_SUBPACKET_ID( VMPI_VRAD_PACKET_ID, VMPI_SUBPACKETID_VIS_LEAFS ) +VMPI_REGISTER_SUBPACKET_ID( VMPI_VRAD_PACKET_ID, VMPI_SUBPACKETID_BUILDFACELIGHTS ) +VMPI_REGISTER_SUBPACKET_ID( VMPI_VRAD_PACKET_ID, VMPI_SUBPACKETID_PLIGHTDATA_RESULTS ) + void VRAD_SetupMPI( int &argc, char **&argv ) { @@ -238,7 +242,6 @@ void RunMPIBuildFacelights() VMPI_SetCurrentStage( "RunMPIBuildFaceLights" ); double elapsed = DistributeWork( numfaces, - VMPI_DISTRIBUTEWORK_PACKETID, MPI_ProcessFaces, MPI_ReceiveFaceResults ); @@ -265,7 +268,7 @@ void RunMPIBuildFacelights() else { if ( g_iVMPIVerboseLevel >= 1 ) - Msg( "\n\n%.1f%% CPU utilization during BuildFaceLights\n\n", ( g_CPUTime.GetSeconds() * 100 / elapsed ) ); + Msg( "\n\n%.1f%% CPU utilization during BuildFaceLights\n\n", (int)( g_CPUTime.GetSeconds() * 100 / elapsed ) ); } } @@ -396,7 +399,6 @@ void RunMPIBuildVisLeafs() double elapsed = DistributeWork( dvis->numclusters, - VMPI_DISTRIBUTEWORK_PACKETID, MPI_ProcessVisLeafs, MPI_ReceiveVisLeafsResults ); diff --git a/utils/vrad/mpivrad.h b/utils/vrad/mpivrad.h index 01c841b37..078d85bc4 100644 --- a/utils/vrad/mpivrad.h +++ b/utils/vrad/mpivrad.h @@ -18,9 +18,6 @@ #define VMPI_SUBPACKETID_BUILDFACELIGHTS 1 #define VMPI_SUBPACKETID_PLIGHTDATA_RESULTS 2 -// DistributeWork owns this packet ID. -#define VMPI_DISTRIBUTEWORK_PACKETID 2 - // Called first thing in the exe. void VRAD_SetupMPI( int &argc, char **&argv ); diff --git a/utils/vrad/radial.cpp b/utils/vrad/radial.cpp index 26dd1a725..2f196414b 100644 --- a/utils/vrad/radial.cpp +++ b/utils/vrad/radial.cpp @@ -647,7 +647,7 @@ void FinalLightFace( int iThread, int facenum ) float minlight; int lightstyles; LightingValue_t lb[NUM_BUMP_VECTS + 1], v[NUM_BUMP_VECTS + 1]; - unsigned char *pdata[NUM_BUMP_VECTS + 1]; + unsigned char *pdata[NUM_BUMP_VECTS + 2]; // +2 is for flat and additional lightmap alpha data int bumpSample; radial_t *rad = NULL; radial_t *prad = NULL; @@ -734,9 +734,9 @@ void FinalLightFace( int iThread, int facenum ) // it isn't going to use those positions (see loop over bumpSample below) // The file offset is correctly computed to only store space for 1 set // of light data if we don't have bumped lighting. - for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) + for( bumpSample = 0; bumpSample < bumpSampleCount + 1; ++bumpSample ) // The +1 is for the additional lightmap alpha data { - pdata[bumpSample] = &(*pdlightdata)[f->lightofs + (k * bumpSampleCount + bumpSample) * fl->numluxels*4]; + pdata[bumpSample] = &(*pdlightdata)[f->lightofs + ( ( k * ( bumpSampleCount + 1 ) ) + bumpSample) * fl->numluxels*4]; } // Compute the average luxel color, but not for the bump samples @@ -773,11 +773,11 @@ void FinalLightFace( int iThread, int facenum ) // v is indirect light that is received on the luxel. if( !bDisp ) { - SampleRadial( prad, fl->luxel[j], v, bumpSampleCount ); + SampleRadial( prad, fl->luxel[j], v, bumpSampleCount ); // indirect on brushes } else { - StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true ); + StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true ); // indirect on displacements } for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) @@ -840,6 +840,16 @@ void FinalLightFace( int iThread, int facenum ) // convert to a 4 byte r,g,b,signed exponent format VectorToColorRGBExp32( Vector( lb[bumpSample].m_vecLighting.x, lb[bumpSample].m_vecLighting.y, lb[bumpSample].m_vecLighting.z ), *( ColorRGBExp32 *)pdata[bumpSample] ); + + // Generate additional lightmap alpha data + if ( bumpSample == 0 ) + { + pdata[bumpSampleCount][0] = uint8( clamp( lb[0].m_flDirectSunAmount, 0.0f, 1.0f ) * 255.0f + 0.5f ); + pdata[bumpSampleCount][1] = uint8( clamp( lb[1].m_flDirectSunAmount, 0.0f, 1.0f ) * 255.0f + 0.5f ); + pdata[bumpSampleCount][2] = uint8( clamp( lb[2].m_flDirectSunAmount, 0.0f, 1.0f ) * 255.0f + 0.5f ); + pdata[bumpSampleCount][3] = uint8( clamp( lb[3].m_flDirectSunAmount, 0.0f, 1.0f ) * 255.0f + 0.5f ); + pdata[bumpSampleCount]+=4; + } #endif pdata[bumpSample] += 4; diff --git a/utils/vrad/trace.cpp b/utils/vrad/trace.cpp index 3bca83503..e8b65d393 100644 --- a/utils/vrad/trace.cpp +++ b/utils/vrad/trace.cpp @@ -133,11 +133,7 @@ class CCoverageCountTexture : public CCoverageCount addedCoverage[s] = 0.0f; if ( ( sign >> s) & 0x1 ) { -#ifdef VRAD_SSE - addedCoverage[s] = ComputeCoverageFromTexture( b0->m128_f32[s], b1->m128_f32[s], b2->m128_f32[s], hitID ); -#else - addedCoverage[s] = ComputeCoverageFromTexture( b0[0][s], b1[0][s], b2[0][s], hitID ); -#endif + addedCoverage[s] = ComputeCoverageFromTexture( (*b0)[s], (*b1)[s], (*b2)[s], hitID ); } } m_coverage = AddSIMD( m_coverage, LoadUnalignedSIMD( addedCoverage ) ); @@ -173,11 +169,7 @@ void TestLine( const FourVectors& start, const FourVectors& stop, { visibility[i] = 1.0f; if ( ( rt_result.HitIds[i] != -1 ) && -#ifdef VRAD_SSE - ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) ) -#else ( rt_result.HitDistance[i] < len[i] ) ) -#endif { visibility[i] = 0.0f; } @@ -187,7 +179,68 @@ void TestLine( const FourVectors& start, const FourVectors& stop, *pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() ); } +void TestLine_IgnoreSky( const FourVectors& start, const FourVectors& stop, + fltx4 *pFractionVisible, int static_prop_index_to_ignore ) +{ + FourRays myrays; + myrays.origin = start; + myrays.direction = stop; + myrays.direction -= myrays.origin; + fltx4 len = myrays.direction.length(); + myrays.direction *= ReciprocalSIMD( len ); + + RayTracingResult rt_result; + CCoverageCountTexture coverageCallback; + + g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_index_to_ignore, g_bTextureShadows ? &coverageCallback : 0 ); + + // Assume we can see the targets unless we get hits + float visibility[4]; + for ( int i = 0; i < 4; i++ ) + { + visibility[i] = 1.0f; + if ( ( rt_result.HitIds[i] != -1 ) && + ( rt_result.HitDistance[i] < len[i] ) ) + { + int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID; + if ( !( id & TRACE_ID_SKY ) ) + { + visibility[i] = 0.0f; + } + } + } + *pFractionVisible = LoadUnalignedSIMD( visibility ); + if ( g_bTextureShadows ) + *pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() ); +} + +void TestLine_LightBlockers( const FourVectors& start, const FourVectors& stop, + fltx4 *pFractionVisible ) +{ + FourRays myrays; + myrays.origin = start; + myrays.direction = stop; + myrays.direction -= myrays.origin; + fltx4 len = myrays.direction.length(); + myrays.direction *= ReciprocalSIMD( len ); + + RayTracingResult rt_result; + + g_RtEnv_LightBlockers.Trace4Rays( myrays, Four_Zeros, len, &rt_result, -1, NULL ); + // Assume we can see the targets unless we get hits + float visibility[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + if ( (rt_result.HitIds[0] != -1) && + (rt_result.HitDistance[0] < len[0]) ) + { + fltx4 dotRaySurfaceN = rt_result.surface_normal * myrays.direction; + if ( dotRaySurfaceN[0] > 0.0f ) + { + visibility[0] = 0.0f; + } + } + *pFractionVisible = LoadUnalignedSIMD( visibility ); +} /* ================ @@ -381,11 +434,7 @@ void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop, { aOcclusion[i] = 0.0f; if ( ( rt_result.HitIds[i] != -1 ) && -#ifdef VRAD_SSE - ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) ) -#else ( rt_result.HitDistance[i] < len[i] ) ) -#endif { int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID; if ( !( id & TRACE_ID_SKY ) ) @@ -501,22 +550,92 @@ dmodel_t *BrushmodelForEntity( entity_t *pEntity ) return NULL; } +// Add one that casts textureshadows +void AddTexturedBrushWinding( winding_t *w, const VMatrix &xform, texinfo_t *tx, int shadowMaterialIndex ) +{ + Vector2D uv[MAX_POINTS_ON_WINDING]; + int mappingWidth = 32; + int mappingHeight = 32; + GetShadowTextureMapping( shadowMaterialIndex, &mappingWidth, &mappingHeight ); + + for ( int j = 0; j < w->numpoints; j++ ) + { + // base texture coordinate + uv[j].x = DotProduct( w->p[j].Base(), tx->textureVecsTexelsPerWorldUnits[0] ) + + tx->textureVecsTexelsPerWorldUnits[0][3]; + uv[j].x /= float(mappingWidth); + + uv[j].y = DotProduct( w->p[j].Base(), tx->textureVecsTexelsPerWorldUnits[1] ) + + tx->textureVecsTexelsPerWorldUnits[1][3]; + uv[j].y /= float(mappingHeight); + } + Vector v0, v1, v2; + + for ( int j = 2; j < w->numpoints; j++ ) + { + v0 = xform.VMul4x3(w->p[0]); + v1 = xform.VMul4x3(w->p[j-1]); + v2 = xform.VMul4x3(w->p[j]); + float coverage = ComputeCoverageForTriangle(shadowMaterialIndex, uv[0], uv[j-1], uv[j] ); + int index = -1; + unsigned short flags = 0; + Vector fullCoverage(0,0,1); + if ( coverage < 1.0 ) + { + index = AddShadowTextureTriangle( shadowMaterialIndex, uv[0], uv[j-1], uv[j] ); + flags = FCACHETRI_TRANSPARENT; + fullCoverage.x = coverage; + } + + g_RtEnv.AddTriangle(TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage, flags, index); + } +} + void AddBrushToRaytraceEnvironment( dbrush_t *pBrush, const VMatrix &xform ) { - if ( !( pBrush->contents & MASK_OPAQUE ) ) + int materialIndexList[256]; + bool bTextureShadows = false; + + if ( !( pBrush->contents & (MASK_OPAQUE) ) && !(g_bTextureShadows && (pBrush->contents & CONTENTS_GRATE)) ) return; + if ( pBrush->contents & CONTENTS_LADDER ) + return; + + // load any transparent textures for shadows + if ( g_bTextureShadows && (pBrush->contents & CONTENTS_GRATE) && pBrush->numsides < ARRAYSIZE(materialIndexList) ) + { + for (int i = 0; i < pBrush->numsides; i++ ) + { + dbrushside_t *side = &dbrushsides[pBrush->firstside + i]; + texinfo_t *tx = &texinfo[side->texinfo]; + dtexdata_t *pTexData = &dtexdata[tx->texdata]; + const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID ); + materialIndexList[i] = LoadShadowTexture( pMaterialName ); + if ( materialIndexList[i] >= 0 ) + { + bTextureShadows = true; + } + } + } Vector v0, v1, v2; + for (int i = 0; i < pBrush->numsides; i++ ) { dbrushside_t *side = &dbrushsides[pBrush->firstside + i]; dplane_t *plane = &dplanes[side->planenum]; texinfo_t *tx = &texinfo[side->texinfo]; winding_t *w = BaseWindingForPlane (plane->normal, plane->dist); + bool bIsLightBlocker = false; if ( tx->flags & SURF_SKY || side->dispinfo ) continue; + if ( ( pBrush->contents & ( CONTENTS_OPAQUE | CONTENTS_SOLID ) ) && ( tx->flags & SURF_NODRAW ) ) + { + bIsLightBlocker = true; + } + for (int j=0 ; jnumsides && w; j++) { if (i == j) @@ -529,14 +648,28 @@ void AddBrushToRaytraceEnvironment( dbrush_t *pBrush, const VMatrix &xform ) } if ( w ) { - for ( int j = 2; j < w->numpoints; j++ ) + if ( bTextureShadows && materialIndexList[i] >= 0 ) + { + AddTexturedBrushWinding( w, xform, tx, materialIndexList[i] ); + } + else { - v0 = xform.VMul4x3(w->p[0]); - v1 = xform.VMul4x3(w->p[j-1]); - v2 = xform.VMul4x3(w->p[j]); - Vector fullCoverage; - fullCoverage.x = 1.0f; - g_RtEnv.AddTriangle(TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage); + // opaque + Vector fullCoverage(1,1,1); + for ( int j = 2; j < w->numpoints; j++ ) + { + v0 = xform.VMul4x3(w->p[0]); + v1 = xform.VMul4x3(w->p[j-1]); + v2 = xform.VMul4x3(w->p[j]); + g_RtEnv.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage ); + + // light blockers + if ( bIsLightBlocker ) + { + g_RtEnv_LightBlockers.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage ); + g_RtEnv_RadiosityPatches.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage ); + } + } } FreeWinding( w ); } @@ -615,7 +748,7 @@ void AddBrushesForRayTrace( void ) CUtlVector brushList; GetBrushes_r ( dmodels[0].headnode, brushList ); - for ( int i = 0; i < brushList.Size(); i++ ) + for ( int i = 0; i < brushList.Count(); i++ ) { dbrush_t *brush = &dbrushes[brushList[i]]; AddBrushToRaytraceEnvironment ( brush, identity ); diff --git a/utils/vrad/vismat.cpp b/utils/vrad/vismat.cpp index d33cd0171..93d6e252b 100644 --- a/utils/vrad/vismat.cpp +++ b/utils/vrad/vismat.cpp @@ -296,6 +296,29 @@ void AddDispsToClusterTable( void ) } +struct ClusterPatchList_t +{ + CUtlVector patches; +}; + +static CUtlVector g_ClusterStaticPropPatches; + +void AddStaticPropPatchesToClusterTable() +{ + g_ClusterStaticPropPatches.SetCount( g_ClusterLeaves.Count() ); + + for ( int i = 0; i < g_Patches.Count(); i++ ) + { + const CPatch &patch = g_Patches[ i ]; + if ( patch.faceNumber >= 0 || patch.clusterNumber < 0 ) + { + continue; + } + + g_ClusterStaticPropPatches[ patch.clusterNumber ].patches.AddToTail( i ); + } +} + /* ============== BuildVisRow @@ -345,7 +368,7 @@ void BuildVisRow (int patchnum, byte *pvs, int head, transfer_t *transfers, CTra } } - int dispCount = g_ClusterDispFaces[j].dispFaces.Size(); + int dispCount = g_ClusterDispFaces[j].dispFaces.Count(); for( int ndxDisp = 0; ndxDisp < dispCount; ndxDisp++ ) { int ndxFace = g_ClusterDispFaces[j].dispFaces[ndxDisp]; @@ -360,6 +383,20 @@ void BuildVisRow (int patchnum, byte *pvs, int head, transfer_t *transfers, CTra TestPatchToFace( patchnum, ndxFace, head, transfers, transferMaker, iThread ); } + + if ( g_bStaticPropBounce ) + { + // Test static prop patches + int staticPropPatchCount = g_ClusterStaticPropPatches[ j ].patches.Count(); + for ( int i = 0; i < staticPropPatchCount; i++ ) + { + int nPatchIdx = g_ClusterStaticPropPatches[ j ].patches[ i ]; + if ( nPatchIdx != patchnum ) + { + TestPatchToPatch( patchnum, nPatchIdx, head, transfers, transferMaker, iThread ); + } + } + } } diff --git a/utils/vrad/vrad.cpp b/utils/vrad/vrad.cpp index 1eb47467a..d13cf873a 100644 --- a/utils/vrad/vrad.cpp +++ b/utils/vrad/vrad.cpp @@ -40,7 +40,7 @@ every surface must be divided into at least two patches each axis */ CUtlVector g_Patches; -CUtlVector g_FacePatches; // contains all patches, children first +CUtlVector g_FacePatches; // constains all patches, children first CUtlVector faceParents; // contains only root patches, use next parent to iterate CUtlVector clusterChildren; CUtlVector emitlight; @@ -66,8 +66,7 @@ bool g_bDumpRtEnv = false; bool bRed2Black = true; bool g_bFastAmbient = false; bool g_bNoSkyRecurse = false; -bool g_bDumpPropLightmaps = false; - +bool g_bFiniteFalloffModel = false; // whether to use 1/xxx or not int junk; @@ -77,6 +76,7 @@ float lightscale = 1.0; float dlight_threshold = 0.1; // was DIRECT_LIGHT constant char source[MAX_PATH] = ""; +char platformPath[MAX_PATH] = ""; char level_name[MAX_PATH] = ""; // map filename, without extension or path info @@ -93,12 +93,14 @@ bool g_bInterrupt = false; // Wsed with background lighting in WC. Tells VRAD float g_SunAngularExtent=0.0; float g_flSkySampleScale = 1.0; +float g_flStaticPropSampleScale = 4.0; bool g_bLargeDispSampleRadius = false; bool g_bOnlyStaticProps = false; bool g_bShowStaticPropNormals = false; - +bool g_bStaticPropBounce = false; +float g_flStaticPropBounceBoost = 1.0f; float qgamma = 0.5; float indirect_sun = 1.0; @@ -125,11 +127,15 @@ bool g_bStaticPropLighting = false; bool g_bStaticPropPolys = false; bool g_bTextureShadows = false; bool g_bDisablePropSelfShadowing = false; - +bool g_bFastStaticProps = false; +bool g_bDumpBumpStaticProps = false; +bool g_bDisableStaticPropVertexInSolidTest = false; CUtlVector g_FacesVisibleToLights; RayTracingEnvironment g_RtEnv; +RayTracingEnvironment g_RtEnv_LightBlockers; // ray tracing environment consisting solely of light blockers - used in conjunction with bsp to solve indirect lighting for static props (as opposed to using the full RTE). +RayTracingEnvironment g_RtEnv_RadiosityPatches; dface_t *g_pFaces=0; @@ -290,7 +296,7 @@ void ReadLightFile (char *filename) texlights[j].filename = filename; file_texlights ++; - num_texlights = MAX( num_texlights, j + 1 ); + num_texlights = max( num_texlights, j + 1 ); } } qprintf ( "[%i texlights parsed from '%s']\n\n", file_texlights, filename); @@ -305,8 +311,6 @@ LightForTexture */ void LightForTexture( const char *name, Vector& result ) { - int i; - result[ 0 ] = result[ 1 ] = result[ 2 ] = 0; char baseFilename[ MAX_PATH ]; @@ -346,7 +350,7 @@ void LightForTexture( const char *name, Vector& result ) } } - for (i=0 ; ichild2 = g_Patches.InvalidIndex(); patch->parent = g_Patches.InvalidIndex(); patch->needsBumpmap = tx->flags & SURF_BUMPLIGHT ? true : false; + patch->staticPropIdx = -1; // link and save patch data patch->ndxNext = g_FacePatches.Element( fn ); @@ -739,6 +744,11 @@ void MakePatches (void) // make the displacement surface patches StaticDispMgr()->MakePatches(); + + if ( g_bStaticPropBounce ) + { + StaticPropMgr()->MakePatches(); + } } /* @@ -755,6 +765,12 @@ SUBDIVIDE //----------------------------------------------------------------------------- bool PreventSubdivision( CPatch *patch ) { + if ( patch->faceNumber < 0 ) + { + // static prop patch + return true; + } + dface_t *f = g_pFaces + patch->faceNumber; texinfo_t *tx = &texinfo[f->texinfo]; @@ -825,7 +841,7 @@ int CreateChildPatch( int nParentIndex, winding_t *pWinding, float flArea, const if ( (child->face_maxs[i] == child->maxs[i] || child->face_mins[i] == child->mins[i] ) && total[i] > minchop ) { - child->chop = MAX( minchop, child->chop / 2 ); + child->chop = max( minchop, child->chop / 2 ); break; } } @@ -885,7 +901,7 @@ void SubdividePatch( int ndxPatch ) if (patch->chop > minchop) { bSubdivide = true; - patch->chop = MAX( minchop, patch->chop / 2 ); + patch->chop = max( minchop, patch->chop / 2 ); } } } @@ -936,7 +952,7 @@ void SubdividePatches (void) if (numbounce == 0) return; - unsigned int uiPatchCount = g_Patches.Size(); + unsigned int uiPatchCount = g_Patches.Count(); qprintf ("%i patches before subdivision\n", uiPatchCount); for (i = 0; i < uiPatchCount; i++) @@ -944,6 +960,12 @@ void SubdividePatches (void) CPatch *pCur = &g_Patches.Element( i ); pCur->planeDist = pCur->plane->dist; + if ( pCur->faceNumber < 0 ) + { + // This and all following patches are "fake" staticprop patches. Set up parent data structure for them. + break; + } + pCur->ndxNextParent = faceParents.Element( pCur->faceNumber ); faceParents[pCur->faceNumber] = pCur - g_Patches.Base(); } @@ -974,10 +996,16 @@ void SubdividePatches (void) g_FacePatches[i] = g_FacePatches.InvalidIndex(); } - uiPatchCount = g_Patches.Size(); + uiPatchCount = g_Patches.Count(); for (i = 0; i < uiPatchCount; i++) { CPatch *pCur = &g_Patches.Element( i ); + if ( pCur->faceNumber < 0) + { + // Static prop patches don't have an associated face + continue; + } + pCur->ndxNext = g_FacePatches.Element( pCur->faceNumber ); g_FacePatches[pCur->faceNumber] = pCur - g_Patches.Base(); @@ -1282,7 +1310,7 @@ void WriteWorld (char *name, int iBump) if (!out) Error ("Couldn't open %s", name); - unsigned int uiPatchCount = g_Patches.Size(); + unsigned int uiPatchCount = g_Patches.Count(); for (j=0; jnumpoints = 3; - for( int i = 0; i < g_RtEnv.OptimizedTriangleList.Size(); i++ ) + for( int i = 0; i < g_RtEnv.OptimizedTriangleList.Count(); i++ ) { triw->p[0] = g_RtEnv.OptimizedTriangleList[i].Vertex( 0); triw->p[1] = g_RtEnv.OptimizedTriangleList[i].Vertex( 1); @@ -1424,7 +1452,7 @@ void CollectLight( Vector& total ) VectorFill( total, 0 ); // process patches in reverse order so that children are processed before their parents - unsigned int uiPatchCount = g_Patches.Size(); + unsigned int uiPatchCount = g_Patches.Count(); for( i = uiPatchCount - 1; i >= 0; i-- ) { patch = &g_Patches.Element( i ); @@ -1563,7 +1591,7 @@ void GatherLight (int threadnum, void *pUserData) Vector normals[NUM_BUMP_VECTS+1]; // Disps - bool bDisp = ( g_pFaces[patch->faceNumber].dispinfo != -1 ); + bool bDisp = ( patch->faceNumber >= 0 ) && ( g_pFaces[ patch->faceNumber ].dispinfo != -1 ); if ( bDisp ) { normals[0] = patch->normal; @@ -1663,7 +1691,7 @@ void BounceLight (void) char name[64]; qboolean bouncing = numbounce > 0; - unsigned int uiPatchCount = g_Patches.Size(); + unsigned int uiPatchCount = g_Patches.Count(); for (i=0 ; iemitlight to receiver->addlight - unsigned int uiPatchCount = g_Patches.Size(); + uiPatchCount = g_Patches.Count(); RunThreadsOn (uiPatchCount, true, GatherLight); // move newly received light (addlight) to light to be sent out (emitlight) // start at children and pull light up to parents @@ -1828,6 +1856,11 @@ void RadWorld_Start() // add displacement faces to cluster table AddDispsToClusterTable(); + if ( g_bStaticPropBounce ) + { + AddStaticPropPatchesToClusterTable(); + } + // create directlights out of patches and lights CreateDirectLights (); @@ -1940,6 +1973,21 @@ void MakeAllScales (void) qprintf ("transfer lists: %5.1f megs\n" , (float)total_transfer * sizeof(transfer_t) / (1024*1024)); + + if ( g_bStaticPropBounce ) + { + int nTransfers = 0; + for ( int i = 0; i < g_Patches.Count(); i++ ) + { + CPatch *pCur = &g_Patches.Element( i ); + if ( pCur->faceNumber >= 0 ) + { + continue; + } + nTransfers += pCur->numtransfers; + } + Msg( "static prop patch transfers %d\n", nTransfers ); + } } @@ -2025,17 +2073,51 @@ bool RadWorld_Go() BuildFacesVisibleToLights( true ); } -#ifdef MPI // build initial facelights +#ifdef MPI if (g_bUseMPI) { // RunThreadsOnIndividual (numfaces, true, BuildFacelights); RunMPIBuildFacelights(); + if ( g_bStaticPropBounce ) + { + RunThreadsOnIndividual( g_Patches.Count(), true, BuildStaticPropPatchlights ); + } } else #endif { - RunThreadsOnIndividual (numfaces, true, BuildFacelights); + RunThreadsOnIndividual( numfaces, true, BuildFacelights ); + if ( g_bStaticPropBounce ) + { + RunThreadsOnIndividual( g_Patches.Count(), true, BuildStaticPropPatchlights ); + } +#if 0 + IScratchPad3D *pPad = ScratchPad3D_Create(); + pPad->SetAutoFlush( false ); + float flMax = 0.0f; + for ( int i = 0; i < g_Patches.Count(); i++ ) + { + if ( g_Patches[ i ].child1 != g_Patches.InvalidIndex() || g_Patches[ i ].child2 != g_Patches.InvalidIndex() ) + continue; + Vector vLight = g_Patches[ i ].directlight; + flMax = Max( flMax, vLight.x ); + flMax = Max( flMax, vLight.y ); + flMax = Max( flMax, vLight.z ); + } + for ( int i = 0; i < g_Patches.Count(); i++ ) + { + if ( g_Patches[ i ].child1 != g_Patches.InvalidIndex() || g_Patches[ i ].child2 != g_Patches.InvalidIndex() ) + continue; + Vector vLight = g_Patches[ i ].directlight * g_Patches[i].reflectivity; + vLight /= flMax; + vLight.x = SrgbLinearToGamma( vLight.x ); + vLight.y = SrgbLinearToGamma( vLight.y ); + vLight.z = SrgbLinearToGamma( vLight.z ); + pPad->DrawPolygon( CSPVertList( g_Patches[ i ].winding->p, g_Patches[ i ].winding->numpoints, CSPColor( vLight ) ) ); + } + pPad->Release(); +#endif } // Was the process interrupted? @@ -2068,10 +2150,10 @@ bool RadWorld_Go() if (numbounce > 0) { // allocate memory for emitlight/addlight - emitlight.SetSize( g_Patches.Size() ); - memset( emitlight.Base(), 0, g_Patches.Size() * sizeof( Vector ) ); - addlight.SetSize( g_Patches.Size() ); - memset( addlight.Base(), 0, g_Patches.Size() * sizeof( bumplights_t ) ); + emitlight.SetSize( g_Patches.Count() ); + memset( emitlight.Base(), 0, g_Patches.Count() * sizeof( Vector ) ); + addlight.SetSize( g_Patches.Count() ); + memset( addlight.Base(), 0, g_Patches.Count() * sizeof( bumplights_t ) ); MakeAllScales (); @@ -2087,12 +2169,13 @@ bool RadWorld_Go() StaticDispMgr()->InsertPatchSampleDataIntoHashTable(); StaticDispMgr()->EndTimer(); -#ifdef MPI // blend bounced light into direct light and save +#ifdef MPI VMPI_SetCurrentStage( "FinalLightFace" ); if ( !g_bUseMPI || g_bMPIMaster ) #endif RunThreadsOnIndividual (numfaces, true, FinalLightFace); + #ifdef MPI // Distribute the lighting data to workers. VMPI_DistributeLightData(); @@ -2131,7 +2214,6 @@ void InitDumpPatchesFiles() } } -extern IFileSystem *g_pOriginalPassThruFileSystem; void VRAD_LoadBSP( char const *pFilename ) { @@ -2204,23 +2286,7 @@ void VRAD_LoadBSP( char const *pFilename ) VMPI_SetCurrentStage( "LoadBSPFile" ); #endif LoadBSPFile (source); - -#ifdef MPI - // Add this bsp to our search path so embedded resources can be found - if ( g_bUseMPI && g_bMPIMaster ) - { - // MPI Master, MPI workers don't need to do anything - g_pOriginalPassThruFileSystem->AddSearchPath(source, "GAME", PATH_ADD_TO_HEAD); - g_pOriginalPassThruFileSystem->AddSearchPath(source, "MOD", PATH_ADD_TO_HEAD); - } - else if ( !g_bUseMPI ) -#endif - { - // Non-MPI - g_pFullFileSystem->AddSearchPath(source, "GAME", PATH_ADD_TO_HEAD); - g_pFullFileSystem->AddSearchPath(source, "MOD", PATH_ADD_TO_HEAD); - } - + // now, set whether or not static prop lighting is present if (g_bStaticPropLighting) g_LevelFlags |= g_bHDR? LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_HDR : LVLFLAGS_BAKED_STATIC_PROP_LIGHTING_NONHDR; @@ -2295,6 +2361,7 @@ void VRAD_LoadBSP( char const *pFilename ) printf ( "Setting up ray-trace acceleration structure... "); float start = Plat_FloatTime(); g_RtEnv.SetupAccelerationStructure(); + g_RtEnv_LightBlockers.SetupAccelerationStructure(); float end = Plat_FloatTime(); printf ( "Done (%.2f seconds)\n", end-start ); @@ -2390,16 +2457,29 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail ) { *onlydetail = false; - int mapArg = -1; - // default to LDR SetHDRMode( false ); int i; for( i=1 ; i : Treat the sun as an area light source of size degrees." " Produces soft shadows.\n" " Recommended values are between 0 and 5. Default is 0.\n" -#ifdef _WIN32 " -FullMinidumps : Write large minidumps on crash.\n" -#endif " -chop : Smallest number of luxel widths for a bounce patch, used on edges\n" - " -maxchop : Coarsest allowed number of luxel widths for a patch, used in face interiors\n" - "\n" - " -LargeDispSampleRadius: This can be used if there are splotches of bounced light\n" - " on terrain. The compile will take longer, but it will gather\n" - " light across a wider area.\n" - " -StaticPropLighting : generate backed static prop vertex lighting\n" + " -maxchop : Coarsest allowed number of luxel widths for a patch, used in face interiors\n" + " -LargeDispSampleRadius: This can be used if there are splotches of bounced\n" + " light on terrain. The compile will take longer, but\n" + " it will gather light across a wider area.\n" + " -StaticPropLighting : generate baked static prop vertex lighting\n" + " -StaticPropLightingFinal : generate baked static prop vertex lighting (uses higher/final quality processing)\n" " -StaticPropPolys : Perform shadow tests of static props at polygon precision\n" " -OnlyStaticProps : Only perform direct static prop lighting (vrad debug option)\n" " -StaticPropNormals : when lighting static props, just show their normal vector\n" + " -StaticPropBounce : Enable static props to bounce light. Experimental option, doesn't work with VMPI right now.\n" " -textureshadows : Allows texture alpha channels to block light - rays intersecting alpha surfaces will sample the texture\n" " -noskyboxrecurse : Turn off recursion into 3d skybox (skybox shadows on world)\n" " -nossprops : Globally disable self-shadowing on static props\n" @@ -2937,23 +3065,17 @@ int RunVRAD( int argc, char **argv ) Msg("\n Valve Radiosity Simulator \n"); Q_strncpy(g_FileName, argv[0], MAX_PATH); - verbose = true; // Originally FALSE bool onlydetail; int i = ParseCommandLine( argc, argv, &onlydetail ); - if (i == -1) + if (i != argc - 1) { PrintUsage( argc, argv ); DeleteCmdLine( argc, argv ); - CmdLib_Exit( 1 ); + Plat_ExitProcess( 0 ); } - // Initialize the filesystem, so additional commandline options can be loaded - Q_StripExtension( argv[ i ], source, sizeof( source ) ); - CmdLib_InitFileSystem( argv[ i ] ); - Q_FileBase( source, source, sizeof( source ) ); - VRAD_LoadBSP( argv[i] ); if ( (! onlydetail) && (! g_bOnlyStaticProps ) ) @@ -2984,7 +3106,14 @@ int VRAD_Main(int argc, char **argv) #ifdef MPI // This must come first. VRAD_SetupMPI( argc, argv ); +#endif + // Initialize the filesystem, so additional commandline options can be loaded + Q_StripExtension( argv[ argc - 1 ], source, sizeof( source ) ); + CmdLib_InitFileSystem( argv[ argc - 1 ] ); + Q_FileBase( source, source, sizeof( source ) ); + +#ifdef MPI #if !defined( _DEBUG ) if ( g_bUseMPI && !g_bMPIMaster ) { diff --git a/utils/vrad/vrad.h b/utils/vrad/vrad.h index 372187628..a4ee65fdd 100644 --- a/utils/vrad/vrad.h +++ b/utils/vrad/vrad.h @@ -34,12 +34,15 @@ #ifdef _WIN32 #include +#pragma warning(disable: 4142 4028) #include +#pragma warning(default: 4142 4028) #include #endif #include #include + #include #include @@ -77,6 +80,11 @@ struct directlight_t float soffset; float toffset; + // Flag indicating that even though light.type is emit_skylight, treat this light as a + // directional light source in vrad + bool m_bSkyLightIsDirectionalLight; + float m_flSkyLightSunAngularExtent; + int dorecalc; // position, vector, spot angle, etc. IncrementalLightID m_IncrementalID; @@ -89,6 +97,8 @@ struct directlight_t directlight_t(void) { + m_bSkyLightIsDirectionalLight = false; + m_flSkyLightSunAngularExtent = 0.0f; m_flEndFadeDistance = -1.0; // end g_NonShadowCastingMaterialStrings; extern void ForceTextureShadowsOnModel( const char *pModelName ); extern bool IsModelTextureShadowsForced( const char *pModelName ); +extern int LoadShadowTexture( const char *pMaterialName ); +extern int AddShadowTextureTriangle( int shadowTextureIndex, const Vector2D &t0, const Vector2D &t1, const Vector2D &t2 ); +extern float ComputeCoverageForTriangle( int shadowTextureIndex, const Vector2D &t0, const Vector2D &t1, const Vector2D &t2 ); +extern void GetShadowTextureMapping( int shadowTextureIndex, int *pWidth, int *pHeight ); // Raytracing #define TRACE_ID_SKY 0x01000000 // sky face ray blocker #define TRACE_ID_OPAQUE 0x02000000 // everyday light blocking face #define TRACE_ID_STATICPROP 0x04000000 // static prop - lower bits are prop ID +#define TRACE_ID_PATCH 0x08000000 // patch - lower bits are patch ID extern RayTracingEnvironment g_RtEnv; +extern RayTracingEnvironment g_RtEnv_LightBlockers; +extern RayTracingEnvironment g_RtEnv_RadiosityPatches; // Contains patches for final gather of indirect light for static prop lighting. #include "mpivrad.h" @@ -307,6 +331,7 @@ void MakeShadowSplits (void); void BuildVisMatrix (void); void BuildClusterTable( void ); void AddDispsToClusterTable( void ); +void AddStaticPropPatchesToClusterTable(); void FreeVisMatrix (void); // qboolean CheckVisBit (unsigned int p1, unsigned int p2); void TouchVMFFile (void); @@ -357,13 +382,11 @@ qboolean IsIncremental(char *filename); int SaveIncremental(char *filename); int PartialHead (void); void BuildFacelights (int facenum, int threadnum); +void BuildStaticPropPatchlights( int iThread, int nPatch ); void PrecompLightmapOffsets(); void FinalLightFace (int threadnum, int facenum); void PvsForOrigin (Vector& org, byte *pvs); -void ConvertRGBExp32ToRGBA8888( const ColorRGBExp32 *pSrc, unsigned char *pDst, Vector* _optOutLinear = NULL ); -void ConvertRGBExp32ToLinear(const ColorRGBExp32 *pSrc, Vector* pDst); -void ConvertLinearToRGBA8888( const Vector *pSrc, unsigned char *pDst ); - +void ConvertRGBExp32ToRGBA8888( const ColorRGBExp32 *pSrc, unsigned char *pDst ); inline byte PVSCheck( const byte *pvs, int iCluster ) { @@ -382,6 +405,9 @@ inline byte PVSCheck( const byte *pvs, int iCluster ) // outputs 1 in fractionVisible if no occlusion, 0 if full occlusion, and in-between values void TestLine( FourVectors const& start, FourVectors const& stop, fltx4 *pFractionVisible, int static_prop_index_to_ignore=-1); +void TestLine_IgnoreSky( FourVectors const& start, FourVectors const& stop, fltx4 *pFractionVisible, int static_prop_index_to_ignore=-1); +void TestLine_LightBlockers( const FourVectors& start, const FourVectors& stop, fltx4 *pFractionVisible ); + // returns 1 if the ray sees the sky, 0 if it doesn't, and in-between values for partial coverage void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop, fltx4 *pFractionVisible, bool canRecurse = true, int static_prop_to_skip=-1, bool bDoDebug = false ); @@ -442,12 +468,14 @@ float TraceLeafBrushes( int leafIndex, const Vector &start, const Vector &end, C struct SSE_sampleLightOutput_t { fltx4 m_flDot[NUM_BUMP_VECTS+1]; + fltx4 m_flSunAmount[NUM_BUMP_VECTS + 1]; fltx4 m_flFalloff; - fltx4 m_flSunAmount; }; -#define GATHERLFLAGS_FORCE_FAST 1 -#define GATHERLFLAGS_IGNORE_NORMALS 2 +#define GATHERLFLAGS_FORCE_FAST 1 /* Use 4x fewer rays when sampling area lights */ +#define GATHERLFLAGS_IGNORE_NORMALS 2 /* Ignore surface normals in lighting calculations */ +#define GATHERLFLAGS_NO_OCCLUSION 4 /* Ignore occlusion for local lights (but not sun, sky or bounce lighting) */ +#define GATHERLFLAGS_STATICPROP 8 /* Paths for static props */ // SSE Gather light stuff void GatherSampleLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum, @@ -471,6 +499,10 @@ void GatherSampleLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int // int static_prop_to_skip=-1, // float flEpsilon = 0.0 ); +void ComputeDirectLightingAtPoint( Vector &position, Vector *normals, Vector *outColors, float *outSunAmount, int numNormals, bool bSkipSkyLight, int iThread, + int static_prop_id_to_skip = -1, int nLFlags = 0 ); + + //----------------------------------------------------------------------------- // VRad Displacements //----------------------------------------------------------------------------- @@ -514,6 +546,8 @@ class IVRadDispMgr // utility virtual void GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal, bool bInside ) = 0; + virtual void GetDispSurfPointAndNormalFromUV( int ndxFace, Vector &pt, Vector &ptNormal, + Vector2D &uv, bool bInside ) = 0; virtual void GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree ) = 0; // bsp tree functions @@ -577,7 +611,9 @@ extern int patchSamplesAdded; void ComputeDetailPropLighting( int iThread ); void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &outColor, - int iThread, bool force_fast = false, bool bIgnoreNormals = false ); + int iThread, bool force_fast = false, bool bIgnoreNormals = false, int nStaticPropToSkip = -1 ); +void ComputeIndirectLightingAtPoint( Vector &position, Vector *normals, Vector *outColors, int numNormals, + int iThread, bool force_fast = false, bool bIgnoreNormals = false, int nStaticPropToSkip = -1 ); //----------------------------------------------------------------------------- // VRad static props @@ -598,6 +634,7 @@ class IVradStaticPropMgr virtual void Shutdown() = 0; virtual void ComputeLighting( int iThread ) = 0; virtual void AddPolysForRayTrace() = 0; + virtual void MakePatches() = 0; }; //extern PropTested_t s_PropTested[MAX_TOOL_THREADS+1]; diff --git a/utils/vrad/vrad_dispcoll.cpp b/utils/vrad/vrad_dispcoll.cpp index b04b2f985..74004f4e7 100644 --- a/utils/vrad/vrad_dispcoll.cpp +++ b/utils/vrad/vrad_dispcoll.cpp @@ -101,7 +101,7 @@ void CVRADDispColl::CalcSampleRadius2AndBox( dface_t *pFace ) m_flSampleHeight = flHeight; // Calculate the sample radius squared. - float flSampleRadius = sqrt( ( ( flWidth * flWidth ) + ( flHeight * flHeight ) ) ) * 2.2f;//RADIALDIST2; + float flSampleRadius = sqrt( ( ( flWidth * flWidth ) + ( flHeight * flHeight ) ) ); // * 2.2f;//RADIALDIST2; // AV - Removing the 2.2 scalar since 1.0 works better with CS:GO if ( flSampleRadius > g_flMaxDispSampleSize ) { flSampleRadius = g_flMaxDispSampleSize; @@ -110,8 +110,7 @@ void CVRADDispColl::CalcSampleRadius2AndBox( dface_t *pFace ) // Calculate the patch radius - the max sample edge length * the number of luxels per edge "chop." float flSampleSize = max( m_flSampleWidth, m_flSampleHeight ); - // Calculate the patch radius - the MAX sample edge length * the number of luxels per edge "chop." - float flPatchSampleRadius = flSampleSize * dispchop * 2.2f; + float flPatchSampleRadius = flSampleSize * dispchop * ( g_bLargeDispSampleRadius ? 2.2f : 1.0f ); // AV - Removing the 2.2 scalar since 1.0 works better with CS:GO. TS - It fixes lighting artefacts in maps with many small displacements. if ( flPatchSampleRadius > g_MaxDispPatchRadius ) { flPatchSampleRadius = g_MaxDispPatchRadius; @@ -441,7 +440,7 @@ void CVRADDispColl::CreateChildPatchesFromRoot( int iParentPatch, int *pChildPat vecEdges[3] = pParentPatch->winding->p[3] - pParentPatch->winding->p[0]; // Should the patch be subdivided - check the area. - float flMaxLength = MAX( m_flSampleWidth, m_flSampleHeight ); + float flMaxLength = max( m_flSampleWidth, m_flSampleHeight ); float flMinEdgeLength = flMaxLength * dispchop; // Find the longest edge. @@ -552,7 +551,7 @@ void CVRADDispColl::CreateChildPatches( int iParentPatch, int nLevel ) return; // Should the patch be subdivided - check the area. - float flMaxLength = MAX( m_flSampleWidth, m_flSampleHeight ); + float flMaxLength = max( m_flSampleWidth, m_flSampleHeight ); float flMinEdgeLength = flMaxLength * dispchop; // Split along the longest edge. @@ -660,14 +659,14 @@ void CVRADDispColl::CreateChildPatchesSub( int iParentPatch ) return; // Should the patch be subdivided - check the area. - float flMaxLength = MAX( m_flSampleWidth, m_flSampleHeight ); + float flMaxLength = max( m_flSampleWidth, m_flSampleHeight ); float flMinEdgeLength = flMaxLength * dispchop; // Split along the longest edge. Vector vecEdges[3]; vecEdges[0] = pParentPatch->winding->p[1] - pParentPatch->winding->p[0]; - vecEdges[1] = pParentPatch->winding->p[2] - pParentPatch->winding->p[1]; - vecEdges[2] = pParentPatch->winding->p[0] - pParentPatch->winding->p[2]; + vecEdges[1] = pParentPatch->winding->p[2] - pParentPatch->winding->p[0]; + vecEdges[2] = pParentPatch->winding->p[2] - pParentPatch->winding->p[1]; // Find the longest edge. float flEdgeLength = 0.0f; @@ -818,6 +817,7 @@ bool CVRADDispColl::InitParentPatch( int iPatch, Vector *pPoints, float &flArea pPatch->parent = g_Patches.InvalidIndex(); pPatch->ndxNextClusterChild = g_Patches.InvalidIndex(); pPatch->ndxNextParent = g_Patches.InvalidIndex(); + pPatch->staticPropIdx = -1; Vector vecEdges[2]; vecEdges[0] = pPoints[1] - pPoints[0]; @@ -911,6 +911,7 @@ bool CVRADDispColl::InitPatch( int iPatch, int iParentPatch, int iChild, Vector // Clear the patch data. memset( pPatch, 0, sizeof( CPatch ) ); + pPatch->staticPropIdx = -1; // Setup the parent if we are not the parent. CPatch *pParentPatch = NULL; @@ -1067,7 +1068,7 @@ void CVRADDispColl::AddPolysForRayTrace( void ) if ( !( m_nContents & MASK_OPAQUE ) ) return; - for ( int ndxTri = 0; ndxTri < m_aTris.Size(); ndxTri++ ) + for ( int ndxTri = 0; ndxTri < m_aTris.Count(); ndxTri++ ) { CDispCollTri *tri = m_aTris.Base() + ndxTri; int v[3]; diff --git a/utils/vrad/vraddetailprops.cpp b/utils/vrad/vraddetailprops.cpp index 8c40bb011..09f514f63 100644 --- a/utils/vrad/vraddetailprops.cpp +++ b/utils/vrad/vraddetailprops.cpp @@ -24,6 +24,8 @@ #endif #include "byteswap.h" +extern float SoftenCosineTerm( float flDot ); +extern float CalculateAmbientOcclusion( Vector *pPosition, Vector *pNormal ); bool LoadStudioModel( char const* pModelName, CUtlBuffer& buf ); @@ -228,12 +230,8 @@ static void ComputeMaxDirectLighting( DetailObjectLump_t& prop, Vector* maxcolor origin4.DuplicateVector( origin ); normal4.DuplicateVector( normal ); - GatherSampleLightSSE ( out, dl, -1, origin4, &normal4, 1, iThread ); -#ifdef VRAD_SSE - VectorMA( maxcolor[dl->light.style], out.m_flFalloff.m128_f32[0] * out.m_flDot[0].m128_f32[0], dl->light.intensity, maxcolor[dl->light.style] ); -#else + GatherSampleLightSSE ( out, dl, -1, origin4, &normal4, 1, iThread, GATHERLFLAGS_STATICPROP ); VectorMA( maxcolor[dl->light.style], out.m_flFalloff[0] * out.m_flDot[0][0], dl->light.intensity, maxcolor[dl->light.style] ); -#endif } } @@ -659,23 +657,80 @@ static void ComputeAmbientLightingAtPoint( int iThread, const Vector &origin, Ve } //----------------------------------------------------------------------------- -// Trace hemispherical rays from a vertex, accumulating indirect -// sources at each ray termination. +// +// Trace a ray from position. in the specified direction to determine a positive +// hit for indirect lighting. +// +// Fire ray out from start, with end as start + direction*MAX_TRACE_LENGTH +// If hit then fire ray back to start to see if it hits a back facing surface that would natually block the incoming light ray +// If still okay then test explicitly against light blockers, test only in the hit to start direction +// Update surfEnum and return true if a valid intersection for indirect light. +// //----------------------------------------------------------------------------- -void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &outColor, - int iThread, bool force_fast, bool bIgnoreNormals ) +bool TraceIndirectLightingSample( Vector &position, Vector &direction, CLightSurface &surfEnum, int iThread, bool force_fast ) { Ray_t ray; - CLightSurface surfEnum(iThread); - outColor.Init(); + // trace to determine surface + Vector vEnd, vStart; + VectorScale( direction, MAX_TRACE_LENGTH, vEnd ); + VectorAdd( position, vEnd, vEnd ); + + if ( force_fast ) + { + vStart = position; + } + else + { + // offset ray start position to compensate for ray leakage due to coincident surfaces (we are seeing some ray tests leak in some situations - e.g. prop vertex lies on ground plane) + VectorScale( direction, -EQUAL_EPSILON, vStart ); + VectorAdd( position, vStart, vStart ); + } + ray.Init( vStart, vEnd, vec3_origin, vec3_origin ); + if ( !surfEnum.FindIntersection( ray ) ) + return false; + + // Now test explicitly against light blockers (surfaces don't exist in the bsp nodes we're checking here, and this feels a safer change than updating indirect lighting for static props to use the slower rte path for all rays) + // test from hitfrac back to start only + VectorScale( direction, MAX_TRACE_LENGTH * surfEnum.m_HitFrac, vEnd ); + VectorAdd( position, vEnd, vEnd ); + FourVectors rayStart, rayEnd, rayDirection; + fltx4 fractionVisible = Four_Ones; + rayStart.DuplicateVector( vStart ); + rayEnd.DuplicateVector( vEnd ); + +// rayDirection.DuplicateVector( direction ); +// TestLine_LightBlockers( rayStart, rayEnd, &fractionVisible ); + + rayDirection.DuplicateVector( -direction ); + TestLine_LightBlockers( rayEnd, rayStart, &fractionVisible ); + + + if ( fractionVisible[0] < 1.0f ) + { + // ray hit blocker + return false; + } + + return true; +} +//----------------------------------------------------------------------------- +// Trace hemispherical rays from a vertex, accumulating indirect +// sources at each ray termination. +// +// force_fast = false currently implies 'new/improved' static prop lighting is to be used. +//----------------------------------------------------------------------------- +void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &outColor, + int iThread, bool force_fast, bool bIgnoreNormals, int nStaticPropToSkip ) +{ + outColor.Zero(); int nSamples = NUMVERTEXNORMALS; - if ( do_fast || force_fast ) - nSamples /= 4; - else - nSamples *= g_flSkySampleScale; + if ( do_fast || force_fast ) + nSamples /= 4; + else + nSamples *= g_flStaticPropSampleScale; float totalDot = 0; DirectionalSampler_t sampler; @@ -696,15 +751,44 @@ void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &o } totalDot += dot; + + // trace static prop indirect + Vector staticPropIndirectColor( 0.0f, 0.0f, 0.0f ); + float flStaticPropHitDist = FLT_MAX; + if ( g_bStaticPropBounce ) + { + FourRays myrays; + myrays.origin.DuplicateVector( position ); + myrays.direction.DuplicateVector( samplingNormal ); + RayTracingResult rt_result; + g_RtEnv_RadiosityPatches.Trace4Rays( myrays, ReplicateX4( 10.0f ), ReplicateX4( MAX_TRACE_LENGTH ), &rt_result ); + if ( rt_result.HitIds[ 0 ] != -1 ) + { + const TriIntersectData_t &intersectData = g_RtEnv_RadiosityPatches.OptimizedTriangleList[ rt_result.HitIds[ 0 ] ].m_Data.m_IntersectData; + int nId = intersectData.m_nTriangleID; + if ( nId & TRACE_ID_PATCH ) + { + int nPatchId = nId & ~TRACE_ID_PATCH; + CPatch &patch = g_Patches[ nPatchId ]; + if ( patch.staticPropIdx != nStaticPropToSkip ) + { + staticPropIndirectColor = dot * ( patch.totallight.light[ 0 ] + patch.directlight ) * patch.reflectivity; + flStaticPropHitDist = SubFloat( rt_result.HitDistance, 0 ); + } + } + } + } - // trace to determine surface - Vector vEnd; - VectorScale( samplingNormal, MAX_TRACE_LENGTH, vEnd ); - VectorAdd( position, vEnd, vEnd ); + // important to put the constructor here to init m_hitfrac, etc + CLightSurface surfEnum( iThread ); - ray.Init( position, vEnd, vec3_origin, vec3_origin ); - if ( !surfEnum.FindIntersection( ray ) ) + // trace to determine surface + if ( !TraceIndirectLightingSample( position, samplingNormal, surfEnum, iThread, force_fast ) || + flStaticPropHitDist < surfEnum.m_HitFrac * MAX_TRACE_LENGTH ) + { + VectorAdd( outColor, staticPropIndirectColor, outColor ); // we may have hit a static prop patch continue; + } // get color from surface lightmap texinfo_t* pTex = &texinfo[surfEnum.m_pSurface->texinfo]; @@ -721,7 +805,6 @@ void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &o continue; } - Vector lightmapColor; if ( !surfEnum.m_bHasLuxel ) { @@ -744,18 +827,282 @@ void ComputeIndirectLightingAtPoint( Vector &position, Vector &normal, Vector &o ColorRGBExp32ToVector( *pLightmap, lightmapColor ); } - float invLengthSqr = 1.0f / (1.0f + ((vEnd - position) * surfEnum.m_HitFrac / 128.0).LengthSqr()); - // Include falloff using invsqrlaw. - VectorMultiply( lightmapColor, invLengthSqr * dtexdata[pTex->texdata].reflectivity, lightmapColor ); + if ( force_fast ) + { + VectorMultiply( lightmapColor, dtexdata[pTex->texdata].reflectivity, lightmapColor ); + } + else + { + // Include dot falloff on accumulating irradiance here + // have tried using inv sqr falloff from TF2 changes to vrad (CL#2394791 & 2395471), but the result is very sensitive to the scale factor that is used (too dark or too bright otherwise) + // this seems to give the most natural looking result (static props matching brushes) + VectorMultiply( lightmapColor, dot * dtexdata[pTex->texdata].reflectivity, lightmapColor ); + } VectorAdd( outColor, lightmapColor, outColor ); } if ( totalDot ) { - VectorScale( outColor, 1.0f/totalDot, outColor ); + VectorScale( outColor, 1.0f / totalDot, outColor ); } } +void ComputeIndirectLightingAtPoint( Vector &position, Vector *normals, Vector *outColors, int numNormals, + int iThread, bool force_fast, bool bIgnoreNormals, int nStaticPropToSkip ) +{ + const Vector vZero(0.0f, 0.0f, 0.0f); + + if ( numNormals != ( NUM_BUMP_VECTS + 1 ) ) + { + for ( int k = 0; k < numNormals; ++k ) + { + ComputeIndirectLightingAtPoint( position, normals[k], outColors[k], iThread, force_fast, bIgnoreNormals, nStaticPropToSkip ); + } + return; + } + + // optimize/unroll for num_bump_vects = 3 + outColors[0].Zero(); + outColors[1].Zero(); + outColors[2].Zero(); + outColors[3].Zero(); + + int nSamples = NUMVERTEXNORMALS; + if ( do_fast || force_fast ) + nSamples /= 4; + else + nSamples *= g_flStaticPropSampleScale; + + float totalDot[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + DirectionalSampler_t sampler; + for ( int j = 0; j < nSamples; j++ ) + { + Vector samplingNormal = sampler.NextValue(); + float dot[4]; + + if ( bIgnoreNormals ) + { + dot[0] = dot[1] = dot[2] = dot[3] = (0.7071 / 2); + } + else + { + samplingNormal.NormalizeInPlace(); + dot[0] = DotProduct( normals[0], samplingNormal ); + dot[1] = DotProduct( normals[1], samplingNormal ); + dot[2] = DotProduct( normals[2], samplingNormal ); + dot[3] = DotProduct( normals[3], samplingNormal ); + } + + bool bDoRayTrace = false; + bool bIncLighting[4] = {false, false, false, false}; + + if ( dot[0] > EQUAL_EPSILON ) + { + dot[0] = SoftenCosineTerm( dot[0] ); + totalDot[0] += dot[0]; + bDoRayTrace = true; + bIncLighting[0] = true; + } + else + { + dot[0] = 0.0f; + } + + if ( dot[1] > EQUAL_EPSILON ) + { + dot[1] = SoftenCosineTerm( dot[1] ); + totalDot[1] += dot[1]; + bDoRayTrace = true; + bIncLighting[1] = true; + } + else + { + dot[1] = 0.0f; + } + + if ( dot[2] > EQUAL_EPSILON ) + { + dot[2] = SoftenCosineTerm( dot[2] ); + totalDot[2] += dot[2]; + bDoRayTrace = true; + bIncLighting[2] = true; + } + else + { + dot[2] = 0.0f; + } + + if ( dot[3] > EQUAL_EPSILON ) + { + dot[3] = SoftenCosineTerm( dot[3] ); + totalDot[3] += dot[3]; + bDoRayTrace = true; + bIncLighting[3] = true; + } + else + { + dot[3] = 0.0f; + } + + // important to skip + if ( dot[0] <= EQUAL_EPSILON ) + { + continue; + } + + if ( bDoRayTrace ) + { + Vector staticPropIndirectColor( 0.0f, 0.0f, 0.0f ); + float flStaticPropHitDist = FLT_MAX; + if ( g_bStaticPropBounce ) + { + FourRays myrays; + myrays.origin.DuplicateVector( position ); + myrays.direction.DuplicateVector( samplingNormal ); + RayTracingResult rt_result; + g_RtEnv_RadiosityPatches.Trace4Rays( myrays, ReplicateX4( 10.0f ), ReplicateX4( MAX_TRACE_LENGTH ), &rt_result ); + if ( rt_result.HitIds[ 0 ] != -1 ) + { + const TriIntersectData_t &intersectData = g_RtEnv_RadiosityPatches.OptimizedTriangleList[ rt_result.HitIds[ 0 ] ].m_Data.m_IntersectData; + int nId = intersectData.m_nTriangleID; + if ( nId & TRACE_ID_PATCH ) + { + int nPatchId = nId & ~TRACE_ID_PATCH; + CPatch &patch = g_Patches[ nPatchId ]; + if ( patch.staticPropIdx != nStaticPropToSkip ) + { + staticPropIndirectColor = ( patch.totallight.light[ 0 ] + patch.directlight ) * patch.reflectivity; + flStaticPropHitDist = SubFloat( rt_result.HitDistance, 0 ); + } + } + } + } + + + // important to put the constructor here to init m_hitfrac, etc + CLightSurface surfEnum( iThread ); + + // trace to determine surface + if ( !TraceIndirectLightingSample( position, samplingNormal, surfEnum, iThread, force_fast ) || + flStaticPropHitDist < surfEnum.m_HitFrac * MAX_TRACE_LENGTH ) + { + // The dot values are 0 if bIncLighting is false so we don't actually need to branch here. + VectorAdd( outColors[ 0 ], dot[ 0 ] * staticPropIndirectColor, outColors[ 0 ] ); // we may have hit a static prop patch + VectorAdd( outColors[ 1 ], dot[ 1 ] * staticPropIndirectColor, outColors[ 1 ] ); + VectorAdd( outColors[ 2 ], dot[ 2 ] * staticPropIndirectColor, outColors[ 2 ] ); + VectorAdd( outColors[ 3 ], dot[ 3 ] * staticPropIndirectColor, outColors[ 3 ] ); + continue; + } + + // get color from surface lightmap + texinfo_t* pTex = &texinfo[surfEnum.m_pSurface->texinfo]; + if ( !pTex || pTex->flags & SURF_SKY ) + { + // ignore contribution from sky + // sky ambient already accounted for during direct pass + continue; + } + + if ( surfEnum.m_pSurface->styles[0] == 255 || surfEnum.m_pSurface->lightofs < 0 ) + { + // no light affects this face + continue; + } + + Vector lightmapColor; + Vector lightmapColors[4]; + if ( !surfEnum.m_bHasLuxel ) + { + ColorRGBExp32* pAvgLightmapColor = dface_AvgLightColor( surfEnum.m_pSurface, 0 ); + ColorRGBExp32ToVector( *pAvgLightmapColor, lightmapColor ); + } + else + { + // get color from displacement + int smax = (surfEnum.m_pSurface->m_LightmapTextureSizeInLuxels[0]) + 1; + int tmax = (surfEnum.m_pSurface->m_LightmapTextureSizeInLuxels[1]) + 1; + + // luxelcoord is in the space of the accumulated lightmap page; we need to convert + // it to be in the space of the surface + int ds = clamp( (int)surfEnum.m_LuxelCoord.x, 0, smax - 1 ); + int dt = clamp( (int)surfEnum.m_LuxelCoord.y, 0, tmax - 1 ); + + ColorRGBExp32* pLightmap = (ColorRGBExp32*)&(*pdlightdata)[surfEnum.m_pSurface->lightofs]; + pLightmap += dt * smax + ds; + ColorRGBExp32ToVector( *pLightmap, lightmapColor ); + } + + lightmapColor.Max( vZero ); + + if ( force_fast ) + { + VectorMultiply( lightmapColor, dtexdata[pTex->texdata].reflectivity, lightmapColors[0] ); + + if ( bIncLighting[0] ) + { + VectorAdd( outColors[0], lightmapColors[0], outColors[0] ); + } + if ( bIncLighting[1] ) + { + VectorAdd( outColors[1], lightmapColors[0], outColors[1] ); + } + if ( bIncLighting[2] ) + { + VectorAdd( outColors[2], lightmapColors[0], outColors[2] ); + } + if ( bIncLighting[3] ) + { + VectorAdd( outColors[3], lightmapColors[0], outColors[3] ); + } + } + else + { + // Include dot falloff on accumulating irradiance here + // have tried using inv sqr falloff from TF2 changes to vrad (CL#2394791 & 2395471), but the result is very sensitive to the scale factor that is used (too dark or too bright otherwise) + // this seems to give the most natural looking result (static props matching brushes) + if ( bIncLighting[0] ) + { + VectorMultiply( lightmapColor, dot[0] * dtexdata[pTex->texdata].reflectivity, lightmapColors[0] ); + VectorAdd( outColors[0], lightmapColors[0], outColors[0] ); + } + if ( bIncLighting[1] ) + { + VectorMultiply( lightmapColor, dot[1] * dtexdata[pTex->texdata].reflectivity, lightmapColors[1] ); + VectorAdd( outColors[1], lightmapColors[1], outColors[1] ); + } + if ( bIncLighting[2] ) + { + VectorMultiply( lightmapColor, dot[2] * dtexdata[pTex->texdata].reflectivity, lightmapColors[2] ); + VectorAdd( outColors[2], lightmapColors[2], outColors[2] ); + } + if ( bIncLighting[3] ) + { + VectorMultiply( lightmapColor, dot[3] * dtexdata[pTex->texdata].reflectivity, lightmapColors[3] ); + VectorAdd( outColors[3], lightmapColors[3], outColors[3] ); + } + } + } + } + + if ( totalDot[0] ) + { + VectorScale( outColors[0], 1.0f / totalDot[0], outColors[0] ); + } + if ( totalDot[1] ) + { + VectorScale( outColors[1], 1.0f / totalDot[1], outColors[1] ); + } + if ( totalDot[2] ) + { + VectorScale( outColors[2], 1.0f / totalDot[2], outColors[2] ); + } + if ( totalDot[3] ) + { + VectorScale( outColors[3], 1.0f / totalDot[3], outColors[3] ); + } +} + + static void ComputeAmbientLighting( int iThread, DetailObjectLump_t& prop, Vector color[MAX_LIGHTSTYLES] ) { Vector origin, normal; @@ -821,7 +1168,7 @@ static void ComputeLighting( DetailObjectLump_t& prop, int iThread ) { if (!hasLightstyles) { - prop.m_LightStyles = s_pDetailPropLightStyleLump->Size(); + prop.m_LightStyles = s_pDetailPropLightStyleLump->Count(); hasLightstyles = true; } @@ -921,14 +1268,14 @@ static void WriteDetailLightingLump( int lumpID, int lumpVersion, CUtlVector &interestingPatches ); - bool IsNeighbor( int iDispFace, int iNeighborFace ); + bool IsNeighbor( int iDispFace, int iNeighborFace, bool bCheck2ndDegreeNeighbors = false ); void GetInterestingPatchesForLuxels( int ndxFace, @@ -329,7 +331,7 @@ void CVRadDispMgr::Init( void ) void CVRadDispMgr::Shutdown( void ) { // remove all displacements from the tree - for( int ndxDisp = m_DispTrees.Size(); ndxDisp >= 0; ndxDisp-- ) + for( int ndxDisp = m_DispTrees.Count(); ndxDisp >= 0; ndxDisp-- ) { RemoveDispFromTree( ndxDisp ); } @@ -500,7 +502,7 @@ void CVRadDispMgr::MakePatches( void ) float flTotalArea = 0.0f; // Create patches for all of the displacements. - int nTreeCount = m_DispTrees.Size(); + int nTreeCount = m_DispTrees.Count(); for( int iTree = 0; iTree < nTreeCount; ++iTree ) { // Get the current displacement collision tree. @@ -537,12 +539,12 @@ void CVRadDispMgr::SubdividePatch( int iPatch ) //----------------------------------------------------------------------------- void CVRadDispMgr::StartRayTest( DispTested_t &dispTested ) { - if( m_DispTrees.Size() > 0 ) + if( m_DispTrees.Count() > 0 ) { if( dispTested.m_pTested == 0 ) { - dispTested.m_pTested = new int[m_DispTrees.Size()]; - memset( dispTested.m_pTested, 0, m_DispTrees.Size() * sizeof( int ) ); + dispTested.m_pTested = new int[m_DispTrees.Count()]; + memset( dispTested.m_pTested, 0, m_DispTrees.Count() * sizeof( int ) ); dispTested.m_Enum = 0; } ++dispTested.m_Enum; @@ -613,7 +615,7 @@ void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &r void CVRadDispMgr::AddPolysForRayTrace( void ) { - int nTreeCount = m_DispTrees.Size(); + int nTreeCount = m_DispTrees.Count(); for( int iTree = 0; iTree < nTreeCount; ++iTree ) { // Get the current displacement collision tree. @@ -656,6 +658,32 @@ void CVRadDispMgr::GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal, pDispTree->DispUVToSurfPoint( uv, pt, 1.0f ); } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CVRadDispMgr::GetDispSurfPointAndNormalFromUV( int ndxFace, Vector &pt, Vector &ptNormal, + Vector2D &uv, bool bInside ) +{ + // get the displacement surface data + DispCollTree_t &dispTree = m_DispTrees[ g_pFaces[ ndxFace ].dispinfo ]; + CVRADDispColl *pDispTree = dispTree.m_pDispTree; + + if ( bInside ) + { + if ( uv[ 0 ] < 0.0f || uv[ 0 ] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[ 0 ] ); } + if ( uv[ 1 ] < 0.0f || uv[ 1 ] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[ 1 ] ); } + } + + if ( uv[ 0 ] < 0.0f ) { uv[ 0 ] = 0.0f; } + if ( uv[ 0 ] > 1.0f ) { uv[ 0 ] = 1.0f; } + if ( uv[ 1 ] < 0.0f ) { uv[ 1 ] = 0.0f; } + if ( uv[ 1 ] > 1.0f ) { uv[ 1 ] = 1.0f; } + + // get the normal at "pt" + pDispTree->DispUVToSurfNormal( uv, ptNormal ); + + // get the new "pt" + pDispTree->DispUVToSurfPoint( uv, pt, 1.0f ); +} //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -778,7 +806,7 @@ bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, intp context ) // check to see if the face already lives in the list int ndx; - int size = m_EnumDispFaceList.m_FaceList.Size(); + int size = m_EnumDispFaceList.m_FaceList.Count(); for( ndx = 0; ndx < size; ndx++ ) { if( m_EnumDispFaceList.m_FaceList[ndx] == ndxLeafFace ) @@ -807,7 +835,7 @@ bool CVRadDispMgr::DispFaceList_EnumerateElement( int userId, intp context ) // check to see if the displacement already lives in the list int ndx; - int size = m_EnumDispFaceList.m_DispList.Size(); + int size = m_EnumDispFaceList.m_DispList.Count(); for( ndx = 0; ndx < size; ndx++ ) { if( m_EnumDispFaceList.m_DispList[ndx] == pDispTree ) @@ -906,7 +934,7 @@ void AddSampleLightToRadial( Vector const &samplePos, Vector const &sampleNormal //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -bool CVRadDispMgr::IsNeighbor( int iFace, int iNeighborFace ) +bool CVRadDispMgr::IsNeighbor( int iFace, int iNeighborFace, bool bCheck2ndDegreeNeighbors ) { if ( iFace == iNeighborFace ) return true; @@ -918,6 +946,19 @@ bool CVRadDispMgr::IsNeighbor( int iFace, int iNeighborFace ) return true; } + if ( bCheck2ndDegreeNeighbors ) + { + for ( int iNeighbor = 0; iNeighbor < pFaceNeighbor->numneighbors; iNeighbor++ ) + { + faceneighbor_t *pFaceNeighbor2 = &faceneighbor[ pFaceNeighbor->neighbor[ iNeighbor ] ]; + for ( int iNeighbor2 = 0; iNeighbor2 < pFaceNeighbor2->numneighbors; iNeighbor2++ ) + { + if ( pFaceNeighbor2->neighbor[ iNeighbor2 ] == iNeighborFace ) + return true; + } + } + } + return false; } @@ -1134,7 +1175,7 @@ void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal if( bNeighborBump ) { float flScale = patchNormal.Dot( normals[0] ); - flScale = MAX( 0.0f, flScale ); + flScale = max( 0.0f, flScale ); float flBumpInfluence = influence * flScale; for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ ) @@ -1147,7 +1188,7 @@ void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal else { float flScale = patchNormal.Dot( normals[0] ); - flScale = MAX( 0.0f, flScale ); + flScale = max( 0.0f, flScale ); float flBumpInfluence = influence * flScale * 0.05f; for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ ) @@ -1161,7 +1202,7 @@ void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal else { float flScale = patchNormal.Dot( luxelNormal ); - flScale = MAX( 0.0f, flScale ); + flScale = max( 0.0f, flScale ); influence *= flScale; pRadial->light[0][ndxRadial].AddWeighted( pPatchLight[0], influence ); @@ -1337,7 +1378,7 @@ void CVRadDispMgr::GetInterestingPatchesForLuxels( { pPatch->m_IterationKey = curIterationKey; - if ( IsNeighbor( ndxFace, pPatch->faceNumber ) ) + if ( IsNeighbor( ndxFace, pPatch->faceNumber, g_bLargeDispSampleRadius ) ) { interestingPatches.AddToTail( pPatch ); } diff --git a/utils/vrad/vradstaticprops.cpp b/utils/vrad/vradstaticprops.cpp index 69e889d0c..eea93c9ad 100644 --- a/utils/vrad/vradstaticprops.cpp +++ b/utils/vrad/vradstaticprops.cpp @@ -27,201 +27,226 @@ #include "pacifier.h" #include "materialsystem/imaterial.h" #include "materialsystem/hardwareverts.h" -#include "materialsystem/hardwaretexels.h" #include "byteswap.h" +#include "mpivrad.h" #include "vtf/vtf.h" #include "tier1/utldict.h" #include "tier1/utlsymbol.h" -#include "bitmap/tgawriter.h" +#include "tier3/tier3.h" #ifdef MPI -#include "mpivrad.h" #include "messbuf.h" #include "vmpi.h" #include "vmpi_distribute_work.h" #endif - +#include "iscratchpad3d.h" #define ALIGN_TO_POW2(x,y) (((x)+(y-1))&~(y-1)) +int g_numVradStaticPropsLightingStreams = 3; + +static const TableVector g_localUpBumpBasis[NUM_BUMP_VECTS] = +{ + // consistent basis wrt lightmaps + { OO_SQRT_2_OVER_3, 0.0f, OO_SQRT_3 }, + { -OO_SQRT_6, OO_SQRT_2, OO_SQRT_3 }, + { -OO_SQRT_6, -OO_SQRT_2, OO_SQRT_3 } +}; + +void GetStaticPropBumpNormals( const Vector& sVect, const Vector& tVect, const Vector& flatNormal, + const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] ) +{ + Vector tmpNormal; + bool leftHanded; + int i; + + assert( NUM_BUMP_VECTS == 3 ); + + // Are we left or right handed? + CrossProduct( sVect, tVect, tmpNormal ); + if( DotProduct( flatNormal, tmpNormal ) < 0.0f ) + { + leftHanded = true; + } + else + { + leftHanded = false; + } + + // Build a basis for the face around the phong normal + matrix3x4_t smoothBasis; + CrossProduct( phongNormal.Base(), sVect.Base(), smoothBasis[1] ); + VectorNormalize( smoothBasis[1] ); + CrossProduct( smoothBasis[1], phongNormal.Base(), smoothBasis[0] ); + VectorNormalize( smoothBasis[0] ); + VectorCopy( phongNormal.Base(), smoothBasis[2] ); + + if( leftHanded ) + { + VectorNegate( smoothBasis[1] ); + } + + // move the g_localUpBumpBasis into world space to create bumpNormals + for( i = 0; i < 3; i++ ) + { + VectorIRotate( g_localUpBumpBasis[i], smoothBasis, bumpNormals[i] ); + } +} + // identifies a vertex embedded in solid // lighting will be copied from nearest valid neighbor struct badVertex_t { int m_ColorVertex; Vector m_Position; - Vector m_Normal; + Vector m_Normals[ NUM_BUMP_VECTS + 1 ]; }; // a final colored vertex struct colorVertex_t { - Vector m_Color; + Vector m_Colors[ NUM_BUMP_VECTS + 1 ]; + float m_SunAmount[ NUM_BUMP_VECTS + 1 ]; Vector m_Position; bool m_bValid; }; -// a texel suitable for a model -struct colorTexel_t -{ - Vector m_Color; - Vector m_WorldPosition; - Vector m_WorldNormal; - float m_fDistanceToTri; // If we are outside of the triangle, how far away is it? - bool m_bValid; - bool m_bPossiblyInteresting; - -}; - class CComputeStaticPropLightingResults { public: ~CComputeStaticPropLightingResults() { m_ColorVertsArrays.PurgeAndDeleteElements(); - m_ColorTexelsArrays.PurgeAndDeleteElements(); } CUtlVector< CUtlVector* > m_ColorVertsArrays; - CUtlVector< CUtlVector* > m_ColorTexelsArrays; }; -//----------------------------------------------------------------------------- -struct Rasterizer +Vector NormalizeVertexBumpedLighting( Vector const *pColorNormal, Vector *pColorBumps ) { - struct Location - { - Vector barycentric; - Vector2D uv; - bool insideTriangle; - }; - - Rasterizer(Vector2D t0, Vector2D t1, Vector2D t2, size_t resX, size_t resY) - : mT0(t0) - , mT1(t1) - , mT2(t2) - , mResX(resX) - , mResY(resY) - , mUvStepX(1.0f / resX) - , mUvStepY(1.0f / resY) - { - Build(); - } + const Vector &linearUnbumped = *( ( const Vector * )pColorNormal ); + Vector linearBump1 = *( ( const Vector * )(pColorBumps + 0) ); + Vector linearBump2 = *( ( const Vector * )(pColorBumps + 1) ); + Vector linearBump3 = *( ( const Vector * )(pColorBumps + 2) ); - CUtlVector< Location >::iterator begin() { return mRasterizedLocations.begin(); } - CUtlVector< Location >::iterator end() { return mRasterizedLocations.end(); } + const float flNormalizationFactor = 1.0f / 3.0f; - void Build(); + // find a scale factor which makes the average of the 3 bumped mapped vectors match the + // straight up vector (if possible), so that flat bumpmapped areas match non-bumpmapped + // areas. + Vector bumpAverage = linearBump1; + bumpAverage += linearBump2; + bumpAverage += linearBump3; + bumpAverage *= flNormalizationFactor; - inline size_t GetRow(float y) const { return size_t(y * mResY); } - inline size_t GetCol(float x) const { return size_t(x * mResX); } + Vector correctionScale; - inline size_t GetLinearPos( const CUtlVector< Location >::iterator& it ) const + if( *( int * )&bumpAverage[0] != 0 && + *( int * )&bumpAverage[1] != 0 && + *( int * )&bumpAverage[2] != 0 ) { - // Given an iterator, return what the linear position in the buffer would be for the data. - return (size_t)(GetRow(it->uv.y) * mResX) - + (size_t)(GetCol(it->uv.x)); + // fast path when we know that we don't have to worry about divide by zero. + VectorDivide( linearUnbumped, bumpAverage, correctionScale ); } - -private: - const Vector2D mT0, mT1, mT2; - const size_t mResX, mResY; - const float mUvStepX, mUvStepY; - - // Right now, we just fill this out and directly iterate over it. - // It could be large. This is a memory/speed tradeoff. We could instead generate them - // on demand. - CUtlVector< Location > mRasterizedLocations; -}; + else + { + correctionScale.Init( 0.0f, 0.0f, 0.0f ); + if( bumpAverage[0] != 0.0f ) + { + correctionScale[0] = linearUnbumped[0] / bumpAverage[0]; + } + if( bumpAverage[1] != 0.0f ) + { + correctionScale[1] = linearUnbumped[1] / bumpAverage[1]; + } + if( bumpAverage[2] != 0.0f ) + { + correctionScale[2] = linearUnbumped[2] / bumpAverage[2]; + } + } + linearBump1 *= correctionScale; + linearBump2 *= correctionScale; + linearBump3 *= correctionScale; -//----------------------------------------------------------------------------- -inline Vector ComputeBarycentric( Vector2D _edgeC, Vector2D _edgeA, Vector2D _edgeB, float _dAA, float _dAB, float _dBB, float _invDenom ) -{ - float dCA = _edgeC.Dot(_edgeA); - float dCB = _edgeC.Dot(_edgeB); - - Vector retVal; - retVal.y = (_dBB * dCA - _dAB * dCB) * _invDenom; - retVal.z = (_dAA * dCB - _dAB * dCA) * _invDenom; - retVal.x = 1.0f - retVal.y - retVal.z; + *((Vector *) (pColorBumps + 0)) = linearBump1; + *((Vector *) (pColorBumps + 1)) = linearBump2; + *((Vector *) (pColorBumps + 2)) = linearBump3; - return retVal; + return correctionScale; } -//----------------------------------------------------------------------------- -void Rasterizer::Build() + +void NormalizeVertexBumpedSunAmount( float const *pSunAmount0, float *pSunAmount1, float *pSunAmount2, float *pSunAmount3 ) { - // For now, use the barycentric method. It's easy, I'm lazy. - // We can optimize later if it's a performance issue. - const float baseX = mUvStepX / 2.0f; - const float baseY = mUvStepY / 2.0f; + const float &linearSunAmountUnbumped = *((const float *)pSunAmount0); + float linearSunAmount1 = *((const float *)(pSunAmount1)); + float linearSunAmount2 = *((const float *)(pSunAmount2)); + float linearSunAmount3 = *((const float *)(pSunAmount3)); + const float flNormalizationFactor = 1.0f;// / 3.0f; - store in 0..1 space (for 0..255 alpha channel), multiply by 3.0 in the shader - float fMinX = MIN(MIN(mT0.x, mT1.x), mT2.x); - float fMinY = MIN(MIN(mT0.y, mT1.y), mT2.y); - float fMaxX = MAX(MAX(mT0.x, mT1.x), mT2.x); - float fMaxY = MAX(MAX(mT0.y, mT1.y), mT2.y); + // find a scale factor which makes the average of the 3 bumped mapped vectors match the + // straight up vector (if possible), so that flat bumpmapped areas match non-bumpmapped + // areas. + float bumpAverage = linearSunAmount1; + bumpAverage += linearSunAmount2; + bumpAverage += linearSunAmount3; + bumpAverage *= flNormalizationFactor; - // Degenerate. Consider warning about these, but otherwise no problem. - if (fMinX == fMaxX || fMinY == fMaxY) - return; + float correctionScale; - // Clamp to 0..1 - fMinX = MAX(0, fMinX); - fMinY = MAX(0, fMinY); - fMaxX = MIN(1.0f, fMaxX); - fMaxY = MIN(1.0f, fMaxY); - - // We puff the interesting area up by 1 so we can hit an inflated region for the necessary bilerp data. - // If we wanted to support better texturing (almost definitely unnecessary), we'd change this to a larger size. - const int kFilterSampleRadius = 1; - - int iMinX = GetCol(fMinX) - kFilterSampleRadius; - int iMinY = GetRow(fMinY) - kFilterSampleRadius; - int iMaxX = GetCol(fMaxX) + 1 + kFilterSampleRadius; - int iMaxY = GetRow(fMaxY) + 1 + kFilterSampleRadius; - - // Clamp to valid texture (integer) locations - iMinX = MAX(0, iMinX); - iMinY = MAX(0, iMinY); - iMaxX = MIN(iMaxX, mResX - 1); - iMaxY = MIN(iMaxY, mResY - 1); - - // Set the size to be as expected. - // TODO: Pass this in from outside to minimize allocations - // TODO: Pass this in from outside to minimize allocations - int count = (iMaxY - iMinY + 1) - * (iMaxX - iMinX + 1); - mRasterizedLocations.EnsureCount(count); - memset( mRasterizedLocations.Base(), 0, mRasterizedLocations.Count() * sizeof( Location ) ); - - // Computing Barycentrics adapted from here http://gamedev.stackexchange.com/questions/23743/whats-the-most-efficient-way-to-find-barycentric-coordinates - Vector2D edgeA = mT1 - mT0; - Vector2D edgeB = mT2 - mT0; - - float dAA = edgeA.Dot(edgeA); - float dAB = edgeA.Dot(edgeB); - float dBB = edgeB.Dot(edgeB); - float invDenom = 1.0f / (dAA * dBB - dAB * dAB); - - int linearPos = 0; - for (int j = iMinY; j <= iMaxY; ++j) { - for (int i = iMinX; i <= iMaxX; ++i) { - Vector2D testPt( i * mUvStepX + baseX, j * mUvStepY + baseY ); - Vector barycentric = ComputeBarycentric( testPt - mT0, edgeA, edgeB, dAA, dAB, dBB, invDenom ); - - // Test whether the point is inside the triangle. - // MCJOHNTODO: Edge rules and whatnot--right now we re-rasterize points on the edge. - Location& newLoc = mRasterizedLocations[linearPos++]; - newLoc.barycentric = barycentric; - newLoc.uv = testPt; - - newLoc.insideTriangle = (barycentric.x >= 0.0f && barycentric.x <= 1.0f && barycentric.y >= 0.0f && barycentric.y <= 1.0f && barycentric.z >= 0.0f && barycentric.z <= 1.0f); + if ( *(int *)&bumpAverage != 0 ) + { + // fast path when we know that we don't have to worry about divide by zero. + correctionScale = linearSunAmountUnbumped / bumpAverage; + } + else + { + correctionScale = 1.0f; + if ( bumpAverage != 0.0f ) + { + correctionScale = linearSunAmountUnbumped / bumpAverage; } } + linearSunAmount1 *= correctionScale; + linearSunAmount2 *= correctionScale; + linearSunAmount3 *= correctionScale; + + *((float *)(pSunAmount1)) = linearSunAmount1; + *((float *)(pSunAmount2)) = linearSunAmount2; + *((float *)(pSunAmount3)) = linearSunAmount3; } +void DumpElapsedTime( int timeTaken ) +{ + if ( g_bDumpBumpStaticProps && (g_numVradStaticPropsLightingStreams == 3) ) + { + char mapName[MAX_PATH]; + Q_FileBase( source, mapName, sizeof( mapName ) ); + + char bumpPropFilename[MAX_PATH]; + sprintf( bumpPropFilename, "vrad_bumpstaticprops_%s.txt", mapName ); + + Msg( "Writing %s...\n", bumpPropFilename ); + + FILE *fp = fopen( bumpPropFilename, "a" ); + + if ( !fp ) + { + Msg( "Writing %s...failed\n", bumpPropFilename ); + return; + } + + char str[512]; + GetHourMinuteSecondsString( timeTaken, str, sizeof( str ) ); + + fprintf( fp, "\n\nUsing -staticpropsamplescale %f (-final defaults to 16)\n", g_flStaticPropSampleScale ); + fprintf( fp, "\nTotal time taken to bake static prop lighting: %s\n", str ); + + fclose( fp ); + } +} //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- @@ -231,18 +256,6 @@ CUtlSymbolTable g_ForcedTextureShadowsModels; // INSIDE PropTested_t. USE THAT INSTEAD. IPhysicsCollision *s_pPhysCollision = NULL; -static void ConvertTexelDataToTexture(unsigned int _resX, unsigned int _resY, ImageFormat _destFmt, const CUtlVector& _srcTexels, CUtlMemory* _outTexture); - -// Such a monstrosity. :( -static void GenerateLightmapSamplesForMesh( const matrix3x4_t& _matPos, const matrix3x4_t& _matNormal, int _iThread, int _skipProp, int _nFlags, int _lightmapResX, int _lightmapResY, - studiohdr_t* _pStudioHdr, mstudiomodel_t* _pStudioModel, OptimizedModel::ModelHeader_t* _pVtxModel, int _meshID, - CComputeStaticPropLightingResults *_pResults ); - -// Debug function, converts lightmaps to linear space then dumps them out. -// TODO: Write out the file in a .dds instead of a .tga, in whatever format we're supposed to use. -static void DumpLightmapLinear( const char* _dstFilename, const CUtlVector& _srcTexels, int _width, int _height ); - - //----------------------------------------------------------------------------- // Vrad's static prop manager //----------------------------------------------------------------------------- @@ -261,6 +274,8 @@ class CVradStaticPropMgr : public IVradStaticPropMgr // iterate all the instanced static props and compute their vertex lighting void ComputeLighting( int iThread ); + virtual void MakePatches() override; + private: #ifdef MPI // VMPI stuff. @@ -294,12 +309,15 @@ class CVradStaticPropMgr : public IVradStaticPropMgr CUtlBuffer m_VtxBuf; CUtlVector m_textureShadowIndex; // each texture has an index if this model casts texture shadows CUtlVector m_triangleMaterialIndex;// each triangle has an index if this model casts texture shadows + Vector m_vReflectivity; + bool m_bHasBumpmap; + bool m_bHasPhong; }; struct MeshData_t { - CUtlVector m_VertexColors; - CUtlMemory m_TexelsEncoded; + CUtlVector m_VertColorData; // w has the additional lightmap alpha data + int m_numVerts; int m_nLod; }; @@ -315,16 +333,9 @@ class CVradStaticPropMgr : public IVradStaticPropMgr BSPTreeDataHandle_t m_Handle; CUtlVector m_MeshData; int m_Flags; + int m_FlagsEx; bool m_bLightingOriginValid; - - // Note that all lightmaps for a given prop share the same resolution (and format)--and there can be multiple lightmaps - // per prop (if there are multiple pieces--the watercooler is an example). - // This is effectively because there's not a good way in hammer for a prop to say "this should be the resolution - // of each of my sub-pieces." - ImageFormat m_LightmapImageFormat; - unsigned int m_LightmapImageWidth; - unsigned int m_LightmapImageHeight; - + Vector m_vReflectivity; }; // Enumeration context @@ -341,7 +352,7 @@ class CVradStaticPropMgr : public IVradStaticPropMgr bool m_bIgnoreStaticPropTrace; void ComputeLighting( CStaticProp &prop, int iThread, int prop_index, CComputeStaticPropLightingResults *pResults ); - void ApplyLightingToStaticProp( int iStaticProp, CStaticProp &prop, const CComputeStaticPropLightingResults *pResults ); + void ApplyLightingToStaticProp( CStaticProp &prop, const CComputeStaticPropLightingResults *pResults ); void SerializeLighting(); void AddPolysForRayTrace(); @@ -392,6 +403,9 @@ bool IsStaticProp( studiohdr_t* pHdr ) //----------------------------------------------------------------------------- static bool LoadFile( char const* pFileName, CUtlBuffer& buf ) { + if ( ReadFileFromPak( GetPakFile(), pFileName, false, buf ) ) + return true; + if ( !g_pFullFileSystem ) return false; @@ -456,7 +470,7 @@ CPhysCollide* ComputeConvexHull( studiohdr_t* pStudioHdr ) // Convert an array of convex elements to a compiled collision model // (this deletes the convex elements) - return s_pPhysCollision->ConvertConvexToCollide( convexHulls.Base(), convexHulls.Size() ); + return s_pPhysCollision->ConvertConvexToCollide( convexHulls.Base(), convexHulls.Count() ); } @@ -500,8 +514,8 @@ bool LoadStudioModel( char const* pModelName, CUtlBuffer& buf ) } // ensure reset - pHdr->SetVertexBase(NULL); - pHdr->SetIndexBase(NULL); + pHdr->SetVertexBase( NULL ); + pHdr->SetIndexBase( NULL ); return true; } @@ -532,7 +546,7 @@ bool LoadVTXFile( char const* pModelName, const studiohdr_t *pStudioHdr, CUtlBuf // construct filename Q_StripExtension( pModelName, filename, sizeof( filename ) ); - strcat( filename, ".dx80.vtx" ); + strcat( filename, ".dx90.vtx" ); if ( !LoadFile( filename, buf ) ) { @@ -784,15 +798,15 @@ class CShadowTextureList // HACKHACK: Compute the average coverage for this triangle by sampling the AABB of its texture space float ComputeCoverageForTriangle( int shadowTextureIndex, const Vector2D &t0, const Vector2D &t1, const Vector2D &t2 ) { - float umin = MIN(t0.x, t1.x); - umin = MIN(umin, t2.x); - float umax = MAX(t0.x, t1.x); - umax = MAX(umax, t2.x); + float umin = min(t0.x, t1.x); + umin = min(umin, t2.x); + float umax = max(t0.x, t1.x); + umax = max(umax, t2.x); - float vmin = MIN(t0.y, t1.y); - vmin = MIN(vmin, t2.y); - float vmax = MAX(t0.y, t1.y); - vmax = MAX(vmax, t2.y); + float vmin = min(t0.y, t1.y); + vmin = min(vmin, t2.y); + float vmax = max(t0.y, t1.y); + vmax = max(vmax, t2.y); // UNDONE: Do something about tiling umin = clamp(umin, 0, 1); @@ -833,21 +847,28 @@ class CShadowTextureList if ( bBackface && !tex.allowBackface ) return 0; Vector2D uv = coords.x * mat.uv[0] + coords.y * mat.uv[1] + coords.z * mat.uv[2]; - int u = RoundFloatToInt( uv[0] * tex.width ); - int v = RoundFloatToInt( uv[1] * tex.height ); - - // asume power of 2, clamp or wrap - // UNDONE: Support clamp? This code should work -#if 0 - u = tex.clampU ? clamp(u,0,(tex.width-1)) : (u & (tex.width-1)); - v = tex.clampV ? clamp(v,0,(tex.height-1)) : (v & (tex.height-1)); -#else - // for now always wrap + // bilinear filtered sample + float ou = uv[0] * tex.width; + float ov = uv[1] * tex.height; + int u = floor( ou ); + int v = floor( ov ); + int u1 = u+1; + int v1 = v+1; u &= (tex.width-1); + u1 &= (tex.width-1); v &= (tex.height-1); -#endif + v1 &= (tex.height-1); + float lerpU = ou - u; + float lerpV = ov - v; + int x = (tex.pAlphaTexels[v * tex.width + u] * (1-lerpU)) + (lerpU*tex.pAlphaTexels[v * tex.width + u1]); + int y = (tex.pAlphaTexels[v1 * tex.width + u] * (1-lerpU)) + (lerpU*tex.pAlphaTexels[v1 * tex.width + u1]); + return int( x * (1-lerpV) + (y*lerpV) ); + } - return tex.pAlphaTexels[v * tex.width + u]; + void GetMapping( int shadowTextureIndex, int *pWidth, int *pHeight ) + { + *pWidth = m_Textures[shadowTextureIndex].width; + *pHeight = m_Textures[shadowTextureIndex].height; } struct alphatexture_t @@ -917,9 +938,36 @@ void CleanModelName( const char *pModelName, char *pOutput, int outLen ) { *dot = 0; } +} +int LoadShadowTexture( const char *pMaterialName ) +{ + int textureIndex = -1; + // try to add each texture to the transparent shadow manager + char szPath[MAX_PATH]; + + Q_strncpy( szPath, "materials/", sizeof( szPath ) ); + Q_strncat( szPath, pMaterialName, sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_strncat( szPath, ".vmt", sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR ); + g_ShadowTextureList.FindOrLoadIfValid( szPath, &textureIndex ); + return textureIndex; +} + +int AddShadowTextureTriangle( int shadowTextureIndex, const Vector2D &t0, const Vector2D &t1, const Vector2D &t2 ) +{ + return g_ShadowTextureList.AddMaterialEntry(shadowTextureIndex, t0, t1, t2 ); +} + +float ComputeCoverageForTriangle( int shadowTextureIndex, const Vector2D &t0, const Vector2D &t1, const Vector2D &t2 ) +{ + return g_ShadowTextureList.ComputeCoverageForTriangle(shadowTextureIndex, t0, t1, t2 ); } +void GetShadowTextureMapping( int shadowTextureIndex, int *pWidth, int *pHeight ) +{ + g_ShadowTextureList.GetMapping( shadowTextureIndex, pWidth, pHeight ); +} void ForceTextureShadowsOnModel( const char *pModelName ) { @@ -938,6 +986,197 @@ bool IsModelTextureShadowsForced( const char *pModelName ) return g_ForcedTextureShadowsModels.Find(buf).IsValid(); } +bool IsStaticPropBumpmapped( studiohdr_t *pStudioHdr ) +{ + if ( g_numVradStaticPropsLightingStreams == 1 ) + { + return false; + } + + // check if prop uses "$bumpmap" in any materials, use this as an indication of valid tangent data (availability of tangentdata does not imply it's valid/used) + for ( int textureIndex = 0; textureIndex < pStudioHdr->numtextures; textureIndex++ ) + { + char szPath[MAX_PATH]; + + // iterate quietly through all specified directories until a valid material is found + for ( int i = 0; i < pStudioHdr->numcdtextures; i++ ) + { + Q_strncpy( szPath, "materials/", sizeof( szPath ) ); + Q_strncat( szPath, pStudioHdr->pCdtexture( i ), sizeof( szPath ) ); + const char *textureName = pStudioHdr->pTexture( textureIndex )->pszName(); + Q_strncat( szPath, textureName, sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_strncat( szPath, ".vmt", sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR ); + + KeyValues *pVMT = new KeyValues( "vmt" ); + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + LoadFileIntoBuffer( buf, szPath ); + if ( pVMT->LoadFromBuffer( szPath, buf ) ) + { + if ( pVMT->FindKey( "$bumpmap" ) ) + { + pVMT->deleteThis(); + return true; + } + } + pVMT->deleteThis(); + } + } + + return false; +} + + +void StaticPropHasPhongBump( studiohdr_t *pStudioHdr, bool *pHasBumpmap, bool *pHasPhong ) +{ + if ( g_numVradStaticPropsLightingStreams == 1 ) + { + return; + } + + *pHasBumpmap = false; + *pHasPhong = false; + + // check if prop uses "$bumpmap" in any materials, use this as an indication of valid tangent data (availability of tangentdata does not imply it's valid/used) + for ( int textureIndex = 0; textureIndex < pStudioHdr->numtextures; textureIndex++ ) + { + char szPath[MAX_PATH]; + + // iterate quietly through all specified directories until a valid material is found + for ( int i = 0; i < pStudioHdr->numcdtextures; i++ ) + { + Q_strncpy( szPath, "materials/", sizeof( szPath ) ); + Q_strncat( szPath, pStudioHdr->pCdtexture( i ), sizeof( szPath ) ); + const char *textureName = pStudioHdr->pTexture( textureIndex )->pszName(); + Q_strncat( szPath, textureName, sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_strncat( szPath, ".vmt", sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR ); + + KeyValues *pVMT = new KeyValues( "vmt" ); + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + LoadFileIntoBuffer( buf, szPath ); + if ( pVMT->LoadFromBuffer( szPath, buf ) ) + { + if ( pVMT->FindKey( "$bumpmap" ) ) + { + *pHasBumpmap = true; + + // is it also phong + if ( pVMT->FindKey( "$phong" ) ) + { + *pHasPhong = true; + + pVMT->deleteThis(); + return; + } + } + } + pVMT->deleteThis(); + } + } + + return; +} + +Vector ReadReflectivityFromVTF( const char *pName ) +{ + Vector vRefl( 0.18f, 0.18f, 0.18f ); + + char szPath[ MAX_PATH ]; + Q_strncpy( szPath, "materials/", sizeof( szPath ) ); + Q_strncat( szPath, pName, sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_strncat( szPath, ".vtf", sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR ); + + int nHeaderSize = VTFFileHeaderSize(); + unsigned char *pMem = (unsigned char *)stackalloc( nHeaderSize ); + CUtlBuffer buf( pMem, nHeaderSize ); + if ( g_pFullFileSystem->ReadFile( szPath, NULL, buf, nHeaderSize ) ) + { + IVTFTexture *pTex = CreateVTFTexture(); + if ( pTex->Unserialize( buf, true ) ) + { + vRefl = pTex->Reflectivity(); + } + DestroyVTFTexture( pTex ); + } + return vRefl; +} + +Vector ComputeStaticPropReflectivity( studiohdr_t *pStudioHdr ) +{ + Vector vReflectivity( 0.18f, 0.18f, 0.18f ); + + for ( int textureIndex = 0; textureIndex < pStudioHdr->numtextures; textureIndex++ ) + { + char szPath[ MAX_PATH ]; + + // iterate quietly through all specified directories until a valid material is found + for ( int i = 0; i < pStudioHdr->numcdtextures; i++ ) + { + Q_strncpy( szPath, "materials/", sizeof( szPath ) ); + Q_strncat( szPath, pStudioHdr->pCdtexture( i ), sizeof( szPath ) ); + const char *textureName = pStudioHdr->pTexture( textureIndex )->pszName(); + Q_strncat( szPath, textureName, sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_strncat( szPath, ".vmt", sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR ); + + Vector vVtfRefl( 1.0f, 1.0f, 1.0f ); + Vector vTint( 1.0f, 1.0f, 1.0f ); + + KeyValues *pVMT = new KeyValues( "vmt" ); + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + LoadFileIntoBuffer( buf, szPath ); + if ( pVMT->LoadFromBuffer( szPath, buf ) ) + { + KeyValues *pBaseTexture = pVMT->FindKey( "$basetexture" ); + if ( pBaseTexture ) + { + const char *pBaseTextureName = pBaseTexture->GetString(); + if ( pBaseTextureName ) + { + vVtfRefl = ReadReflectivityFromVTF( pBaseTextureName ); + } + } + + vReflectivity = vVtfRefl; + + KeyValues *pColorTint = pVMT->FindKey( "color" ); + if ( pColorTint ) + { + const char *pColorString = pColorTint->GetString(); + if ( pColorString[ 0 ] == '{' ) + { + int r = 0; + int g = 0; + int b = 0; + sscanf( pColorString, "{%d %d %d}", &r, &g, &b ); + vTint.x = SrgbGammaToLinear( clamp( float( r ) / 255.0f, 0.0f, 1.0f ) ); + vTint.y = SrgbGammaToLinear( clamp( float( r ) / 255.0f, 0.0f, 1.0f ) ); + vTint.z = SrgbGammaToLinear( clamp( float( r ) / 255.0f, 0.0f, 1.0f ) ); + } + else if ( pColorString[ 0 ] == '[' ) + { + sscanf( pColorString, "[%f %f %f]", &vTint.x, &vTint.y, &vTint.z ); + vTint.x = clamp( vTint.x, 0.0f, 1.0f ); + vTint.y = clamp( vTint.y, 0.0f, 1.0f ); + vTint.z = clamp( vTint.z, 0.0f, 1.0f ); + } + } + } + pVMT->deleteThis(); + + vReflectivity = vVtfRefl * vTint; + if ( vReflectivity.x == 1.0f && vReflectivity.y == 1.0f && vReflectivity.z == 1.0f ) + { + vReflectivity.Init( 0.18f, 0.18f, 0.18f ); + } + return vReflectivity; + } + } + + return vReflectivity; +} //----------------------------------------------------------------------------- // Creates a collision model (based on the render geometry!) @@ -1010,6 +1249,10 @@ void CVradStaticPropMgr::CreateCollisionModel( char const* pModelName ) g_ShadowTextureList.LoadAllTexturesForModel( pHdr, m_StaticPropDict[i].m_textureShadowIndex.Base() ); } } + + // mark static props that use $bumpmap, $phong materials + StaticPropHasPhongBump( pHdr, &m_StaticPropDict[ i ].m_bHasBumpmap, &m_StaticPropDict[ i ].m_bHasPhong ); + m_StaticPropDict[ i ].m_vReflectivity = ComputeStaticPropReflectivity( pHdr ); } @@ -1026,13 +1269,99 @@ void CVradStaticPropMgr::UnserializeModelDict( CUtlBuffer& buf ) CreateCollisionModel( lump.m_Name ); } + + // spew bump static prop info + if ( g_bDumpBumpStaticProps && (g_numVradStaticPropsLightingStreams == 3) ) + { + char mapName[MAX_PATH]; + Q_FileBase( source, mapName, sizeof( mapName ) ); + + char bumpPropFilename[MAX_PATH]; + sprintf( bumpPropFilename, "vrad_bumpstaticprops_%s.txt", mapName); + + Msg( "Writing %s...\n", bumpPropFilename ); + + FILE *fp = fopen( bumpPropFilename, "w" ); + + if ( !fp ) + { + Msg( "Writing %s...failed\n", bumpPropFilename ); + return; + } + + fprintf( fp, "Bumpmap static prop list for %s\n", mapName ); + + int numBumpmapStaticProps = 0; + int numPhongStaticProps = 0; + for ( int i = m_StaticPropDict.Count(); --i >= 0; ) + { + studiohdr_t *pStudioHdr = m_StaticPropDict[i].m_pStudioHdr; + + if ( m_StaticPropDict[i].m_bHasBumpmap ) + { + numBumpmapStaticProps++; + } + + if ( m_StaticPropDict[i].m_bHasPhong ) + { + numPhongStaticProps++; + } + + if ( m_StaticPropDict[i].m_bHasBumpmap || m_StaticPropDict[i].m_bHasPhong ) + { + fprintf( fp, "\nprop: %s\nvmt's containing $bumpmap, $phong:\n", pStudioHdr->pszName() ); + + for ( int textureIndex = 0; textureIndex < pStudioHdr->numtextures; textureIndex++ ) + { + char szPath[MAX_PATH]; + + // iterate quietly through all specified directories until a valid material is found + for ( int i = 0; i < pStudioHdr->numcdtextures; i++ ) + { + Q_strncpy( szPath, "materials/", sizeof( szPath ) ); + Q_strncat( szPath, pStudioHdr->pCdtexture( i ), sizeof( szPath ) ); + const char *textureName = pStudioHdr->pTexture( textureIndex )->pszName(); + Q_strncat( szPath, textureName, sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_strncat( szPath, ".vmt", sizeof( szPath ), COPY_ALL_CHARACTERS ); + Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR ); + + KeyValues *pVMT = new KeyValues( "vmt" ); + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + LoadFileIntoBuffer( buf, szPath ); + if ( pVMT->LoadFromBuffer( szPath, buf ) ) + { + if ( pVMT->FindKey( "$bumpmap" ) ) + { + if ( pVMT->FindKey( "$phong" ) ) + { + fprintf( fp, "$bump, $phong: %s\n", szPath ); + } + else + { + fprintf( fp, "$bump: %s\n", szPath ); + } + } + else if ( pVMT->FindKey( "$phong" ) ) + { + // not possible/error? + fprintf( fp, "$phong: %s\n", szPath ); + } + } + pVMT->deleteThis(); + } + } + } + } + fprintf( fp, "\n%d static props, %d bumped static props (%d phong static props)\n", m_StaticPropDict.Count(), numBumpmapStaticProps, numPhongStaticProps ); + fclose( fp ); + } + } void CVradStaticPropMgr::UnserializeModels( CUtlBuffer& buf ) { int count = buf.GetInt(); - m_StaticProps.AddMultipleToTail(count); for ( int i = 0; i < count; ++i ) { @@ -1046,12 +1375,11 @@ void CVradStaticPropMgr::UnserializeModels( CUtlBuffer& buf ) m_StaticProps[i].m_ModelIdx = lump.m_PropType; m_StaticProps[i].m_Handle = TREEDATA_INVALID_HANDLE; m_StaticProps[i].m_Flags = lump.m_Flags; - - // Changed this from using DXT1 to RGB888 because the compression artifacts were pretty nasty. - // TODO: Consider changing back or basing this on user selection in hammer. - m_StaticProps[i].m_LightmapImageFormat = IMAGE_FORMAT_RGB888; - m_StaticProps[i].m_LightmapImageWidth = lump.m_nLightmapResolutionX; - m_StaticProps[i].m_LightmapImageHeight = lump.m_nLightmapResolutionY; + m_StaticProps[ i ].m_FlagsEx = lump.m_FlagsEx; + m_StaticProps[ i ].m_vReflectivity.Init( SrgbGammaToLinear( float( lump.m_DiffuseModulation.r ) / 255.0f ), + SrgbGammaToLinear( float( lump.m_DiffuseModulation.g ) / 255.0f ), + SrgbGammaToLinear( float( lump.m_DiffuseModulation.b ) / 255.0f ) ); + m_StaticProps[ i ].m_vReflectivity *= m_StaticPropDict[ m_StaticProps[ i ].m_ModelIdx ].m_vReflectivity; } } @@ -1069,7 +1397,7 @@ void CVradStaticPropMgr::UnserializeStaticProps() if ( g_GameLumps.GetGameLumpVersion( handle ) != GAMELUMP_STATIC_PROPS_VERSION ) { - Error( "Cannot load the static props... encountered a stale map version. Re-vbsp the map.\n" ); + Error( "Cannot load the static props... encountered a stale map version. Re-vbsp the map." ); } if ( g_GameLumps.GetGameLump( handle ) ) @@ -1110,7 +1438,7 @@ void CVradStaticPropMgr::Shutdown() { // Remove all static prop model data - for (int i = m_StaticPropDict.Size(); --i >= 0; ) + for (int i = m_StaticPropDict.Count(); --i >= 0; ) { studiohdr_t *pStudioHdr = m_StaticPropDict[i].m_pStudioHdr; if ( pStudioHdr ) @@ -1118,6 +1446,7 @@ void CVradStaticPropMgr::Shutdown() if ( pStudioHdr->VertexBase() ) { free( pStudioHdr->VertexBase() ); + pStudioHdr->SetVertexBase( nullptr ); } free( pStudioHdr ); } @@ -1139,6 +1468,15 @@ void ComputeLightmapColor( dface_t* pFace, Vector &color ) bool PositionInSolid( Vector &position ) { +/* Testing enabling/disabling since it erroneously reports verts inside light blockers + and there are a number of position offsets applied elsewhere to avoid surface acne + that might well be enough */ + + if ( g_bDisableStaticPropVertexInSolidTest ) + { + return false; + } + int ndxLeaf = PointLeafnum( position ); if ( dleafs[ndxLeaf].contents & CONTENTS_SOLID ) { @@ -1149,15 +1487,26 @@ bool PositionInSolid( Vector &position ) return false; } +bool PositionIn3DSkybox( Vector &position ) +{ + int iLeaf = PointLeafnum( position ); + int area = dleafs[ iLeaf ].area; + return area_sky_cameras[ area ] >= 0; +} + //----------------------------------------------------------------------------- // Trace from a vertex to each direct light source, accumulating its contribution. //----------------------------------------------------------------------------- -void ComputeDirectLightingAtPoint( Vector &position, Vector &normal, Vector &outColor, int iThread, - int static_prop_id_to_skip=-1, int nLFlags = 0) +void ComputeDirectLightingAtPoint( Vector &position, Vector *normals, Vector *outColors, float *outSunAmount, int numNormals, bool bSkipSkyLight, int iThread, + int static_prop_id_to_skip, int nLFlags ) { SSE_sampleLightOutput_t sampleOutput; - outColor.Init(); + for ( int k = 0; k < numNormals; ++ k ) + { + outColors[k].Init(); + outSunAmount[k] = 0.0f; + } // Iterate over all direct lights and accumulate their contribution int cluster = ClusterFromPoint( position ); @@ -1177,6 +1526,8 @@ void ComputeDirectLightingAtPoint( Vector &position, Vector &normal, Vector &out Vector adjusted_pos = position; float flEpsilon = 0.0; + const float flFudgeFactor = 4.0; + if (dl->light.type != emit_skyambient) { // push towards the light @@ -1188,48 +1539,142 @@ void ComputeDirectLightingAtPoint( Vector &position, Vector &normal, Vector &out fudge = dl->light.origin-position; VectorNormalize( fudge ); } - fudge *= 4.0; + fudge *= flFudgeFactor; adjusted_pos += fudge; } else { // push out along normal - adjusted_pos += 4.0 * normal; + adjusted_pos += flFudgeFactor * normals[0]; // flEpsilon = 1.0; } FourVectors adjusted_pos4; - FourVectors normal4; adjusted_pos4.DuplicateVector( adjusted_pos ); - normal4.DuplicateVector( normal ); - GatherSampleLightSSE( sampleOutput, dl, -1, adjusted_pos4, &normal4, 1, iThread, nLFlags | GATHERLFLAGS_FORCE_FAST, - static_prop_id_to_skip, flEpsilon ); + FourVectors normal4; + switch( numNormals ) + { + case 4: + normal4.LoadAndSwizzle( normals[0], normals[1], normals[2], normals[3] ); + break; + case 3: + normal4.LoadAndSwizzle( normals[0], normals[1], normals[2], normals[0] ); + break; + default: + normal4.DuplicateVector( normals[0] ); + break; + } + + GatherSampleLightSSE( sampleOutput, dl, -1, adjusted_pos4, &normal4, + 1, // really it's number of FourVectors passed + iThread, g_bFastStaticProps ? ( nLFlags | GATHERLFLAGS_FORCE_FAST ) : nLFlags, + static_prop_id_to_skip, flEpsilon ); -#ifdef VRAD_SSE - VectorMA( outColor, sampleOutput.m_flFalloff.m128_f32[0] * sampleOutput.m_flDot[0].m128_f32[0], dl->light.intensity, outColor ); -#else - VectorMA( outColor, sampleOutput.m_flFalloff[0] * sampleOutput.m_flDot[0][0], dl->light.intensity, outColor ); -#endif + for ( int k = 0; k < numNormals; ++k ) + { + if ( !((dl->light.type == emit_skylight) && bSkipSkyLight) ) + { + VectorMA( outColors[k], + sampleOutput.m_flFalloff[k] * sampleOutput.m_flDot[0][k], + dl->light.intensity, + outColors[k] ); + } + + outSunAmount[k] += SubFloat( sampleOutput.m_flSunAmount[0], k ) * (sampleOutput.m_flDot[0][0] > 0.0f ? 1.0f : 0.0f); + } } } //----------------------------------------------------------------------------- -// Takes the results from a ComputeLighting call and applies it to the static prop in question. +// version of above that just computes/returns the sun amount //----------------------------------------------------------------------------- -void CVradStaticPropMgr::ApplyLightingToStaticProp( int iStaticProp, CStaticProp &prop, const CComputeStaticPropLightingResults *pResults ) +void ComputeSunAmountAtPoint( Vector &position, Vector *normals, float *outSunAmount, int numNormals, int iThread, + int static_prop_id_to_skip = -1, int nLFlags = 0 ) { - if ( pResults->m_ColorVertsArrays.Count() == 0 && pResults->m_ColorTexelsArrays.Count() == 0 ) - return; - - StaticPropDict_t &dict = m_StaticPropDict[prop.m_ModelIdx]; - studiohdr_t *pStudioHdr = dict.m_pStudioHdr; - OptimizedModel::FileHeader_t *pVtxHdr = (OptimizedModel::FileHeader_t *)dict.m_VtxBuf.Base(); - Assert( pStudioHdr && pVtxHdr ); + SSE_sampleLightOutput_t sampleOutput; - int iCurColorVertsArray = 0; - int iCurColorTexelsArray = 0; + for ( int k = 0; k < numNormals; ++k ) + { + outSunAmount[k] = 0.0f; + } + + // Iterate over all direct lights and accumulate their contribution + int cluster = ClusterFromPoint( position ); + for ( directlight_t *dl = activelights; dl != NULL; dl = dl->next ) + { + if ( dl->light.style ) + { + // skip lights with style + continue; + } + + if ( dl->light.type != emit_skylight ) + { + // skip lights that don't contribue to sunamount + continue; + } + + // is this lights cluster visible? + if ( !PVSCheck( dl->pvs, cluster ) ) + continue; + + // push the vertex towards the light to avoid surface acne + Vector adjusted_pos = position; + float flEpsilon = 0.0; + + const float flFudgeFactor = 4.0; + + // push towards the light + Vector fudge; + fudge = -(dl->light.normal); + fudge *= flFudgeFactor; + adjusted_pos += fudge; + + FourVectors adjusted_pos4; + adjusted_pos4.DuplicateVector( adjusted_pos ); + + FourVectors normal4; + switch ( numNormals ) + { + case 4: + normal4.LoadAndSwizzle( normals[0], normals[1], normals[2], normals[3] ); + break; + case 3: + normal4.LoadAndSwizzle( normals[0], normals[1], normals[2], normals[0] ); + break; + default: + normal4.DuplicateVector( normals[0] ); + break; + } + + GatherSampleLightSSE( sampleOutput, dl, -1, adjusted_pos4, &normal4, + 1, // really it's number of FourVectors passed + iThread, g_bFastStaticProps ? (nLFlags | GATHERLFLAGS_FORCE_FAST) : nLFlags, + static_prop_id_to_skip, flEpsilon ); + + for ( int k = 0; k < numNormals; ++k ) + { + outSunAmount[k] += SubFloat( sampleOutput.m_flSunAmount[0], k ) * (sampleOutput.m_flDot[0][0] > 0.0f ? 1.0f : 0.0f); + } + } +} + +//----------------------------------------------------------------------------- +// Takes the results from a ComputeLighting call and applies it to the static prop in question. +//----------------------------------------------------------------------------- +void CVradStaticPropMgr::ApplyLightingToStaticProp( CStaticProp &prop, const CComputeStaticPropLightingResults *pResults ) +{ + if ( pResults->m_ColorVertsArrays.Count() == 0 ) + return; + StaticPropDict_t &dict = m_StaticPropDict[prop.m_ModelIdx]; + studiohdr_t *pStudioHdr = dict.m_pStudioHdr; + OptimizedModel::FileHeader_t *pVtxHdr = (OptimizedModel::FileHeader_t *)dict.m_VtxBuf.Base(); + Assert( pStudioHdr && pVtxHdr ); + + int const numVertexLightComponents = g_numVradStaticPropsLightingStreams; + int iCurColorVertsArray = 0; for ( int bodyID = 0; bodyID < pStudioHdr->numbodyparts; ++bodyID ) { OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart( bodyID ); @@ -1239,9 +1684,8 @@ void CVradStaticPropMgr::ApplyLightingToStaticProp( int iStaticProp, CStaticProp { OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel( modelID ); mstudiomodel_t *pStudioModel = pBodyPart->pModel( modelID ); - - const CUtlVector *colorVerts = pResults->m_ColorVertsArrays.Count() ? pResults->m_ColorVertsArrays[iCurColorVertsArray++] : nullptr; - const CUtlVector *colorTexels = pResults->m_ColorTexelsArrays.Count() ? pResults->m_ColorTexelsArrays[iCurColorTexelsArray++] : nullptr; + + const CUtlVector &colorVerts = *pResults->m_ColorVertsArrays[iCurColorVertsArray++]; for ( int nLod = 0; nLod < pVtxHdr->numLODs; nLod++ ) { @@ -1256,51 +1700,25 @@ void CVradStaticPropMgr::ApplyLightingToStaticProp( int iStaticProp, CStaticProp { OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup( nGroup ); int nMeshIdx = prop.m_MeshData.AddToTail(); + prop.m_MeshData[nMeshIdx].m_VertColorData.AddMultipleToTail( pStripGroup->numVerts * numVertexLightComponents ); + prop.m_MeshData[nMeshIdx].m_numVerts = pStripGroup->numVerts; + prop.m_MeshData[nMeshIdx].m_nLod = nLod; - if (colorVerts) + for ( int nVertex = 0; nVertex < pStripGroup->numVerts; ++nVertex ) { - prop.m_MeshData[nMeshIdx].m_VertexColors.AddMultipleToTail( pStripGroup->numVerts ); - prop.m_MeshData[nMeshIdx].m_nLod = nLod; + int nIndex = pMesh->vertexoffset + pStripGroup->pVertex( nVertex )->origMeshVertID; - for ( int nVertex = 0; nVertex < pStripGroup->numVerts; ++nVertex ) + Assert( nIndex < pStudioModel->numvertices ); + + if ( numVertexLightComponents <= 1 ) { - int nIndex = pMesh->vertexoffset + pStripGroup->pVertex( nVertex )->origMeshVertID; - - Assert( nIndex < pStudioModel->numvertices ); - prop.m_MeshData[nMeshIdx].m_VertexColors[nVertex] = (*colorVerts)[nIndex].m_Color; + prop.m_MeshData[nMeshIdx].m_VertColorData[nVertex].AsVector3D() = colorVerts[nIndex].m_Colors[0]; + prop.m_MeshData[nMeshIdx].m_VertColorData[nVertex].w = colorVerts[nIndex].m_SunAmount[0]; } - } - - if (colorTexels) - { - // TODO: Consider doing this work in the worker threads, because then we distribute it. - ConvertTexelDataToTexture(prop.m_LightmapImageWidth, prop.m_LightmapImageHeight, prop.m_LightmapImageFormat, (*colorTexels), &prop.m_MeshData[nMeshIdx].m_TexelsEncoded); - - if (g_bDumpPropLightmaps) + else for ( int k = 0 ; k < numVertexLightComponents; ++ k ) { - char buffer[_MAX_PATH]; - V_snprintf( - buffer, - _MAX_PATH - 1, - "staticprop_lightmap_%d_%.0f_%.0f_%.0f_%s_%d_%d_%d_%d_%d.tga", - iStaticProp, - prop.m_Origin.x, - prop.m_Origin.y, - prop.m_Origin.z, - dict.m_pStudioHdr->pszName(), - bodyID, - modelID, - nLod, - nMesh, - nGroup - ); - - for ( int i = 0; buffer[i]; ++i ) - { - if (buffer[i] == '/' || buffer[i] == '\\') - buffer[i] = '-'; - } - DumpLightmapLinear( buffer, (*colorTexels), prop.m_LightmapImageWidth, prop.m_LightmapImageHeight ); + prop.m_MeshData[nMeshIdx].m_VertColorData[nVertex * numVertexLightComponents + k].AsVector3D() = colorVerts[nIndex].m_Colors[k + 1]; + prop.m_MeshData[nMeshIdx].m_VertColorData[nVertex * numVertexLightComponents + k].w = colorVerts[nIndex].m_SunAmount[k + 1]; } } } @@ -1310,6 +1728,7 @@ void CVradStaticPropMgr::ApplyLightingToStaticProp( int iStaticProp, CStaticProp } } + //----------------------------------------------------------------------------- // Trace rays from each unique vertex, accumulating direct and indirect // sources at each ray termination. Use the winding data to distribute the unique vertexes @@ -1329,43 +1748,40 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr return; } - const bool withVertexLighting = (prop.m_Flags & STATIC_PROP_NO_PER_VERTEX_LIGHTING) == 0; - const bool withTexelLighting = (prop.m_Flags & STATIC_PROP_NO_PER_TEXEL_LIGHTING) == 0; + int nGatherFlags = (prop.m_Flags & STATIC_PROP_IGNORE_NORMALS) ? GATHERLFLAGS_IGNORE_NORMALS : 0; + nGatherFlags |= (prop.m_Flags & STATIC_PROP_NO_PER_VERTEX_LIGHTING) ? GATHERLFLAGS_NO_OCCLUSION : 0; - if (!withVertexLighting && !withTexelLighting) - return; + if ( dict.m_bHasPhong ) + { + nGatherFlags &= ~GATHERLFLAGS_IGNORE_NORMALS; + } - const int skip_prop = (g_bDisablePropSelfShadowing || (prop.m_Flags & STATIC_PROP_NO_SELF_SHADOWING)) ? prop_index : -1; - const int nFlags = ( prop.m_Flags & STATIC_PROP_IGNORE_NORMALS ) ? GATHERLFLAGS_IGNORE_NORMALS : 0; + nGatherFlags |= GATHERLFLAGS_STATICPROP; #ifdef MPI VMPI_SetCurrentStage( "ComputeLighting" ); #endif - matrix3x4_t matPos, matNormal; - AngleMatrix(prop.m_Angles, prop.m_Origin, matPos); - AngleMatrix(prop.m_Angles, matNormal); - + int numSampleNormals = (g_numVradStaticPropsLightingStreams > 1) ? (NUM_BUMP_VECTS + 1) : 1; + bool bCanUseTangents = dict.m_bHasBumpmap; + bool bSkipDirectSkylight = true; // Only computing indirect GI for all static props now. Direct sunlight applied in shader. + if ( PositionIn3DSkybox( prop.m_Origin ) ) + { + bSkipDirectSkylight = false; + } + for ( int bodyID = 0; bodyID < pStudioHdr->numbodyparts; ++bodyID ) { - OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart( bodyID ); mstudiobodyparts_t *pBodyPart = pStudioHdr->pBodypart( bodyID ); for ( int modelID = 0; modelID < pBodyPart->nummodels; ++modelID ) { - OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel(modelID); mstudiomodel_t *pStudioModel = pBodyPart->pModel( modelID ); - if (withTexelLighting) - { - CUtlVector *pColorTexelArray = new CUtlVector; - pResults->m_ColorTexelsArrays.AddToTail(pColorTexelArray); - } - // light all unique vertexes CUtlVector *pColorVertsArray = new CUtlVector; pResults->m_ColorVertsArrays.AddToTail( pColorVertsArray ); - + CUtlVector &colorVerts = *pColorVertsArray; colorVerts.EnsureCount( pStudioModel->numvertices ); memset( colorVerts.Base(), 0, colorVerts.Count() * sizeof(colorVertex_t) ); @@ -1375,23 +1791,57 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr { mstudiomesh_t *pStudioMesh = pStudioModel->pMesh( meshID ); const mstudio_meshvertexdata_t *vertData = pStudioMesh->GetVertexData((void *)pStudioHdr); - - Assert(vertData); // This can only return NULL on X360 for now - - // TODO: Move this into its own function. In fact, refactor this whole function. - if (withTexelLighting) - { - GenerateLightmapSamplesForMesh( matPos, matNormal, iThread, skip_prop, nFlags, prop.m_LightmapImageWidth, prop.m_LightmapImageHeight, pStudioHdr, pStudioModel, pVtxModel, meshID, pResults ); - } - - // If we do lightmapping, we also do vertex lighting as a potential fallback. This may change. + Assert( vertData ); // This can only return NULL on X360 for now for ( int vertexID = 0; vertexID < pStudioMesh->numvertices; ++vertexID ) { - Vector sampleNormal; + Vector sampleNormals[ NUM_BUMP_VECTS + 1 ]; Vector samplePosition; // transform position and normal into world coordinate system - VectorTransform(*vertData->Position(vertexID), matPos, samplePosition); - VectorTransform(*vertData->Normal(vertexID), matNormal, sampleNormal); + matrix3x4_t matrix; + AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); + VectorTransform( *vertData->Position( vertexID ), matrix, samplePosition ); + AngleMatrix( prop.m_Angles, matrix ); + VectorTransform( *vertData->Normal( vertexID ), matrix, sampleNormals[0] ); + + if( numSampleNormals > 1 ) + { + Vector *bumpVects = &sampleNormals[1]; + Vector4D *vecTangentS = vertData->HasTangentData() ? vertData->TangentS( vertexID ) : NULL; + + if ( vecTangentS && bCanUseTangents ) + { + Vector vecTexS; + VectorTransform( vecTangentS->AsVector3D(), matrix, vecTexS ); + + Vector vecTexT; + CrossProduct( sampleNormals[0], vecTexS, vecTexT ); + vecTexT.NormalizeInPlace(); + + // recompute S-vector to have S, T, N as an orthonormal basis for hl2 vectors + CrossProduct( vecTexT, sampleNormals[0], vecTexS ); + + // respect the flip-factor for T-vector + vecTexT *= vecTangentS->w; + + GetStaticPropBumpNormals( + vecTexS, vecTexT, + sampleNormals[0], + sampleNormals[0], + bumpVects ); + + sampleNormals[0].NormalizeInPlace(); + sampleNormals[1].NormalizeInPlace(); + sampleNormals[2].NormalizeInPlace(); + sampleNormals[3].NormalizeInPlace(); + } + else + { + sampleNormals[1] = sampleNormals[0]; + sampleNormals[2] = sampleNormals[0]; + sampleNormals[3] = sampleNormals[0]; + } + } + if ( PositionInSolid( samplePosition ) ) { @@ -1399,39 +1849,105 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr badVertex_t badVertex; badVertex.m_ColorVertex = numVertexes; badVertex.m_Position = samplePosition; - badVertex.m_Normal = sampleNormal; + memcpy( badVertex.m_Normals, sampleNormals, sizeof( badVertex.m_Normals ) ); badVerts.AddToTail( badVertex ); } - else + else { Vector direct_pos=samplePosition; - - + int skip_prop = -1; + if ( g_bDisablePropSelfShadowing || ( prop.m_Flags & STATIC_PROP_NO_SELF_SHADOWING ) ) + { + skip_prop = prop_index; + } + + Vector directColors[ NUM_BUMP_VECTS + 1 ]; + float sunAmount[ NUM_BUMP_VECTS + 1 ]; + memset( directColors, 0, sizeof( directColors ) ); + memset( sunAmount, 0, sizeof( sunAmount ) ); + + if ( bCanUseTangents ) + { + ComputeDirectLightingAtPoint( direct_pos, + sampleNormals, directColors, sunAmount, numSampleNormals, bSkipDirectSkylight, + iThread, + skip_prop, nGatherFlags ); + } + else + { + ComputeDirectLightingAtPoint( direct_pos, + sampleNormals, directColors, sunAmount, 1, bSkipDirectSkylight, + iThread, + skip_prop, nGatherFlags ); + directColors[1] = directColors[0]; + directColors[2] = directColors[0]; + directColors[3] = directColors[0]; + sunAmount[1] = sunAmount[0]; + sunAmount[2] = sunAmount[0]; + sunAmount[3] = sunAmount[0]; + } + + if ( numSampleNormals > 1 ) + { + // doing this for direct and indirect separately helps eliminate errors with CSM blending + NormalizeVertexBumpedLighting( directColors, directColors + 1 ); + } - Vector directColor(0,0,0); - ComputeDirectLightingAtPoint( direct_pos, - sampleNormal, directColor, iThread, - skip_prop, nFlags ); - Vector indirectColor(0,0,0); + + Vector indirectColors[ NUM_BUMP_VECTS + 1 ]; + memset( indirectColors, 0, sizeof( indirectColors ) ); if (g_bShowStaticPropNormals) { - directColor= sampleNormal; - directColor += Vector(1.0,1.0,1.0); - directColor *= 50.0; + directColors[0] = sampleNormals[0]; + directColors[0] += Vector(1.0,1.0,1.0); + directColors[0] *= 50.0; + directColors[1] = directColors[0]; + directColors[2] = directColors[0]; + directColors[3] = directColors[0]; } else { if (numbounce >= 1) - ComputeIndirectLightingAtPoint( - samplePosition, sampleNormal, - indirectColor, iThread, true, - ( prop.m_Flags & STATIC_PROP_IGNORE_NORMALS) != 0 ); + { + if ( bCanUseTangents ) + { + ComputeIndirectLightingAtPoint( + samplePosition, sampleNormals, + indirectColors, numSampleNormals, iThread, g_bFastStaticProps, + ( prop.m_Flags & STATIC_PROP_IGNORE_NORMALS ) != 0, prop_index ); + } + else + { + ComputeIndirectLightingAtPoint( + samplePosition, sampleNormals, + indirectColors, 1, iThread, g_bFastStaticProps, + ( prop.m_Flags & STATIC_PROP_IGNORE_NORMALS ) != 0, prop_index ); + indirectColors[1] = indirectColors[0]; + indirectColors[2] = indirectColors[0]; + indirectColors[3] = indirectColors[0]; + } + + if ( numSampleNormals > 1 ) + { + // doing this for direct and indirect separately helps eliminate errors with CSM blending + NormalizeVertexBumpedLighting( indirectColors, indirectColors + 1 ); + } + } } - + colorVerts[numVertexes].m_bValid = true; colorVerts[numVertexes].m_Position = samplePosition; - VectorAdd( directColor, indirectColor, colorVerts[numVertexes].m_Color ); + for ( int k = 0; k < numSampleNormals; ++ k ) + { + VectorAdd( directColors[k], indirectColors[k], colorVerts[numVertexes].m_Colors[k] ); + colorVerts[numVertexes].m_SunAmount[k] = sunAmount[k]; + } + if ( numSampleNormals > 1 ) + { + float *pSunAmountUnbumped = &colorVerts[numVertexes].m_SunAmount[0]; + NormalizeVertexBumpedSunAmount( pSunAmountUnbumped, pSunAmountUnbumped+1, pSunAmountUnbumped+2, pSunAmountUnbumped+3 ); + } } numVertexes++; @@ -1478,7 +1994,7 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr } // crawl toward best position - // sudivide to determine a closer valid point to the bad vertex, and re-light + // subdivide to determine a closer valid point to the bad vertex, and re-light Vector midPosition; int numIterations = 20; while ( --numIterations > 0 ) @@ -1490,18 +2006,57 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr bestPosition = midPosition; } + Vector directColors[ NUM_BUMP_VECTS + 1 ]; + memset( directColors, 0, sizeof( directColors ) ); + Vector indirectColors[ NUM_BUMP_VECTS + 1 ]; + memset( indirectColors, 0, sizeof( indirectColors ) ); + float sunAmount[NUM_BUMP_VECTS + 1]; + memset( sunAmount, 0, sizeof( sunAmount ) ); + // re-light from better position - Vector directColor; - ComputeDirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normal, directColor, iThread ); + if ( bCanUseTangents ) + { + ComputeDirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normals, + directColors, sunAmount, numSampleNormals, bSkipDirectSkylight, iThread ); + ComputeIndirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normals, + indirectColors, numSampleNormals, iThread, true, false, prop_index ); + } + else + { + ComputeDirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normals, + directColors, sunAmount, 1, bSkipDirectSkylight, iThread ); + // doing this for direct and indirect separately helps eliminate errors with CSM blending + ComputeIndirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normals, + indirectColors, 1, iThread, true, false, prop_index ); + for ( int k = 1; k < numSampleNormals; ++k ) + { + directColors[k] = directColors[0]; + indirectColors[k] = indirectColors[0]; + sunAmount[k] = sunAmount[0]; + } + } - Vector indirectColor; - ComputeIndirectLightingAtPoint( bestPosition, badVerts[nBadVertex].m_Normal, - indirectColor, iThread, true ); + if ( numSampleNormals > 1 ) + { + // doing this for direct and indirect separately helps eliminate errors with CSM blending + NormalizeVertexBumpedLighting( directColors, directColors + 1 ); + NormalizeVertexBumpedLighting( indirectColors, indirectColors + 1 ); + } // save results, not changing valid status // to ensure this offset position is not considered as a viable candidate - colorVerts[badVerts[nBadVertex].m_ColorVertex].m_Position = bestPosition; - VectorAdd( directColor, indirectColor, colorVerts[badVerts[nBadVertex].m_ColorVertex].m_Color ); + const int idxColorVertex = badVerts[nBadVertex].m_ColorVertex; + colorVerts[idxColorVertex].m_Position = bestPosition; + for ( int k = 0; k < numSampleNormals; ++ k ) + { + VectorAdd( directColors[k], indirectColors[k], colorVerts[idxColorVertex].m_Colors[k] ); + colorVerts[idxColorVertex].m_SunAmount[k] = sunAmount[k]; + } + if ( numSampleNormals > 1 ) + { + float *pSunAmountUnbumped = &colorVerts[idxColorVertex].m_SunAmount[0]; + NormalizeVertexBumpedSunAmount( pSunAmountUnbumped, pSunAmountUnbumped + 1, pSunAmountUnbumped + 2, pSunAmountUnbumped + 3 ); + } } } @@ -1512,7 +2067,7 @@ void CVradStaticPropMgr::ComputeLighting( CStaticProp &prop, int iThread, int pr } //----------------------------------------------------------------------------- -// Write the lighitng to bsp pak lump +// Write the lighting to bsp pak lump //----------------------------------------------------------------------------- void CVradStaticPropMgr::SerializeLighting() { @@ -1533,10 +2088,6 @@ void CVradStaticPropMgr::SerializeLighting() int size; for (int i = 0; i < count; ++i) { - // no need to write this file if we didn't compute the data - // props marked this way will not load the info anyway - if ( m_StaticProps[i].m_Flags & STATIC_PROP_NO_PER_VERTEX_LIGHTING ) - continue; if (g_bHDR) { @@ -1550,13 +2101,15 @@ void CVradStaticPropMgr::SerializeLighting() int totalVertexes = 0; for ( int j=0; jm_nVersion = VHV_VERSION; pVhvHdr->m_nChecksum = m_StaticPropDict[m_StaticProps[i].m_ModelIdx].m_pStudioHdr->checksum; - pVhvHdr->m_nVertexFlags = VERTEX_COLOR; - pVhvHdr->m_nVertexSize = 4; + pVhvHdr->m_nVertexFlags = ( numLightingComponents > 1 ) ? VERTEX_NORMAL : VERTEX_COLOR; + pVhvHdr->m_nVertexSize = 4 * numLightingComponents; pVhvHdr->m_nVertexes = totalVertexes; pVhvHdr->m_nMeshes = m_StaticProps[i].m_MeshData.Count(); @@ -1579,16 +2132,19 @@ void CVradStaticPropMgr::SerializeLighting() // construct mesh dictionary HardwareVerts::MeshHeader_t *pMesh = pVhvHdr->pMesh( n ); pMesh->m_nLod = m_StaticProps[i].m_MeshData[n].m_nLod; - pMesh->m_nVertexes = m_StaticProps[i].m_MeshData[n].m_VertexColors.Count(); - pMesh->m_nOffset = (uintp)pVertexData - (uintp)pVhvHdr; + pMesh->m_nVertexes = m_StaticProps[i].m_MeshData[n].m_numVerts; + pMesh->m_nOffset = (size_t)pVertexData - (size_t)pVhvHdr; // construct vertexes - for (int k=0; km_nVertexes; k++) + for (int k=0; k 1024.0f) || (vector.y > 1024.0f) || (vector.z > 1024.0f) )s + // Msg(" *** out of range prop lighting *** \n"); ColorRGBExp32 rgbColor; - VectorToColorRGBExp32( vertexColor, rgbColor ); + VectorToColorRGBExp32( vector, rgbColor ); unsigned char dstColor[4]; ConvertRGBExp32ToRGBA8888( &rgbColor, dstColor ); @@ -1596,74 +2152,21 @@ void CVradStaticPropMgr::SerializeLighting() pVertexData[0] = dstColor[2]; pVertexData[1] = dstColor[1]; pVertexData[2] = dstColor[0]; - pVertexData[3] = dstColor[3]; + + // Use the unmodified lighting data to generate the sun percentage, not the output of the RGBE conversions above! + float flSunAmount = m_StaticProps[i].m_MeshData[n].m_VertColorData[k].w; + pVertexData[3] = uint8( clamp( flSunAmount, 0.0f, 1.0f ) * 255.0f + 0.5f ); + pVertexData += 4; } } // align to end of file - pVertexData = (unsigned char *)((uintp)pVertexData - (uintp)pVhvHdr); - pVertexData = (unsigned char*)pVhvHdr + ALIGN_TO_POW2( (uintp)pVertexData, 512 ); + pVertexData = (unsigned char *)((size_t)pVertexData - (size_t)pVhvHdr); + pVertexData = (unsigned char*)pVhvHdr + ALIGN_TO_POW2( (size_t)pVertexData, 512 ); AddBufferToPak( GetPakFile(), filename, (void*)pVhvHdr, pVertexData - (unsigned char*)pVhvHdr, false ); } - - for (int i = 0; i < count; ++i) - { - const int kAlignment = 512; - // no need to write this file if we didn't compute the data - // props marked this way will not load the info anyway - if (m_StaticProps[i].m_Flags & STATIC_PROP_NO_PER_TEXEL_LIGHTING) - continue; - - sprintf(filename, "texelslighting_%d.ppl", i); - - ImageFormat fmt = m_StaticProps[i].m_LightmapImageFormat; - - uintp totalTexelSizeBytes = 0; - for (int j = 0; j < m_StaticProps[i].m_MeshData.Count(); j++) - { - totalTexelSizeBytes += m_StaticProps[i].m_MeshData[j].m_TexelsEncoded.Count(); - } - - // allocate a buffer with enough padding for alignment - size = sizeof(HardwareTexels::FileHeader_t) - + m_StaticProps[i].m_MeshData.Count() * sizeof(HardwareTexels::MeshHeader_t) - + totalTexelSizeBytes - + 2 * kAlignment; - - utlBuf.EnsureCapacity(size); - Q_memset(utlBuf.Base(), 0, size); - - HardwareTexels::FileHeader_t *pVhtHdr = (HardwareTexels::FileHeader_t *)utlBuf.Base(); - - // align start of texel data - unsigned char *pTexelData = (unsigned char *)(sizeof(HardwareTexels::FileHeader_t) + m_StaticProps[i].m_MeshData.Count() * sizeof(HardwareTexels::MeshHeader_t)); - pTexelData = (unsigned char*)pVhtHdr + ALIGN_TO_POW2((uintp)pTexelData, kAlignment); - - pVhtHdr->m_nVersion = VHT_VERSION; - pVhtHdr->m_nChecksum = m_StaticPropDict[m_StaticProps[i].m_ModelIdx].m_pStudioHdr->checksum; - pVhtHdr->m_nTexelFormat = fmt; - pVhtHdr->m_nMeshes = m_StaticProps[i].m_MeshData.Count(); - - for (int n = 0; n < pVhtHdr->m_nMeshes; n++) - { - HardwareTexels::MeshHeader_t *pMesh = pVhtHdr->pMesh(n); - pMesh->m_nLod = m_StaticProps[i].m_MeshData[n].m_nLod; - pMesh->m_nOffset = (uintp)pTexelData - (uintp)pVhtHdr; - pMesh->m_nBytes = m_StaticProps[i].m_MeshData[n].m_TexelsEncoded.Count(); - pMesh->m_nWidth = m_StaticProps[i].m_LightmapImageWidth; - pMesh->m_nHeight = m_StaticProps[i].m_LightmapImageHeight; - - Q_memcpy(pTexelData, m_StaticProps[i].m_MeshData[n].m_TexelsEncoded.Base(), m_StaticProps[i].m_MeshData[n].m_TexelsEncoded.Count()); - pTexelData += m_StaticProps[i].m_MeshData[n].m_TexelsEncoded.Count(); - } - - pTexelData = (unsigned char *)((uintp)pTexelData - (uintp)pVhtHdr); - pTexelData = (unsigned char*)pVhtHdr + ALIGN_TO_POW2((uintp)pTexelData, kAlignment); - - AddBufferToPak(GetPakFile(), filename, (void*)pVhtHdr, pTexelData - (unsigned char*)pVhtHdr, false); - } } #ifdef MPI @@ -1700,17 +2203,6 @@ void CVradStaticPropMgr::VMPI_ProcessStaticProp( int iThread, int iStaticProp, M pBuf->write( &count, sizeof( count ) ); pBuf->write( curList.Base(), curList.Count() * sizeof( colorVertex_t ) ); } - - nLists = results.m_ColorTexelsArrays.Count(); - pBuf->write(&nLists, sizeof(nLists)); - - for (int i = 0; i < nLists; i++) - { - CUtlVector &curList = *results.m_ColorTexelsArrays[i]; - int count = curList.Count(); - pBuf->write(&count, sizeof(count)); - pBuf->write(curList.Base(), curList.Count() * sizeof(colorTexel_t)); - } } //----------------------------------------------------------------------------- @@ -1734,22 +2226,9 @@ void CVradStaticPropMgr::VMPI_ReceiveStaticPropResults( int iStaticProp, Message pList->SetSize( count ); pBuf->read( pList->Base(), count * sizeof( colorVertex_t ) ); } - - pBuf->read(&nLists, sizeof(nLists)); - - for (int i = 0; i < nLists; i++) - { - CUtlVector *pList = new CUtlVector; - results.m_ColorTexelsArrays.AddToTail(pList); - - int count; - pBuf->read(&count, sizeof(count)); - pList->SetSize(count); - pBuf->read(pList->Base(), count * sizeof(colorTexel_t)); - } // Apply the results. - ApplyLightingToStaticProp( iStaticProp, m_StaticProps[iStaticProp], &results ); + ApplyLightingToStaticProp( m_StaticProps[iStaticProp], &results ); } #endif @@ -1758,7 +2237,7 @@ void CVradStaticPropMgr::ComputeLightingForProp( int iThread, int iStaticProp ) // Compute the lighting. CComputeStaticPropLightingResults results; ComputeLighting( m_StaticProps[iStaticProp], iThread, iStaticProp, &results ); - ApplyLightingToStaticProp( iStaticProp, m_StaticProps[iStaticProp], &results ); + ApplyLightingToStaticProp( m_StaticProps[iStaticProp], &results ); } void CVradStaticPropMgr::ThreadComputeStaticPropLighting( int iThread, void *pUserData ) @@ -1787,8 +2266,16 @@ void CVradStaticPropMgr::ComputeLighting( int iThread ) return; } + double start = Plat_FloatTime(); + StartPacifier( "Computing static prop lighting : " ); +#if 0 + CGlViewBuffer glViewBuf; + glViewBuf.WriteKDTree( &g_RtEnv ); + g_pFullFileSystem->WriteFile( "maps/rtenv.gl", "GAME", glViewBuf ); +#endif + // ensure any traces against us are ignored because we have no inherit lighting contribution m_bIgnoreStaticPropTrace = true; @@ -1800,7 +2287,6 @@ void CVradStaticPropMgr::ComputeLighting( int iThread ) DistributeWork( count, - VMPI_DISTRIBUTEWORK_PACKETID, &CVradStaticPropMgr::VMPI_ProcessStaticProp_Static, &CVradStaticPropMgr::VMPI_ReceiveStaticPropResults_Static ); } @@ -1812,11 +2298,15 @@ void CVradStaticPropMgr::ComputeLighting( int iThread ) // restore default m_bIgnoreStaticPropTrace = false; - + // save data to bsp SerializeLighting(); EndPacifier( true ); + + double end = Plat_FloatTime(); + + DumpElapsedTime( (int)(end - start) ); } //----------------------------------------------------------------------------- @@ -1879,11 +2369,17 @@ void CVradStaticPropMgr::AddPolysForRayTrace( void ) if ( !pStudioHdr || !pVtxHdr ) { // must have model and its verts for decoding triangles - return; + // must have model and its verts for decoding triangles + printf( "Can't get studio header (%p) and vertex data (%p) for %s\n", pStudioHdr, pVtxHdr, + pStudioHdr ? pStudioHdr->name : "***unknown***" ); + continue; } // only init the triangle table the first time bool bInitTriangles = dict.m_triangleMaterialIndex.Count() ? false : true; int triangleIndex = 0; + // transform position into world coordinate system + matrix3x4_t matrix; + AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); // meshes are deeply hierarchial, divided between three stores, follow the white rabbit // body parts -> models -> lod meshes -> strip groups -> strips @@ -1942,77 +2438,65 @@ void CVradStaticPropMgr::AddPolysForRayTrace( void ) { OptimizedModel::StripHeader_t *pStrip = pStripGroup->pStrip( nStrip ); - if ( pStrip->flags & OptimizedModel::STRIP_IS_TRILIST ) + for ( int i = 0; i < pStrip->numIndices; i += 3 ) { - for ( int i = 0; i < pStrip->numIndices; i += 3 ) + int idx = pStrip->indexOffset + i; + + unsigned short i1 = *pStripGroup->pIndex( idx ); + unsigned short i2 = *pStripGroup->pIndex( idx + 1 ); + unsigned short i3 = *pStripGroup->pIndex( idx + 2 ); + + int vertex1 = pStripGroup->pVertex( i1 )->origMeshVertID; + int vertex2 = pStripGroup->pVertex( i2 )->origMeshVertID; + int vertex3 = pStripGroup->pVertex( i3 )->origMeshVertID; + + // transform position into world coordinate system + matrix3x4_t matrix; + AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); + Vector position1; + Vector position2; + Vector position3; + VectorTransform( *vertData->Position( vertex1 ), matrix, position1 ); + VectorTransform( *vertData->Position( vertex2 ), matrix, position2 ); + VectorTransform( *vertData->Position( vertex3 ), matrix, position3 ); + unsigned short flags = 0; + int materialIndex = -1; + Vector color = vec3_origin; + if ( shadowTextureIndex >= 0 ) { - int idx = pStrip->indexOffset + i; - - unsigned short i1 = *pStripGroup->pIndex( idx ); - unsigned short i2 = *pStripGroup->pIndex( idx + 1 ); - unsigned short i3 = *pStripGroup->pIndex( idx + 2 ); - - int vertex1 = pStripGroup->pVertex( i1 )->origMeshVertID; - int vertex2 = pStripGroup->pVertex( i2 )->origMeshVertID; - int vertex3 = pStripGroup->pVertex( i3 )->origMeshVertID; - - // transform position into world coordinate system - matrix3x4_t matrix; - AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); - - Vector position1; - Vector position2; - Vector position3; - VectorTransform( *vertData->Position( vertex1 ), matrix, position1 ); - VectorTransform( *vertData->Position( vertex2 ), matrix, position2 ); - VectorTransform( *vertData->Position( vertex3 ), matrix, position3 ); - unsigned short flags = 0; - int materialIndex = -1; - Vector color = vec3_origin; - if ( shadowTextureIndex >= 0 ) + if ( bInitTriangles ) { - if ( bInitTriangles ) + // add texture space and texture index to material database + // now + float coverage = g_ShadowTextureList.ComputeCoverageForTriangle(shadowTextureIndex, *vertData->Texcoord(vertex1), *vertData->Texcoord(vertex2), *vertData->Texcoord(vertex3) ); + if ( coverage < 1.0f ) { - // add texture space and texture index to material database - // now - float coverage = g_ShadowTextureList.ComputeCoverageForTriangle(shadowTextureIndex, *vertData->Texcoord(vertex1), *vertData->Texcoord(vertex2), *vertData->Texcoord(vertex3) ); - if ( coverage < 1.0f ) - { - materialIndex = g_ShadowTextureList.AddMaterialEntry( shadowTextureIndex, *vertData->Texcoord(vertex1), *vertData->Texcoord(vertex2), *vertData->Texcoord(vertex3) ); - color.x = coverage; - } - else - { - materialIndex = -1; - } - dict.m_triangleMaterialIndex.AddToTail(materialIndex); + materialIndex = g_ShadowTextureList.AddMaterialEntry( shadowTextureIndex, *vertData->Texcoord(vertex1), *vertData->Texcoord(vertex2), *vertData->Texcoord(vertex3) ); + color.x = coverage; } else { - materialIndex = dict.m_triangleMaterialIndex[triangleIndex]; - triangleIndex++; - } - if ( materialIndex >= 0 ) - { - flags = FCACHETRI_TRANSPARENT; + materialIndex = -1; } + dict.m_triangleMaterialIndex.AddToTail(materialIndex); + } + else + { + materialIndex = dict.m_triangleMaterialIndex[triangleIndex]; + triangleIndex++; } + if ( materialIndex >= 0 ) + { + flags = FCACHETRI_TRANSPARENT; + } + } // printf( "\ngl 3\n" ); // printf( "gl %6.3f %6.3f %6.3f 1 0 0\n", XYZ(position1)); // printf( "gl %6.3f %6.3f %6.3f 0 1 0\n", XYZ(position2)); // printf( "gl %6.3f %6.3f %6.3f 0 0 1\n", XYZ(position3)); - g_RtEnv.AddTriangle( TRACE_ID_STATICPROP | nProp, - position1, position2, position3, - color, flags, materialIndex); - } - } - else - { - // all tris expected to be discrete tri lists - // must fixme if stripping ever occurs - printf( "unexpected strips found\n" ); - Assert( 0 ); - return; + g_RtEnv.AddTriangle( TRACE_ID_STATICPROP | nProp, + position1, position2, position3, + color, flags, materialIndex); } } } @@ -2126,50 +2610,39 @@ void CVradStaticPropMgr::BuildTriList( CStaticProp &prop ) { OptimizedModel::StripHeader_t *pStrip = pStripGroup->pStrip( nStrip ); - if ( pStrip->flags & OptimizedModel::STRIP_IS_TRILIST ) + for ( int i = 0; i < pStrip->numIndices; i += 3 ) { - for ( int i = 0; i < pStrip->numIndices; i += 3 ) - { - int idx = pStrip->indexOffset + i; - - unsigned short i1 = *pStripGroup->pIndex( idx ); - unsigned short i2 = *pStripGroup->pIndex( idx + 1 ); - unsigned short i3 = *pStripGroup->pIndex( idx + 2 ); - - int vertex1 = pStripGroup->pVertex( i1 )->origMeshVertID; - int vertex2 = pStripGroup->pVertex( i2 )->origMeshVertID; - int vertex3 = pStripGroup->pVertex( i3 )->origMeshVertID; - - // transform position into world coordinate system - matrix3x4_t matrix; - AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); - - Vector position1; - Vector position2; - Vector position3; - VectorTransform( *vertData->Position( vertex1 ), matrix, position1 ); - VectorTransform( *vertData->Position( vertex2 ), matrix, position2 ); - VectorTransform( *vertData->Position( vertex3 ), matrix, position3 ); - - Vector normal1; - Vector normal2; - Vector normal3; - VectorTransform( *vertData->Normal( vertex1 ), matrix, normal1 ); - VectorTransform( *vertData->Normal( vertex2 ), matrix, normal2 ); - VectorTransform( *vertData->Normal( vertex3 ), matrix, normal3 ); - - AddTriVertsToList( triListVerts, pMesh->vertexoffset + vertex1, position1, position1, position2, position3, normal1, normal2, normal3 ); - AddTriVertsToList( triListVerts, pMesh->vertexoffset + vertex2, position2, position1, position2, position3, normal1, normal2, normal3 ); - AddTriVertsToList( triListVerts, pMesh->vertexoffset + vertex3, position3, position1, position2, position3, normal1, normal2, normal3 ); - } - } - else - { - // all tris expected to be discrete tri lists - // must fixme if stripping ever occurs - printf( "unexpected strips found\n" ); - Assert( 0 ); - return; + int idx = pStrip->indexOffset + i; + + unsigned short i1 = *pStripGroup->pIndex( idx ); + unsigned short i2 = *pStripGroup->pIndex( idx + 1 ); + unsigned short i3 = *pStripGroup->pIndex( idx + 2 ); + + int vertex1 = pStripGroup->pVertex( i1 )->origMeshVertID; + int vertex2 = pStripGroup->pVertex( i2 )->origMeshVertID; + int vertex3 = pStripGroup->pVertex( i3 )->origMeshVertID; + + // transform position into world coordinate system + matrix3x4_t matrix; + AngleMatrix( prop.m_Angles, prop.m_Origin, matrix ); + + Vector position1; + Vector position2; + Vector position3; + VectorTransform( *vertData->Position( vertex1 ), matrix, position1 ); + VectorTransform( *vertData->Position( vertex2 ), matrix, position2 ); + VectorTransform( *vertData->Position( vertex3 ), matrix, position3 ); + + Vector normal1; + Vector normal2; + Vector normal3; + VectorTransform( *vertData->Normal( vertex1 ), matrix, normal1 ); + VectorTransform( *vertData->Normal( vertex2 ), matrix, normal2 ); + VectorTransform( *vertData->Normal( vertex3 ), matrix, normal3 ); + + AddTriVertsToList( triListVerts, pMesh->vertexoffset + vertex1, position1, position1, position2, position3, normal1, normal2, normal3 ); + AddTriVertsToList( triListVerts, pMesh->vertexoffset + vertex2, position2, position1, position2, position3, normal1, normal2, normal3 ); + AddTriVertsToList( triListVerts, pMesh->vertexoffset + vertex3, position3, position1, position2, position3, normal1, normal2, normal3 ); } } } @@ -2197,23 +2670,20 @@ const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void *pModelData ) strcat( fileName, ".vvd" ); // load the model - FileHandle_t fileHandle = g_pFileSystem->Open( fileName, "rb" ); - if ( !fileHandle ) + CUtlBuffer bufData; + if ( !LoadFile( fileName, bufData ) ) { Error( "Unable to load vertex data \"%s\"\n", fileName ); } // Get the file size - int vvdSize = g_pFileSystem->Size( fileHandle ); + int vvdSize = bufData.TellPut(); if ( vvdSize == 0 ) { - g_pFileSystem->Close( fileHandle ); Error( "Bad size for vertex data \"%s\"\n", fileName ); } - vertexFileHeader_t *pVvdHdr = (vertexFileHeader_t *)malloc( vvdSize ); - g_pFileSystem->Read( pVvdHdr, vvdSize, fileHandle ); - g_pFileSystem->Close( fileHandle ); + vertexFileHeader_t *pVvdHdr = (vertexFileHeader_t *) bufData.Base(); // check header if ( pVvdHdr->id != MODEL_VERTEX_FILE_ID ) @@ -2238,471 +2708,150 @@ const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void *pModelData ) } // load vertexes and run fixups - Studio_LoadVertexes( pVvdHdr, pNewVvdHdr, 0, true ); + Studio_LoadVertexes(pVvdHdr, pNewVvdHdr, 0, true); // discard original - free( pVvdHdr ); pVvdHdr = pNewVvdHdr; - pActiveStudioHdr->SetVertexBase((void*)pVvdHdr); + pActiveStudioHdr->SetVertexBase( (void*)pVvdHdr ); return pVvdHdr; } -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -struct ColorTexelValue -{ - Vector mLinearColor; // Linear color value for this texel - bool mValidData; // Whether there is valid data in this texel. - size_t mTriangleIndex; // Which triangle we used to generate the texel. -}; - -// ------------------------------------------------------------------------------------------------ -inline int ComputeLinearPos( int _x, int _y, int _resX, int _resY ) -{ - return MIN( MAX( 0, _y ), _resY - 1 ) * _resX - + MIN( MAX( 0, _x ), _resX - 1 ); -} - -// ------------------------------------------------------------------------------------------------ -inline float ComputeBarycentricDistanceToTri( Vector _barycentricCoord, Vector2D _v[3] ) -{ - Vector2D realPos = _barycentricCoord.x * _v[0] - + _barycentricCoord.y * _v[1] - + _barycentricCoord.z * _v[2]; - - int minIndex = 0; - float minVal = _barycentricCoord[0]; - for (int i = 1; i < 3; ++i) { - if (_barycentricCoord[i] < minVal) { - minVal = _barycentricCoord[i]; - minIndex = i; - } - } - - Vector2D& first = _v[ (minIndex + 1) % 3]; - Vector2D& second = _v[ (minIndex + 2) % 3]; - - return CalcDistanceToLineSegment2D( realPos, first, second ); -} +extern float totalarea; +extern unsigned num_degenerate_faces; +extern int fakeplanes; +extern int PlaneTypeForNormal( Vector& normal ); -// ------------------------------------------------------------------------------------------------ -static void GenerateLightmapSamplesForMesh( const matrix3x4_t& _matPos, const matrix3x4_t& _matNormal, int _iThread, int _skipProp, int _flags, int _lightmapResX, int _lightmapResY, studiohdr_t* _pStudioHdr, mstudiomodel_t* _pStudioModel, OptimizedModel::ModelHeader_t* _pVtxModel, int _meshID, CComputeStaticPropLightingResults *_outResults ) +void MakePatchForTriangle( winding_t *w, Vector vRefl, int nStaticPropIdx ) { - // Could iterate and gen this if needed. - int nLod = 0; - - OptimizedModel::ModelLODHeader_t *pVtxLOD = _pVtxModel->pLOD(nLod); - - CUtlVector &colorTexels = (*_outResults->m_ColorTexelsArrays.Tail()); - const int cTotalPixelCount = _lightmapResX * _lightmapResY; - colorTexels.EnsureCount(cTotalPixelCount); - memset(colorTexels.Base(), 0, colorTexels.Count() * sizeof(colorTexel_t)); + float area; + CPatch *patch; + Vector centroid( 0, 0, 0 ); - for (int i = 0; i < colorTexels.Count(); ++i) { - colorTexels[i].m_fDistanceToTri = FLT_MAX; - } - - mstudiomesh_t* pMesh = _pStudioModel->pMesh(_meshID); - OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(_meshID); - const mstudio_meshvertexdata_t *vertData = pMesh->GetVertexData((void *)_pStudioHdr); - Assert(vertData); // This can only return NULL on X360 for now - - for (int nGroup = 0; nGroup < pVtxMesh->numStripGroups; ++nGroup) + area = WindingArea( w ); + if ( area <= 0 ) { - OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(nGroup); - - int nStrip; - for (nStrip = 0; nStrip < pStripGroup->numStrips; nStrip++) - { - OptimizedModel::StripHeader_t *pStrip = pStripGroup->pStrip(nStrip); - - // If this hits, re-factor the code to iterate over triangles, and build the triangles - // from the underlying structures. - Assert((pStrip->flags & OptimizedModel::STRIP_IS_TRISTRIP) == 0); - - if (pStrip->flags & OptimizedModel::STRIP_IS_TRILIST) - { - for (int i = 0; i < pStrip->numIndices; i += 3) - { - int idx = pStrip->indexOffset + i; - - unsigned short i1 = *pStripGroup->pIndex(idx); - unsigned short i2 = *pStripGroup->pIndex(idx + 1); - unsigned short i3 = *pStripGroup->pIndex(idx + 2); - - int vertex1 = pStripGroup->pVertex(i1)->origMeshVertID; - int vertex2 = pStripGroup->pVertex(i2)->origMeshVertID; - int vertex3 = pStripGroup->pVertex(i3)->origMeshVertID; - - Vector modelPos[3] = { - *vertData->Position(vertex1), - *vertData->Position(vertex2), - *vertData->Position(vertex3) - }; - - Vector modelNormal[3] = { - *vertData->Normal(vertex1), - *vertData->Normal(vertex2), - *vertData->Normal(vertex3) - }; - - Vector worldPos[3]; - Vector worldNormal[3]; + num_degenerate_faces++; + return; + } - VectorTransform(modelPos[0], _matPos, worldPos[0]); - VectorTransform(modelPos[1], _matPos, worldPos[1]); - VectorTransform(modelPos[2], _matPos, worldPos[2]); + totalarea += area; - VectorTransform(modelNormal[0], _matNormal, worldNormal[0]); - VectorTransform(modelNormal[1], _matNormal, worldNormal[1]); - VectorTransform(modelNormal[2], _matNormal, worldNormal[2]); + // get a patch + int ndxPatch = g_Patches.AddToTail(); + patch = &g_Patches[ ndxPatch ]; + memset( patch, 0, sizeof( CPatch ) ); + patch->ndxNext = g_Patches.InvalidIndex(); + patch->ndxNextParent = g_Patches.InvalidIndex(); + patch->ndxNextClusterChild = g_Patches.InvalidIndex(); + patch->child1 = g_Patches.InvalidIndex(); + patch->child2 = g_Patches.InvalidIndex(); + patch->parent = g_Patches.InvalidIndex(); + patch->needsBumpmap = false; + patch->staticPropIdx = nStaticPropIdx; - Vector2D texcoord[3] = { - *vertData->Texcoord(vertex1), - *vertData->Texcoord(vertex2), - *vertData->Texcoord(vertex3) - }; + patch->scale[ 0 ] = patch->scale[ 1 ] = 1.0f; + patch->area = area; + patch->sky = false; - Rasterizer rasterizer(texcoord[0], texcoord[1], texcoord[2], - _lightmapResX, _lightmapResY); + // chop scaled up lightmaps coarser + patch->luxscale = 16.0f; + patch->chop = maxchop; - for (auto it = rasterizer.begin(); it != rasterizer.end(); ++it) - { - size_t linearPos = rasterizer.GetLinearPos(it); - Assert(linearPos < cTotalPixelCount); + patch->winding = w; - if ( colorTexels[linearPos].m_bValid ) - { - continue; - } + patch->plane = new dplane_t; - float ourDistancetoTri = ComputeBarycentricDistanceToTri( it->barycentric, texcoord ); + Vector vecNormal; + CrossProduct( w->p[ 2 ] - w->p[ 0 ], w->p[ 1 ] - w->p[ 0 ], vecNormal ); + VectorNormalize( vecNormal ); + VectorCopy( vecNormal, patch->plane->normal ); - bool doWrite = it->insideTriangle - || !colorTexels[linearPos].m_bPossiblyInteresting - || colorTexels[linearPos].m_fDistanceToTri > ourDistancetoTri; + patch->plane->dist = vecNormal.Dot( w->p[ 0 ] ); + patch->plane->type = PlaneTypeForNormal( patch->plane->normal ); + patch->planeDist = patch->plane->dist; - if (doWrite) - { - Vector itWorldPos = worldPos[0] * it->barycentric.x - + worldPos[1] * it->barycentric.y - + worldPos[2] * it->barycentric.z; - - Vector itWorldNormal = worldNormal[0] * it->barycentric.x - + worldNormal[1] * it->barycentric.y - + worldNormal[2] * it->barycentric.z; - itWorldNormal.NormalizeInPlace(); - - colorTexels[linearPos].m_WorldPosition = itWorldPos; - colorTexels[linearPos].m_WorldNormal = itWorldNormal; - colorTexels[linearPos].m_bValid = it->insideTriangle; - colorTexels[linearPos].m_bPossiblyInteresting = true; - colorTexels[linearPos].m_fDistanceToTri = ourDistancetoTri; - } - } - } - } - } - } + patch->faceNumber = -1; // This is a bit hacky and is used to identify static prop patches in other parts of the code + WindingCenter( w, patch->origin ); - // Process neighbors to the valid region. Walk through the existing array, look for samples that - // are not valid but are adjacent to valid samples. Works if we are only bilinearly sampling - // on the other side. - // First attempt: Just pretend the triangle was larger and cast a ray from this new world pos - // as above. - int linearPos = 0; - for ( int j = 0; j < _lightmapResY; ++j ) - { - for (int i = 0; i < _lightmapResX; ++i ) - { - bool shouldProcess = colorTexels[linearPos].m_bValid; - // Are any of the eight neighbors valid?? - if ( colorTexels[linearPos].m_bPossiblyInteresting ) - { - // Look at our neighborhood (3x3 centerd on us). - shouldProcess = shouldProcess - || colorTexels[ComputeLinearPos( i - 1, j - 1, _lightmapResX, _lightmapResY )].m_bValid // TL - || colorTexels[ComputeLinearPos( i , j - 1, _lightmapResX, _lightmapResY )].m_bValid // T - || colorTexels[ComputeLinearPos( i + 1, j - 1, _lightmapResX, _lightmapResY )].m_bValid // TR - - || colorTexels[ComputeLinearPos( i - 1, j , _lightmapResX, _lightmapResY )].m_bValid // L - || colorTexels[ComputeLinearPos( i + 1, j , _lightmapResX, _lightmapResY )].m_bValid // R - - || colorTexels[ComputeLinearPos( i - 1, j + 1, _lightmapResX, _lightmapResY )].m_bValid // BL - || colorTexels[ComputeLinearPos( i , j + 1, _lightmapResX, _lightmapResY )].m_bValid // B - || colorTexels[ComputeLinearPos( i + 1, j + 1, _lightmapResX, _lightmapResY )].m_bValid; // BR - } + VectorCopy( patch->plane->normal, patch->normal ); - if (shouldProcess) - { - Vector directColor(0, 0, 0), - indirectColor(0, 0, 0); + WindingBounds( w, patch->face_mins, patch->face_maxs ); + VectorCopy( patch->face_mins, patch->mins ); + VectorCopy( patch->face_maxs, patch->maxs ); - - ComputeDirectLightingAtPoint( colorTexels[linearPos].m_WorldPosition, colorTexels[linearPos].m_WorldNormal, directColor, _iThread, _skipProp, _flags); - - if (numbounce >= 1) { - ComputeIndirectLightingAtPoint( colorTexels[linearPos].m_WorldPosition, colorTexels[linearPos].m_WorldNormal, indirectColor, _iThread, true, (_flags & GATHERLFLAGS_IGNORE_NORMALS) != 0 ); - } - - VectorAdd(directColor, indirectColor, colorTexels[linearPos].m_Color); - } - - ++linearPos; - } - } + patch->baselight.Init( 0.0f, 0.0f, 0.0f ); + patch->basearea = 1; + patch->reflectivity = vRefl; } -// ------------------------------------------------------------------------------------------------ -static int GetTexelCount(unsigned int _resX, unsigned int _resY, bool _mipmaps) -{ - // Because they are unsigned, this is a != check--but if we were to change to ints, this would be - // the right assert (and it's no worse than != now). - Assert(_resX > 0 && _resY > 0); - if (_mipmaps == false) - return _resX * _resY; - int retVal = 0; - while (_resX > 1 || _resY > 1) +void CVradStaticPropMgr::MakePatches() +{ + int count = m_StaticProps.Count(); + if ( !count ) { - retVal += _resX * _resY; - _resX = MAX(1, _resX >> 1); - _resY = MAX(1, _resY >> 1); + // nothing to do + return; } - // Add in the 1x1 mipmap level, which wasn't hit above. This could be done in the initializer of - // retVal, but it's more obvious here. - retVal += 1; - - return retVal; -} - -// ------------------------------------------------------------------------------------------------ -static void FilterFineMipmap(unsigned int _resX, unsigned int _resY, const CUtlVector& _srcTexels, CUtlVector* _outLinear) -{ - Assert(_outLinear); - // We can't filter in place, so go ahead and create a linear buffer here. - CUtlVector filterSrc; - filterSrc.EnsureCount(_srcTexels.Count()); + // Triangle coverage of 1 (full coverage) + Vector fullCoverage; + fullCoverage.x = 1.0f; + int nPatchCount = 0; - for (int i = 0; i < _srcTexels.Count(); ++i) + //IScratchPad3D *pPad = ScratchPad3D_Create(); + //pPad->SetAutoFlush( false ); + for ( int nProp = 0; nProp < count; ++nProp ) { - ColorRGBExp32 rgbColor; - VectorToColorRGBExp32(_srcTexels[i].m_Color, rgbColor); - ConvertRGBExp32ToLinear( &rgbColor, &(filterSrc[i]) ); - } + CStaticProp &prop = m_StaticProps[ nProp ]; + StaticPropDict_t &dict = m_StaticPropDict[ prop.m_ModelIdx ]; - const int cRadius = 1; - const float cOneOverDiameter = 1.0f / pow(2.0f * cRadius + 1.0f, 2.0f) ; - // Filter here. - for (int j = 0; j < _resY; ++j) - { - for (int i = 0; i < _resX; ++i) + if ( dict.m_pModel ) { - Vector value(0, 0, 0); - int thisIndex = ComputeLinearPos(i, j, _resX, _resY); - - if (!_srcTexels[thisIndex].m_bValid) - { - (*_outLinear)[thisIndex] = filterSrc[thisIndex]; - continue; - } - - // TODO: Check ASM for this, unroll by hand if needed. - for ( int offsetJ = -cRadius; offsetJ <= cRadius; ++offsetJ ) + // Get material, get reflectivity + VMatrix xform; + xform.SetupMatrixOrgAngles( prop.m_Origin, prop.m_Angles ); + ICollisionQuery *queryModel = s_pPhysCollision->CreateQueryModel( dict.m_pModel ); + for ( int nConvex = 0; nConvex < queryModel->ConvexCount(); ++nConvex ) { - for ( int offsetI = -cRadius; offsetI <= cRadius; ++offsetI ) + for ( int nTri = 0; nTri < queryModel->TriangleCount( nConvex ); ++nTri ) { - int finalIndex = ComputeLinearPos( i + offsetI, j + offsetJ, _resX, _resY ); - if ( !_srcTexels[finalIndex].m_bValid ) + Vector verts[ 3 ]; + queryModel->GetTriangleVerts( nConvex, nTri, verts ); + for ( int nVert = 0; nVert < 3; ++nVert ) + verts[ nVert ] = xform.VMul4x3( verts[ nVert ] ); + + //pPad->DrawPolygon( CSPVertList( verts, 3, CSPColor( prop.m_vReflectivity ) ) ); + //pPad->DrawLine( CSPVert( g_Patches.Tail().origin ), CSPVert( g_Patches.Tail().origin + 5.0f * g_Patches.Tail().normal) ); + + winding_t *w = AllocWinding( 3 ); + for ( int i = 0; i < 3; i++ ) { - finalIndex = thisIndex; + w->p[ i ] = verts[ i ]; } - - value += filterSrc[finalIndex]; + w->numpoints = 3; + MakePatchForTriangle( w, prop.m_vReflectivity, nProp ); + //pPad->DrawPolygon( CSPVertList( verts, 3 ) ); + //pPad->DrawLine( CSPVert( g_Patches.Tail().origin ), CSPVert( g_Patches.Tail().origin + 5.0f * g_Patches.Tail().normal) ); + g_RtEnv_RadiosityPatches.AddTriangle( TRACE_ID_PATCH | (g_Patches.Count() - 1), verts[ 0 ], verts[ 1 ], verts[ 2 ], Vector( 1.0f, 1.0f, 1.0f ) ); + nPatchCount++; } } - - (*_outLinear)[thisIndex] = value * cOneOverDiameter; - } - } -} - -// ------------------------------------------------------------------------------------------------ -static void BuildFineMipmap(unsigned int _resX, unsigned int _resY, bool _applyFilter, const CUtlVector& _srcTexels, CUtlVector* _outTexelsRGB888, CUtlVector* _outLinear) -{ - // At least one of these needs to be non-null, otherwise what are we doing here? - Assert(_outTexelsRGB888 || _outLinear); - Assert(!_applyFilter || _outLinear); - Assert(_srcTexels.Count() == GetTexelCount(_resX, _resY, false)); - - int texelCount = GetTexelCount(_resX, _resY, true); - - if (_outTexelsRGB888) - (*_outTexelsRGB888).EnsureCount(texelCount); - - if (_outLinear) - (*_outLinear).EnsureCount(GetTexelCount(_resX, _resY, false)); - - // This code can take awhile, so minimize the branchiness of the inner-loop. - if (_applyFilter) - { - - FilterFineMipmap(_resX, _resY, _srcTexels, _outLinear); - - if ( _outTexelsRGB888 ) - { - for (int i = 0; i < _srcTexels.Count(); ++i) - { - RGBA8888_t encodedColor; - - Vector linearColor = (*_outLinear)[i]; - - ConvertLinearToRGBA8888( &linearColor, (unsigned char*)&encodedColor ); - (*_outTexelsRGB888)[i].r = encodedColor.r; - (*_outTexelsRGB888)[i].g = encodedColor.g; - (*_outTexelsRGB888)[i].b = encodedColor.b; - } + s_pPhysCollision->DestroyQueryModel( queryModel ); } - } - else - { - for (int i = 0; i < _srcTexels.Count(); ++i) - { - ColorRGBExp32 rgbColor; - RGBA8888_t encodedColor; - VectorToColorRGBExp32(_srcTexels[i].m_Color, rgbColor); - ConvertRGBExp32ToRGBA8888(&rgbColor, (unsigned char*)&encodedColor, (_outLinear ? (&(*_outLinear)[i]) : NULL) ); - // We drop alpha on the floor here, if this were to fire we'd need to consider using a different compressed format. - Assert(encodedColor.a == 0xFF); - - if (_outTexelsRGB888) - { - (*_outTexelsRGB888)[i].r = encodedColor.r; - (*_outTexelsRGB888)[i].g = encodedColor.g; - (*_outTexelsRGB888)[i].b = encodedColor.b; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -static void FilterCoarserMipmaps(unsigned int _resX, unsigned int _resY, CUtlVector* _scratchLinear, CUtlVector *_outTexelsRGB888) -{ - Assert(_outTexelsRGB888); - - int srcResX = _resX; - int srcResY = _resY; - int dstResX = MAX(1, (srcResX >> 1)); - int dstResY = MAX(1, (srcResY >> 1)); - int dstOffset = GetTexelCount(srcResX, srcResY, false); - - // Build mipmaps here, after being converted to linear space. - // TODO: Should do better filtering for downsampling. But this will work for now. - while (srcResX > 1 || srcResY > 1) - { - for (int j = 0; j < srcResY; j += 2) { - for (int i = 0; i < srcResX; i += 2) { - int srcCol0 = i; - int srcCol1 = i + 1 > srcResX - 1 ? srcResX - 1 : i + 1; - int srcRow0 = j; - int srcRow1 = j + 1 > srcResY - 1 ? srcResY - 1 : j + 1;; - - int dstCol = i >> 1; - int dstRow = j >> 1; - - - const Vector& tl = (*_scratchLinear)[srcCol0 + (srcRow0 * srcResX)]; - const Vector& tr = (*_scratchLinear)[srcCol1 + (srcRow0 * srcResX)]; - const Vector& bl = (*_scratchLinear)[srcCol0 + (srcRow1 * srcResX)]; - const Vector& br = (*_scratchLinear)[srcCol1 + (srcRow1 * srcResX)]; - - Vector sample = (tl + tr + bl + br) / 4.0f; - - ConvertLinearToRGBA8888(&sample, (unsigned char*)&(*_outTexelsRGB888)[dstOffset + dstCol + dstRow * dstResX]); - - // Also overwrite the srcBuffer to filter the next loop. This is safe because we won't be reading this source value - // again during this mipmap level. - (*_scratchLinear)[dstCol + dstRow * dstResX] = sample; - } - } - - srcResX = dstResX; - srcResY = dstResY; - dstResX = MAX(1, (srcResX >> 1)); - dstResY = MAX(1, (srcResY >> 1)); - dstOffset += GetTexelCount(srcResX, srcResY, false); - } -} - -// ------------------------------------------------------------------------------------------------ -static void ConvertToDestinationFormat(unsigned int _resX, unsigned int _resY, ImageFormat _destFmt, const CUtlVector& _scratchRBG888, CUtlMemory* _outTexture) -{ - const ImageFormat cSrcImageFormat = IMAGE_FORMAT_RGB888; - - // Converts from the scratch RGB888 buffer, which should be fully filled out to the output texture. - int destMemoryUsage = ImageLoader::GetMemRequired(_resX, _resY, 1, _destFmt, true); - (*_outTexture).EnsureCapacity(destMemoryUsage); - - int srcResX = _resX; - int srcResY = _resY; - int srcOffset = 0; - int dstOffset = 0; - - // The usual case--that they'll be different. - if (cSrcImageFormat != _destFmt) - { - while (srcResX > 1 || srcResY > 1) + else { - // Convert this mipmap level. - ImageLoader::ConvertImageFormat((unsigned char*)(&_scratchRBG888[srcOffset]), cSrcImageFormat, (*_outTexture).Base() + dstOffset, _destFmt, srcResX, srcResY); - - // Then update offsets for the next mipmap level. - srcOffset += GetTexelCount(srcResX, srcResY, false); - dstOffset += ImageLoader::GetMemRequired(srcResX, srcResY, 1, _destFmt, false); - - srcResX = MAX(1, (srcResX >> 1)); - srcResY = MAX(1, (srcResY >> 1)); + // FIXME +#if 0 + VectorAdd( dict.m_Mins, prop.m_Origin, prop.m_mins ); + VectorAdd( dict.m_Maxs, prop.m_Origin, prop.m_maxs ); + g_RtEnv.AddAxisAlignedRectangularSolid( TRACE_ID_STATICPROP | nProp, prop.m_mins, prop.m_maxs, fullCoverage ); +#endif } - - // Do the 1x1 level also. - ImageLoader::ConvertImageFormat((unsigned char*)_scratchRBG888.Base() + srcOffset, cSrcImageFormat, (*_outTexture).Base() + dstOffset, _destFmt, srcResX, srcResY); - } else { - // But sometimes (particularly for debugging) they will be the same. - Q_memcpy( (*_outTexture).Base(), _scratchRBG888.Base(), destMemoryUsage ); - } -} - -// ------------------------------------------------------------------------------------------------ -static void ConvertTexelDataToTexture(unsigned int _resX, unsigned int _resY, ImageFormat _destFmt, const CUtlVector& _srcTexels, CUtlMemory* _outTexture) -{ - Assert(_outTexture); - Assert(_srcTexels.Count() == _resX * _resY); - - CUtlVector scratchRGB888; - CUtlVector scratchLinear; - - BuildFineMipmap(_resX, _resY, true, _srcTexels, &scratchRGB888, &scratchLinear); - FilterCoarserMipmaps(_resX, _resY, &scratchLinear, &scratchRGB888 ); - ConvertToDestinationFormat(_resX, _resY, _destFmt, scratchRGB888, _outTexture); -} - -// ------------------------------------------------------------------------------------------------ -static void DumpLightmapLinear( const char* _dstFilename, const CUtlVector& _srcTexels, int _width, int _height ) -{ - CUtlVector< Vector > linearFloats; - CUtlVector< BGR888_t > linearBuffer; - BuildFineMipmap( _width, _height, true, _srcTexels, NULL, &linearFloats ); - linearBuffer.SetCount( linearFloats.Count() ); - - for ( int i = 0; i < linearFloats.Count(); ++i ) { - linearBuffer[i].b = RoundFloatToByte(linearFloats[i].z * 255.0f); - linearBuffer[i].g = RoundFloatToByte(linearFloats[i].y * 255.0f); - linearBuffer[i].r = RoundFloatToByte(linearFloats[i].x * 255.0f); } - - TGAWriter::WriteTGAFile( _dstFilename, _width, _height, IMAGE_FORMAT_BGR888, (uint8*)(linearBuffer.Base()), _width * ImageLoader::SizeInBytes(IMAGE_FORMAT_BGR888) ); + //pPad->Release(); + g_RtEnv_RadiosityPatches.SetupAccelerationStructure(); + qprintf( "%i static prop patches\n", nPatchCount ); } diff --git a/wscript b/wscript index a1d448e68..261c68d5f 100644 --- a/wscript +++ b/wscript @@ -455,7 +455,6 @@ def configure(conf): conf.load('mm_hook') define_platform(conf) - conf.env.targets = list(set(conf.env.targets)) conf.env.REL_VERSION = VERSION conf.env.BIT32_MANDATORY = not conf.options.ALLOW64 @@ -610,7 +609,8 @@ def configure(conf): conf.env.CC.insert(0, 'ccache') conf.env.CXX.insert(0, 'ccache') - conf.add_subproject(conf.env.targets) + for v in set(conf.env.targets): + conf.add_subproject(v) def build(bld): if not os.environ.get('CCACHE_DIR'): From 974cf6d8427b7a568b9f0ada6db6e0bb2014dbc0 Mon Sep 17 00:00:00 2001 From: Er2 Date: Sat, 13 May 2023 21:22:15 +0300 Subject: [PATCH 08/11] fix togl when no gl lol --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 261c68d5f..bb2fdf025 100644 --- a/wscript +++ b/wscript @@ -193,7 +193,7 @@ def define_platform(conf): 'GL_GLEXT_PROTOTYPES', 'BINK_VIDEO' ]) - conf.env.targets += ['togles' if conf.env.TOGLES else 'togl'] + conf.env.targets += ['togles' if conf.env.TOGLES else 'togl'] if conf.options.SDL: conf.env.SDL = True From 5a22429e76ccc31b13e81da3d3b8fda04c9c6cce Mon Sep 17 00:00:00 2001 From: Er2 Date: Sun, 14 May 2023 11:49:14 +0300 Subject: [PATCH 09/11] remade ci --- .github/workflows/build.yml | 196 ++++++++++++++++---------------- .github/workflows/tests.yml | 114 ++++++++++++------- scripts/build-android-armv7a.sh | 9 -- scripts/build-macos-amd64.sh | 8 -- scripts/build-ubuntu-amd64.sh | 8 -- scripts/build-ubuntu-i386.sh | 10 -- scripts/tests-macos-amd64.sh | 7 -- scripts/tests-ubuntu-amd64.sh | 10 -- scripts/tests-ubuntu-i386.sh | 11 -- 9 files changed, 168 insertions(+), 205 deletions(-) delete mode 100755 scripts/build-android-armv7a.sh delete mode 100755 scripts/build-macos-amd64.sh delete mode 100755 scripts/build-ubuntu-amd64.sh delete mode 100755 scripts/build-ubuntu-i386.sh delete mode 100755 scripts/tests-macos-amd64.sh delete mode 100755 scripts/tests-ubuntu-amd64.sh delete mode 100755 scripts/tests-ubuntu-i386.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 660986132..e4edb2b4f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,111 +1,109 @@ name: Build on: [push, pull_request] +env: + WAF_FLAGS: -T debug --no-warns --prefix=build_hl2 jobs: - build-linux-i386: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Build linux-i386 - run: | - scripts/build-ubuntu-i386.sh -u - - build-linux-amd64: - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - - name: Build linux-amd64 - run: | - scripts/build-ubuntu-amd64.sh -u - - build-android-armv7a: - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - - name: Build android-armv7a - run: | - scripts/build-android-armv7a.sh - - build-windows-i386: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v2 - - name: Build windows-i386 - run: | - git submodule init && git submodule update - ./waf.bat configure -T debug -u - ./waf.bat build - - build-windows-amd64: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v2 - - name: Build windows-amd64 - run: | - git submodule init && git submodule update - ./waf.bat configure -T debug -8 -u - ./waf.bat build - - build-dedicated-windows-i386: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v2 - - name: Build dedicated windows-i386 - run: | - git submodule init && git submodule update - ./waf.bat configure -T debug -dl - ./waf.bat build - - build-dedicated-windows-amd64: - runs-on: windows-2019 - - steps: - - uses: actions/checkout@v2 - - name: Build dedicated windows-amd64 - run: | - git submodule init && git submodule update - ./waf.bat configure -T debug -dl -8 - ./waf.bat build - - build-dedicated-linux-i386: - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - - name: Build dedicated linux-i386 - run: | - scripts/build-ubuntu-i386.sh -dl - - build-dedicated-linux-amd64: - runs-on: ubuntu-20.04 - + build-linux: + strategy: + matrix: + os: [ubuntu-latest] + bits: ['', '--64bits'] + android: [''] + dedicated: ['', '-dl'] + include: + - os: ubuntu-20.04 + bits: '' + android: '--android=armeabi-v7a-hard,4.9,21 --use-togles' + dedicated: '' + runs-on: ${{ matrix.os }} + env: + DEPS: libopenal-dev libpng-dev libjpeg-dev libfreetype6-dev libfontconfig1-dev libcurl4-gnutls-dev libsdl2-dev zlib1g-dev libbz2-dev libedit-dev steps: - - uses: actions/checkout@v2 - - name: Build dedicated linux-amd64 - run: | - scripts/build-ubuntu-amd64.sh -dl + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install common dependencies + run: sudo apt-get update && sudo apt-get install -y g++-multilib gcc-multilib + - name: Install 32bit dependencies + if: ${{ matrix.bits == '' && !matrix.android }} + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y aptitude + sudo aptitude install -y $(echo $DEPS | sed -r 's/[a-z0-9_\-]+/&:i386/g') + - name: Install Android dependencies + if: ${{ matrix.android != '' }} + run: | + wget https://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip -o /dev/null + unzip android-ndk-r10e-linux-x86_64.zip + export NDK_HOME=$PWD/android-ndk-r10e/ + echo "NDK_HOME=$NDK_HOME" >> $GITHUB_ENV + echo "ANDROID_NDK_HOME=$NDK_HOME" >> $GITHUB_ENV + - name: Install 64bit dependencies + if: ${{ matrix.bits != '' }} + run: | + sudo apt-get install -y $DEPS + + - if: ${{ matrix.bits == '' && !matrix.android }} + name: Set PKG_CONFIG_PATH + run: echo "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig" >> $GITHUB_ENV + + - name: Configure + run: ./waf configure ${{ matrix.bits }} ${{ matrix.android }} ${{ matrix.dedicated }} $WAF_FLAGS + - name: Build ${{ matrix.os }} + run: ./waf install + - name: Tar binaries + run: tar cvf build.tar build_hl2 + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: Linux${{matrix.bits}}${{matrix.dedicated}}${{matrix.android}}.tar + path: build.tar + + build-macos: + strategy: + matrix: + dedicated: ['', '-dl'] - build-macos-amd64: runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: Build macos-amd64 - run: | - scripts/build-macos-amd64.sh -u + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install dependencies + run: brew install sdl2 + + - name: Configure + run: ./waf configure --64bits ${{ matrix.dedicated }} $WAF_FLAGS + - name: Build macos-amd64 + run: ./waf install + - name: Tar binaries + run: tar cvf build.tar build_hl2 + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: macOS--64bits${{matrix.dedicated}}.tar + path: build.tar + + build-windows: + strategy: + matrix: + os: [windows-2019] + bits: ['', '--64bits'] + dedicated: ['', '-dl'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive - build-dedicated-macos-amd64: - runs-on: macos-latest + - name: Configure + run: ./waf configure ${{ matrix.bits }} ${{ matrix.dedicated }} ${{ env.WAF_FLAGS }} + - name: Build ${{ matrix.os }} + run: ./waf install - steps: - - uses: actions/checkout@v2 - - name: Build dedicated macos-amd64 - run: | - scripts/build-macos-amd64.sh -dl diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9578d1cc7..2cb1080cc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,59 +1,87 @@ name: Tests on: [push, pull_request] +env: + WAF_FLAGS: -T release --no-warns --prefix=build_tests -lt --sanitize=address,undefined jobs: - tests-linux-i386: - runs-on: ubuntu-20.04 - + tests-linux: + strategy: + matrix: + os: [ubuntu-latest, ubuntu-20.04] + bits: ['', '--64bits'] + android: [''] + runs-on: ${{ matrix.os }} + env: + DEPS: libbz2-dev steps: - - uses: actions/checkout@v2 - - name: Run tests linux-i386 - run: | - scripts/tests-ubuntu-i386.sh + - uses: actions/checkout@v3 + with: + submodules: recursive - tests-linux-amd64: - runs-on: ubuntu-20.04 + - name: Install common dependencies + run: sudo apt-get update && sudo apt-get install -y g++-multilib gcc-multilib + - name: Install 32bit dependencies + if: ${{ matrix.bits == '' && !matrix.android }} + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install aptitude + sudo aptitude install -y $(echo $DEPS | sed -r 's/[a-z0-9_\-]+/&:i386/g') + - name: Install 64bit dependencies + if: ${{ matrix.bits != '' }} + run: | + sudo apt-get install -y $DEPS - steps: - - uses: actions/checkout@v2 - - name: Run tests linux-amd64 - run: | - scripts/tests-ubuntu-amd64.sh + - if: ${{ matrix.bits == '' && !matrix.android }} + name: Set PKG_CONFIG_PATH + run: echo "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig" >> $GITHUB_ENV + + - name: Configure + run: ./waf configure ${{ matrix.bits }} $WAF_FLAGS + - name: Build ${{ matrix.os }} + run: ./waf install + - name: Run tests + run: | + cd build_tests + LD_LIBRARY_PATH=bin/ ./unittest - tests-macos-amd64: + tests-macos: runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: Run tests macos-amd64 - run: | - scripts/tests-macos-amd64.sh + - uses: actions/checkout@v3 + with: + submodules: recursive - tests-windows-i386: - runs-on: windows-2019 + - name: Configure + run: ./waf configure --64bits $WAF_FLAGS + - name: Build macos-amd64 + run: ./waf install + - name: Run tests + run: | + cd build_tests + DYLD_LIBRARY_PATH=bin/ ./unittest + tests-windows: + strategy: + matrix: + os: [windows-2019] + bits: ['', '--64bits'] + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - name: Run tests windows-i386 - run: | - git submodule init && git submodule update - ./waf.bat configure -T release -lt --prefix=out/ - ./waf.bat install - cd out - $env:Path = "bin"; - ./unittest.exe - - tests-windows-amd64: - runs-on: windows-2019 + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Configure + run: ./waf configure ${{ matrix.bits }} ${{ env.WAF_FLAGS }} + + - name: Build ${{ matrix.os }} + run: ./waf install + - name: Run tests + run: | + cd build_tests + $env:Path = "bin"; + ./unittest.exe - steps: - - uses: actions/checkout@v2 - - name: Run tests windows-amd64 - run: | - git submodule init && git submodule update - ./waf.bat configure -T release -lt --prefix=out/ -8 - ./waf.bat install - cd out - $env:Path = "bin"; - ./unittest.exe diff --git a/scripts/build-android-armv7a.sh b/scripts/build-android-armv7a.sh deleted file mode 100755 index f3e16947d..000000000 --- a/scripts/build-android-armv7a.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -git submodule init && git submodule update -wget https://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip -o /dev/null -unzip android-ndk-r10e-linux-x86_64.zip -export ANDROID_NDK_HOME=$PWD/android-ndk-r10e/ -export NDK_HOME=$PWD/android-ndk-r10e/ -./waf configure -T debug --android=armeabi-v7a-hard,4.9,21 --use-togles --no-warns && -./waf build diff --git a/scripts/build-macos-amd64.sh b/scripts/build-macos-amd64.sh deleted file mode 100755 index 919c66df7..000000000 --- a/scripts/build-macos-amd64.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -git submodule init && git submodule update - -brew install sdl2 - -./waf configure -T debug --64bits --no-warns $* && -./waf build diff --git a/scripts/build-ubuntu-amd64.sh b/scripts/build-ubuntu-amd64.sh deleted file mode 100755 index ac06c47ae..000000000 --- a/scripts/build-ubuntu-amd64.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -git submodule init && git submodule update -sudo apt-get update -sudo apt-get install -f -y libopenal-dev g++-multilib gcc-multilib libpng-dev libjpeg-dev libfreetype6-dev libfontconfig1-dev libcurl4-gnutls-dev libsdl2-dev zlib1g-dev libbz2-dev libedit-dev - -./waf configure -T debug --64bits --no-warns $* && -./waf build diff --git a/scripts/build-ubuntu-i386.sh b/scripts/build-ubuntu-i386.sh deleted file mode 100755 index 10115469e..000000000 --- a/scripts/build-ubuntu-i386.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -git submodule init && git submodule update -sudo dpkg --add-architecture i386 -sudo apt-get update -sudo apt-get install -y aptitude -sudo aptitude install -y libopenal-dev:i386 g++-multilib gcc-multilib libpng-dev:i386 libjpeg-dev:i386 libfreetype6-dev:i386 libfontconfig1-dev:i386 libcurl4-gnutls-dev:i386 libsdl2-dev:i386 zlib1g-dev:i386 libbz2-dev:i386 libedit-dev:i386 - -PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T debug --no-warns $* && -./waf build diff --git a/scripts/tests-macos-amd64.sh b/scripts/tests-macos-amd64.sh deleted file mode 100755 index ee1d0cfa3..000000000 --- a/scripts/tests-macos-amd64.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -git submodule init && git submodule update -./waf configure -T release --sanitize=address,undefined --no-warns -lt -8 --prefix=out/ $* && -./waf install && -cd out && -DYLD_LIBRARY_PATH=bin/ ./unittest || exit 1 diff --git a/scripts/tests-ubuntu-amd64.sh b/scripts/tests-ubuntu-amd64.sh deleted file mode 100755 index 6b1aad9e1..000000000 --- a/scripts/tests-ubuntu-amd64.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -git submodule init && git submodule update -sudo apt-get update -sudo apt-get install -y libbz2-dev - -./waf configure -T release --sanitize=address,undefined --no-warns -lt --prefix=out/ --64bits $* && -./waf install && -cd out && -LD_LIBRARY_PATH=bin/ ./unittest diff --git a/scripts/tests-ubuntu-i386.sh b/scripts/tests-ubuntu-i386.sh deleted file mode 100755 index 178ed67d5..000000000 --- a/scripts/tests-ubuntu-i386.sh +++ /dev/null @@ -1,11 +0,0 @@ -install#!/bin/sh - -git submodule init && git submodule update -sudo dpkg --add-architecture i386 -sudo apt-get update -sudo apt-get install -y g++-multilib gcc-multilib libbz2-dev:i386 - -PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T release --sanitize=address,undefined --no-warns -lt --prefix=out/ $* && -./waf install && -cd out && -LD_LIBRARY_PATH=bin/ ./unittest From 6d8b1917d28c6f0c0d7fabbe0afb85fcd94e8da4 Mon Sep 17 00:00:00 2001 From: Er2 Date: Sun, 14 May 2023 14:45:33 +0300 Subject: [PATCH 10/11] enable utils --- .github/workflows/build.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e4edb2b4f..c8703320c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,16 +7,17 @@ env: jobs: build-linux: strategy: + fail-fast: false matrix: os: [ubuntu-latest] bits: ['', '--64bits'] android: [''] - dedicated: ['', '-dl'] + flags: ['', '-dl', '-u'] include: - os: ubuntu-20.04 bits: '' android: '--android=armeabi-v7a-hard,4.9,21 --use-togles' - dedicated: '' + flags: '' runs-on: ${{ matrix.os }} env: DEPS: libopenal-dev libpng-dev libjpeg-dev libfreetype6-dev libfontconfig1-dev libcurl4-gnutls-dev libsdl2-dev zlib1g-dev libbz2-dev libedit-dev @@ -52,7 +53,7 @@ jobs: run: echo "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig" >> $GITHUB_ENV - name: Configure - run: ./waf configure ${{ matrix.bits }} ${{ matrix.android }} ${{ matrix.dedicated }} $WAF_FLAGS + run: ./waf configure ${{ matrix.bits }} ${{ matrix.android }} ${{ matrix.flags }} $WAF_FLAGS - name: Build ${{ matrix.os }} run: ./waf install - name: Tar binaries @@ -60,13 +61,13 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: Linux${{matrix.bits}}${{matrix.dedicated}}${{matrix.android}}.tar + name: Linux${{matrix.bits}}${{matrix.flags}}${{matrix.android}}.tar path: build.tar build-macos: strategy: matrix: - dedicated: ['', '-dl'] + flags: ['', '-dl', '-u'] runs-on: macos-latest @@ -79,7 +80,7 @@ jobs: run: brew install sdl2 - name: Configure - run: ./waf configure --64bits ${{ matrix.dedicated }} $WAF_FLAGS + run: ./waf configure --64bits ${{ matrix.flags }} $WAF_FLAGS - name: Build macos-amd64 run: ./waf install - name: Tar binaries @@ -87,7 +88,7 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: macOS--64bits${{matrix.dedicated}}.tar + name: macOS--64bits${{matrix.flags}}.tar path: build.tar build-windows: @@ -95,7 +96,7 @@ jobs: matrix: os: [windows-2019] bits: ['', '--64bits'] - dedicated: ['', '-dl'] + flags: ['', '-dl', '-u'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -103,7 +104,7 @@ jobs: submodules: recursive - name: Configure - run: ./waf configure ${{ matrix.bits }} ${{ matrix.dedicated }} ${{ env.WAF_FLAGS }} + run: ./waf configure ${{ matrix.bits }} ${{ matrix.flags }} ${{ env.WAF_FLAGS }} - name: Build ${{ matrix.os }} run: ./waf install From 56485c5f056015f59e0930e4bf6bd777f078504c Mon Sep 17 00:00:00 2001 From: Er2 Date: Sun, 14 May 2023 16:52:26 +0300 Subject: [PATCH 11/11] some fixes --- .github/workflows/build.yml | 4 +++- appframework/glmrendererinfo_osx.mm | 2 +- serverbrowser/wscript | 2 +- tier0/wscript | 6 ++++++ utils/vrad/wscript | 3 --- wscript | 14 ++++++++------ 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8703320c..80e682dbd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build on: [push, pull_request] env: - WAF_FLAGS: -T debug --no-warns --prefix=build_hl2 + WAF_FLAGS: -T release --no-warns --prefix=build_hl2 jobs: build-linux: @@ -66,6 +66,7 @@ jobs: build-macos: strategy: + fail-fast: false matrix: flags: ['', '-dl', '-u'] @@ -93,6 +94,7 @@ jobs: build-windows: strategy: + fail-fast: false matrix: os: [windows-2019] bits: ['', '--64bits'] diff --git a/appframework/glmrendererinfo_osx.mm b/appframework/glmrendererinfo_osx.mm index a36f62494..c51648711 100644 --- a/appframework/glmrendererinfo_osx.mm +++ b/appframework/glmrendererinfo_osx.mm @@ -24,7 +24,7 @@ #include "tier1/utllinkedlist.h" #include "togl/rendermechanism.h" #include "appframework/ilaunchermgr.h" // gets pulled in from glmgr.h -#include "appframework/iappsystemgroup.h" +#include "appframework/IAppSystemGroup.h" #include "inputsystem/ButtonCode.h" diff --git a/serverbrowser/wscript b/serverbrowser/wscript index abeb62977..22e792b4c 100755 --- a/serverbrowser/wscript +++ b/serverbrowser/wscript @@ -5,7 +5,7 @@ from waflib import Utils import os top = '.' -PROJECT_NAME = 'ServerBrowser' +PROJECT_NAME = 'serverbrowser' def options(opt): # stub diff --git a/tier0/wscript b/tier0/wscript index 7604b74bb..d1301a835 100755 --- a/tier0/wscript +++ b/tier0/wscript @@ -19,6 +19,9 @@ def configure(conf): conf.define('GIT_COMMIT_HASH', conf.env.GIT_VERSION) conf.define('REL_VERSION', conf.env.REL_VERSION) + if conf.env.DEST_OS == 'freebsd': + conf.check_cc(lib='execinfo') + def build(bld): source = [ 'assert_dialog.cpp', @@ -85,6 +88,9 @@ def build(bld): else: libs = ['DL', 'M', 'LOG'] + if bld.env.DEST_OS == 'freebsd': + libs += ['EXECINFO'] + install_path = bld.env.LIBDIR bld.shlib( diff --git a/utils/vrad/wscript b/utils/vrad/wscript index 7b6779a53..e0b56780e 100755 --- a/utils/vrad/wscript +++ b/utils/vrad/wscript @@ -14,9 +14,6 @@ def options(opt): def configure(conf): conf.define('VRAD', 1) - conf.define('MAX_TOOL_THREADS', 1) - conf.define('THREADINDEX_MAIN', 0) - conf.define('NO_THREAD_NAMES', 1) return def build(bld): diff --git a/wscript b/wscript index bb2fdf025..88aea3d97 100644 --- a/wscript +++ b/wscript @@ -123,7 +123,7 @@ projects={ 'fgdlib', 'raytrace', 'vphysics', - 'movieobjects', +# 'movieobjects', # 'hammer_launcher', 'ivp/havana', 'ivp/havana/havok/hk_base', @@ -494,12 +494,14 @@ def configure(conf): flags += ['-fsanitize=%s'%conf.options.SANITIZE, '-fno-sanitize=vptr'] if conf.env.DEST_OS != 'win32': - flags += ['-pipe', '-fPIC', '-L'+os.path.abspath('.')+'/lib/'+conf.env.DEST_OS+'/'+conf.env.DEST_CPU+'/'] + flags += ['-pipe', '-fPIC'] + conf.env.RPATH = ['$ORIGIN'] if conf.env.COMPILER_CC != 'msvc': flags += ['-pthread'] if conf.env.DEST_OS == 'android': flags += [ + '-L'+os.path.abspath('.')+'/lib/android/'+conf.env.DEST_CPU+'/', '-I'+os.path.abspath('.')+'/thirdparty/curl/include', '-I'+os.path.abspath('.')+'/thirdparty/SDL', '-I'+os.path.abspath('.')+'/thirdparty/openal-soft/include/', @@ -510,7 +512,10 @@ def configure(conf): ] flags += ['-funwind-tables', '-g'] - elif conf.env.COMPILER_CC != 'msvc' and conf.env.DEST_OS != 'darwin' and conf.env.DEST_CPU in ['x86', 'x86_64']: + elif conf.env.DEST_OS == 'win32': + flags += ['-L'+os.path.abspath('.')+'/lib/win32/'+conf.env.DEST_CPU+'/'] + + if conf.env.COMPILER_CC != 'msvc' and conf.env.DEST_OS != 'darwin' and conf.env.DEST_CPU in ['x86', 'x86_64']: flags += ['-march=core2'] if conf.env.DEST_CPU in ['x86', 'x86_64']: @@ -521,9 +526,6 @@ def configure(conf): if conf.env.DEST_CPU == 'arm': flags += ['-mfpu=neon-vfpv4'] - if conf.env.DEST_OS == 'freebsd': - linkflags += ['-lexecinfo'] - if conf.env.DEST_OS != 'win32': cflags += flags linkflags += flags