aboutsummaryrefslogtreecommitdiff
path: root/mp/src/utils/common
diff options
context:
space:
mode:
authorNarendra Umate <[email protected]>2013-12-02 23:36:05 -0800
committerNarendra Umate <[email protected]>2013-12-02 23:36:05 -0800
commit8737f191f3b59f001a77bf6c08091109211c1c9f (patch)
treedbbf05c004d9b026f2c1f23f06600fe0add82c36 /mp/src/utils/common
parentUpdate .gitignore. (diff)
parentMake .xcconfigs text files too. (diff)
downloadsource-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.tar.xz
source-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.zip
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'mp/src/utils/common')
-rw-r--r--mp/src/utils/common/ISQLDBReplyTarget.h58
-rw-r--r--mp/src/utils/common/MySqlDatabase.cpp384
-rw-r--r--mp/src/utils/common/MySqlDatabase.h208
-rw-r--r--mp/src/utils/common/bsplib.cpp10128
-rw-r--r--mp/src/utils/common/bsplib.h808
-rw-r--r--mp/src/utils/common/cmdlib.cpp2014
-rw-r--r--mp/src/utils/common/cmdlib.h354
-rw-r--r--mp/src/utils/common/consolewnd.cpp666
-rw-r--r--mp/src/utils/common/consolewnd.h90
-rw-r--r--mp/src/utils/common/filesystem_tools.cpp418
-rw-r--r--mp/src/utils/common/filesystem_tools.h118
-rw-r--r--mp/src/utils/common/map_shared.cpp272
-rw-r--r--mp/src/utils/common/map_shared.h182
-rw-r--r--mp/src/utils/common/movie.h66
-rw-r--r--mp/src/utils/common/mpi_stats.cpp1676
-rw-r--r--mp/src/utils/common/mpi_stats.h118
-rw-r--r--mp/src/utils/common/mstristrip.cpp1860
-rw-r--r--mp/src/utils/common/mstristrip.h86
-rw-r--r--mp/src/utils/common/pacifier.cpp126
-rw-r--r--mp/src/utils/common/pacifier.h46
-rw-r--r--mp/src/utils/common/physdll.cpp62
-rw-r--r--mp/src/utils/common/physdll.h60
-rw-r--r--mp/src/utils/common/polylib.cpp1830
-rw-r--r--mp/src/utils/common/polylib.h156
-rw-r--r--mp/src/utils/common/qfiles.h84
-rw-r--r--mp/src/utils/common/scratchpad_helpers.cpp206
-rw-r--r--mp/src/utils/common/scratchpad_helpers.h50
-rw-r--r--mp/src/utils/common/scriplib.cpp2698
-rw-r--r--mp/src/utils/common/scriplib.h192
-rw-r--r--mp/src/utils/common/threads.cpp514
-rw-r--r--mp/src/utils/common/threads.h130
-rw-r--r--mp/src/utils/common/tools_minidump.cpp122
-rw-r--r--mp/src/utils/common/tools_minidump.h70
-rw-r--r--mp/src/utils/common/utilmatlib.cpp368
-rw-r--r--mp/src/utils/common/utilmatlib.h82
-rw-r--r--mp/src/utils/common/vmpi_tools_shared.cpp748
-rw-r--r--mp/src/utils/common/vmpi_tools_shared.h90
-rw-r--r--mp/src/utils/common/wadlib.c668
-rw-r--r--mp/src/utils/common/wadlib.h92
39 files changed, 13950 insertions, 13950 deletions
diff --git a/mp/src/utils/common/ISQLDBReplyTarget.h b/mp/src/utils/common/ISQLDBReplyTarget.h
index 31406368..9049a5c7 100644
--- a/mp/src/utils/common/ISQLDBReplyTarget.h
+++ b/mp/src/utils/common/ISQLDBReplyTarget.h
@@ -1,29 +1,29 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef ISQLDLREPLYTARGET_H
-#define ISQLDLREPLYTARGET_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: Interface to handle results of SQL queries
-//-----------------------------------------------------------------------------
-class ISQLDBReplyTarget
-{
-public:
- // handles a response from the database
- virtual void SQLDBResponse(int cmdID, int returnState, int returnVal, void *data) = 0;
-
- // called from a seperate thread; tells the reply target that a message is waiting for it
- virtual void WakeUp() = 0;
-
-};
-
-
-#endif // ISQLDLREPLYTARGET_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef ISQLDLREPLYTARGET_H
+#define ISQLDLREPLYTARGET_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface to handle results of SQL queries
+//-----------------------------------------------------------------------------
+class ISQLDBReplyTarget
+{
+public:
+ // handles a response from the database
+ virtual void SQLDBResponse(int cmdID, int returnState, int returnVal, void *data) = 0;
+
+ // called from a seperate thread; tells the reply target that a message is waiting for it
+ virtual void WakeUp() = 0;
+
+};
+
+
+#endif // ISQLDLREPLYTARGET_H
diff --git a/mp/src/utils/common/MySqlDatabase.cpp b/mp/src/utils/common/MySqlDatabase.cpp
index 46d8a4b9..2558ba08 100644
--- a/mp/src/utils/common/MySqlDatabase.cpp
+++ b/mp/src/utils/common/MySqlDatabase.cpp
@@ -1,192 +1,192 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "MySqlDatabase.h"
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-//-----------------------------------------------------------------------------
-CMySqlDatabase::CMySqlDatabase()
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-// blocks until db process thread has stopped
-//-----------------------------------------------------------------------------
-CMySqlDatabase::~CMySqlDatabase()
-{
- // flag the thread to stop
- m_bRunThread = false;
-
- // pulse the thread to make it run
- ::SetEvent(m_hEvent);
-
- // make sure it's done
- ::EnterCriticalSection(&m_csThread);
- ::LeaveCriticalSection(&m_csThread);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Thread access function
-//-----------------------------------------------------------------------------
-static DWORD WINAPI staticThreadFunc(void *param)
-{
- ((CMySqlDatabase *)param)->RunThread();
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Establishes connection to the database and sets up this object to handle db command
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMySqlDatabase::Initialize()
-{
- // prepare critical sections
- //!! need to download SDK and replace these with InitializeCriticalSectionAndSpinCount() calls
- ::InitializeCriticalSection(&m_csThread);
- ::InitializeCriticalSection(&m_csInQueue);
- ::InitializeCriticalSection(&m_csOutQueue);
- ::InitializeCriticalSection(&m_csDBAccess);
-
- // initialize wait calls
- m_hEvent = ::CreateEvent(NULL, false, true, NULL);
-
- // start the DB-access thread
- m_bRunThread = true;
-
- unsigned long threadID;
- ::CreateThread(NULL, 0, staticThreadFunc, this, 0, &threadID);
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Main thread loop
-//-----------------------------------------------------------------------------
-void CMySqlDatabase::RunThread()
-{
- ::EnterCriticalSection(&m_csThread);
- while (m_bRunThread)
- {
- if (m_InQueue.Count() > 0)
- {
- // get a dispatched DB request
- ::EnterCriticalSection(&m_csInQueue);
-
- // pop the front of the queue
- int headIndex = m_InQueue.Head();
- msg_t msg = m_InQueue[headIndex];
- m_InQueue.Remove(headIndex);
-
- ::LeaveCriticalSection(&m_csInQueue);
-
- ::EnterCriticalSection(&m_csDBAccess);
-
- // run sqldb command
- msg.result = msg.cmd->RunCommand();
-
- ::LeaveCriticalSection(&m_csDBAccess);
-
- if (msg.replyTarget)
- {
- // put the results in the outgoing queue
- ::EnterCriticalSection(&m_csOutQueue);
- m_OutQueue.AddToTail(msg);
- ::LeaveCriticalSection(&m_csOutQueue);
-
- // wake up out queue
- msg.replyTarget->WakeUp();
- }
- else
- {
- // there is no return data from the call, so kill the object now
- msg.cmd->deleteThis();
- }
- }
- else
- {
- // nothing in incoming queue, so wait until we get the signal
- ::WaitForSingleObject(m_hEvent, INFINITE);
- }
-
- // check the size of the outqueue; if it's getting too big, sleep to let the main thread catch up
- if (m_OutQueue.Count() > 50)
- {
- ::Sleep(2);
- }
- }
- ::LeaveCriticalSection(&m_csThread);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Adds a database command to the queue, and wakes the db thread
-//-----------------------------------------------------------------------------
-void CMySqlDatabase::AddCommandToQueue(ISQLDBCommand *cmd, ISQLDBReplyTarget *replyTarget, int returnState)
-{
- ::EnterCriticalSection(&m_csInQueue);
-
- // add to the queue
- msg_t msg = { cmd, replyTarget, 0, returnState };
- m_InQueue.AddToTail(msg);
-
- ::LeaveCriticalSection(&m_csInQueue);
-
- // signal the thread to start running
- ::SetEvent(m_hEvent);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Dispatches responses to SQLDB queries
-//-----------------------------------------------------------------------------
-bool CMySqlDatabase::RunFrame()
-{
- bool doneWork = false;
-
- while (m_OutQueue.Count() > 0)
- {
- ::EnterCriticalSection(&m_csOutQueue);
-
- // pop the first item in the queue
- int headIndex = m_OutQueue.Head();
- msg_t msg = m_OutQueue[headIndex];
- m_OutQueue.Remove(headIndex);
-
- ::LeaveCriticalSection(&m_csOutQueue);
-
- // run result
- if (msg.replyTarget)
- {
- msg.replyTarget->SQLDBResponse(msg.cmd->GetID(), msg.returnState, msg.result, msg.cmd->GetReturnData());
-
- // kill command
- // it would be a good optimization to be able to reuse these
- msg.cmd->deleteThis();
- }
-
- doneWork = true;
- }
-
- return doneWork;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: load info - returns the number of sql db queries waiting to be processed
-//-----------------------------------------------------------------------------
-int CMySqlDatabase::QueriesInOutQueue()
-{
- // the queue names are from the DB point of view, not the server - thus the reversal
- return m_InQueue.Count();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: number of queries finished processing, waiting to be responded to
-//-----------------------------------------------------------------------------
-int CMySqlDatabase::QueriesInFinishedQueue()
-{
- return m_OutQueue.Count();
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "MySqlDatabase.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMySqlDatabase::CMySqlDatabase()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+// blocks until db process thread has stopped
+//-----------------------------------------------------------------------------
+CMySqlDatabase::~CMySqlDatabase()
+{
+ // flag the thread to stop
+ m_bRunThread = false;
+
+ // pulse the thread to make it run
+ ::SetEvent(m_hEvent);
+
+ // make sure it's done
+ ::EnterCriticalSection(&m_csThread);
+ ::LeaveCriticalSection(&m_csThread);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Thread access function
+//-----------------------------------------------------------------------------
+static DWORD WINAPI staticThreadFunc(void *param)
+{
+ ((CMySqlDatabase *)param)->RunThread();
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Establishes connection to the database and sets up this object to handle db command
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMySqlDatabase::Initialize()
+{
+ // prepare critical sections
+ //!! need to download SDK and replace these with InitializeCriticalSectionAndSpinCount() calls
+ ::InitializeCriticalSection(&m_csThread);
+ ::InitializeCriticalSection(&m_csInQueue);
+ ::InitializeCriticalSection(&m_csOutQueue);
+ ::InitializeCriticalSection(&m_csDBAccess);
+
+ // initialize wait calls
+ m_hEvent = ::CreateEvent(NULL, false, true, NULL);
+
+ // start the DB-access thread
+ m_bRunThread = true;
+
+ unsigned long threadID;
+ ::CreateThread(NULL, 0, staticThreadFunc, this, 0, &threadID);
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Main thread loop
+//-----------------------------------------------------------------------------
+void CMySqlDatabase::RunThread()
+{
+ ::EnterCriticalSection(&m_csThread);
+ while (m_bRunThread)
+ {
+ if (m_InQueue.Count() > 0)
+ {
+ // get a dispatched DB request
+ ::EnterCriticalSection(&m_csInQueue);
+
+ // pop the front of the queue
+ int headIndex = m_InQueue.Head();
+ msg_t msg = m_InQueue[headIndex];
+ m_InQueue.Remove(headIndex);
+
+ ::LeaveCriticalSection(&m_csInQueue);
+
+ ::EnterCriticalSection(&m_csDBAccess);
+
+ // run sqldb command
+ msg.result = msg.cmd->RunCommand();
+
+ ::LeaveCriticalSection(&m_csDBAccess);
+
+ if (msg.replyTarget)
+ {
+ // put the results in the outgoing queue
+ ::EnterCriticalSection(&m_csOutQueue);
+ m_OutQueue.AddToTail(msg);
+ ::LeaveCriticalSection(&m_csOutQueue);
+
+ // wake up out queue
+ msg.replyTarget->WakeUp();
+ }
+ else
+ {
+ // there is no return data from the call, so kill the object now
+ msg.cmd->deleteThis();
+ }
+ }
+ else
+ {
+ // nothing in incoming queue, so wait until we get the signal
+ ::WaitForSingleObject(m_hEvent, INFINITE);
+ }
+
+ // check the size of the outqueue; if it's getting too big, sleep to let the main thread catch up
+ if (m_OutQueue.Count() > 50)
+ {
+ ::Sleep(2);
+ }
+ }
+ ::LeaveCriticalSection(&m_csThread);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a database command to the queue, and wakes the db thread
+//-----------------------------------------------------------------------------
+void CMySqlDatabase::AddCommandToQueue(ISQLDBCommand *cmd, ISQLDBReplyTarget *replyTarget, int returnState)
+{
+ ::EnterCriticalSection(&m_csInQueue);
+
+ // add to the queue
+ msg_t msg = { cmd, replyTarget, 0, returnState };
+ m_InQueue.AddToTail(msg);
+
+ ::LeaveCriticalSection(&m_csInQueue);
+
+ // signal the thread to start running
+ ::SetEvent(m_hEvent);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Dispatches responses to SQLDB queries
+//-----------------------------------------------------------------------------
+bool CMySqlDatabase::RunFrame()
+{
+ bool doneWork = false;
+
+ while (m_OutQueue.Count() > 0)
+ {
+ ::EnterCriticalSection(&m_csOutQueue);
+
+ // pop the first item in the queue
+ int headIndex = m_OutQueue.Head();
+ msg_t msg = m_OutQueue[headIndex];
+ m_OutQueue.Remove(headIndex);
+
+ ::LeaveCriticalSection(&m_csOutQueue);
+
+ // run result
+ if (msg.replyTarget)
+ {
+ msg.replyTarget->SQLDBResponse(msg.cmd->GetID(), msg.returnState, msg.result, msg.cmd->GetReturnData());
+
+ // kill command
+ // it would be a good optimization to be able to reuse these
+ msg.cmd->deleteThis();
+ }
+
+ doneWork = true;
+ }
+
+ return doneWork;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: load info - returns the number of sql db queries waiting to be processed
+//-----------------------------------------------------------------------------
+int CMySqlDatabase::QueriesInOutQueue()
+{
+ // the queue names are from the DB point of view, not the server - thus the reversal
+ return m_InQueue.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: number of queries finished processing, waiting to be responded to
+//-----------------------------------------------------------------------------
+int CMySqlDatabase::QueriesInFinishedQueue()
+{
+ return m_OutQueue.Count();
+}
diff --git a/mp/src/utils/common/MySqlDatabase.h b/mp/src/utils/common/MySqlDatabase.h
index caa5855c..52517f6d 100644
--- a/mp/src/utils/common/MySqlDatabase.h
+++ b/mp/src/utils/common/MySqlDatabase.h
@@ -1,104 +1,104 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef MYSQLDATABASE_H
-#define MYSQLDATABASE_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-#include <windows.h>
-#include "ISQLDBReplyTarget.h"
-#include "utlvector.h"
-#include "UtlLinkedList.h"
-
-class ISQLDBCommand;
-
-//-----------------------------------------------------------------------------
-// Purpose: Generic MySQL accessing database
-// Provides threaded I/O queue functionality for accessing a mysql db
-//-----------------------------------------------------------------------------
-class CMySqlDatabase
-{
-public:
- // constructor
- CMySqlDatabase();
- ~CMySqlDatabase();
-
- // initialization - must be called before this object can be used
- bool Initialize();
-
- // Dispatches responses to SQLDB queries
- bool RunFrame();
-
- // load info - returns the number of sql db queries waiting to be processed
- virtual int QueriesInOutQueue();
-
- // number of queries finished processing, waiting to be responded to
- virtual int QueriesInFinishedQueue();
-
- // activates the thread
- void RunThread();
-
- // command queues
- void AddCommandToQueue(ISQLDBCommand *cmd, ISQLDBReplyTarget *replyTarget, int returnState = 0);
-
-private:
-
- // threading data
- bool m_bRunThread;
- CRITICAL_SECTION m_csThread;
- CRITICAL_SECTION m_csInQueue;
- CRITICAL_SECTION m_csOutQueue;
- CRITICAL_SECTION m_csDBAccess;
-
- // wait event
- HANDLE m_hEvent;
-
- struct msg_t
- {
- ISQLDBCommand *cmd;
- ISQLDBReplyTarget *replyTarget;
- int result;
- int returnState;
- };
-
- // command queues
- CUtlLinkedList<msg_t, int> m_InQueue;
- CUtlLinkedList<msg_t, int> m_OutQueue;
-};
-
-class Connection;
-
-//-----------------------------------------------------------------------------
-// Purpose: Interface to a command
-//-----------------------------------------------------------------------------
-class ISQLDBCommand
-{
-public:
- // makes the command run (blocking), returning the success code
- virtual int RunCommand() = 0;
-
- // return data
- virtual void *GetReturnData() { return NULL; }
-
- // returns the command ID
- virtual int GetID() { return 0; }
-
- // gets information about the command for if it failed
- virtual void GetDebugInfo(char *buf, int bufSize) { buf[0] = 0; }
-
- // use to delete
- virtual void deleteThis() = 0;
-
-protected:
- // protected destructor, so that it has to be deleted through deleteThis()
- virtual ~ISQLDBCommand() {}
-};
-
-
-#endif // MYSQLDATABASE_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MYSQLDATABASE_H
+#define MYSQLDATABASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <windows.h>
+#include "ISQLDBReplyTarget.h"
+#include "utlvector.h"
+#include "UtlLinkedList.h"
+
+class ISQLDBCommand;
+
+//-----------------------------------------------------------------------------
+// Purpose: Generic MySQL accessing database
+// Provides threaded I/O queue functionality for accessing a mysql db
+//-----------------------------------------------------------------------------
+class CMySqlDatabase
+{
+public:
+ // constructor
+ CMySqlDatabase();
+ ~CMySqlDatabase();
+
+ // initialization - must be called before this object can be used
+ bool Initialize();
+
+ // Dispatches responses to SQLDB queries
+ bool RunFrame();
+
+ // load info - returns the number of sql db queries waiting to be processed
+ virtual int QueriesInOutQueue();
+
+ // number of queries finished processing, waiting to be responded to
+ virtual int QueriesInFinishedQueue();
+
+ // activates the thread
+ void RunThread();
+
+ // command queues
+ void AddCommandToQueue(ISQLDBCommand *cmd, ISQLDBReplyTarget *replyTarget, int returnState = 0);
+
+private:
+
+ // threading data
+ bool m_bRunThread;
+ CRITICAL_SECTION m_csThread;
+ CRITICAL_SECTION m_csInQueue;
+ CRITICAL_SECTION m_csOutQueue;
+ CRITICAL_SECTION m_csDBAccess;
+
+ // wait event
+ HANDLE m_hEvent;
+
+ struct msg_t
+ {
+ ISQLDBCommand *cmd;
+ ISQLDBReplyTarget *replyTarget;
+ int result;
+ int returnState;
+ };
+
+ // command queues
+ CUtlLinkedList<msg_t, int> m_InQueue;
+ CUtlLinkedList<msg_t, int> m_OutQueue;
+};
+
+class Connection;
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface to a command
+//-----------------------------------------------------------------------------
+class ISQLDBCommand
+{
+public:
+ // makes the command run (blocking), returning the success code
+ virtual int RunCommand() = 0;
+
+ // return data
+ virtual void *GetReturnData() { return NULL; }
+
+ // returns the command ID
+ virtual int GetID() { return 0; }
+
+ // gets information about the command for if it failed
+ virtual void GetDebugInfo(char *buf, int bufSize) { buf[0] = 0; }
+
+ // use to delete
+ virtual void deleteThis() = 0;
+
+protected:
+ // protected destructor, so that it has to be deleted through deleteThis()
+ virtual ~ISQLDBCommand() {}
+};
+
+
+#endif // MYSQLDATABASE_H
diff --git a/mp/src/utils/common/bsplib.cpp b/mp/src/utils/common/bsplib.cpp
index 84d1a1d0..c3ad433e 100644
--- a/mp/src/utils/common/bsplib.cpp
+++ b/mp/src/utils/common/bsplib.cpp
@@ -1,5064 +1,5064 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Revision: $
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cmdlib.h"
-#include "mathlib/mathlib.h"
-#include "bsplib.h"
-#include "zip_utils.h"
-#include "scriplib.h"
-#include "utllinkedlist.h"
-#include "bsptreedata.h"
-#include "cmodel.h"
-#include "gamebspfile.h"
-#include "materialsystem/imaterial.h"
-#include "materialsystem/hardwareverts.h"
-#include "utlbuffer.h"
-#include "utlrbtree.h"
-#include "utlsymbol.h"
-#include "utlstring.h"
-#include "checksum_crc.h"
-#include "physdll.h"
-#include "tier0/dbg.h"
-#include "lumpfiles.h"
-#include "vtf/vtf.h"
-
-//=============================================================================
-
-// Boundary each lump should be aligned to
-#define LUMP_ALIGNMENT 4
-
-// Data descriptions for byte swapping - only needed
-// for structures that are written to file for use by the game.
-BEGIN_BYTESWAP_DATADESC( dheader_t )
- DEFINE_FIELD( ident, FIELD_INTEGER ),
- DEFINE_FIELD( version, FIELD_INTEGER ),
- DEFINE_EMBEDDED_ARRAY( lumps, HEADER_LUMPS ),
- DEFINE_FIELD( mapRevision, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-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 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dflagslump_t )
- DEFINE_FIELD( m_LevelFlags, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dplane_t )
- DEFINE_FIELD( normal, FIELD_VECTOR ),
- DEFINE_FIELD( dist, FIELD_FLOAT ),
- DEFINE_FIELD( type, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleaf_version_0_t )
- DEFINE_FIELD( contents, FIELD_INTEGER ),
- DEFINE_FIELD( cluster, FIELD_SHORT ),
- DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
- DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
- DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
- DEFINE_FIELD( firstleafface, FIELD_SHORT ),
- DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
- DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
- DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
- DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
- DEFINE_EMBEDDED( m_AmbientLighting ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleaf_t )
- DEFINE_FIELD( contents, FIELD_INTEGER ),
- DEFINE_FIELD( cluster, FIELD_SHORT ),
- DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
- DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
- DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
- DEFINE_FIELD( firstleafface, FIELD_SHORT ),
- DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
- DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
- DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
- DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CompressedLightCube ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
- DEFINE_ARRAY( m_Color, FIELD_CHARACTER, 6 * sizeof(ColorRGBExp32) ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleafambientindex_t )
- DEFINE_FIELD( ambientSampleCount, FIELD_SHORT ),
- DEFINE_FIELD( firstAmbientSample, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleafambientlighting_t ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
- DEFINE_EMBEDDED( cube ),
- DEFINE_FIELD( x, FIELD_CHARACTER ),
- DEFINE_FIELD( y, FIELD_CHARACTER ),
- DEFINE_FIELD( z, FIELD_CHARACTER ),
- DEFINE_FIELD( pad, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dvertex_t )
- DEFINE_FIELD( point, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dnode_t )
- DEFINE_FIELD( planenum, FIELD_INTEGER ),
- DEFINE_ARRAY( children, FIELD_INTEGER, 2 ),
- DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
- DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
- DEFINE_FIELD( firstface, FIELD_SHORT ),
- DEFINE_FIELD( numfaces, FIELD_SHORT ),
- DEFINE_FIELD( area, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( texinfo_t )
- DEFINE_ARRAY( textureVecsTexelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
- DEFINE_ARRAY( lightmapVecsLuxelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
- DEFINE_FIELD( flags, FIELD_INTEGER ),
- DEFINE_FIELD( texdata, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dtexdata_t )
- DEFINE_FIELD( reflectivity, FIELD_VECTOR ),
- DEFINE_FIELD( nameStringTableID, FIELD_INTEGER ),
- DEFINE_FIELD( width, FIELD_INTEGER ),
- DEFINE_FIELD( height, FIELD_INTEGER ),
- DEFINE_FIELD( view_width, FIELD_INTEGER ),
- DEFINE_FIELD( view_height, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( ddispinfo_t )
- DEFINE_FIELD( startPosition, FIELD_VECTOR ),
- DEFINE_FIELD( m_iDispVertStart, FIELD_INTEGER ),
- DEFINE_FIELD( m_iDispTriStart, FIELD_INTEGER ),
- DEFINE_FIELD( power, FIELD_INTEGER ),
- DEFINE_FIELD( minTess, FIELD_INTEGER ),
- DEFINE_FIELD( smoothingAngle, FIELD_FLOAT ),
- DEFINE_FIELD( contents, FIELD_INTEGER ),
- DEFINE_FIELD( m_iMapFace, FIELD_SHORT ),
- DEFINE_FIELD( m_iLightmapAlphaStart, FIELD_INTEGER ),
- DEFINE_FIELD( m_iLightmapSamplePositionStart, FIELD_INTEGER ),
- DEFINE_EMBEDDED_ARRAY( m_EdgeNeighbors, 4 ),
- DEFINE_EMBEDDED_ARRAY( m_CornerNeighbors, 4 ),
- DEFINE_ARRAY( m_AllowedVerts, FIELD_INTEGER, ddispinfo_t::ALLOWEDVERTS_SIZE ), // unsigned long
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispNeighbor )
- DEFINE_EMBEDDED_ARRAY( m_SubNeighbors, 2 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispCornerNeighbors )
- DEFINE_ARRAY( m_Neighbors, FIELD_SHORT, MAX_DISP_CORNER_NEIGHBORS ),
- DEFINE_FIELD( m_nNeighbors, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispSubNeighbor )
- DEFINE_FIELD( m_iNeighbor, FIELD_SHORT ),
- DEFINE_FIELD( m_NeighborOrientation, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Span, FIELD_CHARACTER ),
- DEFINE_FIELD( m_NeighborSpan, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispVert )
- DEFINE_FIELD( m_vVector, FIELD_VECTOR ),
- DEFINE_FIELD( m_flDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_flAlpha, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispTri )
- DEFINE_FIELD( m_uiTags, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CFaceMacroTextureInfo )
- DEFINE_FIELD( m_MacroTextureNameID, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dprimitive_t )
- DEFINE_FIELD( type, FIELD_CHARACTER ),
- DEFINE_FIELD( firstIndex, FIELD_SHORT ),
- DEFINE_FIELD( indexCount, FIELD_SHORT ),
- DEFINE_FIELD( firstVert, FIELD_SHORT ),
- DEFINE_FIELD( vertCount, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dprimvert_t )
- DEFINE_FIELD( pos, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dface_t )
- DEFINE_FIELD( planenum, FIELD_SHORT ),
- DEFINE_FIELD( side, FIELD_CHARACTER ),
- DEFINE_FIELD( onNode, FIELD_CHARACTER ),
- DEFINE_FIELD( firstedge, FIELD_INTEGER ),
- DEFINE_FIELD( numedges, FIELD_SHORT ),
- DEFINE_FIELD( texinfo, FIELD_SHORT ),
- DEFINE_FIELD( dispinfo, FIELD_SHORT ),
- DEFINE_FIELD( surfaceFogVolumeID, FIELD_SHORT ),
- DEFINE_ARRAY( styles, FIELD_CHARACTER, MAXLIGHTMAPS ),
- DEFINE_FIELD( lightofs, FIELD_INTEGER ),
- DEFINE_FIELD( area, FIELD_FLOAT ),
- DEFINE_ARRAY( m_LightmapTextureMinsInLuxels, FIELD_INTEGER, 2 ),
- DEFINE_ARRAY( m_LightmapTextureSizeInLuxels, FIELD_INTEGER, 2 ),
- DEFINE_FIELD( origFace, FIELD_INTEGER ),
- DEFINE_FIELD( m_NumPrims, FIELD_SHORT ),
- DEFINE_FIELD( firstPrimID, FIELD_SHORT ),
- DEFINE_FIELD( smoothingGroups, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dfaceid_t )
- DEFINE_FIELD( hammerfaceid, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dbrush_t )
- DEFINE_FIELD( firstside, FIELD_INTEGER ),
- DEFINE_FIELD( numsides, FIELD_INTEGER ),
- DEFINE_FIELD( contents, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dbrushside_t )
- DEFINE_FIELD( planenum, FIELD_SHORT ),
- DEFINE_FIELD( texinfo, FIELD_SHORT ),
- DEFINE_FIELD( dispinfo, FIELD_SHORT ),
- DEFINE_FIELD( bevel, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dedge_t )
- DEFINE_ARRAY( v, FIELD_SHORT, 2 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dmodel_t )
- DEFINE_FIELD( mins, FIELD_VECTOR ),
- DEFINE_FIELD( maxs, FIELD_VECTOR ),
- DEFINE_FIELD( origin, FIELD_VECTOR ),
- DEFINE_FIELD( headnode, FIELD_INTEGER ),
- DEFINE_FIELD( firstface, FIELD_INTEGER ),
- DEFINE_FIELD( numfaces, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dphysmodel_t )
- DEFINE_FIELD( modelIndex, FIELD_INTEGER ),
- DEFINE_FIELD( dataSize, FIELD_INTEGER ),
- DEFINE_FIELD( keydataSize, FIELD_INTEGER ),
- DEFINE_FIELD( solidCount, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dphysdisp_t )
- DEFINE_FIELD( numDisplacements, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( darea_t )
- DEFINE_FIELD( numareaportals, FIELD_INTEGER ),
- DEFINE_FIELD( firstareaportal, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dareaportal_t )
- DEFINE_FIELD( m_PortalKey, FIELD_SHORT ),
- DEFINE_FIELD( otherarea, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstClipPortalVert, FIELD_SHORT ),
- DEFINE_FIELD( m_nClipPortalVerts, FIELD_SHORT ),
- DEFINE_FIELD( planenum, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dworldlight_t )
- DEFINE_FIELD( origin, FIELD_VECTOR ),
- DEFINE_FIELD( intensity, FIELD_VECTOR ),
- DEFINE_FIELD( normal, FIELD_VECTOR ),
- DEFINE_FIELD( cluster, FIELD_INTEGER ),
- DEFINE_FIELD( type, FIELD_INTEGER ), // enumeration
- DEFINE_FIELD( style, FIELD_INTEGER ),
- DEFINE_FIELD( stopdot, FIELD_FLOAT ),
- DEFINE_FIELD( stopdot2, FIELD_FLOAT ),
- DEFINE_FIELD( exponent, FIELD_FLOAT ),
- DEFINE_FIELD( radius, FIELD_FLOAT ),
- DEFINE_FIELD( constant_attn, FIELD_FLOAT ),
- DEFINE_FIELD( linear_attn, FIELD_FLOAT ),
- DEFINE_FIELD( quadratic_attn, FIELD_FLOAT ),
- DEFINE_FIELD( flags, FIELD_INTEGER ),
- DEFINE_FIELD( texinfo, FIELD_INTEGER ),
- DEFINE_FIELD( owner, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleafwaterdata_t )
- DEFINE_FIELD( surfaceZ, FIELD_FLOAT ),
- DEFINE_FIELD( minZ, FIELD_FLOAT ),
- DEFINE_FIELD( surfaceTexInfoID, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doccluderdata_t )
- DEFINE_FIELD( flags, FIELD_INTEGER ),
- DEFINE_FIELD( firstpoly, FIELD_INTEGER ),
- DEFINE_FIELD( polycount, FIELD_INTEGER ),
- DEFINE_FIELD( mins, FIELD_VECTOR ),
- DEFINE_FIELD( maxs, FIELD_VECTOR ),
- DEFINE_FIELD( area, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doccluderpolydata_t )
- DEFINE_FIELD( firstvertexindex, FIELD_INTEGER ),
- DEFINE_FIELD( vertexcount, FIELD_INTEGER ),
- DEFINE_FIELD( planenum, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dcubemapsample_t )
- DEFINE_ARRAY( origin, FIELD_INTEGER, 3 ),
- DEFINE_FIELD( size, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doverlay_t )
- DEFINE_FIELD( nId, FIELD_INTEGER ),
- DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
- DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
- DEFINE_ARRAY( aFaces, FIELD_INTEGER, OVERLAY_BSP_FACE_COUNT ),
- DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
- DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dwateroverlay_t )
- DEFINE_FIELD( nId, FIELD_INTEGER ),
- DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
- DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
- DEFINE_ARRAY( aFaces, FIELD_INTEGER, WATEROVERLAY_BSP_FACE_COUNT ),
- DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
- DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doverlayfade_t )
- DEFINE_FIELD( flFadeDistMinSq, FIELD_FLOAT ),
- DEFINE_FIELD( flFadeDistMaxSq, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dgamelumpheader_t )
- DEFINE_FIELD( lumpCount, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dgamelump_t )
- DEFINE_FIELD( id, FIELD_INTEGER ), // GameLumpId_t
- DEFINE_FIELD( flags, FIELD_SHORT ),
- DEFINE_FIELD( version, FIELD_SHORT ),
- DEFINE_FIELD( fileofs, FIELD_INTEGER ),
- DEFINE_FIELD( filelen, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-// From gamebspfile.h
-BEGIN_BYTESWAP_DATADESC( StaticPropDictLump_t )
- DEFINE_ARRAY( m_Name, FIELD_CHARACTER, STATIC_PROP_NAME_LENGTH ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLump_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_PropType, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
- DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
- DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
- DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
- DEFINE_FIELD( m_nMinDXLevel, FIELD_SHORT ),
- DEFINE_FIELD( m_nMaxDXLevel, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLumpV4_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_PropType, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
- DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
- DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
- DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLumpV5_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_PropType, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
- DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
- DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
- DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLeafLump_t )
- DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailObjectDictLump_t )
- DEFINE_ARRAY( m_Name, FIELD_CHARACTER, DETAIL_NAME_LENGTH ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailObjectLump_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_DetailModel, FIELD_SHORT ),
- DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
- DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
- DEFINE_FIELD( m_LightStyles, FIELD_INTEGER ),
- DEFINE_FIELD( m_LightStyleCount, FIELD_CHARACTER ),
- DEFINE_FIELD( m_SwayAmount, FIELD_CHARACTER ),
- DEFINE_FIELD( m_ShapeAngle, FIELD_CHARACTER ),
- DEFINE_FIELD( m_ShapeSize, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Orientation, FIELD_CHARACTER ),
- DEFINE_ARRAY( m_Padding2, FIELD_CHARACTER, 3 ),
- DEFINE_FIELD( m_Type, FIELD_CHARACTER ),
- DEFINE_ARRAY( m_Padding3, FIELD_CHARACTER, 3 ),
- DEFINE_FIELD( m_flScale, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailSpriteDictLump_t )
- DEFINE_FIELD( m_UL, FIELD_VECTOR2D ),
- DEFINE_FIELD( m_LR, FIELD_VECTOR2D ),
- DEFINE_FIELD( m_TexUL, FIELD_VECTOR2D ),
- DEFINE_FIELD( m_TexLR, FIELD_VECTOR2D ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailPropLightstylesLump_t )
- DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
- DEFINE_FIELD( m_Style, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-// From vradstaticprops.h
-namespace HardwareVerts
-{
-BEGIN_BYTESWAP_DATADESC( MeshHeader_t )
- DEFINE_FIELD( m_nLod, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
- DEFINE_FIELD( m_nOffset, FIELD_INTEGER ),
- DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( FileHeader_t )
- DEFINE_FIELD( m_nVersion, FIELD_INTEGER ),
- DEFINE_FIELD( m_nChecksum, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexFlags, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexSize, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
- DEFINE_FIELD( m_nMeshes, FIELD_INTEGER ),
- DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
-END_BYTESWAP_DATADESC()
-} // end namespace
-
-static const char *s_LumpNames[] = {
- "LUMP_ENTITIES", // 0
- "LUMP_PLANES", // 1
- "LUMP_TEXDATA", // 2
- "LUMP_VERTEXES", // 3
- "LUMP_VISIBILITY", // 4
- "LUMP_NODES", // 5
- "LUMP_TEXINFO", // 6
- "LUMP_FACES", // 7
- "LUMP_LIGHTING", // 8
- "LUMP_OCCLUSION", // 9
- "LUMP_LEAFS", // 10
- "LUMP_FACEIDS", // 11
- "LUMP_EDGES", // 12
- "LUMP_SURFEDGES", // 13
- "LUMP_MODELS", // 14
- "LUMP_WORLDLIGHTS", // 15
- "LUMP_LEAFFACES", // 16
- "LUMP_LEAFBRUSHES", // 17
- "LUMP_BRUSHES", // 18
- "LUMP_BRUSHSIDES", // 19
- "LUMP_AREAS", // 20
- "LUMP_AREAPORTALS", // 21
- "LUMP_UNUSED0", // 22
- "LUMP_UNUSED1", // 23
- "LUMP_UNUSED2", // 24
- "LUMP_UNUSED3", // 25
- "LUMP_DISPINFO", // 26
- "LUMP_ORIGINALFACES", // 27
- "LUMP_PHYSDISP", // 28
- "LUMP_PHYSCOLLIDE", // 29
- "LUMP_VERTNORMALS", // 30
- "LUMP_VERTNORMALINDICES", // 31
- "LUMP_DISP_LIGHTMAP_ALPHAS", // 32
- "LUMP_DISP_VERTS", // 33
- "LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS", // 34
- "LUMP_GAME_LUMP", // 35
- "LUMP_LEAFWATERDATA", // 36
- "LUMP_PRIMITIVES", // 37
- "LUMP_PRIMVERTS", // 38
- "LUMP_PRIMINDICES", // 39
- "LUMP_PAKFILE", // 40
- "LUMP_CLIPPORTALVERTS", // 41
- "LUMP_CUBEMAPS", // 42
- "LUMP_TEXDATA_STRING_DATA", // 43
- "LUMP_TEXDATA_STRING_TABLE", // 44
- "LUMP_OVERLAYS", // 45
- "LUMP_LEAFMINDISTTOWATER", // 46
- "LUMP_FACE_MACRO_TEXTURE_INFO", // 47
- "LUMP_DISP_TRIS", // 48
- "LUMP_PHYSCOLLIDESURFACE", // 49
- "LUMP_WATEROVERLAYS", // 50
- "LUMP_LEAF_AMBIENT_INDEX_HDR", // 51
- "LUMP_LEAF_AMBIENT_INDEX", // 52
- "LUMP_LIGHTING_HDR", // 53
- "LUMP_WORLDLIGHTS_HDR", // 54
- "LUMP_LEAF_AMBIENT_LIGHTING_HDR", // 55
- "LUMP_LEAF_AMBIENT_LIGHTING", // 56
- "LUMP_XZIPPAKFILE", // 57
- "LUMP_FACES_HDR", // 58
- "LUMP_MAP_FLAGS", // 59
- "LUMP_OVERLAY_FADES", // 60
-};
-
-const char *GetLumpName( unsigned int lumpnum )
-{
- if ( lumpnum >= ARRAYSIZE( s_LumpNames ) )
- {
- return "UNKNOWN";
- }
- return s_LumpNames[lumpnum];
-}
-
-// "-hdr" tells us to use the HDR fields (if present) on the light sources. Also, tells us to write
-// out the HDR lumps for lightmaps, ambient leaves, and lights sources.
-bool g_bHDR = false;
-
-// Set to true to generate Xbox360 native output files
-static bool g_bSwapOnLoad = false;
-static bool g_bSwapOnWrite = false;
-
-VTFConvertFunc_t g_pVTFConvertFunc;
-VHVFixupFunc_t g_pVHVFixupFunc;
-CompressFunc_t g_pCompressFunc;
-
-CUtlVector< CUtlString > g_StaticPropNames;
-CUtlVector< int > g_StaticPropInstances;
-
-CByteswap g_Swap;
-
-uint32 g_LevelFlags = 0;
-
-int nummodels;
-dmodel_t dmodels[MAX_MAP_MODELS];
-
-int visdatasize;
-byte dvisdata[MAX_MAP_VISIBILITY];
-dvis_t *dvis = (dvis_t *)dvisdata;
-
-CUtlVector<byte> dlightdataHDR;
-CUtlVector<byte> dlightdataLDR;
-CUtlVector<byte> *pdlightdata = &dlightdataLDR;
-
-CUtlVector<char> dentdata;
-
-int numleafs;
-#if !defined( BSP_USE_LESS_MEMORY )
-dleaf_t dleafs[MAX_MAP_LEAFS];
-#else
-dleaf_t *dleafs;
-#endif
-
-CUtlVector<dleafambientindex_t> g_LeafAmbientIndexLDR;
-CUtlVector<dleafambientindex_t> g_LeafAmbientIndexHDR;
-CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex = NULL;
-CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingLDR;
-CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingHDR;
-CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting = NULL;
-
-unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
-
-int numplanes;
-dplane_t dplanes[MAX_MAP_PLANES];
-
-int numvertexes;
-dvertex_t dvertexes[MAX_MAP_VERTS];
-
-int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
-unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
-
-int g_numvertnormals;
-Vector g_vertnormals[MAX_MAP_VERTNORMALS];
-
-int numnodes;
-dnode_t dnodes[MAX_MAP_NODES];
-
-CUtlVector<texinfo_t> texinfo( MAX_MAP_TEXINFO );
-
-int numtexdata;
-dtexdata_t dtexdata[MAX_MAP_TEXDATA];
-
-//
-// displacement map bsp file info: dispinfo
-//
-CUtlVector<ddispinfo_t> g_dispinfo;
-CUtlVector<CDispVert> g_DispVerts;
-CUtlVector<CDispTri> g_DispTris;
-CUtlVector<unsigned char> g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
-
-int numorigfaces;
-dface_t dorigfaces[MAX_MAP_FACES];
-
-int g_numprimitives = 0;
-dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
-
-int g_numprimverts = 0;
-dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
-
-int g_numprimindices = 0;
-unsigned short g_primindices[MAX_MAP_PRIMINDICES];
-
-int numfaces;
-dface_t dfaces[MAX_MAP_FACES];
-
-int numfaceids;
-CUtlVector<dfaceid_t> dfaceids;
-
-int numfaces_hdr;
-dface_t dfaces_hdr[MAX_MAP_FACES];
-
-int numedges;
-dedge_t dedges[MAX_MAP_EDGES];
-
-int numleaffaces;
-unsigned short dleaffaces[MAX_MAP_LEAFFACES];
-
-int numleafbrushes;
-unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
-
-int numsurfedges;
-int dsurfedges[MAX_MAP_SURFEDGES];
-
-int numbrushes;
-dbrush_t dbrushes[MAX_MAP_BRUSHES];
-
-int numbrushsides;
-dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
-
-int numareas;
-darea_t dareas[MAX_MAP_AREAS];
-
-int numareaportals;
-dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
-
-int numworldlightsLDR;
-dworldlight_t dworldlightsLDR[MAX_MAP_WORLDLIGHTS];
-
-int numworldlightsHDR;
-dworldlight_t dworldlightsHDR[MAX_MAP_WORLDLIGHTS];
-
-int *pNumworldlights = &numworldlightsLDR;
-dworldlight_t *dworldlights = dworldlightsLDR;
-
-int numleafwaterdata = 0;
-dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
-
-CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
-
-Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
-int g_nClipPortalVerts;
-
-dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
-int g_nCubemapSamples = 0;
-
-int g_nOverlayCount;
-doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
-doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS];
-
-int g_nWaterOverlayCount;
-dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
-
-CUtlVector<char> g_TexDataStringData;
-CUtlVector<int> g_TexDataStringTable;
-
-byte *g_pPhysCollide = NULL;
-int g_PhysCollideSize = 0;
-int g_MapRevision = 0;
-
-byte *g_pPhysDisp = NULL;
-int g_PhysDispSize = 0;
-
-CUtlVector<doccluderdata_t> g_OccluderData( 256, 256 );
-CUtlVector<doccluderpolydata_t> g_OccluderPolyData( 1024, 1024 );
-CUtlVector<int> g_OccluderVertexIndices( 2048, 2048 );
-
-template <class T> static void WriteData( T *pData, int count = 1 );
-template <class T> static void WriteData( int fieldType, T *pData, int count = 1 );
-template< class T > static void AddLump( int lumpnum, T *pData, int count, int version = 0 );
-template< class T > static void AddLump( int lumpnum, CUtlVector<T> &data, int version = 0 );
-
-dheader_t *g_pBSPHeader;
-FileHandle_t g_hBSPFile;
-
-struct Lump_t
-{
- void *pLumps[HEADER_LUMPS];
- int size[HEADER_LUMPS];
- bool bLumpParsed[HEADER_LUMPS];
-} g_Lumps;
-
-CGameLump g_GameLumps;
-
-static IZip *s_pakFile = 0;
-
-//-----------------------------------------------------------------------------
-// Keep the file position aligned to an arbitrary boundary.
-// Returns updated file position.
-//-----------------------------------------------------------------------------
-static unsigned int AlignFilePosition( FileHandle_t hFile, int alignment )
-{
- unsigned int currPosition = g_pFileSystem->Tell( hFile );
-
- if ( alignment >= 2 )
- {
- unsigned int newPosition = AlignValue( currPosition, alignment );
- unsigned int count = newPosition - currPosition;
- if ( count )
- {
- char *pBuffer;
- char smallBuffer[4096];
- if ( count > sizeof( smallBuffer ) )
- {
- pBuffer = (char *)malloc( count );
- }
- else
- {
- pBuffer = smallBuffer;
- }
-
- memset( pBuffer, 0, count );
- SafeWrite( hFile, pBuffer, count );
-
- if ( pBuffer != smallBuffer )
- {
- free( pBuffer );
- }
-
- currPosition = newPosition;
- }
- }
-
- return currPosition;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: // Get a pakfile instance
-// Output : IZip*
-//-----------------------------------------------------------------------------
-IZip* GetPakFile( void )
-{
- if ( !s_pakFile )
- {
- s_pakFile = IZip::CreateZip();
- }
- return s_pakFile;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Free the pak files
-//-----------------------------------------------------------------------------
-void ReleasePakFileLumps( void )
-{
- // Release the pak files
- IZip::ReleaseZip( s_pakFile );
- s_pakFile = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the sector alignment for all subsequent zip operations
-//-----------------------------------------------------------------------------
-void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize )
-{
- pak->ForceAlignment( bAlign, bCompatibleFormat, alignmentSize );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Store data back out to .bsp file
-//-----------------------------------------------------------------------------
-static void WritePakFileLump( void )
-{
- CUtlBuffer buf( 0, 0 );
- GetPakFile()->ActivateByteSwapping( IsX360() );
- GetPakFile()->SaveToBuffer( buf );
-
- // must respect pak file alignment
- // pad up and ensure lump starts on same aligned boundary
- AlignFilePosition( g_hBSPFile, GetPakFile()->GetAlignment() );
-
- // Now store final buffers out to file
- AddLump( LUMP_PAKFILE, (byte*)buf.Base(), buf.TellPut() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Remove all entries
-//-----------------------------------------------------------------------------
-void ClearPakFile( IZip *pak )
-{
- pak->Reset();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Add file from disk to .bsp PAK lump
-// Input : *relativename -
-// *fullpath -
-//-----------------------------------------------------------------------------
-void AddFileToPak( IZip *pak, const char *relativename, const char *fullpath )
-{
- pak->AddFileToZip( relativename, fullpath );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Add buffer to .bsp PAK lump as named file
-// Input : *relativename -
-// *data -
-// length -
-//-----------------------------------------------------------------------------
-void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode )
-{
- pak->AddBufferToZip( pRelativeName, data, length, bTextMode );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Check if a file already exists in the pack file.
-// Input : *relativename -
-//-----------------------------------------------------------------------------
-bool FileExistsInPak( IZip *pak, const char *pRelativeName )
-{
- return pak->FileExistsInZip( pRelativeName );
-}
-
-
-//-----------------------------------------------------------------------------
-// Read a file from the pack file
-//-----------------------------------------------------------------------------
-bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
-{
- return pak->ReadFileFromZip( pRelativeName, bTextMode, buf );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Remove file from .bsp PAK lump
-// Input : *relativename -
-//-----------------------------------------------------------------------------
-void RemoveFileFromPak( IZip *pak, const char *relativename )
-{
- pak->RemoveFileFromZip( relativename );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Get next filename in directory
-// Input : id, -1 to start, returns next id, or -1 at list conclusion
-//-----------------------------------------------------------------------------
-int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize )
-{
- return pak->GetNextFilename( id, pBuffer, bufferSize, fileSize );
-}
-
-//-----------------------------------------------------------------------------
-// Convert four-CC code to a handle + back
-//-----------------------------------------------------------------------------
-GameLumpHandle_t CGameLump::GetGameLumpHandle( GameLumpId_t id )
-{
- // NOTE: I'm also expecting game lump id's to be four-CC codes
- Assert( id > HEADER_LUMPS );
-
- FOR_EACH_LL(m_GameLumps, i)
- {
- if (m_GameLumps[i].m_Id == id)
- return i;
- }
-
- return InvalidGameLump();
-}
-
-GameLumpId_t CGameLump::GetGameLumpId( GameLumpHandle_t handle )
-{
- return m_GameLumps[handle].m_Id;
-}
-
-int CGameLump::GetGameLumpFlags( GameLumpHandle_t handle )
-{
- return m_GameLumps[handle].m_Flags;
-}
-
-int CGameLump::GetGameLumpVersion( GameLumpHandle_t handle )
-{
- return m_GameLumps[handle].m_Version;
-}
-
-
-//-----------------------------------------------------------------------------
-// Game lump accessor methods
-//-----------------------------------------------------------------------------
-
-void* CGameLump::GetGameLump( GameLumpHandle_t id )
-{
- return m_GameLumps[id].m_Memory.Base();
-}
-
-int CGameLump::GameLumpSize( GameLumpHandle_t id )
-{
- return m_GameLumps[id].m_Memory.NumAllocated();
-}
-
-
-//-----------------------------------------------------------------------------
-// Game lump iteration methods
-//-----------------------------------------------------------------------------
-
-GameLumpHandle_t CGameLump::FirstGameLump()
-{
- return (m_GameLumps.Count()) ? m_GameLumps.Head() : InvalidGameLump();
-}
-
-GameLumpHandle_t CGameLump::NextGameLump( GameLumpHandle_t handle )
-{
-
- return (m_GameLumps.IsValidIndex(handle)) ? m_GameLumps.Next(handle) : InvalidGameLump();
-}
-
-GameLumpHandle_t CGameLump::InvalidGameLump()
-{
- return 0xFFFF;
-}
-
-
-//-----------------------------------------------------------------------------
-// Game lump creation/destruction method
-//-----------------------------------------------------------------------------
-
-GameLumpHandle_t CGameLump::CreateGameLump( GameLumpId_t id, int size, int flags, int version )
-{
- Assert( GetGameLumpHandle(id) == InvalidGameLump() );
- GameLumpHandle_t handle = m_GameLumps.AddToTail();
- m_GameLumps[handle].m_Id = id;
- m_GameLumps[handle].m_Flags = flags;
- m_GameLumps[handle].m_Version = version;
- m_GameLumps[handle].m_Memory.EnsureCapacity( size );
- return handle;
-}
-
-void CGameLump::DestroyGameLump( GameLumpHandle_t handle )
-{
- m_GameLumps.Remove( handle );
-}
-
-void CGameLump::DestroyAllGameLumps()
-{
- m_GameLumps.RemoveAll();
-}
-
-//-----------------------------------------------------------------------------
-// Compute file size and clump count
-//-----------------------------------------------------------------------------
-
-void CGameLump::ComputeGameLumpSizeAndCount( int& size, int& clumpCount )
-{
- // Figure out total size of the client lumps
- size = 0;
- clumpCount = 0;
- GameLumpHandle_t h;
- for( h = FirstGameLump(); h != InvalidGameLump(); h = NextGameLump( h ) )
- {
- ++clumpCount;
- size += GameLumpSize( h );
- }
-
- // Add on headers
- size += sizeof( dgamelumpheader_t ) + clumpCount * sizeof( dgamelump_t );
-}
-
-
-void CGameLump::SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int length )
-{
- int count = 0;
- switch( id )
- {
- case GAMELUMP_STATIC_PROPS:
- // Swap the static prop model dict
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (StaticPropDictLump_t*)dest, (StaticPropDictLump_t*)src, count );
- src += sizeof(StaticPropDictLump_t) * count;
- dest += sizeof(StaticPropDictLump_t) * count;
-
- // Swap the leaf list
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (StaticPropLeafLump_t*)dest, (StaticPropLeafLump_t*)src, count );
- src += sizeof(StaticPropLeafLump_t) * count;
- dest += sizeof(StaticPropLeafLump_t) * count;
-
- // Swap the models
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- // The one-at-a-time swap is to compensate for these structures
- // possibly being misaligned, which crashes the Xbox 360.
- if ( version == 4 )
- {
- StaticPropLumpV4_t lump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &lump, src, sizeof(StaticPropLumpV4_t) );
- g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
- Q_memcpy( dest, &lump, sizeof(StaticPropLumpV4_t) );
- src += sizeof( StaticPropLumpV4_t );
- dest += sizeof( StaticPropLumpV4_t );
- }
- }
- else if ( version == 5 )
- {
- StaticPropLumpV5_t lump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &lump, src, sizeof(StaticPropLumpV5_t) );
- g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
- Q_memcpy( dest, &lump, sizeof(StaticPropLumpV5_t) );
- src += sizeof( StaticPropLumpV5_t );
- dest += sizeof( StaticPropLumpV5_t );
- }
- }
- else
- {
- if ( version != 6 )
- {
- Error( "Unknown Static Prop Lump version %d didn't get swapped!\n", version );
- }
-
- StaticPropLump_t lump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &lump, src, sizeof(StaticPropLump_t) );
- g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
- Q_memcpy( dest, &lump, sizeof(StaticPropLump_t) );
- src += sizeof( StaticPropLump_t );
- dest += sizeof( StaticPropLump_t );
- }
- }
- break;
-
- case GAMELUMP_DETAIL_PROPS:
- // Swap the detail prop model dict
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (DetailObjectDictLump_t*)dest, (DetailObjectDictLump_t*)src, count );
- src += sizeof(DetailObjectDictLump_t) * count;
- dest += sizeof(DetailObjectDictLump_t) * count;
-
- if ( version == 4 )
- {
- // Swap the detail sprite dict
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- DetailSpriteDictLump_t spritelump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &spritelump, src, sizeof(DetailSpriteDictLump_t) );
- g_Swap.SwapFieldsToTargetEndian( &spritelump, &spritelump );
- Q_memcpy( dest, &spritelump, sizeof(DetailSpriteDictLump_t) );
- src += sizeof(DetailSpriteDictLump_t);
- dest += sizeof(DetailSpriteDictLump_t);
- }
-
- // Swap the models
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- DetailObjectLump_t objectlump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &objectlump, src, sizeof(DetailObjectLump_t) );
- g_Swap.SwapFieldsToTargetEndian( &objectlump, &objectlump );
- Q_memcpy( dest, &objectlump, sizeof(DetailObjectLump_t) );
- src += sizeof(DetailObjectLump_t);
- dest += sizeof(DetailObjectLump_t);
- }
- }
- break;
-
- case GAMELUMP_DETAIL_PROP_LIGHTING:
- // Swap the LDR light styles
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
- src += sizeof(DetailObjectDictLump_t) * count;
- dest += sizeof(DetailObjectDictLump_t) * count;
- break;
-
- case GAMELUMP_DETAIL_PROP_LIGHTING_HDR:
- // Swap the HDR light styles
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
- src += sizeof(DetailObjectDictLump_t) * count;
- dest += sizeof(DetailObjectDictLump_t) * count;
- break;
-
- default:
- char idchars[5] = {0};
- Q_memcpy( idchars, &id, 4 );
- Warning( "Unknown game lump '%s' didn't get swapped!\n", idchars );
- memcpy ( dest, src, length);
- break;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Game lump file I/O
-//-----------------------------------------------------------------------------
-void CGameLump::ParseGameLump( dheader_t* pHeader )
-{
- g_GameLumps.DestroyAllGameLumps();
-
- g_Lumps.bLumpParsed[LUMP_GAME_LUMP] = true;
-
- int length = pHeader->lumps[LUMP_GAME_LUMP].filelen;
- int ofs = pHeader->lumps[LUMP_GAME_LUMP].fileofs;
-
- if (length > 0)
- {
- // Read dictionary...
- dgamelumpheader_t* pGameLumpHeader = (dgamelumpheader_t*)((byte *)pHeader + ofs);
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( pGameLumpHeader );
- }
- dgamelump_t* pGameLump = (dgamelump_t*)(pGameLumpHeader + 1);
- for (int i = 0; i < pGameLumpHeader->lumpCount; ++i )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( &pGameLump[i] );
- }
-
- int length = pGameLump[i].filelen;
- GameLumpHandle_t lump = g_GameLumps.CreateGameLump( pGameLump[i].id, length, pGameLump[i].flags, pGameLump[i].version );
- if ( g_bSwapOnLoad )
- {
- SwapGameLump( pGameLump[i].id, pGameLump[i].version, (byte*)g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
- }
- else
- {
- memcpy( g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// String table methods
-//-----------------------------------------------------------------------------
-const char *TexDataStringTable_GetString( int stringID )
-{
- return &g_TexDataStringData[g_TexDataStringTable[stringID]];
-}
-
-int TexDataStringTable_AddOrFindString( const char *pString )
-{
- int i;
- // garymcthack: Make this use an RBTree!
- for( i = 0; i < g_TexDataStringTable.Count(); i++ )
- {
- if( stricmp( pString, &g_TexDataStringData[g_TexDataStringTable[i]] ) == 0 )
- {
- return i;
- }
- }
-
- int len = strlen( pString );
- int outOffset = g_TexDataStringData.AddMultipleToTail( len+1, pString );
- int outIndex = g_TexDataStringTable.AddToTail( outOffset );
- return outIndex;
-}
-
-//-----------------------------------------------------------------------------
-// Adds all game lumps into one big block
-//-----------------------------------------------------------------------------
-
-static void AddGameLumps( )
-{
- // Figure out total size of the client lumps
- int size, clumpCount;
- g_GameLumps.ComputeGameLumpSizeAndCount( size, clumpCount );
-
- // Set up the main lump dictionary entry
- g_Lumps.size[LUMP_GAME_LUMP] = 0; // mark it written
-
- lump_t* lump = &g_pBSPHeader->lumps[LUMP_GAME_LUMP];
-
- lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
- lump->filelen = size;
-
- // write header
- dgamelumpheader_t header;
- header.lumpCount = clumpCount;
- WriteData( &header );
-
- // write dictionary
- dgamelump_t dict;
- int offset = lump->fileofs + sizeof(header) + clumpCount * sizeof(dgamelump_t);
- GameLumpHandle_t h;
- for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
- {
- dict.id = g_GameLumps.GetGameLumpId(h);
- dict.version = g_GameLumps.GetGameLumpVersion(h);
- dict.flags = g_GameLumps.GetGameLumpFlags(h);
- dict.fileofs = offset;
- dict.filelen = g_GameLumps.GameLumpSize( h );
- offset += dict.filelen;
-
- WriteData( &dict );
- }
-
- // write lumps..
- for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
- {
- unsigned int lumpsize = g_GameLumps.GameLumpSize(h);
- if ( g_bSwapOnWrite )
- {
- g_GameLumps.SwapGameLump( g_GameLumps.GetGameLumpId(h), g_GameLumps.GetGameLumpVersion(h), (byte*)g_GameLumps.GetGameLump(h), (byte*)g_GameLumps.GetGameLump(h), lumpsize );
- }
- SafeWrite( g_hBSPFile, g_GameLumps.GetGameLump(h), lumpsize );
- }
-
- // align to doubleword
- AlignFilePosition( g_hBSPFile, 4 );
-}
-
-
-//-----------------------------------------------------------------------------
-// Adds the occluder lump...
-//-----------------------------------------------------------------------------
-static void AddOcclusionLump( )
-{
- g_Lumps.size[LUMP_OCCLUSION] = 0; // mark it written
-
- int nOccluderCount = g_OccluderData.Count();
- int nOccluderPolyDataCount = g_OccluderPolyData.Count();
- int nOccluderVertexIndices = g_OccluderVertexIndices.Count();
-
- int nLumpLength = nOccluderCount * sizeof(doccluderdata_t) +
- nOccluderPolyDataCount * sizeof(doccluderpolydata_t) +
- nOccluderVertexIndices * sizeof(int) +
- 3 * sizeof(int);
-
- lump_t *lump = &g_pBSPHeader->lumps[LUMP_OCCLUSION];
-
- lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
- lump->filelen = nLumpLength;
- lump->version = LUMP_OCCLUSION_VERSION;
- lump->fourCC[0] = ( char )0;
- lump->fourCC[1] = ( char )0;
- lump->fourCC[2] = ( char )0;
- lump->fourCC[3] = ( char )0;
-
- // Data is swapped in place, so the 'Count' variables aren't safe to use after they're written
- WriteData( FIELD_INTEGER, &nOccluderCount );
- WriteData( (doccluderdata_t*)g_OccluderData.Base(), g_OccluderData.Count() );
- WriteData( FIELD_INTEGER, &nOccluderPolyDataCount );
- WriteData( (doccluderpolydata_t*)g_OccluderPolyData.Base(), g_OccluderPolyData.Count() );
- WriteData( FIELD_INTEGER, &nOccluderVertexIndices );
- WriteData( FIELD_INTEGER, (int*)g_OccluderVertexIndices.Base(), g_OccluderVertexIndices.Count() );
-}
-
-
-//-----------------------------------------------------------------------------
-// Loads the occluder lump...
-//-----------------------------------------------------------------------------
-static void UnserializeOcclusionLumpV2( CUtlBuffer &buf )
-{
- int nCount = buf.GetInt();
- if ( nCount )
- {
- g_OccluderData.SetCount( nCount );
- buf.GetObjects( g_OccluderData.Base(), nCount );
- }
-
- nCount = buf.GetInt();
- if ( nCount )
- {
- g_OccluderPolyData.SetCount( nCount );
- buf.GetObjects( g_OccluderPolyData.Base(), nCount );
- }
-
- nCount = buf.GetInt();
- if ( nCount )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( (int*)buf.PeekGet(), (int*)buf.PeekGet(), nCount );
- }
- g_OccluderVertexIndices.SetCount( nCount );
- buf.Get( g_OccluderVertexIndices.Base(), nCount * sizeof(g_OccluderVertexIndices[0]) );
- }
-}
-
-
-static void LoadOcclusionLump()
-{
- g_OccluderData.RemoveAll();
- g_OccluderPolyData.RemoveAll();
- g_OccluderVertexIndices.RemoveAll();
-
- int length, ofs;
-
- g_Lumps.bLumpParsed[LUMP_OCCLUSION] = true;
-
- length = g_pBSPHeader->lumps[LUMP_OCCLUSION].filelen;
- ofs = g_pBSPHeader->lumps[LUMP_OCCLUSION].fileofs;
-
- CUtlBuffer buf( (byte *)g_pBSPHeader + ofs, length, CUtlBuffer::READ_ONLY );
- buf.ActivateByteSwapping( g_bSwapOnLoad );
- switch ( g_pBSPHeader->lumps[LUMP_OCCLUSION].version )
- {
- case 2:
- UnserializeOcclusionLumpV2( buf );
- break;
-
- case 0:
- break;
-
- default:
- Error("Unknown occlusion lump version!\n");
- break;
- }
-}
-
-
-/*
-===============
-CompressVis
-
-===============
-*/
-int CompressVis (byte *vis, byte *dest)
-{
- int j;
- int rep;
- int visrow;
- byte *dest_p;
-
- dest_p = dest;
-// visrow = (r_numvisleafs + 7)>>3;
- visrow = (dvis->numclusters + 7)>>3;
-
- for (j=0 ; j<visrow ; j++)
- {
- *dest_p++ = vis[j];
- if (vis[j])
- continue;
-
- rep = 1;
- for ( j++; j<visrow ; j++)
- if (vis[j] || rep == 255)
- break;
- else
- rep++;
- *dest_p++ = rep;
- j--;
- }
-
- return dest_p - dest;
-}
-
-
-/*
-===================
-DecompressVis
-===================
-*/
-void DecompressVis (byte *in, byte *decompressed)
-{
- int c;
- byte *out;
- int row;
-
-// row = (r_numvisleafs+7)>>3;
- row = (dvis->numclusters+7)>>3;
- out = decompressed;
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- if (!c)
- Error ("DecompressVis: 0 repeat");
- in += 2;
- if ((out - decompressed) + c > row)
- {
- c = row - (out - decompressed);
- Warning( "warning: Vis decompression overrun\n" );
- }
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
-}
-
-//-----------------------------------------------------------------------------
-// Lump-specific swap functions
-//-----------------------------------------------------------------------------
-struct swapcollideheader_t
-{
- DECLARE_BYTESWAP_DATADESC();
- int size;
- int vphysicsID;
- short version;
- short modelType;
-};
-
-struct swapcompactsurfaceheader_t : swapcollideheader_t
-{
- DECLARE_BYTESWAP_DATADESC();
- int surfaceSize;
- Vector dragAxisAreas;
- int axisMapSize;
-};
-
-struct swapmoppsurfaceheader_t : swapcollideheader_t
-{
- DECLARE_BYTESWAP_DATADESC();
- int moppSize;
-};
-
-BEGIN_BYTESWAP_DATADESC( swapcollideheader_t )
- DEFINE_FIELD( size, FIELD_INTEGER ),
- DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
- DEFINE_FIELD( version, FIELD_SHORT ),
- DEFINE_FIELD( modelType, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC_( swapcompactsurfaceheader_t, swapcollideheader_t )
- DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
- DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
- DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC_( swapmoppsurfaceheader_t, swapcollideheader_t )
- DEFINE_FIELD( moppSize, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-
-static void SwapPhyscollideLump( byte *pDestBase, byte *pSrcBase, unsigned int &count )
-{
- IPhysicsCollision *physcollision = NULL;
- CSysModule *pPhysicsModule = g_pFullFileSystem->LoadModule( "vphysics.dll" );
- if ( pPhysicsModule )
- {
- CreateInterfaceFn physicsFactory = Sys_GetFactory( pPhysicsModule );
- if ( physicsFactory )
- {
- physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
- }
- }
-
- if ( !physcollision )
- {
- Warning("!!! WARNING: Can't swap the physcollide lump!\n" );
- return;
- }
-
- // physics data is variable length. The last physmodel is a NULL pointer
- // with modelIndex -1, dataSize -1
- dphysmodel_t *pPhysModel;
- byte *pSrc = pSrcBase;
-
- // first the src chunks have to be aligned properly
- // swap increases size, allocate enough expansion room
- byte *pSrcAlignedBase = (byte*)malloc( 2*count );
- byte *basePtr = pSrcAlignedBase;
- byte *pSrcAligned = pSrcAlignedBase;
-
- do
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pSrcAligned, (dphysmodel_t*)pSrc );
- }
- else
- {
- Q_memcpy( pSrcAligned, pSrc, sizeof(dphysmodel_t) );
- }
- pPhysModel = (dphysmodel_t*)pSrcAligned;
-
- pSrc += sizeof(dphysmodel_t);
- pSrcAligned += sizeof(dphysmodel_t);
-
- if ( pPhysModel->dataSize > 0 )
- {
- // Align the collide headers
- for ( int i = 0; i < pPhysModel->solidCount; ++i )
- {
- // Get data size
- int size;
- Q_memcpy( &size, pSrc, sizeof(int) );
- if ( g_bSwapOnLoad )
- size = SwapLong( size );
-
- // Fixup size
- int padBytes = 0;
- if ( size % 4 != 0 )
- {
- padBytes = ( 4 - size % 4 );
- count += padBytes;
- pPhysModel->dataSize += padBytes;
- }
-
- // Copy data and size into alligned buffer
- int newsize = size + padBytes;
- if ( g_bSwapOnLoad )
- newsize = SwapLong( newsize );
-
- Q_memcpy( pSrcAligned, &newsize, sizeof(int) );
- Q_memcpy( pSrcAligned + sizeof(int), pSrc + sizeof(int), size );
- pSrcAligned += size + padBytes + sizeof(int);
- pSrc += size + sizeof(int);
- }
-
- int padBytes = 0;
- int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
- Q_memcpy( pSrcAligned, pSrc, pPhysModel->keydataSize );
- pSrc += pPhysModel->keydataSize;
- pSrcAligned += pPhysModel->keydataSize;
- if ( dataSize % 4 != 0 )
- {
- // Next chunk will be unaligned
- padBytes = ( 4 - dataSize % 4 );
- pPhysModel->keydataSize += padBytes;
- count += padBytes;
- Q_memset( pSrcAligned, 0, padBytes );
- pSrcAligned += padBytes;
- }
- }
- } while ( pPhysModel->dataSize > 0 );
-
- // Now the data can be swapped properly
- pSrcBase = pSrcAlignedBase;
- pSrc = pSrcBase;
- byte *pDest = pDestBase;
-
- do
- {
- // src headers are in native format
- pPhysModel = (dphysmodel_t*)pSrc;
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pDest, (dphysmodel_t*)pSrc );
- }
- else
- {
- Q_memcpy( pDest, pSrc, sizeof(dphysmodel_t) );
- }
-
- pSrc += sizeof(dphysmodel_t);
- pDest += sizeof(dphysmodel_t);
-
- pSrcBase = pSrc;
- pDestBase = pDest;
-
- if ( pPhysModel->dataSize > 0 )
- {
- vcollide_t collide = {0};
- int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
-
- if ( g_bSwapOnWrite )
- {
- // Load the collide data
- physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, false );
- }
-
- int *offsets = new int[ pPhysModel->solidCount ];
-
- // Swap the collision data headers
- for ( int i = 0; i < pPhysModel->solidCount; ++i )
- {
- int headerSize = 0;
- swapcollideheader_t *baseHdr = (swapcollideheader_t*)pSrc;
- short modelType = baseHdr->modelType;
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( &modelType );
- }
-
- if ( modelType == 0 ) // COLLIDE_POLY
- {
- headerSize = sizeof(swapcompactsurfaceheader_t);
- swapcompactsurfaceheader_t swapHdr;
- Q_memcpy( &swapHdr, pSrc, headerSize );
- g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
- Q_memcpy( pDest, &swapHdr, headerSize );
- }
- else if ( modelType == 1 ) // COLLIDE_MOPP
- {
- // The PC still unserializes these, but we don't support them
- if ( g_bSwapOnWrite )
- {
- collide.solids[i] = NULL;
- }
-
- headerSize = sizeof(swapmoppsurfaceheader_t);
- swapmoppsurfaceheader_t swapHdr;
- Q_memcpy( &swapHdr, pSrc, headerSize );
- g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
- Q_memcpy( pDest, &swapHdr, headerSize );
-
- }
- else
- {
- // Shouldn't happen
- Assert( 0 );
- }
-
- if ( g_bSwapOnLoad )
- {
- // src needs the native header data to load the vcollides
- Q_memcpy( pSrc, pDest, headerSize );
- }
- // HACK: Need either surfaceSize or moppSize - both sit at the same offset in the structure
- swapmoppsurfaceheader_t *hdr = (swapmoppsurfaceheader_t*)pSrc;
- pSrc += hdr->size + sizeof(int);
- pDest += hdr->size + sizeof(int);
- offsets[i] = hdr->size;
- }
-
- pSrc = pSrcBase;
- pDest = pDestBase;
- if ( g_bSwapOnLoad )
- {
- physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, true );
- }
-
- // Write out the ledge tree data
- for ( int i = 0; i < pPhysModel->solidCount; ++i )
- {
- if ( collide.solids[i] )
- {
- // skip over the size member
- pSrc += sizeof(int);
- pDest += sizeof(int);
- int offset = physcollision->CollideWrite( (char*)pDest, collide.solids[i], g_bSwapOnWrite );
- pSrc += offset;
- pDest += offset;
- }
- else
- {
- pSrc += offsets[i] + sizeof(int);
- pDest += offsets[i] + sizeof(int);
- }
- }
-
- // copy the keyvalues data
- Q_memcpy( pDest, pSrc, pPhysModel->keydataSize );
- pDest += pPhysModel->keydataSize;
- pSrc += pPhysModel->keydataSize;
-
- // Free the memory
- physcollision->VCollideUnload( &collide );
- delete [] offsets;
- }
-
- // avoid infinite loop on badly formed file
- if ( (pSrc - basePtr) > count )
- break;
-
- } while ( pPhysModel->dataSize > 0 );
-
- free( pSrcAlignedBase );
-}
-
-
-// UNDONE: This code is not yet tested.
-static void SwapPhysdispLump( byte *pDest, byte *pSrc, int count )
-{
- // the format of this lump is one unsigned short dispCount, then dispCount unsigned shorts of sizes
- // followed by an array of variable length (each element is the length of the corresponding entry in the
- // previous table) byte-stream data structure of the displacement collision models
- // these byte-stream structs are endian-neutral because each element is byte-sized
- unsigned short dispCount = *(unsigned short*)pSrc;
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( &dispCount );
- }
- g_Swap.SwapBufferToTargetEndian( (unsigned short*)pDest, (unsigned short*)pSrc, dispCount + 1 );
-
- const int nBytes = (dispCount + 1) * sizeof( unsigned short );
- pSrc += nBytes;
- pDest += nBytes;
- count -= nBytes;
-
- g_Swap.SwapBufferToTargetEndian( pDest, pSrc, count );
-}
-
-
-static void SwapVisibilityLump( byte *pDest, byte *pSrc, int count )
-{
- int firstInt = *(int*)pSrc;
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( &firstInt );
- }
- int intCt = firstInt * 2 + 1;
- const int hdrSize = intCt * sizeof(int);
- g_Swap.SwapBufferToTargetEndian( (int*)pDest, (int*)pSrc, intCt );
- g_Swap.SwapBufferToTargetEndian( pDest + hdrSize, pSrc + hdrSize, count - hdrSize );
-}
-
-//=============================================================================
-void Lumps_Init( void )
-{
- memset( &g_Lumps, 0, sizeof(g_Lumps) );
-}
-
-int LumpVersion( int lump )
-{
- return g_pBSPHeader->lumps[lump].version;
-}
-
-bool HasLump( int lump )
-{
- return g_pBSPHeader->lumps[lump].filelen > 0;
-}
-
-void ValidateLump( int lump, int length, int size, int forceVersion )
-{
- if ( length % size )
- {
- Error( "ValidateLump: odd size for lump %d", lump );
- }
-
- if ( forceVersion >= 0 && forceVersion != g_pBSPHeader->lumps[lump].version )
- {
- Error( "ValidateLump: old version for lump %d in map!", lump );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Add Lumps of integral types without datadescs
-//-----------------------------------------------------------------------------
-template< class T >
-int CopyLumpInternal( int fieldType, int lump, T *dest, int forceVersion )
-{
- g_Lumps.bLumpParsed[lump] = true;
-
- // Vectors are passed in as floats
- int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
- unsigned int length = g_pBSPHeader->lumps[lump].filelen;
- unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
-
- // count must be of the integral type
- unsigned int count = length / sizeof(T);
-
- ValidateLump( lump, length, fieldSize, forceVersion );
-
- if ( g_bSwapOnLoad )
- {
- switch( lump )
- {
- case LUMP_VISIBILITY:
- SwapVisibilityLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
- break;
-
- case LUMP_PHYSCOLLIDE:
- // SwapPhyscollideLump may change size
- SwapPhyscollideLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
- length = count;
- break;
-
- case LUMP_PHYSDISP:
- SwapPhysdispLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
- break;
-
- default:
- g_Swap.SwapBufferToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
- break;
- }
- }
- else
- {
- memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
- }
-
- // Return actual count of elements
- return length / fieldSize;
-}
-
-template< class T >
-int CopyLump( int fieldType, int lump, T *dest, int forceVersion = -1 )
-{
- return CopyLumpInternal( fieldType, lump, dest, forceVersion );
-}
-
-template< class T >
-void CopyLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- Assert( fieldType != FIELD_VECTOR ); // TODO: Support this if necessary
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-void CopyOptionalLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- // not fatal if not present
- if ( !HasLump( lump ) )
- return;
-
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-int CopyVariableLump( int fieldType, int lump, void **dest, int forceVersion = -1 )
-{
- int length = g_pBSPHeader->lumps[lump].filelen;
- *dest = malloc( length );
-
- return CopyLumpInternal<T>( fieldType, lump, (T*)*dest, forceVersion );
-}
-
-//-----------------------------------------------------------------------------
-// Add Lumps of object types with datadescs
-//-----------------------------------------------------------------------------
-template< class T >
-int CopyLumpInternal( int lump, T *dest, int forceVersion )
-{
- g_Lumps.bLumpParsed[lump] = true;
-
- unsigned int length = g_pBSPHeader->lumps[lump].filelen;
- unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
- unsigned int count = length / sizeof(T);
-
- ValidateLump( lump, length, sizeof(T), forceVersion );
-
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
- }
- else
- {
- memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
- }
-
- return count;
-}
-
-template< class T >
-int CopyLump( int lump, T *dest, int forceVersion = -1 )
-{
- return CopyLumpInternal( lump, dest, forceVersion );
-}
-
-template< class T >
-void CopyLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-void CopyOptionalLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- // not fatal if not present
- if ( !HasLump( lump ) )
- return;
-
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-int CopyVariableLump( int lump, void **dest, int forceVersion = -1 )
-{
- int length = g_pBSPHeader->lumps[lump].filelen;
- *dest = malloc( length );
-
- return CopyLumpInternal<T>( lump, (T*)*dest, forceVersion );
-}
-
-//-----------------------------------------------------------------------------
-// Add/Write unknown lumps
-//-----------------------------------------------------------------------------
-void Lumps_Parse( void )
-{
- int i;
-
- for ( i = 0; i < HEADER_LUMPS; i++ )
- {
- if ( !g_Lumps.bLumpParsed[i] && g_pBSPHeader->lumps[i].filelen )
- {
- g_Lumps.size[i] = CopyVariableLump<byte>( FIELD_CHARACTER, i, &g_Lumps.pLumps[i], -1 );
- Msg( "Reading unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
- }
- }
-}
-
-void Lumps_Write( void )
-{
- int i;
-
- for ( i = 0; i < HEADER_LUMPS; i++ )
- {
- if ( g_Lumps.size[i] )
- {
- Msg( "Writing unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
- AddLump( i, (byte*)g_Lumps.pLumps[i], g_Lumps.size[i] );
- }
- if ( g_Lumps.pLumps[i] )
- {
- free( g_Lumps.pLumps[i] );
- g_Lumps.pLumps[i] = NULL;
- }
- }
-}
-
-int LoadLeafs( void )
-{
-#if defined( BSP_USE_LESS_MEMORY )
- dleafs = (dleaf_t*)malloc( g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
-#endif
-
- switch ( LumpVersion( LUMP_LEAFS ) )
- {
- case 0:
- {
- g_Lumps.bLumpParsed[LUMP_LEAFS] = true;
- int length = g_pBSPHeader->lumps[LUMP_LEAFS].filelen;
- int size = sizeof( dleaf_version_0_t );
- if ( length % size )
- {
- Error( "odd size for LUMP_LEAFS\n" );
- }
- int count = length / size;
-
- void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAFS].fileofs );
- dleaf_version_0_t *pSrc = (dleaf_version_0_t *)pSrcBase;
- dleaf_t *pDst = dleafs;
-
- // version 0 predates HDR, build the LDR
- g_LeafAmbientLightingLDR.SetCount( count );
- g_LeafAmbientIndexLDR.SetCount( count );
-
- dleafambientlighting_t *pDstLeafAmbientLighting = &g_LeafAmbientLightingLDR[0];
- for ( int i = 0; i < count; i++ )
- {
- g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
- g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
-
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( pSrc );
- }
- // pDst is a subset of pSrc;
- *pDst = *( ( dleaf_t * )( void * )pSrc );
- pDstLeafAmbientLighting->cube = pSrc->m_AmbientLighting;
- pDstLeafAmbientLighting->x = pDstLeafAmbientLighting->y = pDstLeafAmbientLighting->z = pDstLeafAmbientLighting->pad = 0;
- pDst++;
- pSrc++;
- pDstLeafAmbientLighting++;
- }
- return count;
- }
-
- case 1:
- return CopyLump( LUMP_LEAFS, dleafs );
-
- default:
- Assert( 0 );
- Error( "Unknown LUMP_LEAFS version\n" );
- return 0;
- }
-}
-
-void LoadLeafAmbientLighting( int numLeafs )
-{
- if ( LumpVersion( LUMP_LEAFS ) == 0 )
- {
- // an older leaf version already built the LDR ambient lighting on load
- return;
- }
-
- // old BSP with ambient, or new BSP with no lighting, convert ambient light to new format or create dummy ambient
- if ( !HasLump( LUMP_LEAF_AMBIENT_INDEX ) )
- {
- // a bunch of legacy maps, have these lumps with garbage versions
- // expect them to be NOT the current version
- if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING) )
- {
- Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
- }
- if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING_HDR) )
- {
- Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
- }
-
- void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].fileofs );
- CompressedLightCube *pSrc = NULL;
- if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING ) )
- {
- pSrc = (CompressedLightCube*)pSrcBase;
- }
- g_LeafAmbientIndexLDR.SetCount( numLeafs );
- g_LeafAmbientLightingLDR.SetCount( numLeafs );
-
- void *pSrcBaseHDR = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].fileofs );
- CompressedLightCube *pSrcHDR = NULL;
- if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
- {
- pSrcHDR = (CompressedLightCube*)pSrcBaseHDR;
- }
- g_LeafAmbientIndexHDR.SetCount( numLeafs );
- g_LeafAmbientLightingHDR.SetCount( numLeafs );
-
- for ( int i = 0; i < numLeafs; i++ )
- {
- g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
- g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
- g_LeafAmbientIndexHDR[i].ambientSampleCount = 1;
- g_LeafAmbientIndexHDR[i].firstAmbientSample = i;
-
- Q_memset( &g_LeafAmbientLightingLDR[i], 0, sizeof(g_LeafAmbientLightingLDR[i]) );
- Q_memset( &g_LeafAmbientLightingHDR[i], 0, sizeof(g_LeafAmbientLightingHDR[i]) );
-
- if ( pSrc )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( &pSrc[i] );
- }
- g_LeafAmbientLightingLDR[i].cube = pSrc[i];
- }
- if ( pSrcHDR )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( &pSrcHDR[i] );
- }
- g_LeafAmbientLightingHDR[i].cube = pSrcHDR[i];
- }
- }
-
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
- }
- else
- {
- CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR );
- CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
- CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR );
- CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
- }
-}
-
-void ValidateHeader( const char *filename, const dheader_t *pHeader )
-{
- if ( pHeader->ident != IDBSPHEADER )
- {
- Error ("%s is not a IBSP file", filename);
- }
- if ( pHeader->version < MINBSPVERSION || pHeader->version > BSPVERSION )
- {
- Error ("%s is version %i, not %i", filename, pHeader->version, BSPVERSION);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Low level BSP opener for external parsing. Parses headers, but nothing else.
-// You must close the BSP, via CloseBSPFile().
-//-----------------------------------------------------------------------------
-void OpenBSPFile( const char *filename )
-{
- Lumps_Init();
-
- // load the file header
- LoadFile( filename, (void **)&g_pBSPHeader );
-
- if ( g_bSwapOnLoad )
- {
- g_Swap.ActivateByteSwapping( true );
- g_Swap.SwapFieldsToTargetEndian( g_pBSPHeader );
- }
-
- ValidateHeader( filename, g_pBSPHeader );
-
- g_MapRevision = g_pBSPHeader->mapRevision;
-}
-
-//-----------------------------------------------------------------------------
-// CloseBSPFile
-//-----------------------------------------------------------------------------
-void CloseBSPFile( void )
-{
- free( g_pBSPHeader );
- g_pBSPHeader = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// LoadBSPFile
-//-----------------------------------------------------------------------------
-void LoadBSPFile( const char *filename )
-{
- OpenBSPFile( filename );
-
- nummodels = CopyLump( LUMP_MODELS, dmodels );
- numvertexes = CopyLump( LUMP_VERTEXES, dvertexes );
- numplanes = CopyLump( LUMP_PLANES, dplanes );
- numleafs = LoadLeafs();
- numnodes = CopyLump( LUMP_NODES, dnodes );
- CopyLump( LUMP_TEXINFO, texinfo );
- numtexdata = CopyLump( LUMP_TEXDATA, dtexdata );
-
- CopyLump( LUMP_DISPINFO, g_dispinfo );
- CopyLump( LUMP_DISP_VERTS, g_DispVerts );
- CopyLump( LUMP_DISP_TRIS, g_DispTris );
- CopyLump( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
- CopyLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
-
- numfaces = CopyLump(LUMP_FACES, dfaces, LUMP_FACES_VERSION);
- if ( HasLump( LUMP_FACES_HDR ) )
- numfaces_hdr = CopyLump( LUMP_FACES_HDR, dfaces_hdr, LUMP_FACES_VERSION );
- else
- numfaces_hdr = 0;
-
- CopyOptionalLump( LUMP_FACEIDS, dfaceids );
-
- g_numprimitives = CopyLump( LUMP_PRIMITIVES, g_primitives );
- g_numprimverts = CopyLump( LUMP_PRIMVERTS, g_primverts );
- g_numprimindices = CopyLump( FIELD_SHORT, LUMP_PRIMINDICES, g_primindices );
- numorigfaces = CopyLump( LUMP_ORIGINALFACES, dorigfaces ); // original faces
- numleaffaces = CopyLump( FIELD_SHORT, LUMP_LEAFFACES, dleaffaces );
- numleafbrushes = CopyLump( FIELD_SHORT, LUMP_LEAFBRUSHES, dleafbrushes );
- numsurfedges = CopyLump( FIELD_INTEGER, LUMP_SURFEDGES, dsurfedges );
- numedges = CopyLump( LUMP_EDGES, dedges );
- numbrushes = CopyLump( LUMP_BRUSHES, dbrushes );
- numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides );
- numareas = CopyLump( LUMP_AREAS, dareas );
- numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals );
-
- visdatasize = CopyLump ( FIELD_CHARACTER, LUMP_VISIBILITY, dvisdata );
- CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
- CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
-
- LoadLeafAmbientLighting( numleafs );
-
- CopyLump( FIELD_CHARACTER, LUMP_ENTITIES, dentdata );
- numworldlightsLDR = CopyLump( LUMP_WORLDLIGHTS, dworldlightsLDR );
- numworldlightsHDR = CopyLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR );
-
- numleafwaterdata = CopyLump( LUMP_LEAFWATERDATA, dleafwaterdata );
- g_PhysCollideSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE, (void**)&g_pPhysCollide );
- g_PhysDispSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSDISP, (void**)&g_pPhysDisp );
-
- g_numvertnormals = CopyLump( FIELD_VECTOR, LUMP_VERTNORMALS, (float*)g_vertnormals );
- g_numvertnormalindices = CopyLump( FIELD_SHORT, LUMP_VERTNORMALINDICES, g_vertnormalindices );
-
- g_nClipPortalVerts = CopyLump( FIELD_VECTOR, LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts );
- g_nCubemapSamples = CopyLump( LUMP_CUBEMAPS, g_CubemapSamples );
-
- CopyLump( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
- CopyLump( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
-
- g_nOverlayCount = CopyLump( LUMP_OVERLAYS, g_Overlays );
- g_nWaterOverlayCount = CopyLump( LUMP_WATEROVERLAYS, g_WaterOverlays );
- CopyLump( LUMP_OVERLAY_FADES, g_OverlayFades );
-
- dflagslump_t flags_lump;
-
- if ( HasLump( LUMP_MAP_FLAGS ) )
- CopyLump ( LUMP_MAP_FLAGS, &flags_lump );
- else
- memset( &flags_lump, 0, sizeof( flags_lump ) ); // default flags to 0
-
- g_LevelFlags = flags_lump.m_LevelFlags;
-
- LoadOcclusionLump();
-
- CopyLump( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater );
-
- /*
- int crap;
- for( crap = 0; crap < g_nBSPStringTable; crap++ )
- {
- Msg( "stringtable %d", ( int )crap );
- Msg( " %d:", ( int )g_BSPStringTable[crap] );
- puts( &g_BSPStringData[g_BSPStringTable[crap]] );
- puts( "\n" );
- }
- */
-
- // Load PAK file lump into appropriate data structure
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
- if ( paksize > 0 )
- {
- GetPakFile()->ActivateByteSwapping( IsX360() );
- GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
- }
- else
- {
- GetPakFile()->Reset();
- }
-
- free( pakbuffer );
-
- g_GameLumps.ParseGameLump( g_pBSPHeader );
-
- // NOTE: Do NOT call CopyLump after Lumps_Parse() it parses all un-Copied lumps
- // parse any additional lumps
- Lumps_Parse();
-
- // everything has been copied out
- CloseBSPFile();
-
- g_Swap.ActivateByteSwapping( false );
-}
-
-//-----------------------------------------------------------------------------
-// Reset any state.
-//-----------------------------------------------------------------------------
-void UnloadBSPFile()
-{
- nummodels = 0;
- numvertexes = 0;
- numplanes = 0;
-
- numleafs = 0;
-#if defined( BSP_USE_LESS_MEMORY )
- if ( dleafs )
- {
- free( dleafs );
- dleafs = NULL;
- }
-#endif
-
- numnodes = 0;
- texinfo.Purge();
- numtexdata = 0;
-
- g_dispinfo.Purge();
- g_DispVerts.Purge();
- g_DispTris.Purge();
-
- g_DispLightmapSamplePositions.Purge();
- g_FaceMacroTextureInfos.Purge();
-
- numfaces = 0;
- numfaces_hdr = 0;
-
- dfaceids.Purge();
-
- g_numprimitives = 0;
- g_numprimverts = 0;
- g_numprimindices = 0;
- numorigfaces = 0;
- numleaffaces = 0;
- numleafbrushes = 0;
- numsurfedges = 0;
- numedges = 0;
- numbrushes = 0;
- numbrushsides = 0;
- numareas = 0;
- numareaportals = 0;
-
- visdatasize = 0;
- dlightdataLDR.Purge();
- dlightdataHDR.Purge();
-
- g_LeafAmbientLightingLDR.Purge();
- g_LeafAmbientLightingHDR.Purge();
- g_LeafAmbientIndexHDR.Purge();
- g_LeafAmbientIndexLDR.Purge();
-
- dentdata.Purge();
- numworldlightsLDR = 0;
- numworldlightsHDR = 0;
-
- numleafwaterdata = 0;
-
- if ( g_pPhysCollide )
- {
- free( g_pPhysCollide );
- g_pPhysCollide = NULL;
- }
- g_PhysCollideSize = 0;
-
- if ( g_pPhysDisp )
- {
- free( g_pPhysDisp );
- g_pPhysDisp = NULL;
- }
- g_PhysDispSize = 0;
-
- g_numvertnormals = 0;
- g_numvertnormalindices = 0;
-
- g_nClipPortalVerts = 0;
- g_nCubemapSamples = 0;
-
- g_TexDataStringData.Purge();
- g_TexDataStringTable.Purge();
-
- g_nOverlayCount = 0;
- g_nWaterOverlayCount = 0;
-
- g_LevelFlags = 0;
-
- g_OccluderData.Purge();
- g_OccluderPolyData.Purge();
- g_OccluderVertexIndices.Purge();
-
- g_GameLumps.DestroyAllGameLumps();
-
- for ( int i = 0; i < HEADER_LUMPS; i++ )
- {
- if ( g_Lumps.pLumps[i] )
- {
- free( g_Lumps.pLumps[i] );
- g_Lumps.pLumps[i] = NULL;
- }
- }
-
- ReleasePakFileLumps();
-}
-
-//-----------------------------------------------------------------------------
-// LoadBSPFileFilesystemOnly
-//-----------------------------------------------------------------------------
-void LoadBSPFile_FileSystemOnly( const char *filename )
-{
- Lumps_Init();
-
- //
- // load the file header
- //
- LoadFile( filename, (void **)&g_pBSPHeader );
-
- ValidateHeader( filename, g_pBSPHeader );
-
- // Load PAK file lump into appropriate data structure
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer, 1 );
- if ( paksize > 0 )
- {
- GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
- }
- else
- {
- GetPakFile()->Reset();
- }
-
- free( pakbuffer );
-
- // everything has been copied out
- free( g_pBSPHeader );
- g_pBSPHeader = NULL;
-}
-
-void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName )
-{
- Lumps_Init();
-
- //
- // load the file header
- //
- LoadFile( pBSPFileName, (void **)&g_pBSPHeader);
-
- ValidateHeader( pBSPFileName, g_pBSPHeader );
-
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
- if ( paksize > 0 )
- {
- FILE *fp;
- fp = fopen( pZipFileName, "wb" );
- if( !fp )
- {
- fprintf( stderr, "can't open %s\n", pZipFileName );
- return;
- }
-
- fwrite( pakbuffer, paksize, 1, fp );
- fclose( fp );
- }
- else
- {
- fprintf( stderr, "zip file is zero length!\n" );
- }
-}
-
-/*
-=============
-LoadBSPFileTexinfo
-
-Only loads the texinfo lump, so qdata can scan for textures
-=============
-*/
-void LoadBSPFileTexinfo( const char *filename )
-{
- FILE *f;
- int length, ofs;
-
- g_pBSPHeader = (dheader_t*)malloc( sizeof(dheader_t) );
-
- f = fopen( filename, "rb" );
- fread( g_pBSPHeader, sizeof(dheader_t), 1, f);
-
- ValidateHeader( filename, g_pBSPHeader );
-
- length = g_pBSPHeader->lumps[LUMP_TEXINFO].filelen;
- ofs = g_pBSPHeader->lumps[LUMP_TEXINFO].fileofs;
-
- int nCount = length / sizeof(texinfo_t);
-
- texinfo.Purge();
- texinfo.AddMultipleToTail( nCount );
-
- fseek( f, ofs, SEEK_SET );
- fread( texinfo.Base(), length, 1, f );
- fclose( f );
-
- // everything has been copied out
- free( g_pBSPHeader );
- g_pBSPHeader = NULL;
-}
-
-static void AddLumpInternal( int lumpnum, void *data, int len, int version )
-{
- lump_t *lump;
-
- g_Lumps.size[lumpnum] = 0; // mark it written
-
- lump = &g_pBSPHeader->lumps[lumpnum];
-
- lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
- lump->filelen = len;
- lump->version = version;
- lump->fourCC[0] = ( char )0;
- lump->fourCC[1] = ( char )0;
- lump->fourCC[2] = ( char )0;
- lump->fourCC[3] = ( char )0;
-
- SafeWrite( g_hBSPFile, data, len );
-
- // pad out to the next dword
- AlignFilePosition( g_hBSPFile, 4 );
-}
-
-template< class T >
-static void SwapInPlace( T *pData, int count )
-{
- if ( !pData )
- return;
-
- // use the datadesc to swap the fields in place
- g_Swap.SwapFieldsToTargetEndian<T>( (T*)pData, pData, count );
-}
-
-template< class T >
-static void SwapInPlace( int fieldType, T *pData, int count )
-{
- if ( !pData )
- return;
-
- // swap the data in place
- g_Swap.SwapBufferToTargetEndian<T>( (T*)pData, (T*)pData, count );
-}
-
-//-----------------------------------------------------------------------------
-// Add raw data chunk to file (not a lump)
-//-----------------------------------------------------------------------------
-template< class T >
-static void WriteData( int fieldType, T *pData, int count )
-{
- if ( g_bSwapOnWrite )
- {
- SwapInPlace( fieldType, pData, count );
- }
- SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
-}
-
-template< class T >
-static void WriteData( T *pData, int count )
-{
- if ( g_bSwapOnWrite )
- {
- SwapInPlace( pData, count );
- }
- SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
-}
-
-//-----------------------------------------------------------------------------
-// Add Lump of object types with datadescs
-//-----------------------------------------------------------------------------
-template< class T >
-static void AddLump( int lumpnum, T *pData, int count, int version )
-{
- AddLumpInternal( lumpnum, pData, count * sizeof(T), version );
-}
-
-template< class T >
-static void AddLump( int lumpnum, CUtlVector<T> &data, int version )
-{
- AddLumpInternal( lumpnum, data.Base(), data.Count() * sizeof(T), version );
-}
-
-/*
-=============
-WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void WriteBSPFile( const char *filename, char *pUnused )
-{
- if ( texinfo.Count() > MAX_MAP_TEXINFO )
- {
- Error( "Map has too many texinfos (has %d, can have at most %d)\n", texinfo.Count(), MAX_MAP_TEXINFO );
- return;
- }
-
- dheader_t outHeader;
- g_pBSPHeader = &outHeader;
- memset( g_pBSPHeader, 0, sizeof( dheader_t ) );
-
- g_pBSPHeader->ident = IDBSPHEADER;
- g_pBSPHeader->version = BSPVERSION;
- g_pBSPHeader->mapRevision = g_MapRevision;
-
- g_hBSPFile = SafeOpenWrite( filename );
- WriteData( g_pBSPHeader ); // overwritten later
-
- AddLump( LUMP_PLANES, dplanes, numplanes );
- AddLump( LUMP_LEAFS, dleafs, numleafs, LUMP_LEAFS_VERSION );
- AddLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
- AddLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
- AddLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
- AddLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
-
- AddLump( LUMP_VERTEXES, dvertexes, numvertexes );
- AddLump( LUMP_NODES, dnodes, numnodes );
- AddLump( LUMP_TEXINFO, texinfo );
- AddLump( LUMP_TEXDATA, dtexdata, numtexdata );
-
- AddLump( LUMP_DISPINFO, g_dispinfo );
- AddLump( LUMP_DISP_VERTS, g_DispVerts );
- AddLump( LUMP_DISP_TRIS, g_DispTris );
- AddLump( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
- AddLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
-
- AddLump( LUMP_PRIMITIVES, g_primitives, g_numprimitives );
- AddLump( LUMP_PRIMVERTS, g_primverts, g_numprimverts );
- AddLump( LUMP_PRIMINDICES, g_primindices, g_numprimindices );
- AddLump( LUMP_FACES, dfaces, numfaces, LUMP_FACES_VERSION );
- if (numfaces_hdr)
- AddLump( LUMP_FACES_HDR, dfaces_hdr, numfaces_hdr, LUMP_FACES_VERSION );
- AddLump ( LUMP_FACEIDS, dfaceids, numfaceids );
-
- AddLump( LUMP_ORIGINALFACES, dorigfaces, numorigfaces ); // original faces lump
- AddLump( LUMP_BRUSHES, dbrushes, numbrushes );
- AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides );
- AddLump( LUMP_LEAFFACES, dleaffaces, numleaffaces );
- AddLump( LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes );
- AddLump( LUMP_SURFEDGES, dsurfedges, numsurfedges );
- AddLump( LUMP_EDGES, dedges, numedges );
- AddLump( LUMP_MODELS, dmodels, nummodels );
- AddLump( LUMP_AREAS, dareas, numareas );
- AddLump( LUMP_AREAPORTALS, dareaportals, numareaportals );
-
- AddLump( LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
- AddLump( LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
- AddLump( LUMP_VISIBILITY, dvisdata, visdatasize );
- AddLump( LUMP_ENTITIES, dentdata );
- AddLump( LUMP_WORLDLIGHTS, dworldlightsLDR, numworldlightsLDR );
- AddLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR, numworldlightsHDR );
- AddLump( LUMP_LEAFWATERDATA, dleafwaterdata, numleafwaterdata );
-
- AddOcclusionLump();
-
- dflagslump_t flags_lump;
- flags_lump.m_LevelFlags = g_LevelFlags;
- AddLump( LUMP_MAP_FLAGS, &flags_lump, 1 );
-
- // NOTE: This is just for debugging, so it is disabled in release maps
-#if 0
- // add the vis portals to the BSP for visualization
- AddLump( LUMP_PORTALS, dportals, numportals );
- AddLump( LUMP_CLUSTERS, dclusters, numclusters );
- AddLump( LUMP_PORTALVERTS, dportalverts, numportalverts );
- AddLump( LUMP_CLUSTERPORTALS, dclusterportals, numclusterportals );
-#endif
-
- AddLump( LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts, g_nClipPortalVerts * 3 );
- AddLump( LUMP_CUBEMAPS, g_CubemapSamples, g_nCubemapSamples );
- AddLump( LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
- AddLump( LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
- AddLump( LUMP_OVERLAYS, g_Overlays, g_nOverlayCount );
- AddLump( LUMP_WATEROVERLAYS, g_WaterOverlays, g_nWaterOverlayCount );
- AddLump( LUMP_OVERLAY_FADES, g_OverlayFades, g_nOverlayCount );
-
- if ( g_pPhysCollide )
- {
- AddLump( LUMP_PHYSCOLLIDE, g_pPhysCollide, g_PhysCollideSize );
- }
-
- if ( g_pPhysDisp )
- {
- AddLump ( LUMP_PHYSDISP, g_pPhysDisp, g_PhysDispSize );
- }
-
- AddLump( LUMP_VERTNORMALS, (float*)g_vertnormals, g_numvertnormals * 3 );
- AddLump( LUMP_VERTNORMALINDICES, g_vertnormalindices, g_numvertnormalindices );
-
- AddLump( LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater, numleafs );
-
- AddGameLumps();
-
- // Write pakfile lump to disk
- WritePakFileLump();
-
- // NOTE: Do NOT call AddLump after Lumps_Write() it writes all un-Added lumps
- // write any additional lumps
- Lumps_Write();
-
- g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
- WriteData( g_pBSPHeader );
- g_pFileSystem->Close( g_hBSPFile );
-}
-
-// Generate the next clear lump filename for the bsp file
-bool GenerateNextLumpFileName( const char *bspfilename, char *lumpfilename, int buffsize )
-{
- for (int i = 0; i < MAX_LUMPFILES; i++)
- {
- GenerateLumpFileName( bspfilename, lumpfilename, buffsize, i );
-
- if ( !g_pFileSystem->FileExists( lumpfilename ) )
- return true;
- }
-
- return false;
-}
-
-void WriteLumpToFile( char *filename, int lump )
-{
- if ( !HasLump(lump) )
- return;
-
- char lumppre[MAX_PATH];
- if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
- {
- Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
- return;
- }
-
- // Open the file
- FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
- if ( !lumpfile )
- {
- Error ("Error opening %s! (Check for write enable)\n",filename);
- return;
- }
-
- int ofs = g_pBSPHeader->lumps[lump].fileofs;
- int length = g_pBSPHeader->lumps[lump].filelen;
-
- // Write the header
- lumpfileheader_t lumpHeader;
- lumpHeader.lumpID = lump;
- lumpHeader.lumpVersion = LumpVersion(lump);
- lumpHeader.lumpLength = length;
- lumpHeader.mapRevision = LittleLong( g_MapRevision );
- lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
- SafeWrite (lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
-
- // Write the lump
- SafeWrite (lumpfile, (byte *)g_pBSPHeader + ofs, length);
-}
-
-void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen )
-{
- char lumppre[MAX_PATH];
- if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
- {
- Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
- return;
- }
-
- // Open the file
- FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
- if ( !lumpfile )
- {
- Error ("Error opening %s! (Check for write enable)\n",filename);
- return;
- }
-
- // Write the header
- lumpfileheader_t lumpHeader;
- lumpHeader.lumpID = lump;
- lumpHeader.lumpVersion = nLumpVersion;
- lumpHeader.lumpLength = nBufLen;
- lumpHeader.mapRevision = LittleLong( g_MapRevision );
- lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
- SafeWrite( lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
-
- // Write the lump
- SafeWrite( lumpfile, pBuffer, nBufLen );
-
- g_pFileSystem->Close( lumpfile );
-}
-
-
-//============================================================================
-#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
-#define ENTRYSIZE(a) (sizeof(*(a)))
-
-int ArrayUsage( const char *szItem, int items, int maxitems, int itemsize )
-{
- float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
-
- Msg("%-17.17s %8i/%-8i %8i/%-8i (%4.1f%%) ",
- szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
- if ( percentage > 80.0 )
- Msg( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- Msg( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- Msg( "SIZE OVERFLOW!!!\n" );
- else
- Msg( "\n" );
- return items * itemsize;
-}
-
-int GlobUsage( const char *szItem, int itemstorage, int maxstorage )
-{
- float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
- Msg("%-17.17s [variable] %8i/%-8i (%4.1f%%) ",
- szItem, itemstorage, maxstorage, percentage );
- if ( percentage > 80.0 )
- Msg( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- Msg( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- Msg( "SIZE OVERFLOW!!!\n" );
- else
- Msg( "\n" );
- return itemstorage;
-}
-
-/*
-=============
-PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void PrintBSPFileSizes (void)
-{
- int totalmemory = 0;
-
-// if (!num_entities)
-// ParseEntities ();
-
- Msg("\n");
- Msg( "%-17s %16s %16s %9s \n", "Object names", "Objects/Maxobjs", "Memory / Maxmem", "Fullness" );
- Msg( "%-17s %16s %16s %9s \n", "------------", "---------------", "---------------", "--------" );
-
- totalmemory += ArrayUsage( "models", nummodels, ENTRIES(dmodels), ENTRYSIZE(dmodels) );
- totalmemory += ArrayUsage( "brushes", numbrushes, ENTRIES(dbrushes), ENTRYSIZE(dbrushes) );
- totalmemory += ArrayUsage( "brushsides", numbrushsides, ENTRIES(dbrushsides), ENTRYSIZE(dbrushsides) );
- totalmemory += ArrayUsage( "planes", numplanes, ENTRIES(dplanes), ENTRYSIZE(dplanes) );
- totalmemory += ArrayUsage( "vertexes", numvertexes, ENTRIES(dvertexes), ENTRYSIZE(dvertexes) );
- totalmemory += ArrayUsage( "nodes", numnodes, ENTRIES(dnodes), ENTRYSIZE(dnodes) );
- totalmemory += ArrayUsage( "texinfos", texinfo.Count(),MAX_MAP_TEXINFO, sizeof(texinfo_t) );
- totalmemory += ArrayUsage( "texdata", numtexdata, ENTRIES(dtexdata), ENTRYSIZE(dtexdata) );
-
- totalmemory += ArrayUsage( "dispinfos", g_dispinfo.Count(), 0, sizeof( ddispinfo_t ) );
- totalmemory += ArrayUsage( "disp_verts", g_DispVerts.Count(), 0, sizeof( g_DispVerts[0] ) );
- totalmemory += ArrayUsage( "disp_tris", g_DispTris.Count(), 0, sizeof( g_DispTris[0] ) );
- totalmemory += ArrayUsage( "disp_lmsamples",g_DispLightmapSamplePositions.Count(),0,sizeof( g_DispLightmapSamplePositions[0] ) );
-
- totalmemory += ArrayUsage( "faces", numfaces, ENTRIES(dfaces), ENTRYSIZE(dfaces) );
- totalmemory += ArrayUsage( "hdr faces", numfaces_hdr, ENTRIES(dfaces_hdr), ENTRYSIZE(dfaces_hdr) );
- totalmemory += ArrayUsage( "origfaces", numorigfaces, ENTRIES(dorigfaces), ENTRYSIZE(dorigfaces) ); // original faces
- totalmemory += ArrayUsage( "leaves", numleafs, ENTRIES(dleafs), ENTRYSIZE(dleafs) );
- totalmemory += ArrayUsage( "leaffaces", numleaffaces, ENTRIES(dleaffaces), ENTRYSIZE(dleaffaces) );
- totalmemory += ArrayUsage( "leafbrushes", numleafbrushes, ENTRIES(dleafbrushes), ENTRYSIZE(dleafbrushes) );
- totalmemory += ArrayUsage( "areas", numareas, ENTRIES(dareas), ENTRYSIZE(dareas) );
- totalmemory += ArrayUsage( "surfedges", numsurfedges, ENTRIES(dsurfedges), ENTRYSIZE(dsurfedges) );
- totalmemory += ArrayUsage( "edges", numedges, ENTRIES(dedges), ENTRYSIZE(dedges) );
- totalmemory += ArrayUsage( "LDR worldlights", numworldlightsLDR, ENTRIES(dworldlightsLDR), ENTRYSIZE(dworldlightsLDR) );
- totalmemory += ArrayUsage( "HDR worldlights", numworldlightsHDR, ENTRIES(dworldlightsHDR), ENTRYSIZE(dworldlightsHDR) );
-
- totalmemory += ArrayUsage( "leafwaterdata", numleafwaterdata,ENTRIES(dleafwaterdata), ENTRYSIZE(dleafwaterdata) );
- totalmemory += ArrayUsage( "waterstrips", g_numprimitives,ENTRIES(g_primitives), ENTRYSIZE(g_primitives) );
- totalmemory += ArrayUsage( "waterverts", g_numprimverts, ENTRIES(g_primverts), ENTRYSIZE(g_primverts) );
- totalmemory += ArrayUsage( "waterindices", g_numprimindices,ENTRIES(g_primindices),ENTRYSIZE(g_primindices) );
- totalmemory += ArrayUsage( "cubemapsamples", g_nCubemapSamples,ENTRIES(g_CubemapSamples),ENTRYSIZE(g_CubemapSamples) );
- totalmemory += ArrayUsage( "overlays", g_nOverlayCount, ENTRIES(g_Overlays), ENTRYSIZE(g_Overlays) );
-
- totalmemory += GlobUsage( "LDR lightdata", dlightdataLDR.Count(), 0 );
- totalmemory += GlobUsage( "HDR lightdata", dlightdataHDR.Count(), 0 );
- totalmemory += GlobUsage( "visdata", visdatasize, sizeof(dvisdata) );
- totalmemory += GlobUsage( "entdata", dentdata.Count(), 384*1024 ); // goal is <384K
-
- totalmemory += ArrayUsage( "LDR ambient table", g_LeafAmbientIndexLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexLDR[0] ) );
- totalmemory += ArrayUsage( "HDR ambient table", g_LeafAmbientIndexHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexHDR[0] ) );
- totalmemory += ArrayUsage( "LDR leaf ambient lighting", g_LeafAmbientLightingLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingLDR[0] ) );
- totalmemory += ArrayUsage( "HDR leaf ambient lighting", g_LeafAmbientLightingHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingHDR[0] ) );
-
- totalmemory += ArrayUsage( "occluders", g_OccluderData.Count(), 0, sizeof( g_OccluderData[0] ) );
- totalmemory += ArrayUsage( "occluder polygons", g_OccluderPolyData.Count(), 0, sizeof( g_OccluderPolyData[0] ) );
- totalmemory += ArrayUsage( "occluder vert ind",g_OccluderVertexIndices.Count(),0, sizeof( g_OccluderVertexIndices[0] ) );
-
- GameLumpHandle_t h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "detail props", 1, g_GameLumps.GameLumpSize(h) );
- h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
- h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING_HDR );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "HDR dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
- h = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "static props", 1, g_GameLumps.GameLumpSize(h) );
-
- totalmemory += GlobUsage( "pakfile", GetPakFile()->EstimateSize(), 0 );
- // HACKHACK: Set physics limit at 4MB, in reality this is totally dynamic
- totalmemory += GlobUsage( "physics", g_PhysCollideSize, 4*1024*1024 );
- totalmemory += GlobUsage( "physics terrain", g_PhysDispSize, 1*1024*1024 );
-
- Msg( "\nLevel flags = %x\n", g_LevelFlags );
-
- Msg( "\n" );
-
- int triangleCount = 0;
-
- for ( int i = 0; i < numfaces; i++ )
- {
- // face tris = numedges - 2
- triangleCount += dfaces[i].numedges - 2;
- }
- Msg("Total triangle count: %d\n", triangleCount );
-
- // UNDONE:
- // areaportals, portals, texdata, clusters, worldlights, portalverts
-}
-
-/*
-=============
-PrintBSPPackDirectory
-
-Dumps a list of files stored in the bsp pack.
-=============
-*/
-void PrintBSPPackDirectory( void )
-{
- GetPakFile()->PrintDirectory();
-}
-
-
-//============================================
-
-int num_entities;
-entity_t entities[MAX_MAP_ENTITIES];
-
-void StripTrailing (char *e)
-{
- char *s;
-
- s = e + strlen(e)-1;
- while (s >= e && *s <= 32)
- {
- *s = 0;
- s--;
- }
-}
-
-/*
-=================
-ParseEpair
-=================
-*/
-epair_t *ParseEpair (void)
-{
- epair_t *e;
-
- e = (epair_t*)malloc (sizeof(epair_t));
- memset (e, 0, sizeof(epair_t));
-
- if (strlen(token) >= MAX_KEY-1)
- Error ("ParseEpar: token too long");
- e->key = copystring(token);
-
- GetToken (false);
- if (strlen(token) >= MAX_VALUE-1)
- Error ("ParseEpar: token too long");
- e->value = copystring(token);
-
- // strip trailing spaces
- StripTrailing (e->key);
- StripTrailing (e->value);
-
- return e;
-}
-
-
-/*
-================
-ParseEntity
-================
-*/
-qboolean ParseEntity (void)
-{
- epair_t *e;
- entity_t *mapent;
-
- if (!GetToken (true))
- return false;
-
- if (Q_stricmp (token, "{") )
- Error ("ParseEntity: { not found");
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- mapent = &entities[num_entities];
- num_entities++;
-
- do
- {
- if (!GetToken (true))
- Error ("ParseEntity: EOF without closing brace");
- if (!Q_stricmp (token, "}") )
- break;
- e = ParseEpair ();
- e->next = mapent->epairs;
- mapent->epairs = e;
- } while (1);
-
- return true;
-}
-
-/*
-================
-ParseEntities
-
-Parses the dentdata string into entities
-================
-*/
-void ParseEntities (void)
-{
- num_entities = 0;
- ParseFromMemory (dentdata.Base(), dentdata.Count());
-
- while (ParseEntity ())
- {
- }
-}
-
-
-/*
-================
-UnparseEntities
-
-Generates the dentdata string from all the entities
-================
-*/
-void UnparseEntities (void)
-{
- epair_t *ep;
- char line[2048];
- int i;
- char key[1024], value[1024];
-
- CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
- buffer.EnsureCapacity( 256 * 1024 );
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- buffer.PutString( "{\n" );
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- strcpy (key, ep->key);
- StripTrailing (key);
- strcpy (value, ep->value);
- StripTrailing (value);
-
- sprintf(line, "\"%s\" \"%s\"\n", key, value);
- buffer.PutString( line );
- }
- buffer.PutString("}\n");
- }
- int entdatasize = buffer.TellPut()+1;
-
- dentdata.SetSize( entdatasize );
- memcpy( dentdata.Base(), buffer.Base(), entdatasize-1 );
- dentdata[entdatasize-1] = 0;
-}
-
-void PrintEntity (entity_t *ent)
-{
- epair_t *ep;
-
- Msg ("------- entity %p -------\n", ent);
- for (ep=ent->epairs ; ep ; ep=ep->next)
- {
- Msg ("%s = %s\n", ep->key, ep->value);
- }
-
-}
-
-void SetKeyValue(entity_t *ent, const char *key, const char *value)
-{
- epair_t *ep;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!Q_stricmp (ep->key, key) )
- {
- free (ep->value);
- ep->value = copystring(value);
- return;
- }
- ep = (epair_t*)malloc (sizeof(*ep));
- ep->next = ent->epairs;
- ent->epairs = ep;
- ep->key = copystring(key);
- ep->value = copystring(value);
-}
-
-char *ValueForKey (entity_t *ent, char *key)
-{
- for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
- if (!Q_stricmp (ep->key, key) )
- return ep->value;
- return "";
-}
-
-vec_t FloatForKey (entity_t *ent, char *key)
-{
- char *k = ValueForKey (ent, key);
- return atof(k);
-}
-
-vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value)
-{
- for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
- if (!Q_stricmp (ep->key, key) )
- return atof( ep->value );
- return default_value;
-}
-
-
-
-int IntForKey (entity_t *ent, char *key)
-{
- char *k = ValueForKey (ent, key);
- return atol(k);
-}
-
-int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault )
-{
- char *k = ValueForKey (ent, key);
- if ( !k[0] )
- return nDefault;
- return atol(k);
-}
-
-void GetVectorForKey (entity_t *ent, char *key, Vector& vec)
-{
-
- char *k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- double v1, v2, v3;
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- vec[0] = v1;
- vec[1] = v2;
- vec[2] = v3;
-}
-
-void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec)
-{
- double v1, v2;
-
- char *k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = 0;
- sscanf (k, "%lf %lf", &v1, &v2);
- vec[0] = v1;
- vec[1] = v2;
-}
-
-void GetAnglesForKey (entity_t *ent, char *key, QAngle& angle)
-{
- char *k;
- double v1, v2, v3;
-
- k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- angle[0] = v1;
- angle[1] = v2;
- angle[2] = v3;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void BuildFaceCalcWindingData( dface_t *pFace, int *points )
-{
- for( int i = 0; i < pFace->numedges; i++ )
- {
- int eIndex = dsurfedges[pFace->firstedge+i];
- if( eIndex < 0 )
- {
- points[i] = dedges[-eIndex].v[1];
- }
- else
- {
- points[i] = dedges[eIndex].v[0];
- }
- }
-}
-
-
-void TriStripToTriList(
- unsigned short const *pTriStripIndices,
- int nTriStripIndices,
- unsigned short **pTriListIndices,
- int *pnTriListIndices )
-{
- int nMaxTriListIndices = (nTriStripIndices - 2) * 3;
- *pTriListIndices = new unsigned short[ nMaxTriListIndices ];
- *pnTriListIndices = 0;
-
- for( int i=0; i < nTriStripIndices - 2; i++ )
- {
- if( pTriStripIndices[i] == pTriStripIndices[i+1] ||
- pTriStripIndices[i] == pTriStripIndices[i+2] ||
- pTriStripIndices[i+1] == pTriStripIndices[i+2] )
- {
- }
- else
- {
- // Flip odd numbered tris..
- if( i & 1 )
- {
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
- }
- else
- {
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
- }
- }
- }
-}
-
-
-void CalcTextureCoordsAtPoints(
- float const texelsPerWorldUnits[2][4],
- int const subtractOffset[2],
- Vector const *pPoints,
- int const nPoints,
- Vector2D *pCoords )
-{
- for( int i=0; i < nPoints; i++ )
- {
- for( int iCoord=0; iCoord < 2; iCoord++ )
- {
- float *pDestCoord = &pCoords[i][iCoord];
-
- *pDestCoord = 0;
- for( int iDot=0; iDot < 3; iDot++ )
- *pDestCoord += pPoints[i][iDot] * texelsPerWorldUnits[iCoord][iDot];
-
- *pDestCoord += texelsPerWorldUnits[iCoord][3];
- *pDestCoord -= subtractOffset[iCoord];
- }
- }
-}
-
-
-/*
-================
-CalcFaceExtents
-
-Fills in s->texmins[] and s->texsize[]
-================
-*/
-void CalcFaceExtents(dface_t *s, int lightmapTextureMinsInLuxels[2], int lightmapTextureSizeInLuxels[2])
-{
- vec_t mins[2], maxs[2], val=0;
- int i,j, e=0;
- dvertex_t *v=NULL;
- texinfo_t *tex=NULL;
-
- mins[0] = mins[1] = 1e24;
- maxs[0] = maxs[1] = -1e24;
-
- tex = &texinfo[s->texinfo];
-
- for (i=0 ; i<s->numedges ; i++)
- {
- e = dsurfedges[s->firstedge+i];
- if (e >= 0)
- v = dvertexes + dedges[e].v[0];
- else
- v = dvertexes + dedges[-e].v[1];
-
- for (j=0 ; j<2 ; j++)
- {
- val = v->point[0] * tex->lightmapVecsLuxelsPerWorldUnits[j][0] +
- v->point[1] * tex->lightmapVecsLuxelsPerWorldUnits[j][1] +
- v->point[2] * tex->lightmapVecsLuxelsPerWorldUnits[j][2] +
- tex->lightmapVecsLuxelsPerWorldUnits[j][3];
- if (val < mins[j])
- mins[j] = val;
- if (val > maxs[j])
- maxs[j] = val;
- }
- }
-
- int nMaxLightmapDim = (s->dispinfo == -1) ? MAX_LIGHTMAP_DIM_WITHOUT_BORDER : MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER;
- for (i=0 ; i<2 ; i++)
- {
- mins[i] = ( float )floor( mins[i] );
- maxs[i] = ( float )ceil( maxs[i] );
-
- lightmapTextureMinsInLuxels[i] = ( int )mins[i];
- lightmapTextureSizeInLuxels[i] = ( int )( maxs[i] - mins[i] );
- if( lightmapTextureSizeInLuxels[i] > nMaxLightmapDim + 1 )
- {
- Vector point = vec3_origin;
- for (int j=0 ; j<s->numedges ; j++)
- {
- e = dsurfedges[s->firstedge+j];
- v = (e<0)?dvertexes + dedges[-e].v[1] : dvertexes + dedges[e].v[0];
- point += v->point;
- Warning( "Bad surface extents point: %f %f %f\n", v->point.x, v->point.y, v->point.z );
- }
- point *= 1.0f/s->numedges;
- Error( "Bad surface extents - surface is too big to have a lightmap\n\tmaterial %s around point (%.1f %.1f %.1f)\n\t(dimension: %d, %d>%d)\n",
- TexDataStringTable_GetString( dtexdata[texinfo[s->texinfo].texdata].nameStringTableID ),
- point.x, point.y, point.z,
- ( int )i,
- ( int )lightmapTextureSizeInLuxels[i],
- ( int )( nMaxLightmapDim + 1 )
- );
- }
- }
-}
-
-
-void UpdateAllFaceLightmapExtents()
-{
- for( int i=0; i < numfaces; i++ )
- {
- dface_t *pFace = &dfaces[i];
-
- if ( texinfo[pFace->texinfo].flags & (SURF_SKY|SURF_NOLIGHT) )
- continue; // non-lit texture
-
- CalcFaceExtents( pFace, pFace->m_LightmapTextureMinsInLuxels, pFace->m_LightmapTextureSizeInLuxels );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//
-// Helper class to iterate over leaves, used by tools
-//
-//-----------------------------------------------------------------------------
-
-#define TEST_EPSILON (0.03125)
-
-
-class CToolBSPTree : public ISpatialQuery
-{
-public:
- // Returns the number of leaves
- int LeafCount() const;
-
- // Enumerates the leaves along a ray, box, etc.
- bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context );
- bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context );
- bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
- bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
-};
-
-
-//-----------------------------------------------------------------------------
-// Returns the number of leaves
-//-----------------------------------------------------------------------------
-
-int CToolBSPTree::LeafCount() const
-{
- return numleafs;
-}
-
-
-//-----------------------------------------------------------------------------
-// Enumerates the leaves at a point
-//-----------------------------------------------------------------------------
-
-bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt,
- ISpatialLeafEnumerator* pEnum, int context )
-{
- int node = 0;
- while( node >= 0 )
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if (DotProduct( pPlane->normal, pt ) <= pPlane->dist)
- {
- node = pNode->children[1];
- }
- else
- {
- node = pNode->children[0];
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Enumerates the leaves in a box
-//-----------------------------------------------------------------------------
-
-static bool EnumerateLeavesInBox_R( int node, Vector const& mins,
- Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context )
-{
- Vector cornermin, cornermax;
-
- while( node >= 0 )
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- // Arbitrary split plane here
- for (int i = 0; i < 3; ++i)
- {
- if (pPlane->normal[i] >= 0)
- {
- cornermin[i] = mins[i];
- cornermax[i] = maxs[i];
- }
- else
- {
- cornermin[i] = maxs[i];
- cornermax[i] = mins[i];
- }
- }
-
- if ( (DotProduct( pPlane->normal, cornermax ) - pPlane->dist) <= -TEST_EPSILON )
- {
- node = pNode->children[1];
- }
- else if ( (DotProduct( pPlane->normal, cornermin ) - pPlane->dist) >= TEST_EPSILON )
- {
- node = pNode->children[0];
- }
- else
- {
- if (!EnumerateLeavesInBox_R( pNode->children[0], mins, maxs, pEnum, context ))
- {
- return false;
- }
-
- return EnumerateLeavesInBox_R( pNode->children[1], mins, maxs, pEnum, context );
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs,
- ISpatialLeafEnumerator* pEnum, int context )
-{
- return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
-}
-
-//-----------------------------------------------------------------------------
-// Enumerate leaves within a sphere
-//-----------------------------------------------------------------------------
-
-static bool EnumerateLeavesInSphere_R( int node, Vector const& origin,
- float radius, ISpatialLeafEnumerator* pEnum, int context )
-{
- while( node >= 0 )
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if (DotProduct( pPlane->normal, origin ) + radius - pPlane->dist <= -TEST_EPSILON )
- {
- node = pNode->children[1];
- }
- else if (DotProduct( pPlane->normal, origin ) - radius - pPlane->dist >= TEST_EPSILON )
- {
- node = pNode->children[0];
- }
- else
- {
- if (!EnumerateLeavesInSphere_R( pNode->children[0],
- origin, radius, pEnum, context ))
- {
- return false;
- }
-
- return EnumerateLeavesInSphere_R( pNode->children[1],
- origin, radius, pEnum, context );
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context )
-{
- return EnumerateLeavesInSphere_R( 0, center, radius, pEnum, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Enumerate leaves along a ray
-//-----------------------------------------------------------------------------
-
-static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray,
- Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, int context )
-{
- float front,back;
-
- while (node >= 0)
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if ( pPlane->type <= PLANE_Z )
- {
- front = start[pPlane->type] - pPlane->dist;
- back = end[pPlane->type] - pPlane->dist;
- }
- else
- {
- front = DotProduct(start, pPlane->normal) - pPlane->dist;
- back = DotProduct(end, pPlane->normal) - pPlane->dist;
- }
-
- if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
- {
- node = pNode->children[1];
- }
- else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
- {
- node = pNode->children[0];
- }
- else
- {
- // test the front side first
- bool side = front < 0;
-
- // Compute intersection point based on the original ray
- float splitfrac;
- float denom = DotProduct( ray.m_Delta, pPlane->normal );
- if ( denom == 0.0f )
- {
- splitfrac = 1.0f;
- }
- else
- {
- splitfrac = ( pPlane->dist - DotProduct( ray.m_Start, pPlane->normal ) ) / denom;
- if (splitfrac < 0)
- splitfrac = 0;
- else if (splitfrac > 1)
- splitfrac = 1;
- }
-
- // Compute the split point
- Vector split;
- VectorMA( ray.m_Start, splitfrac, ray.m_Delta, split );
-
- bool r = EnumerateLeavesAlongRay_R (pNode->children[side], ray, start, split, pEnum, context );
- if (!r)
- return r;
- return EnumerateLeavesAlongRay_R (pNode->children[!side], ray, split, end, pEnum, context);
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
-{
- if (!ray.m_IsSwept)
- {
- Vector mins, maxs;
- VectorAdd( ray.m_Start, ray.m_Extents, maxs );
- VectorSubtract( ray.m_Start, ray.m_Extents, mins );
-
- return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
- }
-
- // FIXME: Extruded ray not implemented yet
- Assert( ray.m_IsRay );
-
- Vector end;
- VectorAdd( ray.m_Start, ray.m_Delta, end );
- return EnumerateLeavesAlongRay_R( 0, ray, ray.m_Start, end, pEnum, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Singleton accessor
-//-----------------------------------------------------------------------------
-
-ISpatialQuery* ToolBSPTree()
-{
- static CToolBSPTree s_ToolBSPTree;
- return &s_ToolBSPTree;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Enumerates nodes in front to back order...
-//-----------------------------------------------------------------------------
-
-// FIXME: Do we want this in the IBSPTree interface?
-
-static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, float end,
- IBSPNodeEnumerator* pEnum, int context )
-{
- float front, back;
- float startDotN, deltaDotN;
-
- while (node >= 0)
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if ( pPlane->type <= PLANE_Z )
- {
- startDotN = ray.m_Start[pPlane->type];
- deltaDotN = ray.m_Delta[pPlane->type];
- }
- else
- {
- startDotN = DotProduct( ray.m_Start, pPlane->normal );
- deltaDotN = DotProduct( ray.m_Delta, pPlane->normal );
- }
-
- front = startDotN + start * deltaDotN - pPlane->dist;
- back = startDotN + end * deltaDotN - pPlane->dist;
-
- if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
- {
- node = pNode->children[1];
- }
- else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
- {
- node = pNode->children[0];
- }
- else
- {
- // test the front side first
- bool side = front < 0;
-
- // Compute intersection point based on the original ray
- float splitfrac;
- if ( deltaDotN == 0.0f )
- {
- splitfrac = 1.0f;
- }
- else
- {
- splitfrac = ( pPlane->dist - startDotN ) / deltaDotN;
- if (splitfrac < 0.0f)
- splitfrac = 0.0f;
- else if (splitfrac > 1.0f)
- splitfrac = 1.0f;
- }
-
- bool r = EnumerateNodesAlongRay_R (pNode->children[side], ray, start, splitfrac, pEnum, context );
- if (!r)
- return r;
-
- // Visit the node...
- if (!pEnum->EnumerateNode( node, ray, splitfrac, context ))
- return false;
-
- return EnumerateNodesAlongRay_R (pNode->children[!side], ray, splitfrac, end, pEnum, context);
- }
- }
-
- // Visit the leaf...
- return pEnum->EnumerateLeaf( - node - 1, ray, start, end, context );
-}
-
-
-bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context )
-{
- Vector end;
- VectorAdd( ray.m_Start, ray.m_Delta, end );
- return EnumerateNodesAlongRay_R( 0, ray, 0.0f, 1.0f, pEnum, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Helps us find all leaves associated with a particular cluster
-//-----------------------------------------------------------------------------
-CUtlVector<clusterlist_t> g_ClusterLeaves;
-
-void BuildClusterTable( void )
-{
- int i, j;
- int leafCount;
- int leafList[MAX_MAP_LEAFS];
-
- g_ClusterLeaves.SetCount( dvis->numclusters );
- for ( i = 0; i < dvis->numclusters; i++ )
- {
- leafCount = 0;
- for ( j = 0; j < numleafs; j++ )
- {
- if ( dleafs[j].cluster == i )
- {
- leafList[ leafCount ] = j;
- leafCount++;
- }
- }
-
- g_ClusterLeaves[i].leafCount = leafCount;
- if ( leafCount )
- {
- g_ClusterLeaves[i].leafs.SetCount( leafCount );
- memcpy( g_ClusterLeaves[i].leafs.Base(), leafList, sizeof(int) * leafCount );
- }
- }
-}
-
-// There's a version of this in host.cpp!!! Make sure that they match.
-void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int dxlevel, int maxLength )
-{
- Q_StripExtension( pMapPath, pPlatformMapPath, maxLength );
-
-// if( dxlevel <= 60 )
-// {
-// Q_strncat( pPlatformMapPath, "_dx60", maxLength, COPY_ALL_CHARACTERS );
-// }
-
- Q_strncat( pPlatformMapPath, ".bsp", maxLength, COPY_ALL_CHARACTERS );
-}
-
-// There's a version of this in checksum_engine.cpp!!! Make sure that they match.
-static bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
-{
- byte chunk[1024];
- lump_t *curLump;
-
- FileHandle_t fp = g_pFileSystem->Open( pszFileName, "rb" );
- if ( !fp )
- return false;
-
- // CRC across all lumps except for the Entities lump
- for ( int l = 0; l < HEADER_LUMPS; ++l )
- {
- if (l == LUMP_ENTITIES)
- continue;
-
- curLump = &g_pBSPHeader->lumps[l];
- unsigned int nSize = curLump->filelen;
-
- g_pFileSystem->Seek( fp, curLump->fileofs, FILESYSTEM_SEEK_HEAD );
-
- // Now read in 1K chunks
- while ( nSize > 0 )
- {
- int nBytesRead = 0;
-
- if ( nSize > 1024 )
- nBytesRead = g_pFileSystem->Read( chunk, 1024, fp );
- else
- nBytesRead = g_pFileSystem->Read( chunk, nSize, fp );
-
- // If any data was received, CRC it.
- if ( nBytesRead > 0 )
- {
- nSize -= nBytesRead;
- CRC32_ProcessBuffer( crcvalue, chunk, nBytesRead );
- }
- else
- {
- g_pFileSystem->Close( fp );
- return false;
- }
- }
- }
-
- g_pFileSystem->Close( fp );
- return true;
-}
-
-
-void SetHDRMode( bool bHDR )
-{
- g_bHDR = bHDR;
- if ( bHDR )
- {
- pdlightdata = &dlightdataHDR;
- g_pLeafAmbientLighting = &g_LeafAmbientLightingHDR;
- g_pLeafAmbientIndex = &g_LeafAmbientIndexHDR;
- pNumworldlights = &numworldlightsHDR;
- dworldlights = dworldlightsHDR;
-#ifdef VRAD
- extern void VRadDetailProps_SetHDRMode( bool bHDR );
- VRadDetailProps_SetHDRMode( bHDR );
-#endif
- }
- else
- {
- pdlightdata = &dlightdataLDR;
- g_pLeafAmbientLighting = &g_LeafAmbientLightingLDR;
- g_pLeafAmbientIndex = &g_LeafAmbientIndexLDR;
- pNumworldlights = &numworldlightsLDR;
- dworldlights = dworldlightsLDR;
-#ifdef VRAD
- extern void VRadDetailProps_SetHDRMode( bool bHDR );
- VRadDetailProps_SetHDRMode( bHDR );
-#endif
- }
-}
-
-bool SwapVHV( void *pDestBase, void *pSrcBase )
-{
- byte *pDest = (byte*)pDestBase;
- byte *pSrc = (byte*)pSrcBase;
-
- HardwareVerts::FileHeader_t *pHdr = (HardwareVerts::FileHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
- g_Swap.SwapFieldsToTargetEndian<HardwareVerts::FileHeader_t>( (HardwareVerts::FileHeader_t*)pDest, (HardwareVerts::FileHeader_t*)pSrc );
- pSrc += sizeof(HardwareVerts::FileHeader_t);
- pDest += sizeof(HardwareVerts::FileHeader_t);
-
- // This swap is pretty format specific
- Assert( pHdr->m_nVersion == VHV_VERSION );
- if ( pHdr->m_nVersion != VHV_VERSION )
- return false;
-
- HardwareVerts::MeshHeader_t *pSrcMesh = (HardwareVerts::MeshHeader_t*)pSrc;
- HardwareVerts::MeshHeader_t *pDestMesh = (HardwareVerts::MeshHeader_t*)pDest;
- HardwareVerts::MeshHeader_t *pMesh = (HardwareVerts::MeshHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
- for ( int i = 0; i < pHdr->m_nMeshes; ++i, ++pMesh, ++pSrcMesh, ++pDestMesh )
- {
- g_Swap.SwapFieldsToTargetEndian( pDestMesh, pSrcMesh );
-
- pSrc = (byte*)pSrcBase + pMesh->m_nOffset;
- pDest = (byte*)pDestBase + pMesh->m_nOffset;
-
- // Swap as a buffer of integers
- // (source is bgra for an Intel swap to argb. PowerPC won't swap, so we need argb source.
- g_Swap.SwapBufferToTargetEndian<int>( (int*)pDest, (int*)pSrc, pMesh->m_nVertexes );
- }
- return true;
-}
-
-const char *ResolveStaticPropToModel( const char *pPropName )
-{
- // resolve back to static prop
- int iProp = -1;
-
- // filename should be sp_???.vhv or sp_hdr_???.vhv
- if ( V_strnicmp( pPropName, "sp_", 3 ) )
- {
- return NULL;
- }
- const char *pPropNumber = V_strrchr( pPropName, '_' );
- if ( pPropNumber )
- {
- sscanf( pPropNumber+1, "%d.vhv", &iProp );
- }
- else
- {
- return NULL;
- }
-
- // look up the prop to get to the actual model
- if ( iProp < 0 || iProp >= g_StaticPropInstances.Count() )
- {
- // prop out of range
- return NULL;
- }
- int iModel = g_StaticPropInstances[iProp];
- if ( iModel < 0 || iModel >= g_StaticPropNames.Count() )
- {
- // model out of range
- return NULL;
- }
-
- return g_StaticPropNames[iModel].String();
-}
-
-//-----------------------------------------------------------------------------
-// Iterate files in pak file, distribute to converters
-// pak file will be ready for serialization upon completion
-//-----------------------------------------------------------------------------
-void ConvertPakFileContents( const char *pInFilename )
-{
- IZip *newPakFile = IZip::CreateZip( NULL );
-
- CUtlBuffer sourceBuf;
- CUtlBuffer targetBuf;
- bool bConverted;
- CUtlVector< CUtlString > hdrFiles;
-
- int id = -1;
- int fileSize;
- while ( 1 )
- {
- char relativeName[MAX_PATH];
- id = GetNextFilename( GetPakFile(), id, relativeName, sizeof( relativeName ), fileSize );
- if ( id == -1)
- break;
-
- bConverted = false;
- sourceBuf.Purge();
- targetBuf.Purge();
-
- const char* pExtension = V_GetFileExtension( relativeName );
- const char* pExt = 0;
-
- bool bOK = ReadFileFromPak( GetPakFile(), relativeName, false, sourceBuf );
- if ( !bOK )
- {
- Warning( "Failed to load '%s' from lump pak for conversion or copy in '%s'.\n", relativeName, pInFilename );
- continue;
- }
-
- if ( pExtension && !V_stricmp( pExtension, "vtf" ) )
- {
- bOK = g_pVTFConvertFunc( relativeName, sourceBuf, targetBuf, g_pCompressFunc );
- if ( !bOK )
- {
- Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
- continue;
- }
-
- bConverted = true;
- pExt = ".vtf";
- }
- else if ( pExtension && !V_stricmp( pExtension, "vhv" ) )
- {
- CUtlBuffer tempBuffer;
- if ( g_pVHVFixupFunc )
- {
- // caller supplied a fixup
- const char *pModelName = ResolveStaticPropToModel( relativeName );
- if ( !pModelName )
- {
- Warning( "Static Prop '%s' failed to resolve actual model in '%s'.\n", relativeName, pInFilename );
- continue;
- }
-
- // output temp buffer may shrink, must use TellPut() to determine size
- bOK = g_pVHVFixupFunc( relativeName, pModelName, sourceBuf, tempBuffer );
- if ( !bOK )
- {
- Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
- continue;
- }
- }
- else
- {
- // use the source buffer as-is
- tempBuffer.EnsureCapacity( sourceBuf.TellMaxPut() );
- tempBuffer.Put( sourceBuf.Base(), sourceBuf.TellMaxPut() );
- }
-
- // swap the VHV
- targetBuf.EnsureCapacity( tempBuffer.TellPut() );
- bOK = SwapVHV( targetBuf.Base(), tempBuffer.Base() );
- if ( !bOK )
- {
- Warning( "Failed to swap '%s' in '%s'.\n", relativeName, pInFilename );
- continue;
- }
- targetBuf.SeekPut( CUtlBuffer::SEEK_HEAD, tempBuffer.TellPut() );
-
- if ( g_pCompressFunc )
- {
- CUtlBuffer compressedBuffer;
- targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, sizeof( HardwareVerts::FileHeader_t ) );
- bool bCompressed = g_pCompressFunc( targetBuf, compressedBuffer );
- if ( bCompressed )
- {
- // copy all the header data off
- CUtlBuffer headerBuffer;
- headerBuffer.EnsureCapacity( sizeof( HardwareVerts::FileHeader_t ) );
- headerBuffer.Put( targetBuf.Base(), sizeof( HardwareVerts::FileHeader_t ) );
-
- // reform the target with the header and then the compressed data
- targetBuf.Clear();
- targetBuf.Put( headerBuffer.Base(), sizeof( HardwareVerts::FileHeader_t ) );
- targetBuf.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
- }
-
- targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
- }
-
- bConverted = true;
- pExt = ".vhv";
- }
-
- if ( !bConverted )
- {
- // straight copy
- AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false );
- }
- else
- {
- // converted filename
- V_StripExtension( relativeName, relativeName, sizeof( relativeName ) );
- V_strcat( relativeName, ".360", sizeof( relativeName ) );
- V_strcat( relativeName, pExt, sizeof( relativeName ) );
- AddBufferToPak( newPakFile, relativeName, targetBuf.Base(), targetBuf.TellMaxPut(), false );
- }
-
- if ( V_stristr( relativeName, ".hdr" ) || V_stristr( relativeName, "_hdr" ) )
- {
- hdrFiles.AddToTail( relativeName );
- }
-
- DevMsg( "Created '%s' in lump pak in '%s'.\n", relativeName, pInFilename );
- }
-
- // strip ldr version of hdr files
- for ( int i=0; i<hdrFiles.Count(); i++ )
- {
- char ldrFileName[MAX_PATH];
-
- strcpy( ldrFileName, hdrFiles[i].String() );
-
- char *pHDRExtension = V_stristr( ldrFileName, ".hdr" );
- if ( !pHDRExtension )
- {
- pHDRExtension = V_stristr( ldrFileName, "_hdr" );
- }
-
- if ( pHDRExtension )
- {
- // strip .hdr or _hdr to get ldr filename
- memcpy( pHDRExtension, pHDRExtension+4, strlen( pHDRExtension+4 )+1 );
-
- DevMsg( "Stripping LDR: %s\n", ldrFileName );
- newPakFile->RemoveFileFromZip( ldrFileName );
- }
- }
-
- // discard old pak in favor of new pak
- IZip::ReleaseZip( s_pakFile );
- s_pakFile = newPakFile;
-}
-
-void SetAlignedLumpPosition( int lumpnum, int alignment = LUMP_ALIGNMENT )
-{
- g_pBSPHeader->lumps[lumpnum].fileofs = AlignFilePosition( g_hBSPFile, alignment );
-}
-
-template< class T >
-int SwapLumpToDisk( int fieldType, int lumpnum )
-{
- if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 )
- return 0;
-
- DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
-
- // lump swap may expand, allocate enough expansion room
- void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
-
- // CopyLumpInternal will handle the swap on load case
- unsigned int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
- unsigned int count = CopyLumpInternal<T>( fieldType, lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
- g_pBSPHeader->lumps[lumpnum].filelen = count * fieldSize;
-
- if ( g_bSwapOnWrite )
- {
- // Swap the lump in place before writing
- switch( lumpnum )
- {
- case LUMP_VISIBILITY:
- SwapVisibilityLump( (byte*)pBuffer, (byte*)pBuffer, count );
- break;
-
- case LUMP_PHYSCOLLIDE:
- // SwapPhyscollideLump may change size
- SwapPhyscollideLump( (byte*)pBuffer, (byte*)pBuffer, count );
- g_pBSPHeader->lumps[lumpnum].filelen = count;
- break;
-
- case LUMP_PHYSDISP:
- SwapPhysdispLump( (byte*)pBuffer, (byte*)pBuffer, count );
- break;
-
- default:
- g_Swap.SwapBufferToTargetEndian( (T*)pBuffer, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].filelen / sizeof(T) );
- break;
- }
- }
-
- SetAlignedLumpPosition( lumpnum );
- SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
-
- free( pBuffer );
-
- return g_pBSPHeader->lumps[lumpnum].filelen;
-}
-
-template< class T >
-int SwapLumpToDisk( int lumpnum )
-{
- if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 || g_Lumps.bLumpParsed[lumpnum] )
- return 0;
-
- DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
-
- // lump swap may expand, allocate enough room
- void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
-
- // CopyLumpInternal will handle the swap on load case
- int count = CopyLumpInternal<T>( lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
- g_pBSPHeader->lumps[lumpnum].filelen = count * sizeof(T);
-
- if ( g_bSwapOnWrite )
- {
- // Swap the lump in place before writing
- g_Swap.SwapFieldsToTargetEndian( (T*)pBuffer, (T*)pBuffer, count );
- }
-
- SetAlignedLumpPosition( lumpnum );
- SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
- free( pBuffer );
-
- return g_pBSPHeader->lumps[lumpnum].filelen;
-}
-
-void SwapLeafAmbientLightingLumpToDisk()
-{
- if ( HasLump( LUMP_LEAF_AMBIENT_INDEX ) || HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
- {
- // current version, swap in place
- if ( HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
- {
- // write HDR
- SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
- SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX_HDR );
-
- // cull LDR
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING );
- SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX );
- }
- }
- else
- {
- // older ambient lighting version (before index)
- // load older ambient lighting into memory and build ambient/index
- // an older leaf version would have already built the new LDR leaf ambient/index
- int numLeafs = g_pBSPHeader->lumps[LUMP_LEAFS].filelen / sizeof( dleaf_t );
- LoadLeafAmbientLighting( numLeafs );
-
- if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
- {
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) );
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX_HDR ) );
-
- // write HDR
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingHDR.Base(), g_LeafAmbientLightingHDR.Count() );
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexHDR.Base(), g_LeafAmbientIndexHDR.Count() );
- }
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen = g_LeafAmbientLightingHDR.Count() * sizeof( dleafambientlighting_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientLightingHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen );
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX_HDR );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen = g_LeafAmbientIndexHDR.Count() * sizeof( dleafambientindex_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientIndexHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen );
-
- // mark as processed
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
-
- // cull LDR
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING ) );
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX ) );
-
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingLDR.Base(), g_LeafAmbientLightingLDR.Count() );
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexLDR.Base(), g_LeafAmbientIndexLDR.Count() );
- }
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = g_LeafAmbientLightingLDR.Count() * sizeof( dleafambientlighting_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientLightingLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen );
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = g_LeafAmbientIndexLDR.Count() * sizeof( dleafambientindex_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientIndexLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen );
-
- // mark as processed
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
- }
-
- g_LeafAmbientLightingLDR.Purge();
- g_LeafAmbientIndexLDR.Purge();
- g_LeafAmbientLightingHDR.Purge();
- g_LeafAmbientIndexHDR.Purge();
- }
-}
-
-void SwapLeafLumpToDisk( void )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAFS ) );
-
- // load the leafs
- int count = LoadLeafs();
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( dleafs, count );
- }
-
- bool bOldLeafVersion = ( LumpVersion( LUMP_LEAFS ) == 0 );
- if ( bOldLeafVersion )
- {
- // version has been converted in the load process
- // not updating the version ye, SwapLeafAmbientLightingLumpToDisk() can detect
- g_pBSPHeader->lumps[LUMP_LEAFS].filelen = count * sizeof( dleaf_t );
- }
-
- SetAlignedLumpPosition( LUMP_LEAFS );
- SafeWrite( g_hBSPFile, dleafs, g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
-
- SwapLeafAmbientLightingLumpToDisk();
-
- if ( bOldLeafVersion )
- {
- // version has been converted in the load process
- // can now safely change
- g_pBSPHeader->lumps[LUMP_LEAFS].version = 1;
- }
-
-#if defined( BSP_USE_LESS_MEMORY )
- if ( dleafs )
- {
- free( dleafs );
- dleafs = NULL;
- }
-#endif
-}
-
-void SwapOcclusionLumpToDisk( void )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_OCCLUSION ) );
-
- LoadOcclusionLump();
- SetAlignedLumpPosition( LUMP_OCCLUSION );
- AddOcclusionLump();
-}
-
-void SwapPakfileLumpToDisk( const char *pInFilename )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_PAKFILE ) );
-
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
- if ( paksize > 0 )
- {
- GetPakFile()->ActivateByteSwapping( IsX360() );
- GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
-
- ConvertPakFileContents( pInFilename );
- }
- free( pakbuffer );
-
- SetAlignedLumpPosition( LUMP_PAKFILE, XBOX_DVD_SECTORSIZE );
- WritePakFileLump();
-
- ReleasePakFileLumps();
-}
-
-void SwapGameLumpsToDisk( void )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_GAME_LUMP ) );
-
- g_GameLumps.ParseGameLump( g_pBSPHeader );
- SetAlignedLumpPosition( LUMP_GAME_LUMP );
- AddGameLumps();
-}
-
-//-----------------------------------------------------------------------------
-// Generate a table of all static props, used for resolving static prop lighting
-// files back to their actual mdl.
-//-----------------------------------------------------------------------------
-void BuildStaticPropNameTable()
-{
- g_StaticPropNames.Purge();
- g_StaticPropInstances.Purge();
-
- g_GameLumps.ParseGameLump( g_pBSPHeader );
-
- GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
- if ( hGameLump != g_GameLumps.InvalidGameLump() )
- {
- int nVersion = g_GameLumps.GetGameLumpVersion( hGameLump );
- if ( nVersion < 4 )
- {
- // old unsupported version
- return;
- }
-
- if ( nVersion != 4 && nVersion != 5 && nVersion != 6 )
- {
- Error( "Unknown Static Prop Lump version %d!\n", nVersion );
- }
-
- byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
- if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
- {
- // get the model dictionary
- int count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
- for ( int i = 0; i < count; i++ )
- {
- g_StaticPropNames.AddToTail( pStaticPropDictLump[i].m_Name );
- }
- pGameLumpData += count * sizeof( StaticPropDictLump_t );
-
- // skip the leaf list
- count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- pGameLumpData += count * sizeof( StaticPropLeafLump_t );
-
- // get the instances
- count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- for ( int i = 0; i < count; i++ )
- {
- int propType;
- if ( nVersion == 4 )
- {
- propType = ((StaticPropLumpV4_t *)pGameLumpData)->m_PropType;
- pGameLumpData += sizeof( StaticPropLumpV4_t );
- }
- else if ( nVersion == 5 )
- {
- propType = ((StaticPropLumpV5_t *)pGameLumpData)->m_PropType;
- pGameLumpData += sizeof( StaticPropLumpV5_t );
- }
- else
- {
- propType = ((StaticPropLump_t *)pGameLumpData)->m_PropType;
- pGameLumpData += sizeof( StaticPropLump_t );
- }
- g_StaticPropInstances.AddToTail( propType );
- }
- }
- }
-
- g_GameLumps.DestroyAllGameLumps();
-}
-
-int AlignBuffer( CUtlBuffer &buffer, int alignment )
-{
- unsigned int newPosition = AlignValue( buffer.TellPut(), alignment );
- int padLength = newPosition - buffer.TellPut();
- for ( int i = 0; i<padLength; i++ )
- {
- buffer.PutChar( '\0' );
- }
- return buffer.TellPut();
-}
-
-struct SortedLump_t
-{
- int lumpNum;
- lump_t *pLump;
-};
-
-int SortLumpsByOffset( const SortedLump_t *pSortedLumpA, const SortedLump_t *pSortedLumpB )
-{
- int fileOffsetA = pSortedLumpA->pLump->fileofs;
- int fileOffsetB = pSortedLumpB->pLump->fileofs;
-
- int fileSizeA = pSortedLumpA->pLump->filelen;
- int fileSizeB = pSortedLumpB->pLump->filelen;
-
- // invalid or empty lumps get sorted together
- if ( !fileSizeA )
- {
- fileOffsetA = 0;
- }
- if ( !fileSizeB )
- {
- fileOffsetB = 0;
- }
-
- // compare by offset, want ascending
- if ( fileOffsetA < fileOffsetB )
- {
- return -1;
- }
- else if ( fileOffsetA > fileOffsetB )
- {
- return 1;
- }
-
- return 0;
-}
-
-bool CompressGameLump( dheader_t *pInBSPHeader, dheader_t *pOutBSPHeader, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
-{
- CByteswap byteSwap;
-
- dgamelumpheader_t* pInGameLumpHeader = (dgamelumpheader_t*)(((byte *)pInBSPHeader) + pInBSPHeader->lumps[LUMP_GAME_LUMP].fileofs);
- dgamelump_t* pInGameLump = (dgamelump_t*)(pInGameLumpHeader + 1);
-
- byteSwap.ActivateByteSwapping( true );
- byteSwap.SwapFieldsToTargetEndian( pInGameLumpHeader );
- byteSwap.SwapFieldsToTargetEndian( pInGameLump, pInGameLumpHeader->lumpCount );
-
- unsigned int newOffset = outputBuffer.TellPut();
- outputBuffer.Put( pInGameLumpHeader, sizeof( dgamelumpheader_t ) );
- outputBuffer.Put( pInGameLump, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) );
-
- dgamelumpheader_t* pOutGameLumpHeader = (dgamelumpheader_t*)((byte *)outputBuffer.Base() + newOffset);
- dgamelump_t* pOutGameLump = (dgamelump_t*)(pOutGameLumpHeader + 1);
-
- // add a dummy terminal gamelump
- // purposely NOT updating the .filelen to reflect the compressed size, but leaving as original size
- // callers use the next entry offset to determine compressed size
- pOutGameLumpHeader->lumpCount++;
- dgamelump_t dummyLump = { 0 };
- outputBuffer.Put( &dummyLump, sizeof( dgamelump_t ) );
-
- for ( int i = 0; i < pInGameLumpHeader->lumpCount; i++ )
- {
- CUtlBuffer inputBuffer;
- CUtlBuffer compressedBuffer;
-
- pOutGameLump[i].fileofs = AlignBuffer( outputBuffer, 4 );
-
- if ( pInGameLump[i].filelen )
- {
- inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pInGameLump[i].fileofs, pInGameLump[i].filelen, pInGameLump[i].filelen );
-
- bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
- if ( bCompressed )
- {
- pOutGameLump[i].flags |= GAMELUMPFLAG_COMPRESSED;
-
- outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
- compressedBuffer.Purge();
- }
- else
- {
- // as is
- outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
- }
- }
- }
-
- // fix the dummy terminal lump
- int lastLump = pOutGameLumpHeader->lumpCount-1;
- pOutGameLump[lastLump].fileofs = outputBuffer.TellPut();
-
- // fix the output for 360, swapping it back
- byteSwap.SwapFieldsToTargetEndian( pOutGameLump, pOutGameLumpHeader->lumpCount );
- byteSwap.SwapFieldsToTargetEndian( pOutGameLumpHeader );
-
- pOutBSPHeader->lumps[LUMP_GAME_LUMP].fileofs = newOffset;
- pOutBSPHeader->lumps[LUMP_GAME_LUMP].filelen = outputBuffer.TellPut() - newOffset;
-
- return true;
-}
-
-bool CompressBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
-{
- CByteswap byteSwap;
-
- dheader_t *pInBSPHeader = (dheader_t *)inputBuffer.Base();
- if ( pInBSPHeader->ident != BigLong( IDBSPHEADER ) || !pCompressFunc )
- {
- // only compress 360 bsp's
- return false;
- }
-
- // bsp is 360, swap the header back
- byteSwap.ActivateByteSwapping( true );
- byteSwap.SwapFieldsToTargetEndian( pInBSPHeader );
-
- // output will be smaller, use input size as upper bound
- outputBuffer.EnsureCapacity( inputBuffer.TellMaxPut() );
- outputBuffer.Put( pInBSPHeader, sizeof( dheader_t ) );
-
- dheader_t *pOutBSPHeader = (dheader_t *)outputBuffer.Base();
-
- // must adhere to input lump's offset order and process according to that, NOT lump num
- // sort by offset order
- CUtlVector< SortedLump_t > sortedLumps;
- for ( int i = 0; i < HEADER_LUMPS; i++ )
- {
- int iIndex = sortedLumps.AddToTail();
- sortedLumps[iIndex].lumpNum = i;
- sortedLumps[iIndex].pLump = &pInBSPHeader->lumps[i];
- }
- sortedLumps.Sort( SortLumpsByOffset );
-
- // iterate in sorted order
- for ( int i = 0; i < HEADER_LUMPS; ++i )
- {
- SortedLump_t *pSortedLump = &sortedLumps[i];
- int lumpNum = pSortedLump->lumpNum;
-
- if ( !pSortedLump->pLump->filelen )
- {
- // degenerate
- pOutBSPHeader->lumps[lumpNum].fileofs = 0;
- }
- else
- {
- int alignment = 4;
- if ( lumpNum == LUMP_PAKFILE )
- {
- alignment = 2048;
- }
- unsigned int newOffset = AlignBuffer( outputBuffer, alignment );
-
- // only set by compressed lumps, hides the uncompressed size
- *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = 0;
-
- CUtlBuffer inputBuffer;
- inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs, pSortedLump->pLump->filelen, pSortedLump->pLump->filelen );
-
- if ( lumpNum == LUMP_GAME_LUMP )
- {
- // the game lump has to have each of its components individually compressed
- CompressGameLump( pInBSPHeader, pOutBSPHeader, outputBuffer, pCompressFunc );
- }
- else if ( lumpNum == LUMP_PAKFILE )
- {
- // add as is
- pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
- outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
- }
- else
- {
- CUtlBuffer compressedBuffer;
- bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
- if ( bCompressed )
- {
- // placing the uncompressed size in the unused fourCC, will decode at runtime
- *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = BigLong( inputBuffer.TellPut() );
- pOutBSPHeader->lumps[lumpNum].filelen = compressedBuffer.TellPut();
- pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
- outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
- compressedBuffer.Purge();
- }
- else
- {
- // add as is
- pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
- outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
- }
- }
- }
- }
-
- // fix the output for 360, swapping it back
- byteSwap.SetTargetBigEndian( true );
- byteSwap.SwapFieldsToTargetEndian( pOutBSPHeader );
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// For all lumps in a bsp: Loads the lump from file A, swaps it, writes it to file B.
-// This limits the memory used for the swap process which helps the Xbox 360.
-//
-// NOTE: These lumps will be written to the file in exactly the order they appear here,
-// so they can be shifted around if desired for file access optimization.
-//-----------------------------------------------------------------------------
-bool SwapBSPFile( const char *pInFilename, const char *pOutFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc )
-{
- DevMsg( "Creating %s\n", pOutFilename );
-
- if ( !g_pFileSystem->FileExists( pInFilename ) )
- {
- Warning( "Error! Couldn't open input file %s - BSP swap failed!\n", pInFilename );
- return false;
- }
-
- g_hBSPFile = SafeOpenWrite( pOutFilename );
- if ( !g_hBSPFile )
- {
- Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
- return false;
- }
-
- if ( !pVTFConvertFunc )
- {
- Warning( "Error! Missing VTF Conversion function\n" );
- return false;
- }
- g_pVTFConvertFunc = pVTFConvertFunc;
-
- // optional VHV fixup
- g_pVHVFixupFunc = pVHVFixupFunc;
-
- // optional compression callback
- g_pCompressFunc = pCompressFunc;
-
- // These must be mutually exclusive
- g_bSwapOnLoad = bSwapOnLoad;
- g_bSwapOnWrite = !bSwapOnLoad;
-
- g_Swap.ActivateByteSwapping( true );
-
- OpenBSPFile( pInFilename );
-
- // CRC the bsp first
- CRC32_t mapCRC;
- CRC32_Init(&mapCRC);
- if ( !CRC_MapFile( &mapCRC, pInFilename ) )
- {
- Warning( "Failed to CRC the bsp\n" );
- return false;
- }
-
- // hold a dictionary of all the static prop names
- // this is needed to properly convert any VHV files inside the pak lump
- BuildStaticPropNameTable();
-
- // Set the output file pointer after the header
- dheader_t dummyHeader = { 0 };
- SafeWrite( g_hBSPFile, &dummyHeader, sizeof( dheader_t ) );
-
- // To allow for alignment fixups, the lumps will be written to the
- // output file in the order they appear in this function.
-
- // NOTE: Flags for 360 !!!MUST!!! be first
- SwapLumpToDisk< dflagslump_t >( LUMP_MAP_FLAGS );
-
- // complex lump swaps first or for later contingent data
- SwapLeafLumpToDisk();
- SwapOcclusionLumpToDisk();
- SwapGameLumpsToDisk();
-
- // Strip dead or non relevant lumps
- g_pBSPHeader->lumps[LUMP_DISP_LIGHTMAP_ALPHAS].filelen = 0;
- g_pBSPHeader->lumps[LUMP_FACEIDS].filelen = 0;
-
- // Strip obsolete LDR in favor of HDR
- if ( SwapLumpToDisk<dface_t>( LUMP_FACES_HDR ) )
- {
- g_pBSPHeader->lumps[LUMP_FACES].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk<dface_t>( LUMP_FACES );
- }
-
- if ( SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS_HDR ) )
- {
- g_pBSPHeader->lumps[LUMP_WORLDLIGHTS].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS );
- }
-
- // Simple lump swaps
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSDISP );
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE );
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_VISIBILITY );
- SwapLumpToDisk<dmodel_t>( LUMP_MODELS );
- SwapLumpToDisk<dvertex_t>( LUMP_VERTEXES );
- SwapLumpToDisk<dplane_t>( LUMP_PLANES );
- SwapLumpToDisk<dnode_t>( LUMP_NODES );
- SwapLumpToDisk<texinfo_t>( LUMP_TEXINFO );
- SwapLumpToDisk<dtexdata_t>( LUMP_TEXDATA );
- SwapLumpToDisk<ddispinfo_t>( LUMP_DISPINFO );
- SwapLumpToDisk<CDispVert>( LUMP_DISP_VERTS );
- SwapLumpToDisk<CDispTri>( LUMP_DISP_TRIS );
- SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
- SwapLumpToDisk<CFaceMacroTextureInfo>( LUMP_FACE_MACRO_TEXTURE_INFO );
- SwapLumpToDisk<dprimitive_t>( LUMP_PRIMITIVES );
- SwapLumpToDisk<dprimvert_t>( LUMP_PRIMVERTS );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_PRIMINDICES );
- SwapLumpToDisk<dface_t>( LUMP_ORIGINALFACES );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFFACES );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFBRUSHES );
- SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_SURFEDGES );
- SwapLumpToDisk<dedge_t>( LUMP_EDGES );
- SwapLumpToDisk<dbrush_t>( LUMP_BRUSHES );
- SwapLumpToDisk<dbrushside_t>( LUMP_BRUSHSIDES );
- SwapLumpToDisk<darea_t>( LUMP_AREAS );
- SwapLumpToDisk<dareaportal_t>( LUMP_AREAPORTALS );
- SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_ENTITIES );
- SwapLumpToDisk<dleafwaterdata_t>( LUMP_LEAFWATERDATA );
- SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_VERTNORMALS );
- SwapLumpToDisk<short>( FIELD_SHORT, LUMP_VERTNORMALINDICES );
- SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_CLIPPORTALVERTS );
- SwapLumpToDisk<dcubemapsample_t>( LUMP_CUBEMAPS );
- SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA );
- SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE );
- SwapLumpToDisk<doverlay_t>( LUMP_OVERLAYS );
- SwapLumpToDisk<dwateroverlay_t>( LUMP_WATEROVERLAYS );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER );
- SwapLumpToDisk<doverlayfade_t>( LUMP_OVERLAY_FADES );
-
-
- // NOTE: this data placed at the end for the sake of 360:
- {
- // NOTE: lighting must be the penultimate lump
- // (allows 360 to free this memory part-way through map loading)
- if ( SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING_HDR ) )
- {
- g_pBSPHeader->lumps[LUMP_LIGHTING].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING );
- }
- // NOTE: Pakfile for 360 !!!MUST!!! be last
- SwapPakfileLumpToDisk( pInFilename );
- }
-
-
- // Store the crc in the flags lump version field
- g_pBSPHeader->lumps[LUMP_MAP_FLAGS].version = mapCRC;
-
- // Pad out the end of the file to a sector boundary for optimal IO
- AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
-
- // Warn of any lumps that didn't get swapped
- for ( int i = 0; i < HEADER_LUMPS; ++i )
- {
- if ( HasLump( i ) && !g_Lumps.bLumpParsed[i] )
- {
- // a new lump got added that needs to have a swap function
- Warning( "BSP: '%s', %s has no swap or copy function. Discarding!\n", pInFilename, GetLumpName(i) );
-
- // the data didn't get copied, so don't reference garbage
- g_pBSPHeader->lumps[i].filelen = 0;
- }
- }
-
- // Write the updated header
- g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
- WriteData( g_pBSPHeader );
- g_pFileSystem->Close( g_hBSPFile );
- g_hBSPFile = 0;
-
- // Cleanup
- g_Swap.ActivateByteSwapping( false );
-
- CloseBSPFile();
-
- g_StaticPropNames.Purge();
- g_StaticPropInstances.Purge();
-
- DevMsg( "Finished BSP Swap\n" );
-
- // caller provided compress func will further compress compatible lumps
- if ( pCompressFunc )
- {
- CUtlBuffer inputBuffer;
- if ( !g_pFileSystem->ReadFile( pOutFilename, NULL, inputBuffer ) )
- {
- Warning( "Error! Couldn't read file %s - final BSP compression failed!\n", pOutFilename );
- return false;
- }
-
- CUtlBuffer outputBuffer;
- if ( !CompressBSP( inputBuffer, outputBuffer, pCompressFunc ) )
- {
- Warning( "Error! Failed to compress BSP '%s'!\n", pOutFilename );
- return false;
- }
-
- g_hBSPFile = SafeOpenWrite( pOutFilename );
- if ( !g_hBSPFile )
- {
- Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
- return false;
- }
- SafeWrite( g_hBSPFile, outputBuffer.Base(), outputBuffer.TellPut() );
- g_pFileSystem->Close( g_hBSPFile );
- g_hBSPFile = 0;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Get the pak lump from a BSP
-//-----------------------------------------------------------------------------
-bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize )
-{
- *pPakData = NULL;
- *pPakSize = 0;
-
- if ( !g_pFileSystem->FileExists( pBSPFilename ) )
- {
- Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
- return false;
- }
-
- // determine endian nature
- dheader_t *pHeader;
- LoadFile( pBSPFilename, (void **)&pHeader );
- bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
- free( pHeader );
-
- g_bSwapOnLoad = bSwap;
- g_bSwapOnWrite = !bSwap;
-
- OpenBSPFile( pBSPFilename );
-
- if ( g_pBSPHeader->lumps[LUMP_PAKFILE].filelen )
- {
- *pPakSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, pPakData );
- }
-
- CloseBSPFile();
-
- return true;
-}
-
-// compare function for qsort below
-static int LumpOffsetCompare( const void *pElem1, const void *pElem2 )
-{
- int lump1 = *(byte *)pElem1;
- int lump2 = *(byte *)pElem2;
-
- if ( lump1 != lump2 )
- {
- // force LUMP_MAP_FLAGS to be first, always
- if ( lump1 == LUMP_MAP_FLAGS )
- {
- return -1;
- }
- else if ( lump2 == LUMP_MAP_FLAGS )
- {
- return 1;
- }
-
- // force LUMP_PAKFILE to be last, always
- if ( lump1 == LUMP_PAKFILE )
- {
- return 1;
- }
- else if ( lump2 == LUMP_PAKFILE )
- {
- return -1;
- }
- }
-
- int fileOffset1 = g_pBSPHeader->lumps[lump1].fileofs;
- int fileOffset2 = g_pBSPHeader->lumps[lump2].fileofs;
-
- // invalid or empty lumps will get sorted together
- if ( !g_pBSPHeader->lumps[lump1].filelen )
- {
- fileOffset1 = 0;
- }
-
- if ( !g_pBSPHeader->lumps[lump2].filelen )
- {
- fileOffset2 = 0;
- }
-
- // compare by offset
- if ( fileOffset1 < fileOffset2 )
- {
- return -1;
- }
- else if ( fileOffset1 > fileOffset2 )
- {
- return 1;
- }
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Replace the pak lump in a BSP
-//-----------------------------------------------------------------------------
-bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize )
-{
- if ( !g_pFileSystem->FileExists( pBSPFilename ) )
- {
- Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
- return false;
- }
-
- // determine endian nature
- dheader_t *pHeader;
- LoadFile( pBSPFilename, (void **)&pHeader );
- bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
- free( pHeader );
-
- g_bSwapOnLoad = bSwap;
- g_bSwapOnWrite = bSwap;
-
- OpenBSPFile( pBSPFilename );
-
- // save a copy of the old header
- // generating a new bsp is a destructive operation
- dheader_t oldHeader;
- oldHeader = *g_pBSPHeader;
-
- g_hBSPFile = SafeOpenWrite( pNewFilename );
- if ( !g_hBSPFile )
- {
- return false;
- }
-
- // placeholder only, reset at conclusion
- WriteData( &oldHeader );
-
- // lumps must be reserialized in same relative offset order
- // build sorted order table
- int readOrder[HEADER_LUMPS];
- for ( int i=0; i<HEADER_LUMPS; i++ )
- {
- readOrder[i] = i;
- }
- qsort( readOrder, HEADER_LUMPS, sizeof( int ), LumpOffsetCompare );
-
- for ( int i = 0; i < HEADER_LUMPS; i++ )
- {
- int lump = readOrder[i];
-
- if ( lump == LUMP_PAKFILE )
- {
- // pak lump always written last, with special alignment
- continue;
- }
-
- int length = g_pBSPHeader->lumps[lump].filelen;
- if ( length )
- {
- // save the lump data
- int offset = g_pBSPHeader->lumps[lump].fileofs;
- SetAlignedLumpPosition( lump );
- SafeWrite( g_hBSPFile, (byte *)g_pBSPHeader + offset, length );
- }
- else
- {
- g_pBSPHeader->lumps[lump].fileofs = 0;
- }
- }
-
- // Always write the pak file at the end
- // Pad out the end of the file to a sector boundary for optimal IO
- g_pBSPHeader->lumps[LUMP_PAKFILE].fileofs = AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
- g_pBSPHeader->lumps[LUMP_PAKFILE].filelen = pakSize;
- SafeWrite( g_hBSPFile, pPakData, pakSize );
-
- // Pad out the end of the file to a sector boundary for optimal IO
- AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
-
- // Write the updated header
- g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
- WriteData( g_pBSPHeader );
- g_pFileSystem->Close( g_hBSPFile );
-
- CloseBSPFile();
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Build a list of files that BSP owns, world/cubemap materials, static props, etc.
-//-----------------------------------------------------------------------------
-bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList )
-{
- if ( !g_pFileSystem->FileExists( pBSPFilename ) )
- {
- Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
- return false;
- }
-
- // must be set, but exact hdr not critical for dependant traversal
- SetHDRMode( false );
-
- LoadBSPFile( pBSPFilename );
-
- char szBspName[MAX_PATH];
- V_FileBase( pBSPFilename, szBspName, sizeof( szBspName ) );
- V_SetExtension( szBspName, ".bsp", sizeof( szBspName ) );
-
- // get embedded pak files, and internals
- char szFilename[MAX_PATH];
- int fileSize;
- int fileId = -1;
- for ( ;; )
- {
- fileId = GetPakFile()->GetNextFilename( fileId, szFilename, sizeof( szFilename ), fileSize );
- if ( fileId == -1 )
- {
- break;
- }
- pList->AddToTail( szFilename );
- }
-
- // get all the world materials
- for ( int i=0; i<numtexdata; i++ )
- {
- const char *pName = TexDataStringTable_GetString( dtexdata[i].nameStringTableID );
- V_ComposeFileName( "materials", pName, szFilename, sizeof( szFilename ) );
- V_SetExtension( szFilename, ".vmt", sizeof( szFilename ) );
- pList->AddToTail( szFilename );
- }
-
- // get all the static props
- GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
- if ( hGameLump != g_GameLumps.InvalidGameLump() )
- {
- byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
- if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
- {
- int count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
-
- StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
- for ( int i=0; i<count; i++ )
- {
- pList->AddToTail( pStaticPropDictLump[i].m_Name );
- }
- }
- }
-
- // get all the detail props
- hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
- if ( hGameLump != g_GameLumps.InvalidGameLump() )
- {
- byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
- if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
- {
- int count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
-
- DetailObjectDictLump_t *pDetailObjectDictLump = (DetailObjectDictLump_t *)pGameLumpData;
- for ( int i=0; i<count; i++ )
- {
- pList->AddToTail( pDetailObjectDictLump[i].m_Name );
- }
- pGameLumpData += count * sizeof( DetailObjectDictLump_t );
-
- if ( g_GameLumps.GetGameLumpVersion( hGameLump ) == 4 )
- {
- count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- if ( count )
- {
- // All detail prop sprites must lie in the material detail/detailsprites
- pList->AddToTail( "materials/detail/detailsprites.vmt" );
- }
- }
- }
- }
-
- UnloadBSPFile();
-
- return true;
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cmdlib.h"
+#include "mathlib/mathlib.h"
+#include "bsplib.h"
+#include "zip_utils.h"
+#include "scriplib.h"
+#include "utllinkedlist.h"
+#include "bsptreedata.h"
+#include "cmodel.h"
+#include "gamebspfile.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/hardwareverts.h"
+#include "utlbuffer.h"
+#include "utlrbtree.h"
+#include "utlsymbol.h"
+#include "utlstring.h"
+#include "checksum_crc.h"
+#include "physdll.h"
+#include "tier0/dbg.h"
+#include "lumpfiles.h"
+#include "vtf/vtf.h"
+
+//=============================================================================
+
+// Boundary each lump should be aligned to
+#define LUMP_ALIGNMENT 4
+
+// Data descriptions for byte swapping - only needed
+// for structures that are written to file for use by the game.
+BEGIN_BYTESWAP_DATADESC( dheader_t )
+ DEFINE_FIELD( ident, FIELD_INTEGER ),
+ DEFINE_FIELD( version, FIELD_INTEGER ),
+ DEFINE_EMBEDDED_ARRAY( lumps, HEADER_LUMPS ),
+ DEFINE_FIELD( mapRevision, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+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 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dflagslump_t )
+ DEFINE_FIELD( m_LevelFlags, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dplane_t )
+ DEFINE_FIELD( normal, FIELD_VECTOR ),
+ DEFINE_FIELD( dist, FIELD_FLOAT ),
+ DEFINE_FIELD( type, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleaf_version_0_t )
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+ DEFINE_FIELD( cluster, FIELD_SHORT ),
+ DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
+ DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
+ DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
+ DEFINE_FIELD( firstleafface, FIELD_SHORT ),
+ DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
+ DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
+ DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
+ DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
+ DEFINE_EMBEDDED( m_AmbientLighting ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleaf_t )
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+ DEFINE_FIELD( cluster, FIELD_SHORT ),
+ DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
+ DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
+ DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
+ DEFINE_FIELD( firstleafface, FIELD_SHORT ),
+ DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
+ DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
+ DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
+ DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CompressedLightCube ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
+ DEFINE_ARRAY( m_Color, FIELD_CHARACTER, 6 * sizeof(ColorRGBExp32) ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleafambientindex_t )
+ DEFINE_FIELD( ambientSampleCount, FIELD_SHORT ),
+ DEFINE_FIELD( firstAmbientSample, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleafambientlighting_t ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
+ DEFINE_EMBEDDED( cube ),
+ DEFINE_FIELD( x, FIELD_CHARACTER ),
+ DEFINE_FIELD( y, FIELD_CHARACTER ),
+ DEFINE_FIELD( z, FIELD_CHARACTER ),
+ DEFINE_FIELD( pad, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dvertex_t )
+ DEFINE_FIELD( point, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dnode_t )
+ DEFINE_FIELD( planenum, FIELD_INTEGER ),
+ DEFINE_ARRAY( children, FIELD_INTEGER, 2 ),
+ DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
+ DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
+ DEFINE_FIELD( firstface, FIELD_SHORT ),
+ DEFINE_FIELD( numfaces, FIELD_SHORT ),
+ DEFINE_FIELD( area, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( texinfo_t )
+ DEFINE_ARRAY( textureVecsTexelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
+ DEFINE_ARRAY( lightmapVecsLuxelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
+ DEFINE_FIELD( flags, FIELD_INTEGER ),
+ DEFINE_FIELD( texdata, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dtexdata_t )
+ DEFINE_FIELD( reflectivity, FIELD_VECTOR ),
+ DEFINE_FIELD( nameStringTableID, FIELD_INTEGER ),
+ DEFINE_FIELD( width, FIELD_INTEGER ),
+ DEFINE_FIELD( height, FIELD_INTEGER ),
+ DEFINE_FIELD( view_width, FIELD_INTEGER ),
+ DEFINE_FIELD( view_height, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( ddispinfo_t )
+ DEFINE_FIELD( startPosition, FIELD_VECTOR ),
+ DEFINE_FIELD( m_iDispVertStart, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iDispTriStart, FIELD_INTEGER ),
+ DEFINE_FIELD( power, FIELD_INTEGER ),
+ DEFINE_FIELD( minTess, FIELD_INTEGER ),
+ DEFINE_FIELD( smoothingAngle, FIELD_FLOAT ),
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iMapFace, FIELD_SHORT ),
+ DEFINE_FIELD( m_iLightmapAlphaStart, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iLightmapSamplePositionStart, FIELD_INTEGER ),
+ DEFINE_EMBEDDED_ARRAY( m_EdgeNeighbors, 4 ),
+ DEFINE_EMBEDDED_ARRAY( m_CornerNeighbors, 4 ),
+ DEFINE_ARRAY( m_AllowedVerts, FIELD_INTEGER, ddispinfo_t::ALLOWEDVERTS_SIZE ), // unsigned long
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispNeighbor )
+ DEFINE_EMBEDDED_ARRAY( m_SubNeighbors, 2 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispCornerNeighbors )
+ DEFINE_ARRAY( m_Neighbors, FIELD_SHORT, MAX_DISP_CORNER_NEIGHBORS ),
+ DEFINE_FIELD( m_nNeighbors, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispSubNeighbor )
+ DEFINE_FIELD( m_iNeighbor, FIELD_SHORT ),
+ DEFINE_FIELD( m_NeighborOrientation, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Span, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_NeighborSpan, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispVert )
+ DEFINE_FIELD( m_vVector, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_flAlpha, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispTri )
+ DEFINE_FIELD( m_uiTags, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CFaceMacroTextureInfo )
+ DEFINE_FIELD( m_MacroTextureNameID, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dprimitive_t )
+ DEFINE_FIELD( type, FIELD_CHARACTER ),
+ DEFINE_FIELD( firstIndex, FIELD_SHORT ),
+ DEFINE_FIELD( indexCount, FIELD_SHORT ),
+ DEFINE_FIELD( firstVert, FIELD_SHORT ),
+ DEFINE_FIELD( vertCount, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dprimvert_t )
+ DEFINE_FIELD( pos, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dface_t )
+ DEFINE_FIELD( planenum, FIELD_SHORT ),
+ DEFINE_FIELD( side, FIELD_CHARACTER ),
+ DEFINE_FIELD( onNode, FIELD_CHARACTER ),
+ DEFINE_FIELD( firstedge, FIELD_INTEGER ),
+ DEFINE_FIELD( numedges, FIELD_SHORT ),
+ DEFINE_FIELD( texinfo, FIELD_SHORT ),
+ DEFINE_FIELD( dispinfo, FIELD_SHORT ),
+ DEFINE_FIELD( surfaceFogVolumeID, FIELD_SHORT ),
+ DEFINE_ARRAY( styles, FIELD_CHARACTER, MAXLIGHTMAPS ),
+ DEFINE_FIELD( lightofs, FIELD_INTEGER ),
+ DEFINE_FIELD( area, FIELD_FLOAT ),
+ DEFINE_ARRAY( m_LightmapTextureMinsInLuxels, FIELD_INTEGER, 2 ),
+ DEFINE_ARRAY( m_LightmapTextureSizeInLuxels, FIELD_INTEGER, 2 ),
+ DEFINE_FIELD( origFace, FIELD_INTEGER ),
+ DEFINE_FIELD( m_NumPrims, FIELD_SHORT ),
+ DEFINE_FIELD( firstPrimID, FIELD_SHORT ),
+ DEFINE_FIELD( smoothingGroups, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dfaceid_t )
+ DEFINE_FIELD( hammerfaceid, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dbrush_t )
+ DEFINE_FIELD( firstside, FIELD_INTEGER ),
+ DEFINE_FIELD( numsides, FIELD_INTEGER ),
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dbrushside_t )
+ DEFINE_FIELD( planenum, FIELD_SHORT ),
+ DEFINE_FIELD( texinfo, FIELD_SHORT ),
+ DEFINE_FIELD( dispinfo, FIELD_SHORT ),
+ DEFINE_FIELD( bevel, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dedge_t )
+ DEFINE_ARRAY( v, FIELD_SHORT, 2 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dmodel_t )
+ DEFINE_FIELD( mins, FIELD_VECTOR ),
+ DEFINE_FIELD( maxs, FIELD_VECTOR ),
+ DEFINE_FIELD( origin, FIELD_VECTOR ),
+ DEFINE_FIELD( headnode, FIELD_INTEGER ),
+ DEFINE_FIELD( firstface, FIELD_INTEGER ),
+ DEFINE_FIELD( numfaces, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dphysmodel_t )
+ DEFINE_FIELD( modelIndex, FIELD_INTEGER ),
+ DEFINE_FIELD( dataSize, FIELD_INTEGER ),
+ DEFINE_FIELD( keydataSize, FIELD_INTEGER ),
+ DEFINE_FIELD( solidCount, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dphysdisp_t )
+ DEFINE_FIELD( numDisplacements, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( darea_t )
+ DEFINE_FIELD( numareaportals, FIELD_INTEGER ),
+ DEFINE_FIELD( firstareaportal, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dareaportal_t )
+ DEFINE_FIELD( m_PortalKey, FIELD_SHORT ),
+ DEFINE_FIELD( otherarea, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstClipPortalVert, FIELD_SHORT ),
+ DEFINE_FIELD( m_nClipPortalVerts, FIELD_SHORT ),
+ DEFINE_FIELD( planenum, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dworldlight_t )
+ DEFINE_FIELD( origin, FIELD_VECTOR ),
+ DEFINE_FIELD( intensity, FIELD_VECTOR ),
+ DEFINE_FIELD( normal, FIELD_VECTOR ),
+ DEFINE_FIELD( cluster, FIELD_INTEGER ),
+ DEFINE_FIELD( type, FIELD_INTEGER ), // enumeration
+ DEFINE_FIELD( style, FIELD_INTEGER ),
+ DEFINE_FIELD( stopdot, FIELD_FLOAT ),
+ DEFINE_FIELD( stopdot2, FIELD_FLOAT ),
+ DEFINE_FIELD( exponent, FIELD_FLOAT ),
+ DEFINE_FIELD( radius, FIELD_FLOAT ),
+ DEFINE_FIELD( constant_attn, FIELD_FLOAT ),
+ DEFINE_FIELD( linear_attn, FIELD_FLOAT ),
+ DEFINE_FIELD( quadratic_attn, FIELD_FLOAT ),
+ DEFINE_FIELD( flags, FIELD_INTEGER ),
+ DEFINE_FIELD( texinfo, FIELD_INTEGER ),
+ DEFINE_FIELD( owner, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleafwaterdata_t )
+ DEFINE_FIELD( surfaceZ, FIELD_FLOAT ),
+ DEFINE_FIELD( minZ, FIELD_FLOAT ),
+ DEFINE_FIELD( surfaceTexInfoID, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doccluderdata_t )
+ DEFINE_FIELD( flags, FIELD_INTEGER ),
+ DEFINE_FIELD( firstpoly, FIELD_INTEGER ),
+ DEFINE_FIELD( polycount, FIELD_INTEGER ),
+ DEFINE_FIELD( mins, FIELD_VECTOR ),
+ DEFINE_FIELD( maxs, FIELD_VECTOR ),
+ DEFINE_FIELD( area, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doccluderpolydata_t )
+ DEFINE_FIELD( firstvertexindex, FIELD_INTEGER ),
+ DEFINE_FIELD( vertexcount, FIELD_INTEGER ),
+ DEFINE_FIELD( planenum, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dcubemapsample_t )
+ DEFINE_ARRAY( origin, FIELD_INTEGER, 3 ),
+ DEFINE_FIELD( size, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doverlay_t )
+ DEFINE_FIELD( nId, FIELD_INTEGER ),
+ DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
+ DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
+ DEFINE_ARRAY( aFaces, FIELD_INTEGER, OVERLAY_BSP_FACE_COUNT ),
+ DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
+ DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dwateroverlay_t )
+ DEFINE_FIELD( nId, FIELD_INTEGER ),
+ DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
+ DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
+ DEFINE_ARRAY( aFaces, FIELD_INTEGER, WATEROVERLAY_BSP_FACE_COUNT ),
+ DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
+ DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doverlayfade_t )
+ DEFINE_FIELD( flFadeDistMinSq, FIELD_FLOAT ),
+ DEFINE_FIELD( flFadeDistMaxSq, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dgamelumpheader_t )
+ DEFINE_FIELD( lumpCount, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dgamelump_t )
+ DEFINE_FIELD( id, FIELD_INTEGER ), // GameLumpId_t
+ DEFINE_FIELD( flags, FIELD_SHORT ),
+ DEFINE_FIELD( version, FIELD_SHORT ),
+ DEFINE_FIELD( fileofs, FIELD_INTEGER ),
+ DEFINE_FIELD( filelen, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+// From gamebspfile.h
+BEGIN_BYTESWAP_DATADESC( StaticPropDictLump_t )
+ DEFINE_ARRAY( m_Name, FIELD_CHARACTER, STATIC_PROP_NAME_LENGTH ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLump_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_PropType, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
+ DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
+ DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
+ DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
+ DEFINE_FIELD( m_nMinDXLevel, FIELD_SHORT ),
+ DEFINE_FIELD( m_nMaxDXLevel, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLumpV4_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_PropType, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
+ DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
+ DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
+ DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLumpV5_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_PropType, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
+ DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
+ DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
+ DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLeafLump_t )
+ DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailObjectDictLump_t )
+ DEFINE_ARRAY( m_Name, FIELD_CHARACTER, DETAIL_NAME_LENGTH ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailObjectLump_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_DetailModel, FIELD_SHORT ),
+ DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
+ DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
+ DEFINE_FIELD( m_LightStyles, FIELD_INTEGER ),
+ DEFINE_FIELD( m_LightStyleCount, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_SwayAmount, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_ShapeAngle, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_ShapeSize, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Orientation, FIELD_CHARACTER ),
+ DEFINE_ARRAY( m_Padding2, FIELD_CHARACTER, 3 ),
+ DEFINE_FIELD( m_Type, FIELD_CHARACTER ),
+ DEFINE_ARRAY( m_Padding3, FIELD_CHARACTER, 3 ),
+ DEFINE_FIELD( m_flScale, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailSpriteDictLump_t )
+ DEFINE_FIELD( m_UL, FIELD_VECTOR2D ),
+ DEFINE_FIELD( m_LR, FIELD_VECTOR2D ),
+ DEFINE_FIELD( m_TexUL, FIELD_VECTOR2D ),
+ DEFINE_FIELD( m_TexLR, FIELD_VECTOR2D ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailPropLightstylesLump_t )
+ DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
+ DEFINE_FIELD( m_Style, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+// From vradstaticprops.h
+namespace HardwareVerts
+{
+BEGIN_BYTESWAP_DATADESC( MeshHeader_t )
+ DEFINE_FIELD( m_nLod, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nOffset, FIELD_INTEGER ),
+ DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( FileHeader_t )
+ DEFINE_FIELD( m_nVersion, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nChecksum, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexFlags, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexSize, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nMeshes, FIELD_INTEGER ),
+ DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
+END_BYTESWAP_DATADESC()
+} // end namespace
+
+static const char *s_LumpNames[] = {
+ "LUMP_ENTITIES", // 0
+ "LUMP_PLANES", // 1
+ "LUMP_TEXDATA", // 2
+ "LUMP_VERTEXES", // 3
+ "LUMP_VISIBILITY", // 4
+ "LUMP_NODES", // 5
+ "LUMP_TEXINFO", // 6
+ "LUMP_FACES", // 7
+ "LUMP_LIGHTING", // 8
+ "LUMP_OCCLUSION", // 9
+ "LUMP_LEAFS", // 10
+ "LUMP_FACEIDS", // 11
+ "LUMP_EDGES", // 12
+ "LUMP_SURFEDGES", // 13
+ "LUMP_MODELS", // 14
+ "LUMP_WORLDLIGHTS", // 15
+ "LUMP_LEAFFACES", // 16
+ "LUMP_LEAFBRUSHES", // 17
+ "LUMP_BRUSHES", // 18
+ "LUMP_BRUSHSIDES", // 19
+ "LUMP_AREAS", // 20
+ "LUMP_AREAPORTALS", // 21
+ "LUMP_UNUSED0", // 22
+ "LUMP_UNUSED1", // 23
+ "LUMP_UNUSED2", // 24
+ "LUMP_UNUSED3", // 25
+ "LUMP_DISPINFO", // 26
+ "LUMP_ORIGINALFACES", // 27
+ "LUMP_PHYSDISP", // 28
+ "LUMP_PHYSCOLLIDE", // 29
+ "LUMP_VERTNORMALS", // 30
+ "LUMP_VERTNORMALINDICES", // 31
+ "LUMP_DISP_LIGHTMAP_ALPHAS", // 32
+ "LUMP_DISP_VERTS", // 33
+ "LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS", // 34
+ "LUMP_GAME_LUMP", // 35
+ "LUMP_LEAFWATERDATA", // 36
+ "LUMP_PRIMITIVES", // 37
+ "LUMP_PRIMVERTS", // 38
+ "LUMP_PRIMINDICES", // 39
+ "LUMP_PAKFILE", // 40
+ "LUMP_CLIPPORTALVERTS", // 41
+ "LUMP_CUBEMAPS", // 42
+ "LUMP_TEXDATA_STRING_DATA", // 43
+ "LUMP_TEXDATA_STRING_TABLE", // 44
+ "LUMP_OVERLAYS", // 45
+ "LUMP_LEAFMINDISTTOWATER", // 46
+ "LUMP_FACE_MACRO_TEXTURE_INFO", // 47
+ "LUMP_DISP_TRIS", // 48
+ "LUMP_PHYSCOLLIDESURFACE", // 49
+ "LUMP_WATEROVERLAYS", // 50
+ "LUMP_LEAF_AMBIENT_INDEX_HDR", // 51
+ "LUMP_LEAF_AMBIENT_INDEX", // 52
+ "LUMP_LIGHTING_HDR", // 53
+ "LUMP_WORLDLIGHTS_HDR", // 54
+ "LUMP_LEAF_AMBIENT_LIGHTING_HDR", // 55
+ "LUMP_LEAF_AMBIENT_LIGHTING", // 56
+ "LUMP_XZIPPAKFILE", // 57
+ "LUMP_FACES_HDR", // 58
+ "LUMP_MAP_FLAGS", // 59
+ "LUMP_OVERLAY_FADES", // 60
+};
+
+const char *GetLumpName( unsigned int lumpnum )
+{
+ if ( lumpnum >= ARRAYSIZE( s_LumpNames ) )
+ {
+ return "UNKNOWN";
+ }
+ return s_LumpNames[lumpnum];
+}
+
+// "-hdr" tells us to use the HDR fields (if present) on the light sources. Also, tells us to write
+// out the HDR lumps for lightmaps, ambient leaves, and lights sources.
+bool g_bHDR = false;
+
+// Set to true to generate Xbox360 native output files
+static bool g_bSwapOnLoad = false;
+static bool g_bSwapOnWrite = false;
+
+VTFConvertFunc_t g_pVTFConvertFunc;
+VHVFixupFunc_t g_pVHVFixupFunc;
+CompressFunc_t g_pCompressFunc;
+
+CUtlVector< CUtlString > g_StaticPropNames;
+CUtlVector< int > g_StaticPropInstances;
+
+CByteswap g_Swap;
+
+uint32 g_LevelFlags = 0;
+
+int nummodels;
+dmodel_t dmodels[MAX_MAP_MODELS];
+
+int visdatasize;
+byte dvisdata[MAX_MAP_VISIBILITY];
+dvis_t *dvis = (dvis_t *)dvisdata;
+
+CUtlVector<byte> dlightdataHDR;
+CUtlVector<byte> dlightdataLDR;
+CUtlVector<byte> *pdlightdata = &dlightdataLDR;
+
+CUtlVector<char> dentdata;
+
+int numleafs;
+#if !defined( BSP_USE_LESS_MEMORY )
+dleaf_t dleafs[MAX_MAP_LEAFS];
+#else
+dleaf_t *dleafs;
+#endif
+
+CUtlVector<dleafambientindex_t> g_LeafAmbientIndexLDR;
+CUtlVector<dleafambientindex_t> g_LeafAmbientIndexHDR;
+CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex = NULL;
+CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingLDR;
+CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingHDR;
+CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting = NULL;
+
+unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
+
+int numplanes;
+dplane_t dplanes[MAX_MAP_PLANES];
+
+int numvertexes;
+dvertex_t dvertexes[MAX_MAP_VERTS];
+
+int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
+unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
+
+int g_numvertnormals;
+Vector g_vertnormals[MAX_MAP_VERTNORMALS];
+
+int numnodes;
+dnode_t dnodes[MAX_MAP_NODES];
+
+CUtlVector<texinfo_t> texinfo( MAX_MAP_TEXINFO );
+
+int numtexdata;
+dtexdata_t dtexdata[MAX_MAP_TEXDATA];
+
+//
+// displacement map bsp file info: dispinfo
+//
+CUtlVector<ddispinfo_t> g_dispinfo;
+CUtlVector<CDispVert> g_DispVerts;
+CUtlVector<CDispTri> g_DispTris;
+CUtlVector<unsigned char> g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
+
+int numorigfaces;
+dface_t dorigfaces[MAX_MAP_FACES];
+
+int g_numprimitives = 0;
+dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
+
+int g_numprimverts = 0;
+dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
+
+int g_numprimindices = 0;
+unsigned short g_primindices[MAX_MAP_PRIMINDICES];
+
+int numfaces;
+dface_t dfaces[MAX_MAP_FACES];
+
+int numfaceids;
+CUtlVector<dfaceid_t> dfaceids;
+
+int numfaces_hdr;
+dface_t dfaces_hdr[MAX_MAP_FACES];
+
+int numedges;
+dedge_t dedges[MAX_MAP_EDGES];
+
+int numleaffaces;
+unsigned short dleaffaces[MAX_MAP_LEAFFACES];
+
+int numleafbrushes;
+unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int numsurfedges;
+int dsurfedges[MAX_MAP_SURFEDGES];
+
+int numbrushes;
+dbrush_t dbrushes[MAX_MAP_BRUSHES];
+
+int numbrushsides;
+dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
+
+int numareas;
+darea_t dareas[MAX_MAP_AREAS];
+
+int numareaportals;
+dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
+
+int numworldlightsLDR;
+dworldlight_t dworldlightsLDR[MAX_MAP_WORLDLIGHTS];
+
+int numworldlightsHDR;
+dworldlight_t dworldlightsHDR[MAX_MAP_WORLDLIGHTS];
+
+int *pNumworldlights = &numworldlightsLDR;
+dworldlight_t *dworldlights = dworldlightsLDR;
+
+int numleafwaterdata = 0;
+dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
+
+CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
+
+Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
+int g_nClipPortalVerts;
+
+dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
+int g_nCubemapSamples = 0;
+
+int g_nOverlayCount;
+doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
+doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS];
+
+int g_nWaterOverlayCount;
+dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
+
+CUtlVector<char> g_TexDataStringData;
+CUtlVector<int> g_TexDataStringTable;
+
+byte *g_pPhysCollide = NULL;
+int g_PhysCollideSize = 0;
+int g_MapRevision = 0;
+
+byte *g_pPhysDisp = NULL;
+int g_PhysDispSize = 0;
+
+CUtlVector<doccluderdata_t> g_OccluderData( 256, 256 );
+CUtlVector<doccluderpolydata_t> g_OccluderPolyData( 1024, 1024 );
+CUtlVector<int> g_OccluderVertexIndices( 2048, 2048 );
+
+template <class T> static void WriteData( T *pData, int count = 1 );
+template <class T> static void WriteData( int fieldType, T *pData, int count = 1 );
+template< class T > static void AddLump( int lumpnum, T *pData, int count, int version = 0 );
+template< class T > static void AddLump( int lumpnum, CUtlVector<T> &data, int version = 0 );
+
+dheader_t *g_pBSPHeader;
+FileHandle_t g_hBSPFile;
+
+struct Lump_t
+{
+ void *pLumps[HEADER_LUMPS];
+ int size[HEADER_LUMPS];
+ bool bLumpParsed[HEADER_LUMPS];
+} g_Lumps;
+
+CGameLump g_GameLumps;
+
+static IZip *s_pakFile = 0;
+
+//-----------------------------------------------------------------------------
+// Keep the file position aligned to an arbitrary boundary.
+// Returns updated file position.
+//-----------------------------------------------------------------------------
+static unsigned int AlignFilePosition( FileHandle_t hFile, int alignment )
+{
+ unsigned int currPosition = g_pFileSystem->Tell( hFile );
+
+ if ( alignment >= 2 )
+ {
+ unsigned int newPosition = AlignValue( currPosition, alignment );
+ unsigned int count = newPosition - currPosition;
+ if ( count )
+ {
+ char *pBuffer;
+ char smallBuffer[4096];
+ if ( count > sizeof( smallBuffer ) )
+ {
+ pBuffer = (char *)malloc( count );
+ }
+ else
+ {
+ pBuffer = smallBuffer;
+ }
+
+ memset( pBuffer, 0, count );
+ SafeWrite( hFile, pBuffer, count );
+
+ if ( pBuffer != smallBuffer )
+ {
+ free( pBuffer );
+ }
+
+ currPosition = newPosition;
+ }
+ }
+
+ return currPosition;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: // Get a pakfile instance
+// Output : IZip*
+//-----------------------------------------------------------------------------
+IZip* GetPakFile( void )
+{
+ if ( !s_pakFile )
+ {
+ s_pakFile = IZip::CreateZip();
+ }
+ return s_pakFile;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Free the pak files
+//-----------------------------------------------------------------------------
+void ReleasePakFileLumps( void )
+{
+ // Release the pak files
+ IZip::ReleaseZip( s_pakFile );
+ s_pakFile = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the sector alignment for all subsequent zip operations
+//-----------------------------------------------------------------------------
+void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize )
+{
+ pak->ForceAlignment( bAlign, bCompatibleFormat, alignmentSize );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Store data back out to .bsp file
+//-----------------------------------------------------------------------------
+static void WritePakFileLump( void )
+{
+ CUtlBuffer buf( 0, 0 );
+ GetPakFile()->ActivateByteSwapping( IsX360() );
+ GetPakFile()->SaveToBuffer( buf );
+
+ // must respect pak file alignment
+ // pad up and ensure lump starts on same aligned boundary
+ AlignFilePosition( g_hBSPFile, GetPakFile()->GetAlignment() );
+
+ // Now store final buffers out to file
+ AddLump( LUMP_PAKFILE, (byte*)buf.Base(), buf.TellPut() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all entries
+//-----------------------------------------------------------------------------
+void ClearPakFile( IZip *pak )
+{
+ pak->Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add file from disk to .bsp PAK lump
+// Input : *relativename -
+// *fullpath -
+//-----------------------------------------------------------------------------
+void AddFileToPak( IZip *pak, const char *relativename, const char *fullpath )
+{
+ pak->AddFileToZip( relativename, fullpath );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add buffer to .bsp PAK lump as named file
+// Input : *relativename -
+// *data -
+// length -
+//-----------------------------------------------------------------------------
+void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode )
+{
+ pak->AddBufferToZip( pRelativeName, data, length, bTextMode );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if a file already exists in the pack file.
+// Input : *relativename -
+//-----------------------------------------------------------------------------
+bool FileExistsInPak( IZip *pak, const char *pRelativeName )
+{
+ return pak->FileExistsInZip( pRelativeName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Read a file from the pack file
+//-----------------------------------------------------------------------------
+bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
+{
+ return pak->ReadFileFromZip( pRelativeName, bTextMode, buf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove file from .bsp PAK lump
+// Input : *relativename -
+//-----------------------------------------------------------------------------
+void RemoveFileFromPak( IZip *pak, const char *relativename )
+{
+ pak->RemoveFileFromZip( relativename );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get next filename in directory
+// Input : id, -1 to start, returns next id, or -1 at list conclusion
+//-----------------------------------------------------------------------------
+int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize )
+{
+ return pak->GetNextFilename( id, pBuffer, bufferSize, fileSize );
+}
+
+//-----------------------------------------------------------------------------
+// Convert four-CC code to a handle + back
+//-----------------------------------------------------------------------------
+GameLumpHandle_t CGameLump::GetGameLumpHandle( GameLumpId_t id )
+{
+ // NOTE: I'm also expecting game lump id's to be four-CC codes
+ Assert( id > HEADER_LUMPS );
+
+ FOR_EACH_LL(m_GameLumps, i)
+ {
+ if (m_GameLumps[i].m_Id == id)
+ return i;
+ }
+
+ return InvalidGameLump();
+}
+
+GameLumpId_t CGameLump::GetGameLumpId( GameLumpHandle_t handle )
+{
+ return m_GameLumps[handle].m_Id;
+}
+
+int CGameLump::GetGameLumpFlags( GameLumpHandle_t handle )
+{
+ return m_GameLumps[handle].m_Flags;
+}
+
+int CGameLump::GetGameLumpVersion( GameLumpHandle_t handle )
+{
+ return m_GameLumps[handle].m_Version;
+}
+
+
+//-----------------------------------------------------------------------------
+// Game lump accessor methods
+//-----------------------------------------------------------------------------
+
+void* CGameLump::GetGameLump( GameLumpHandle_t id )
+{
+ return m_GameLumps[id].m_Memory.Base();
+}
+
+int CGameLump::GameLumpSize( GameLumpHandle_t id )
+{
+ return m_GameLumps[id].m_Memory.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Game lump iteration methods
+//-----------------------------------------------------------------------------
+
+GameLumpHandle_t CGameLump::FirstGameLump()
+{
+ return (m_GameLumps.Count()) ? m_GameLumps.Head() : InvalidGameLump();
+}
+
+GameLumpHandle_t CGameLump::NextGameLump( GameLumpHandle_t handle )
+{
+
+ return (m_GameLumps.IsValidIndex(handle)) ? m_GameLumps.Next(handle) : InvalidGameLump();
+}
+
+GameLumpHandle_t CGameLump::InvalidGameLump()
+{
+ return 0xFFFF;
+}
+
+
+//-----------------------------------------------------------------------------
+// Game lump creation/destruction method
+//-----------------------------------------------------------------------------
+
+GameLumpHandle_t CGameLump::CreateGameLump( GameLumpId_t id, int size, int flags, int version )
+{
+ Assert( GetGameLumpHandle(id) == InvalidGameLump() );
+ GameLumpHandle_t handle = m_GameLumps.AddToTail();
+ m_GameLumps[handle].m_Id = id;
+ m_GameLumps[handle].m_Flags = flags;
+ m_GameLumps[handle].m_Version = version;
+ m_GameLumps[handle].m_Memory.EnsureCapacity( size );
+ return handle;
+}
+
+void CGameLump::DestroyGameLump( GameLumpHandle_t handle )
+{
+ m_GameLumps.Remove( handle );
+}
+
+void CGameLump::DestroyAllGameLumps()
+{
+ m_GameLumps.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Compute file size and clump count
+//-----------------------------------------------------------------------------
+
+void CGameLump::ComputeGameLumpSizeAndCount( int& size, int& clumpCount )
+{
+ // Figure out total size of the client lumps
+ size = 0;
+ clumpCount = 0;
+ GameLumpHandle_t h;
+ for( h = FirstGameLump(); h != InvalidGameLump(); h = NextGameLump( h ) )
+ {
+ ++clumpCount;
+ size += GameLumpSize( h );
+ }
+
+ // Add on headers
+ size += sizeof( dgamelumpheader_t ) + clumpCount * sizeof( dgamelump_t );
+}
+
+
+void CGameLump::SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int length )
+{
+ int count = 0;
+ switch( id )
+ {
+ case GAMELUMP_STATIC_PROPS:
+ // Swap the static prop model dict
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (StaticPropDictLump_t*)dest, (StaticPropDictLump_t*)src, count );
+ src += sizeof(StaticPropDictLump_t) * count;
+ dest += sizeof(StaticPropDictLump_t) * count;
+
+ // Swap the leaf list
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (StaticPropLeafLump_t*)dest, (StaticPropLeafLump_t*)src, count );
+ src += sizeof(StaticPropLeafLump_t) * count;
+ dest += sizeof(StaticPropLeafLump_t) * count;
+
+ // Swap the models
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ // The one-at-a-time swap is to compensate for these structures
+ // possibly being misaligned, which crashes the Xbox 360.
+ if ( version == 4 )
+ {
+ StaticPropLumpV4_t lump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &lump, src, sizeof(StaticPropLumpV4_t) );
+ g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
+ Q_memcpy( dest, &lump, sizeof(StaticPropLumpV4_t) );
+ src += sizeof( StaticPropLumpV4_t );
+ dest += sizeof( StaticPropLumpV4_t );
+ }
+ }
+ else if ( version == 5 )
+ {
+ StaticPropLumpV5_t lump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &lump, src, sizeof(StaticPropLumpV5_t) );
+ g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
+ Q_memcpy( dest, &lump, sizeof(StaticPropLumpV5_t) );
+ src += sizeof( StaticPropLumpV5_t );
+ dest += sizeof( StaticPropLumpV5_t );
+ }
+ }
+ else
+ {
+ if ( version != 6 )
+ {
+ Error( "Unknown Static Prop Lump version %d didn't get swapped!\n", version );
+ }
+
+ StaticPropLump_t lump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &lump, src, sizeof(StaticPropLump_t) );
+ g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
+ Q_memcpy( dest, &lump, sizeof(StaticPropLump_t) );
+ src += sizeof( StaticPropLump_t );
+ dest += sizeof( StaticPropLump_t );
+ }
+ }
+ break;
+
+ case GAMELUMP_DETAIL_PROPS:
+ // Swap the detail prop model dict
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (DetailObjectDictLump_t*)dest, (DetailObjectDictLump_t*)src, count );
+ src += sizeof(DetailObjectDictLump_t) * count;
+ dest += sizeof(DetailObjectDictLump_t) * count;
+
+ if ( version == 4 )
+ {
+ // Swap the detail sprite dict
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ DetailSpriteDictLump_t spritelump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &spritelump, src, sizeof(DetailSpriteDictLump_t) );
+ g_Swap.SwapFieldsToTargetEndian( &spritelump, &spritelump );
+ Q_memcpy( dest, &spritelump, sizeof(DetailSpriteDictLump_t) );
+ src += sizeof(DetailSpriteDictLump_t);
+ dest += sizeof(DetailSpriteDictLump_t);
+ }
+
+ // Swap the models
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ DetailObjectLump_t objectlump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &objectlump, src, sizeof(DetailObjectLump_t) );
+ g_Swap.SwapFieldsToTargetEndian( &objectlump, &objectlump );
+ Q_memcpy( dest, &objectlump, sizeof(DetailObjectLump_t) );
+ src += sizeof(DetailObjectLump_t);
+ dest += sizeof(DetailObjectLump_t);
+ }
+ }
+ break;
+
+ case GAMELUMP_DETAIL_PROP_LIGHTING:
+ // Swap the LDR light styles
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
+ src += sizeof(DetailObjectDictLump_t) * count;
+ dest += sizeof(DetailObjectDictLump_t) * count;
+ break;
+
+ case GAMELUMP_DETAIL_PROP_LIGHTING_HDR:
+ // Swap the HDR light styles
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
+ src += sizeof(DetailObjectDictLump_t) * count;
+ dest += sizeof(DetailObjectDictLump_t) * count;
+ break;
+
+ default:
+ char idchars[5] = {0};
+ Q_memcpy( idchars, &id, 4 );
+ Warning( "Unknown game lump '%s' didn't get swapped!\n", idchars );
+ memcpy ( dest, src, length);
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Game lump file I/O
+//-----------------------------------------------------------------------------
+void CGameLump::ParseGameLump( dheader_t* pHeader )
+{
+ g_GameLumps.DestroyAllGameLumps();
+
+ g_Lumps.bLumpParsed[LUMP_GAME_LUMP] = true;
+
+ int length = pHeader->lumps[LUMP_GAME_LUMP].filelen;
+ int ofs = pHeader->lumps[LUMP_GAME_LUMP].fileofs;
+
+ if (length > 0)
+ {
+ // Read dictionary...
+ dgamelumpheader_t* pGameLumpHeader = (dgamelumpheader_t*)((byte *)pHeader + ofs);
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( pGameLumpHeader );
+ }
+ dgamelump_t* pGameLump = (dgamelump_t*)(pGameLumpHeader + 1);
+ for (int i = 0; i < pGameLumpHeader->lumpCount; ++i )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( &pGameLump[i] );
+ }
+
+ int length = pGameLump[i].filelen;
+ GameLumpHandle_t lump = g_GameLumps.CreateGameLump( pGameLump[i].id, length, pGameLump[i].flags, pGameLump[i].version );
+ if ( g_bSwapOnLoad )
+ {
+ SwapGameLump( pGameLump[i].id, pGameLump[i].version, (byte*)g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
+ }
+ else
+ {
+ memcpy( g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// String table methods
+//-----------------------------------------------------------------------------
+const char *TexDataStringTable_GetString( int stringID )
+{
+ return &g_TexDataStringData[g_TexDataStringTable[stringID]];
+}
+
+int TexDataStringTable_AddOrFindString( const char *pString )
+{
+ int i;
+ // garymcthack: Make this use an RBTree!
+ for( i = 0; i < g_TexDataStringTable.Count(); i++ )
+ {
+ if( stricmp( pString, &g_TexDataStringData[g_TexDataStringTable[i]] ) == 0 )
+ {
+ return i;
+ }
+ }
+
+ int len = strlen( pString );
+ int outOffset = g_TexDataStringData.AddMultipleToTail( len+1, pString );
+ int outIndex = g_TexDataStringTable.AddToTail( outOffset );
+ return outIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Adds all game lumps into one big block
+//-----------------------------------------------------------------------------
+
+static void AddGameLumps( )
+{
+ // Figure out total size of the client lumps
+ int size, clumpCount;
+ g_GameLumps.ComputeGameLumpSizeAndCount( size, clumpCount );
+
+ // Set up the main lump dictionary entry
+ g_Lumps.size[LUMP_GAME_LUMP] = 0; // mark it written
+
+ lump_t* lump = &g_pBSPHeader->lumps[LUMP_GAME_LUMP];
+
+ lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
+ lump->filelen = size;
+
+ // write header
+ dgamelumpheader_t header;
+ header.lumpCount = clumpCount;
+ WriteData( &header );
+
+ // write dictionary
+ dgamelump_t dict;
+ int offset = lump->fileofs + sizeof(header) + clumpCount * sizeof(dgamelump_t);
+ GameLumpHandle_t h;
+ for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
+ {
+ dict.id = g_GameLumps.GetGameLumpId(h);
+ dict.version = g_GameLumps.GetGameLumpVersion(h);
+ dict.flags = g_GameLumps.GetGameLumpFlags(h);
+ dict.fileofs = offset;
+ dict.filelen = g_GameLumps.GameLumpSize( h );
+ offset += dict.filelen;
+
+ WriteData( &dict );
+ }
+
+ // write lumps..
+ for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
+ {
+ unsigned int lumpsize = g_GameLumps.GameLumpSize(h);
+ if ( g_bSwapOnWrite )
+ {
+ g_GameLumps.SwapGameLump( g_GameLumps.GetGameLumpId(h), g_GameLumps.GetGameLumpVersion(h), (byte*)g_GameLumps.GetGameLump(h), (byte*)g_GameLumps.GetGameLump(h), lumpsize );
+ }
+ SafeWrite( g_hBSPFile, g_GameLumps.GetGameLump(h), lumpsize );
+ }
+
+ // align to doubleword
+ AlignFilePosition( g_hBSPFile, 4 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds the occluder lump...
+//-----------------------------------------------------------------------------
+static void AddOcclusionLump( )
+{
+ g_Lumps.size[LUMP_OCCLUSION] = 0; // mark it written
+
+ int nOccluderCount = g_OccluderData.Count();
+ int nOccluderPolyDataCount = g_OccluderPolyData.Count();
+ int nOccluderVertexIndices = g_OccluderVertexIndices.Count();
+
+ int nLumpLength = nOccluderCount * sizeof(doccluderdata_t) +
+ nOccluderPolyDataCount * sizeof(doccluderpolydata_t) +
+ nOccluderVertexIndices * sizeof(int) +
+ 3 * sizeof(int);
+
+ lump_t *lump = &g_pBSPHeader->lumps[LUMP_OCCLUSION];
+
+ lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
+ lump->filelen = nLumpLength;
+ lump->version = LUMP_OCCLUSION_VERSION;
+ lump->fourCC[0] = ( char )0;
+ lump->fourCC[1] = ( char )0;
+ lump->fourCC[2] = ( char )0;
+ lump->fourCC[3] = ( char )0;
+
+ // Data is swapped in place, so the 'Count' variables aren't safe to use after they're written
+ WriteData( FIELD_INTEGER, &nOccluderCount );
+ WriteData( (doccluderdata_t*)g_OccluderData.Base(), g_OccluderData.Count() );
+ WriteData( FIELD_INTEGER, &nOccluderPolyDataCount );
+ WriteData( (doccluderpolydata_t*)g_OccluderPolyData.Base(), g_OccluderPolyData.Count() );
+ WriteData( FIELD_INTEGER, &nOccluderVertexIndices );
+ WriteData( FIELD_INTEGER, (int*)g_OccluderVertexIndices.Base(), g_OccluderVertexIndices.Count() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the occluder lump...
+//-----------------------------------------------------------------------------
+static void UnserializeOcclusionLumpV2( CUtlBuffer &buf )
+{
+ int nCount = buf.GetInt();
+ if ( nCount )
+ {
+ g_OccluderData.SetCount( nCount );
+ buf.GetObjects( g_OccluderData.Base(), nCount );
+ }
+
+ nCount = buf.GetInt();
+ if ( nCount )
+ {
+ g_OccluderPolyData.SetCount( nCount );
+ buf.GetObjects( g_OccluderPolyData.Base(), nCount );
+ }
+
+ nCount = buf.GetInt();
+ if ( nCount )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( (int*)buf.PeekGet(), (int*)buf.PeekGet(), nCount );
+ }
+ g_OccluderVertexIndices.SetCount( nCount );
+ buf.Get( g_OccluderVertexIndices.Base(), nCount * sizeof(g_OccluderVertexIndices[0]) );
+ }
+}
+
+
+static void LoadOcclusionLump()
+{
+ g_OccluderData.RemoveAll();
+ g_OccluderPolyData.RemoveAll();
+ g_OccluderVertexIndices.RemoveAll();
+
+ int length, ofs;
+
+ g_Lumps.bLumpParsed[LUMP_OCCLUSION] = true;
+
+ length = g_pBSPHeader->lumps[LUMP_OCCLUSION].filelen;
+ ofs = g_pBSPHeader->lumps[LUMP_OCCLUSION].fileofs;
+
+ CUtlBuffer buf( (byte *)g_pBSPHeader + ofs, length, CUtlBuffer::READ_ONLY );
+ buf.ActivateByteSwapping( g_bSwapOnLoad );
+ switch ( g_pBSPHeader->lumps[LUMP_OCCLUSION].version )
+ {
+ case 2:
+ UnserializeOcclusionLumpV2( buf );
+ break;
+
+ case 0:
+ break;
+
+ default:
+ Error("Unknown occlusion lump version!\n");
+ break;
+ }
+}
+
+
+/*
+===============
+CompressVis
+
+===============
+*/
+int CompressVis (byte *vis, byte *dest)
+{
+ int j;
+ int rep;
+ int visrow;
+ byte *dest_p;
+
+ dest_p = dest;
+// visrow = (r_numvisleafs + 7)>>3;
+ visrow = (dvis->numclusters + 7)>>3;
+
+ for (j=0 ; j<visrow ; j++)
+ {
+ *dest_p++ = vis[j];
+ if (vis[j])
+ continue;
+
+ rep = 1;
+ for ( j++; j<visrow ; j++)
+ if (vis[j] || rep == 255)
+ break;
+ else
+ rep++;
+ *dest_p++ = rep;
+ j--;
+ }
+
+ return dest_p - dest;
+}
+
+
+/*
+===================
+DecompressVis
+===================
+*/
+void DecompressVis (byte *in, byte *decompressed)
+{
+ int c;
+ byte *out;
+ int row;
+
+// row = (r_numvisleafs+7)>>3;
+ row = (dvis->numclusters+7)>>3;
+ out = decompressed;
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ if (!c)
+ Error ("DecompressVis: 0 repeat");
+ in += 2;
+ if ((out - decompressed) + c > row)
+ {
+ c = row - (out - decompressed);
+ Warning( "warning: Vis decompression overrun\n" );
+ }
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+}
+
+//-----------------------------------------------------------------------------
+// Lump-specific swap functions
+//-----------------------------------------------------------------------------
+struct swapcollideheader_t
+{
+ DECLARE_BYTESWAP_DATADESC();
+ int size;
+ int vphysicsID;
+ short version;
+ short modelType;
+};
+
+struct swapcompactsurfaceheader_t : swapcollideheader_t
+{
+ DECLARE_BYTESWAP_DATADESC();
+ int surfaceSize;
+ Vector dragAxisAreas;
+ int axisMapSize;
+};
+
+struct swapmoppsurfaceheader_t : swapcollideheader_t
+{
+ DECLARE_BYTESWAP_DATADESC();
+ int moppSize;
+};
+
+BEGIN_BYTESWAP_DATADESC( swapcollideheader_t )
+ DEFINE_FIELD( size, FIELD_INTEGER ),
+ DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
+ DEFINE_FIELD( version, FIELD_SHORT ),
+ DEFINE_FIELD( modelType, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC_( swapcompactsurfaceheader_t, swapcollideheader_t )
+ DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
+ DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
+ DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC_( swapmoppsurfaceheader_t, swapcollideheader_t )
+ DEFINE_FIELD( moppSize, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+
+static void SwapPhyscollideLump( byte *pDestBase, byte *pSrcBase, unsigned int &count )
+{
+ IPhysicsCollision *physcollision = NULL;
+ CSysModule *pPhysicsModule = g_pFullFileSystem->LoadModule( "vphysics.dll" );
+ if ( pPhysicsModule )
+ {
+ CreateInterfaceFn physicsFactory = Sys_GetFactory( pPhysicsModule );
+ if ( physicsFactory )
+ {
+ physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
+ }
+ }
+
+ if ( !physcollision )
+ {
+ Warning("!!! WARNING: Can't swap the physcollide lump!\n" );
+ return;
+ }
+
+ // physics data is variable length. The last physmodel is a NULL pointer
+ // with modelIndex -1, dataSize -1
+ dphysmodel_t *pPhysModel;
+ byte *pSrc = pSrcBase;
+
+ // first the src chunks have to be aligned properly
+ // swap increases size, allocate enough expansion room
+ byte *pSrcAlignedBase = (byte*)malloc( 2*count );
+ byte *basePtr = pSrcAlignedBase;
+ byte *pSrcAligned = pSrcAlignedBase;
+
+ do
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pSrcAligned, (dphysmodel_t*)pSrc );
+ }
+ else
+ {
+ Q_memcpy( pSrcAligned, pSrc, sizeof(dphysmodel_t) );
+ }
+ pPhysModel = (dphysmodel_t*)pSrcAligned;
+
+ pSrc += sizeof(dphysmodel_t);
+ pSrcAligned += sizeof(dphysmodel_t);
+
+ if ( pPhysModel->dataSize > 0 )
+ {
+ // Align the collide headers
+ for ( int i = 0; i < pPhysModel->solidCount; ++i )
+ {
+ // Get data size
+ int size;
+ Q_memcpy( &size, pSrc, sizeof(int) );
+ if ( g_bSwapOnLoad )
+ size = SwapLong( size );
+
+ // Fixup size
+ int padBytes = 0;
+ if ( size % 4 != 0 )
+ {
+ padBytes = ( 4 - size % 4 );
+ count += padBytes;
+ pPhysModel->dataSize += padBytes;
+ }
+
+ // Copy data and size into alligned buffer
+ int newsize = size + padBytes;
+ if ( g_bSwapOnLoad )
+ newsize = SwapLong( newsize );
+
+ Q_memcpy( pSrcAligned, &newsize, sizeof(int) );
+ Q_memcpy( pSrcAligned + sizeof(int), pSrc + sizeof(int), size );
+ pSrcAligned += size + padBytes + sizeof(int);
+ pSrc += size + sizeof(int);
+ }
+
+ int padBytes = 0;
+ int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
+ Q_memcpy( pSrcAligned, pSrc, pPhysModel->keydataSize );
+ pSrc += pPhysModel->keydataSize;
+ pSrcAligned += pPhysModel->keydataSize;
+ if ( dataSize % 4 != 0 )
+ {
+ // Next chunk will be unaligned
+ padBytes = ( 4 - dataSize % 4 );
+ pPhysModel->keydataSize += padBytes;
+ count += padBytes;
+ Q_memset( pSrcAligned, 0, padBytes );
+ pSrcAligned += padBytes;
+ }
+ }
+ } while ( pPhysModel->dataSize > 0 );
+
+ // Now the data can be swapped properly
+ pSrcBase = pSrcAlignedBase;
+ pSrc = pSrcBase;
+ byte *pDest = pDestBase;
+
+ do
+ {
+ // src headers are in native format
+ pPhysModel = (dphysmodel_t*)pSrc;
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pDest, (dphysmodel_t*)pSrc );
+ }
+ else
+ {
+ Q_memcpy( pDest, pSrc, sizeof(dphysmodel_t) );
+ }
+
+ pSrc += sizeof(dphysmodel_t);
+ pDest += sizeof(dphysmodel_t);
+
+ pSrcBase = pSrc;
+ pDestBase = pDest;
+
+ if ( pPhysModel->dataSize > 0 )
+ {
+ vcollide_t collide = {0};
+ int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
+
+ if ( g_bSwapOnWrite )
+ {
+ // Load the collide data
+ physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, false );
+ }
+
+ int *offsets = new int[ pPhysModel->solidCount ];
+
+ // Swap the collision data headers
+ for ( int i = 0; i < pPhysModel->solidCount; ++i )
+ {
+ int headerSize = 0;
+ swapcollideheader_t *baseHdr = (swapcollideheader_t*)pSrc;
+ short modelType = baseHdr->modelType;
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( &modelType );
+ }
+
+ if ( modelType == 0 ) // COLLIDE_POLY
+ {
+ headerSize = sizeof(swapcompactsurfaceheader_t);
+ swapcompactsurfaceheader_t swapHdr;
+ Q_memcpy( &swapHdr, pSrc, headerSize );
+ g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
+ Q_memcpy( pDest, &swapHdr, headerSize );
+ }
+ else if ( modelType == 1 ) // COLLIDE_MOPP
+ {
+ // The PC still unserializes these, but we don't support them
+ if ( g_bSwapOnWrite )
+ {
+ collide.solids[i] = NULL;
+ }
+
+ headerSize = sizeof(swapmoppsurfaceheader_t);
+ swapmoppsurfaceheader_t swapHdr;
+ Q_memcpy( &swapHdr, pSrc, headerSize );
+ g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
+ Q_memcpy( pDest, &swapHdr, headerSize );
+
+ }
+ else
+ {
+ // Shouldn't happen
+ Assert( 0 );
+ }
+
+ if ( g_bSwapOnLoad )
+ {
+ // src needs the native header data to load the vcollides
+ Q_memcpy( pSrc, pDest, headerSize );
+ }
+ // HACK: Need either surfaceSize or moppSize - both sit at the same offset in the structure
+ swapmoppsurfaceheader_t *hdr = (swapmoppsurfaceheader_t*)pSrc;
+ pSrc += hdr->size + sizeof(int);
+ pDest += hdr->size + sizeof(int);
+ offsets[i] = hdr->size;
+ }
+
+ pSrc = pSrcBase;
+ pDest = pDestBase;
+ if ( g_bSwapOnLoad )
+ {
+ physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, true );
+ }
+
+ // Write out the ledge tree data
+ for ( int i = 0; i < pPhysModel->solidCount; ++i )
+ {
+ if ( collide.solids[i] )
+ {
+ // skip over the size member
+ pSrc += sizeof(int);
+ pDest += sizeof(int);
+ int offset = physcollision->CollideWrite( (char*)pDest, collide.solids[i], g_bSwapOnWrite );
+ pSrc += offset;
+ pDest += offset;
+ }
+ else
+ {
+ pSrc += offsets[i] + sizeof(int);
+ pDest += offsets[i] + sizeof(int);
+ }
+ }
+
+ // copy the keyvalues data
+ Q_memcpy( pDest, pSrc, pPhysModel->keydataSize );
+ pDest += pPhysModel->keydataSize;
+ pSrc += pPhysModel->keydataSize;
+
+ // Free the memory
+ physcollision->VCollideUnload( &collide );
+ delete [] offsets;
+ }
+
+ // avoid infinite loop on badly formed file
+ if ( (pSrc - basePtr) > count )
+ break;
+
+ } while ( pPhysModel->dataSize > 0 );
+
+ free( pSrcAlignedBase );
+}
+
+
+// UNDONE: This code is not yet tested.
+static void SwapPhysdispLump( byte *pDest, byte *pSrc, int count )
+{
+ // the format of this lump is one unsigned short dispCount, then dispCount unsigned shorts of sizes
+ // followed by an array of variable length (each element is the length of the corresponding entry in the
+ // previous table) byte-stream data structure of the displacement collision models
+ // these byte-stream structs are endian-neutral because each element is byte-sized
+ unsigned short dispCount = *(unsigned short*)pSrc;
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( &dispCount );
+ }
+ g_Swap.SwapBufferToTargetEndian( (unsigned short*)pDest, (unsigned short*)pSrc, dispCount + 1 );
+
+ const int nBytes = (dispCount + 1) * sizeof( unsigned short );
+ pSrc += nBytes;
+ pDest += nBytes;
+ count -= nBytes;
+
+ g_Swap.SwapBufferToTargetEndian( pDest, pSrc, count );
+}
+
+
+static void SwapVisibilityLump( byte *pDest, byte *pSrc, int count )
+{
+ int firstInt = *(int*)pSrc;
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( &firstInt );
+ }
+ int intCt = firstInt * 2 + 1;
+ const int hdrSize = intCt * sizeof(int);
+ g_Swap.SwapBufferToTargetEndian( (int*)pDest, (int*)pSrc, intCt );
+ g_Swap.SwapBufferToTargetEndian( pDest + hdrSize, pSrc + hdrSize, count - hdrSize );
+}
+
+//=============================================================================
+void Lumps_Init( void )
+{
+ memset( &g_Lumps, 0, sizeof(g_Lumps) );
+}
+
+int LumpVersion( int lump )
+{
+ return g_pBSPHeader->lumps[lump].version;
+}
+
+bool HasLump( int lump )
+{
+ return g_pBSPHeader->lumps[lump].filelen > 0;
+}
+
+void ValidateLump( int lump, int length, int size, int forceVersion )
+{
+ if ( length % size )
+ {
+ Error( "ValidateLump: odd size for lump %d", lump );
+ }
+
+ if ( forceVersion >= 0 && forceVersion != g_pBSPHeader->lumps[lump].version )
+ {
+ Error( "ValidateLump: old version for lump %d in map!", lump );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Add Lumps of integral types without datadescs
+//-----------------------------------------------------------------------------
+template< class T >
+int CopyLumpInternal( int fieldType, int lump, T *dest, int forceVersion )
+{
+ g_Lumps.bLumpParsed[lump] = true;
+
+ // Vectors are passed in as floats
+ int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
+ unsigned int length = g_pBSPHeader->lumps[lump].filelen;
+ unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
+
+ // count must be of the integral type
+ unsigned int count = length / sizeof(T);
+
+ ValidateLump( lump, length, fieldSize, forceVersion );
+
+ if ( g_bSwapOnLoad )
+ {
+ switch( lump )
+ {
+ case LUMP_VISIBILITY:
+ SwapVisibilityLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
+ break;
+
+ case LUMP_PHYSCOLLIDE:
+ // SwapPhyscollideLump may change size
+ SwapPhyscollideLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
+ length = count;
+ break;
+
+ case LUMP_PHYSDISP:
+ SwapPhysdispLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
+ break;
+
+ default:
+ g_Swap.SwapBufferToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
+ break;
+ }
+ }
+ else
+ {
+ memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
+ }
+
+ // Return actual count of elements
+ return length / fieldSize;
+}
+
+template< class T >
+int CopyLump( int fieldType, int lump, T *dest, int forceVersion = -1 )
+{
+ return CopyLumpInternal( fieldType, lump, dest, forceVersion );
+}
+
+template< class T >
+void CopyLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ Assert( fieldType != FIELD_VECTOR ); // TODO: Support this if necessary
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+void CopyOptionalLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ // not fatal if not present
+ if ( !HasLump( lump ) )
+ return;
+
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+int CopyVariableLump( int fieldType, int lump, void **dest, int forceVersion = -1 )
+{
+ int length = g_pBSPHeader->lumps[lump].filelen;
+ *dest = malloc( length );
+
+ return CopyLumpInternal<T>( fieldType, lump, (T*)*dest, forceVersion );
+}
+
+//-----------------------------------------------------------------------------
+// Add Lumps of object types with datadescs
+//-----------------------------------------------------------------------------
+template< class T >
+int CopyLumpInternal( int lump, T *dest, int forceVersion )
+{
+ g_Lumps.bLumpParsed[lump] = true;
+
+ unsigned int length = g_pBSPHeader->lumps[lump].filelen;
+ unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
+ unsigned int count = length / sizeof(T);
+
+ ValidateLump( lump, length, sizeof(T), forceVersion );
+
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
+ }
+ else
+ {
+ memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
+ }
+
+ return count;
+}
+
+template< class T >
+int CopyLump( int lump, T *dest, int forceVersion = -1 )
+{
+ return CopyLumpInternal( lump, dest, forceVersion );
+}
+
+template< class T >
+void CopyLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+void CopyOptionalLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ // not fatal if not present
+ if ( !HasLump( lump ) )
+ return;
+
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+int CopyVariableLump( int lump, void **dest, int forceVersion = -1 )
+{
+ int length = g_pBSPHeader->lumps[lump].filelen;
+ *dest = malloc( length );
+
+ return CopyLumpInternal<T>( lump, (T*)*dest, forceVersion );
+}
+
+//-----------------------------------------------------------------------------
+// Add/Write unknown lumps
+//-----------------------------------------------------------------------------
+void Lumps_Parse( void )
+{
+ int i;
+
+ for ( i = 0; i < HEADER_LUMPS; i++ )
+ {
+ if ( !g_Lumps.bLumpParsed[i] && g_pBSPHeader->lumps[i].filelen )
+ {
+ g_Lumps.size[i] = CopyVariableLump<byte>( FIELD_CHARACTER, i, &g_Lumps.pLumps[i], -1 );
+ Msg( "Reading unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
+ }
+ }
+}
+
+void Lumps_Write( void )
+{
+ int i;
+
+ for ( i = 0; i < HEADER_LUMPS; i++ )
+ {
+ if ( g_Lumps.size[i] )
+ {
+ Msg( "Writing unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
+ AddLump( i, (byte*)g_Lumps.pLumps[i], g_Lumps.size[i] );
+ }
+ if ( g_Lumps.pLumps[i] )
+ {
+ free( g_Lumps.pLumps[i] );
+ g_Lumps.pLumps[i] = NULL;
+ }
+ }
+}
+
+int LoadLeafs( void )
+{
+#if defined( BSP_USE_LESS_MEMORY )
+ dleafs = (dleaf_t*)malloc( g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
+#endif
+
+ switch ( LumpVersion( LUMP_LEAFS ) )
+ {
+ case 0:
+ {
+ g_Lumps.bLumpParsed[LUMP_LEAFS] = true;
+ int length = g_pBSPHeader->lumps[LUMP_LEAFS].filelen;
+ int size = sizeof( dleaf_version_0_t );
+ if ( length % size )
+ {
+ Error( "odd size for LUMP_LEAFS\n" );
+ }
+ int count = length / size;
+
+ void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAFS].fileofs );
+ dleaf_version_0_t *pSrc = (dleaf_version_0_t *)pSrcBase;
+ dleaf_t *pDst = dleafs;
+
+ // version 0 predates HDR, build the LDR
+ g_LeafAmbientLightingLDR.SetCount( count );
+ g_LeafAmbientIndexLDR.SetCount( count );
+
+ dleafambientlighting_t *pDstLeafAmbientLighting = &g_LeafAmbientLightingLDR[0];
+ for ( int i = 0; i < count; i++ )
+ {
+ g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
+ g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
+
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( pSrc );
+ }
+ // pDst is a subset of pSrc;
+ *pDst = *( ( dleaf_t * )( void * )pSrc );
+ pDstLeafAmbientLighting->cube = pSrc->m_AmbientLighting;
+ pDstLeafAmbientLighting->x = pDstLeafAmbientLighting->y = pDstLeafAmbientLighting->z = pDstLeafAmbientLighting->pad = 0;
+ pDst++;
+ pSrc++;
+ pDstLeafAmbientLighting++;
+ }
+ return count;
+ }
+
+ case 1:
+ return CopyLump( LUMP_LEAFS, dleafs );
+
+ default:
+ Assert( 0 );
+ Error( "Unknown LUMP_LEAFS version\n" );
+ return 0;
+ }
+}
+
+void LoadLeafAmbientLighting( int numLeafs )
+{
+ if ( LumpVersion( LUMP_LEAFS ) == 0 )
+ {
+ // an older leaf version already built the LDR ambient lighting on load
+ return;
+ }
+
+ // old BSP with ambient, or new BSP with no lighting, convert ambient light to new format or create dummy ambient
+ if ( !HasLump( LUMP_LEAF_AMBIENT_INDEX ) )
+ {
+ // a bunch of legacy maps, have these lumps with garbage versions
+ // expect them to be NOT the current version
+ if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING) )
+ {
+ Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+ }
+ if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING_HDR) )
+ {
+ Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+ }
+
+ void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].fileofs );
+ CompressedLightCube *pSrc = NULL;
+ if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING ) )
+ {
+ pSrc = (CompressedLightCube*)pSrcBase;
+ }
+ g_LeafAmbientIndexLDR.SetCount( numLeafs );
+ g_LeafAmbientLightingLDR.SetCount( numLeafs );
+
+ void *pSrcBaseHDR = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].fileofs );
+ CompressedLightCube *pSrcHDR = NULL;
+ if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
+ {
+ pSrcHDR = (CompressedLightCube*)pSrcBaseHDR;
+ }
+ g_LeafAmbientIndexHDR.SetCount( numLeafs );
+ g_LeafAmbientLightingHDR.SetCount( numLeafs );
+
+ for ( int i = 0; i < numLeafs; i++ )
+ {
+ g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
+ g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
+ g_LeafAmbientIndexHDR[i].ambientSampleCount = 1;
+ g_LeafAmbientIndexHDR[i].firstAmbientSample = i;
+
+ Q_memset( &g_LeafAmbientLightingLDR[i], 0, sizeof(g_LeafAmbientLightingLDR[i]) );
+ Q_memset( &g_LeafAmbientLightingHDR[i], 0, sizeof(g_LeafAmbientLightingHDR[i]) );
+
+ if ( pSrc )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( &pSrc[i] );
+ }
+ g_LeafAmbientLightingLDR[i].cube = pSrc[i];
+ }
+ if ( pSrcHDR )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( &pSrcHDR[i] );
+ }
+ g_LeafAmbientLightingHDR[i].cube = pSrcHDR[i];
+ }
+ }
+
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
+ }
+ else
+ {
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR );
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR );
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
+ }
+}
+
+void ValidateHeader( const char *filename, const dheader_t *pHeader )
+{
+ if ( pHeader->ident != IDBSPHEADER )
+ {
+ Error ("%s is not a IBSP file", filename);
+ }
+ if ( pHeader->version < MINBSPVERSION || pHeader->version > BSPVERSION )
+ {
+ Error ("%s is version %i, not %i", filename, pHeader->version, BSPVERSION);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Low level BSP opener for external parsing. Parses headers, but nothing else.
+// You must close the BSP, via CloseBSPFile().
+//-----------------------------------------------------------------------------
+void OpenBSPFile( const char *filename )
+{
+ Lumps_Init();
+
+ // load the file header
+ LoadFile( filename, (void **)&g_pBSPHeader );
+
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.ActivateByteSwapping( true );
+ g_Swap.SwapFieldsToTargetEndian( g_pBSPHeader );
+ }
+
+ ValidateHeader( filename, g_pBSPHeader );
+
+ g_MapRevision = g_pBSPHeader->mapRevision;
+}
+
+//-----------------------------------------------------------------------------
+// CloseBSPFile
+//-----------------------------------------------------------------------------
+void CloseBSPFile( void )
+{
+ free( g_pBSPHeader );
+ g_pBSPHeader = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// LoadBSPFile
+//-----------------------------------------------------------------------------
+void LoadBSPFile( const char *filename )
+{
+ OpenBSPFile( filename );
+
+ nummodels = CopyLump( LUMP_MODELS, dmodels );
+ numvertexes = CopyLump( LUMP_VERTEXES, dvertexes );
+ numplanes = CopyLump( LUMP_PLANES, dplanes );
+ numleafs = LoadLeafs();
+ numnodes = CopyLump( LUMP_NODES, dnodes );
+ CopyLump( LUMP_TEXINFO, texinfo );
+ numtexdata = CopyLump( LUMP_TEXDATA, dtexdata );
+
+ CopyLump( LUMP_DISPINFO, g_dispinfo );
+ CopyLump( LUMP_DISP_VERTS, g_DispVerts );
+ CopyLump( LUMP_DISP_TRIS, g_DispTris );
+ CopyLump( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
+ CopyLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
+
+ numfaces = CopyLump(LUMP_FACES, dfaces, LUMP_FACES_VERSION);
+ if ( HasLump( LUMP_FACES_HDR ) )
+ numfaces_hdr = CopyLump( LUMP_FACES_HDR, dfaces_hdr, LUMP_FACES_VERSION );
+ else
+ numfaces_hdr = 0;
+
+ CopyOptionalLump( LUMP_FACEIDS, dfaceids );
+
+ g_numprimitives = CopyLump( LUMP_PRIMITIVES, g_primitives );
+ g_numprimverts = CopyLump( LUMP_PRIMVERTS, g_primverts );
+ g_numprimindices = CopyLump( FIELD_SHORT, LUMP_PRIMINDICES, g_primindices );
+ numorigfaces = CopyLump( LUMP_ORIGINALFACES, dorigfaces ); // original faces
+ numleaffaces = CopyLump( FIELD_SHORT, LUMP_LEAFFACES, dleaffaces );
+ numleafbrushes = CopyLump( FIELD_SHORT, LUMP_LEAFBRUSHES, dleafbrushes );
+ numsurfedges = CopyLump( FIELD_INTEGER, LUMP_SURFEDGES, dsurfedges );
+ numedges = CopyLump( LUMP_EDGES, dedges );
+ numbrushes = CopyLump( LUMP_BRUSHES, dbrushes );
+ numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides );
+ numareas = CopyLump( LUMP_AREAS, dareas );
+ numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals );
+
+ visdatasize = CopyLump ( FIELD_CHARACTER, LUMP_VISIBILITY, dvisdata );
+ CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
+ CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
+
+ LoadLeafAmbientLighting( numleafs );
+
+ CopyLump( FIELD_CHARACTER, LUMP_ENTITIES, dentdata );
+ numworldlightsLDR = CopyLump( LUMP_WORLDLIGHTS, dworldlightsLDR );
+ numworldlightsHDR = CopyLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR );
+
+ numleafwaterdata = CopyLump( LUMP_LEAFWATERDATA, dleafwaterdata );
+ g_PhysCollideSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE, (void**)&g_pPhysCollide );
+ g_PhysDispSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSDISP, (void**)&g_pPhysDisp );
+
+ g_numvertnormals = CopyLump( FIELD_VECTOR, LUMP_VERTNORMALS, (float*)g_vertnormals );
+ g_numvertnormalindices = CopyLump( FIELD_SHORT, LUMP_VERTNORMALINDICES, g_vertnormalindices );
+
+ g_nClipPortalVerts = CopyLump( FIELD_VECTOR, LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts );
+ g_nCubemapSamples = CopyLump( LUMP_CUBEMAPS, g_CubemapSamples );
+
+ CopyLump( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
+ CopyLump( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
+
+ g_nOverlayCount = CopyLump( LUMP_OVERLAYS, g_Overlays );
+ g_nWaterOverlayCount = CopyLump( LUMP_WATEROVERLAYS, g_WaterOverlays );
+ CopyLump( LUMP_OVERLAY_FADES, g_OverlayFades );
+
+ dflagslump_t flags_lump;
+
+ if ( HasLump( LUMP_MAP_FLAGS ) )
+ CopyLump ( LUMP_MAP_FLAGS, &flags_lump );
+ else
+ memset( &flags_lump, 0, sizeof( flags_lump ) ); // default flags to 0
+
+ g_LevelFlags = flags_lump.m_LevelFlags;
+
+ LoadOcclusionLump();
+
+ CopyLump( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater );
+
+ /*
+ int crap;
+ for( crap = 0; crap < g_nBSPStringTable; crap++ )
+ {
+ Msg( "stringtable %d", ( int )crap );
+ Msg( " %d:", ( int )g_BSPStringTable[crap] );
+ puts( &g_BSPStringData[g_BSPStringTable[crap]] );
+ puts( "\n" );
+ }
+ */
+
+ // Load PAK file lump into appropriate data structure
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
+ if ( paksize > 0 )
+ {
+ GetPakFile()->ActivateByteSwapping( IsX360() );
+ GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
+ }
+ else
+ {
+ GetPakFile()->Reset();
+ }
+
+ free( pakbuffer );
+
+ g_GameLumps.ParseGameLump( g_pBSPHeader );
+
+ // NOTE: Do NOT call CopyLump after Lumps_Parse() it parses all un-Copied lumps
+ // parse any additional lumps
+ Lumps_Parse();
+
+ // everything has been copied out
+ CloseBSPFile();
+
+ g_Swap.ActivateByteSwapping( false );
+}
+
+//-----------------------------------------------------------------------------
+// Reset any state.
+//-----------------------------------------------------------------------------
+void UnloadBSPFile()
+{
+ nummodels = 0;
+ numvertexes = 0;
+ numplanes = 0;
+
+ numleafs = 0;
+#if defined( BSP_USE_LESS_MEMORY )
+ if ( dleafs )
+ {
+ free( dleafs );
+ dleafs = NULL;
+ }
+#endif
+
+ numnodes = 0;
+ texinfo.Purge();
+ numtexdata = 0;
+
+ g_dispinfo.Purge();
+ g_DispVerts.Purge();
+ g_DispTris.Purge();
+
+ g_DispLightmapSamplePositions.Purge();
+ g_FaceMacroTextureInfos.Purge();
+
+ numfaces = 0;
+ numfaces_hdr = 0;
+
+ dfaceids.Purge();
+
+ g_numprimitives = 0;
+ g_numprimverts = 0;
+ g_numprimindices = 0;
+ numorigfaces = 0;
+ numleaffaces = 0;
+ numleafbrushes = 0;
+ numsurfedges = 0;
+ numedges = 0;
+ numbrushes = 0;
+ numbrushsides = 0;
+ numareas = 0;
+ numareaportals = 0;
+
+ visdatasize = 0;
+ dlightdataLDR.Purge();
+ dlightdataHDR.Purge();
+
+ g_LeafAmbientLightingLDR.Purge();
+ g_LeafAmbientLightingHDR.Purge();
+ g_LeafAmbientIndexHDR.Purge();
+ g_LeafAmbientIndexLDR.Purge();
+
+ dentdata.Purge();
+ numworldlightsLDR = 0;
+ numworldlightsHDR = 0;
+
+ numleafwaterdata = 0;
+
+ if ( g_pPhysCollide )
+ {
+ free( g_pPhysCollide );
+ g_pPhysCollide = NULL;
+ }
+ g_PhysCollideSize = 0;
+
+ if ( g_pPhysDisp )
+ {
+ free( g_pPhysDisp );
+ g_pPhysDisp = NULL;
+ }
+ g_PhysDispSize = 0;
+
+ g_numvertnormals = 0;
+ g_numvertnormalindices = 0;
+
+ g_nClipPortalVerts = 0;
+ g_nCubemapSamples = 0;
+
+ g_TexDataStringData.Purge();
+ g_TexDataStringTable.Purge();
+
+ g_nOverlayCount = 0;
+ g_nWaterOverlayCount = 0;
+
+ g_LevelFlags = 0;
+
+ g_OccluderData.Purge();
+ g_OccluderPolyData.Purge();
+ g_OccluderVertexIndices.Purge();
+
+ g_GameLumps.DestroyAllGameLumps();
+
+ for ( int i = 0; i < HEADER_LUMPS; i++ )
+ {
+ if ( g_Lumps.pLumps[i] )
+ {
+ free( g_Lumps.pLumps[i] );
+ g_Lumps.pLumps[i] = NULL;
+ }
+ }
+
+ ReleasePakFileLumps();
+}
+
+//-----------------------------------------------------------------------------
+// LoadBSPFileFilesystemOnly
+//-----------------------------------------------------------------------------
+void LoadBSPFile_FileSystemOnly( const char *filename )
+{
+ Lumps_Init();
+
+ //
+ // load the file header
+ //
+ LoadFile( filename, (void **)&g_pBSPHeader );
+
+ ValidateHeader( filename, g_pBSPHeader );
+
+ // Load PAK file lump into appropriate data structure
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer, 1 );
+ if ( paksize > 0 )
+ {
+ GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
+ }
+ else
+ {
+ GetPakFile()->Reset();
+ }
+
+ free( pakbuffer );
+
+ // everything has been copied out
+ free( g_pBSPHeader );
+ g_pBSPHeader = NULL;
+}
+
+void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName )
+{
+ Lumps_Init();
+
+ //
+ // load the file header
+ //
+ LoadFile( pBSPFileName, (void **)&g_pBSPHeader);
+
+ ValidateHeader( pBSPFileName, g_pBSPHeader );
+
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
+ if ( paksize > 0 )
+ {
+ FILE *fp;
+ fp = fopen( pZipFileName, "wb" );
+ if( !fp )
+ {
+ fprintf( stderr, "can't open %s\n", pZipFileName );
+ return;
+ }
+
+ fwrite( pakbuffer, paksize, 1, fp );
+ fclose( fp );
+ }
+ else
+ {
+ fprintf( stderr, "zip file is zero length!\n" );
+ }
+}
+
+/*
+=============
+LoadBSPFileTexinfo
+
+Only loads the texinfo lump, so qdata can scan for textures
+=============
+*/
+void LoadBSPFileTexinfo( const char *filename )
+{
+ FILE *f;
+ int length, ofs;
+
+ g_pBSPHeader = (dheader_t*)malloc( sizeof(dheader_t) );
+
+ f = fopen( filename, "rb" );
+ fread( g_pBSPHeader, sizeof(dheader_t), 1, f);
+
+ ValidateHeader( filename, g_pBSPHeader );
+
+ length = g_pBSPHeader->lumps[LUMP_TEXINFO].filelen;
+ ofs = g_pBSPHeader->lumps[LUMP_TEXINFO].fileofs;
+
+ int nCount = length / sizeof(texinfo_t);
+
+ texinfo.Purge();
+ texinfo.AddMultipleToTail( nCount );
+
+ fseek( f, ofs, SEEK_SET );
+ fread( texinfo.Base(), length, 1, f );
+ fclose( f );
+
+ // everything has been copied out
+ free( g_pBSPHeader );
+ g_pBSPHeader = NULL;
+}
+
+static void AddLumpInternal( int lumpnum, void *data, int len, int version )
+{
+ lump_t *lump;
+
+ g_Lumps.size[lumpnum] = 0; // mark it written
+
+ lump = &g_pBSPHeader->lumps[lumpnum];
+
+ lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
+ lump->filelen = len;
+ lump->version = version;
+ lump->fourCC[0] = ( char )0;
+ lump->fourCC[1] = ( char )0;
+ lump->fourCC[2] = ( char )0;
+ lump->fourCC[3] = ( char )0;
+
+ SafeWrite( g_hBSPFile, data, len );
+
+ // pad out to the next dword
+ AlignFilePosition( g_hBSPFile, 4 );
+}
+
+template< class T >
+static void SwapInPlace( T *pData, int count )
+{
+ if ( !pData )
+ return;
+
+ // use the datadesc to swap the fields in place
+ g_Swap.SwapFieldsToTargetEndian<T>( (T*)pData, pData, count );
+}
+
+template< class T >
+static void SwapInPlace( int fieldType, T *pData, int count )
+{
+ if ( !pData )
+ return;
+
+ // swap the data in place
+ g_Swap.SwapBufferToTargetEndian<T>( (T*)pData, (T*)pData, count );
+}
+
+//-----------------------------------------------------------------------------
+// Add raw data chunk to file (not a lump)
+//-----------------------------------------------------------------------------
+template< class T >
+static void WriteData( int fieldType, T *pData, int count )
+{
+ if ( g_bSwapOnWrite )
+ {
+ SwapInPlace( fieldType, pData, count );
+ }
+ SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
+}
+
+template< class T >
+static void WriteData( T *pData, int count )
+{
+ if ( g_bSwapOnWrite )
+ {
+ SwapInPlace( pData, count );
+ }
+ SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
+}
+
+//-----------------------------------------------------------------------------
+// Add Lump of object types with datadescs
+//-----------------------------------------------------------------------------
+template< class T >
+static void AddLump( int lumpnum, T *pData, int count, int version )
+{
+ AddLumpInternal( lumpnum, pData, count * sizeof(T), version );
+}
+
+template< class T >
+static void AddLump( int lumpnum, CUtlVector<T> &data, int version )
+{
+ AddLumpInternal( lumpnum, data.Base(), data.Count() * sizeof(T), version );
+}
+
+/*
+=============
+WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void WriteBSPFile( const char *filename, char *pUnused )
+{
+ if ( texinfo.Count() > MAX_MAP_TEXINFO )
+ {
+ Error( "Map has too many texinfos (has %d, can have at most %d)\n", texinfo.Count(), MAX_MAP_TEXINFO );
+ return;
+ }
+
+ dheader_t outHeader;
+ g_pBSPHeader = &outHeader;
+ memset( g_pBSPHeader, 0, sizeof( dheader_t ) );
+
+ g_pBSPHeader->ident = IDBSPHEADER;
+ g_pBSPHeader->version = BSPVERSION;
+ g_pBSPHeader->mapRevision = g_MapRevision;
+
+ g_hBSPFile = SafeOpenWrite( filename );
+ WriteData( g_pBSPHeader ); // overwritten later
+
+ AddLump( LUMP_PLANES, dplanes, numplanes );
+ AddLump( LUMP_LEAFS, dleafs, numleafs, LUMP_LEAFS_VERSION );
+ AddLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+ AddLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
+ AddLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
+ AddLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+
+ AddLump( LUMP_VERTEXES, dvertexes, numvertexes );
+ AddLump( LUMP_NODES, dnodes, numnodes );
+ AddLump( LUMP_TEXINFO, texinfo );
+ AddLump( LUMP_TEXDATA, dtexdata, numtexdata );
+
+ AddLump( LUMP_DISPINFO, g_dispinfo );
+ AddLump( LUMP_DISP_VERTS, g_DispVerts );
+ AddLump( LUMP_DISP_TRIS, g_DispTris );
+ AddLump( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
+ AddLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
+
+ AddLump( LUMP_PRIMITIVES, g_primitives, g_numprimitives );
+ AddLump( LUMP_PRIMVERTS, g_primverts, g_numprimverts );
+ AddLump( LUMP_PRIMINDICES, g_primindices, g_numprimindices );
+ AddLump( LUMP_FACES, dfaces, numfaces, LUMP_FACES_VERSION );
+ if (numfaces_hdr)
+ AddLump( LUMP_FACES_HDR, dfaces_hdr, numfaces_hdr, LUMP_FACES_VERSION );
+ AddLump ( LUMP_FACEIDS, dfaceids, numfaceids );
+
+ AddLump( LUMP_ORIGINALFACES, dorigfaces, numorigfaces ); // original faces lump
+ AddLump( LUMP_BRUSHES, dbrushes, numbrushes );
+ AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides );
+ AddLump( LUMP_LEAFFACES, dleaffaces, numleaffaces );
+ AddLump( LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes );
+ AddLump( LUMP_SURFEDGES, dsurfedges, numsurfedges );
+ AddLump( LUMP_EDGES, dedges, numedges );
+ AddLump( LUMP_MODELS, dmodels, nummodels );
+ AddLump( LUMP_AREAS, dareas, numareas );
+ AddLump( LUMP_AREAPORTALS, dareaportals, numareaportals );
+
+ AddLump( LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
+ AddLump( LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
+ AddLump( LUMP_VISIBILITY, dvisdata, visdatasize );
+ AddLump( LUMP_ENTITIES, dentdata );
+ AddLump( LUMP_WORLDLIGHTS, dworldlightsLDR, numworldlightsLDR );
+ AddLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR, numworldlightsHDR );
+ AddLump( LUMP_LEAFWATERDATA, dleafwaterdata, numleafwaterdata );
+
+ AddOcclusionLump();
+
+ dflagslump_t flags_lump;
+ flags_lump.m_LevelFlags = g_LevelFlags;
+ AddLump( LUMP_MAP_FLAGS, &flags_lump, 1 );
+
+ // NOTE: This is just for debugging, so it is disabled in release maps
+#if 0
+ // add the vis portals to the BSP for visualization
+ AddLump( LUMP_PORTALS, dportals, numportals );
+ AddLump( LUMP_CLUSTERS, dclusters, numclusters );
+ AddLump( LUMP_PORTALVERTS, dportalverts, numportalverts );
+ AddLump( LUMP_CLUSTERPORTALS, dclusterportals, numclusterportals );
+#endif
+
+ AddLump( LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts, g_nClipPortalVerts * 3 );
+ AddLump( LUMP_CUBEMAPS, g_CubemapSamples, g_nCubemapSamples );
+ AddLump( LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
+ AddLump( LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
+ AddLump( LUMP_OVERLAYS, g_Overlays, g_nOverlayCount );
+ AddLump( LUMP_WATEROVERLAYS, g_WaterOverlays, g_nWaterOverlayCount );
+ AddLump( LUMP_OVERLAY_FADES, g_OverlayFades, g_nOverlayCount );
+
+ if ( g_pPhysCollide )
+ {
+ AddLump( LUMP_PHYSCOLLIDE, g_pPhysCollide, g_PhysCollideSize );
+ }
+
+ if ( g_pPhysDisp )
+ {
+ AddLump ( LUMP_PHYSDISP, g_pPhysDisp, g_PhysDispSize );
+ }
+
+ AddLump( LUMP_VERTNORMALS, (float*)g_vertnormals, g_numvertnormals * 3 );
+ AddLump( LUMP_VERTNORMALINDICES, g_vertnormalindices, g_numvertnormalindices );
+
+ AddLump( LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater, numleafs );
+
+ AddGameLumps();
+
+ // Write pakfile lump to disk
+ WritePakFileLump();
+
+ // NOTE: Do NOT call AddLump after Lumps_Write() it writes all un-Added lumps
+ // write any additional lumps
+ Lumps_Write();
+
+ g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
+ WriteData( g_pBSPHeader );
+ g_pFileSystem->Close( g_hBSPFile );
+}
+
+// Generate the next clear lump filename for the bsp file
+bool GenerateNextLumpFileName( const char *bspfilename, char *lumpfilename, int buffsize )
+{
+ for (int i = 0; i < MAX_LUMPFILES; i++)
+ {
+ GenerateLumpFileName( bspfilename, lumpfilename, buffsize, i );
+
+ if ( !g_pFileSystem->FileExists( lumpfilename ) )
+ return true;
+ }
+
+ return false;
+}
+
+void WriteLumpToFile( char *filename, int lump )
+{
+ if ( !HasLump(lump) )
+ return;
+
+ char lumppre[MAX_PATH];
+ if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
+ {
+ Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
+ return;
+ }
+
+ // Open the file
+ FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
+ if ( !lumpfile )
+ {
+ Error ("Error opening %s! (Check for write enable)\n",filename);
+ return;
+ }
+
+ int ofs = g_pBSPHeader->lumps[lump].fileofs;
+ int length = g_pBSPHeader->lumps[lump].filelen;
+
+ // Write the header
+ lumpfileheader_t lumpHeader;
+ lumpHeader.lumpID = lump;
+ lumpHeader.lumpVersion = LumpVersion(lump);
+ lumpHeader.lumpLength = length;
+ lumpHeader.mapRevision = LittleLong( g_MapRevision );
+ lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
+ SafeWrite (lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
+
+ // Write the lump
+ SafeWrite (lumpfile, (byte *)g_pBSPHeader + ofs, length);
+}
+
+void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen )
+{
+ char lumppre[MAX_PATH];
+ if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
+ {
+ Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
+ return;
+ }
+
+ // Open the file
+ FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
+ if ( !lumpfile )
+ {
+ Error ("Error opening %s! (Check for write enable)\n",filename);
+ return;
+ }
+
+ // Write the header
+ lumpfileheader_t lumpHeader;
+ lumpHeader.lumpID = lump;
+ lumpHeader.lumpVersion = nLumpVersion;
+ lumpHeader.lumpLength = nBufLen;
+ lumpHeader.mapRevision = LittleLong( g_MapRevision );
+ lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
+ SafeWrite( lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
+
+ // Write the lump
+ SafeWrite( lumpfile, pBuffer, nBufLen );
+
+ g_pFileSystem->Close( lumpfile );
+}
+
+
+//============================================================================
+#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
+#define ENTRYSIZE(a) (sizeof(*(a)))
+
+int ArrayUsage( const char *szItem, int items, int maxitems, int itemsize )
+{
+ float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
+
+ Msg("%-17.17s %8i/%-8i %8i/%-8i (%4.1f%%) ",
+ szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
+ if ( percentage > 80.0 )
+ Msg( "VERY FULL!\n" );
+ else if ( percentage > 95.0 )
+ Msg( "SIZE DANGER!\n" );
+ else if ( percentage > 99.9 )
+ Msg( "SIZE OVERFLOW!!!\n" );
+ else
+ Msg( "\n" );
+ return items * itemsize;
+}
+
+int GlobUsage( const char *szItem, int itemstorage, int maxstorage )
+{
+ float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
+ Msg("%-17.17s [variable] %8i/%-8i (%4.1f%%) ",
+ szItem, itemstorage, maxstorage, percentage );
+ if ( percentage > 80.0 )
+ Msg( "VERY FULL!\n" );
+ else if ( percentage > 95.0 )
+ Msg( "SIZE DANGER!\n" );
+ else if ( percentage > 99.9 )
+ Msg( "SIZE OVERFLOW!!!\n" );
+ else
+ Msg( "\n" );
+ return itemstorage;
+}
+
+/*
+=============
+PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void PrintBSPFileSizes (void)
+{
+ int totalmemory = 0;
+
+// if (!num_entities)
+// ParseEntities ();
+
+ Msg("\n");
+ Msg( "%-17s %16s %16s %9s \n", "Object names", "Objects/Maxobjs", "Memory / Maxmem", "Fullness" );
+ Msg( "%-17s %16s %16s %9s \n", "------------", "---------------", "---------------", "--------" );
+
+ totalmemory += ArrayUsage( "models", nummodels, ENTRIES(dmodels), ENTRYSIZE(dmodels) );
+ totalmemory += ArrayUsage( "brushes", numbrushes, ENTRIES(dbrushes), ENTRYSIZE(dbrushes) );
+ totalmemory += ArrayUsage( "brushsides", numbrushsides, ENTRIES(dbrushsides), ENTRYSIZE(dbrushsides) );
+ totalmemory += ArrayUsage( "planes", numplanes, ENTRIES(dplanes), ENTRYSIZE(dplanes) );
+ totalmemory += ArrayUsage( "vertexes", numvertexes, ENTRIES(dvertexes), ENTRYSIZE(dvertexes) );
+ totalmemory += ArrayUsage( "nodes", numnodes, ENTRIES(dnodes), ENTRYSIZE(dnodes) );
+ totalmemory += ArrayUsage( "texinfos", texinfo.Count(),MAX_MAP_TEXINFO, sizeof(texinfo_t) );
+ totalmemory += ArrayUsage( "texdata", numtexdata, ENTRIES(dtexdata), ENTRYSIZE(dtexdata) );
+
+ totalmemory += ArrayUsage( "dispinfos", g_dispinfo.Count(), 0, sizeof( ddispinfo_t ) );
+ totalmemory += ArrayUsage( "disp_verts", g_DispVerts.Count(), 0, sizeof( g_DispVerts[0] ) );
+ totalmemory += ArrayUsage( "disp_tris", g_DispTris.Count(), 0, sizeof( g_DispTris[0] ) );
+ totalmemory += ArrayUsage( "disp_lmsamples",g_DispLightmapSamplePositions.Count(),0,sizeof( g_DispLightmapSamplePositions[0] ) );
+
+ totalmemory += ArrayUsage( "faces", numfaces, ENTRIES(dfaces), ENTRYSIZE(dfaces) );
+ totalmemory += ArrayUsage( "hdr faces", numfaces_hdr, ENTRIES(dfaces_hdr), ENTRYSIZE(dfaces_hdr) );
+ totalmemory += ArrayUsage( "origfaces", numorigfaces, ENTRIES(dorigfaces), ENTRYSIZE(dorigfaces) ); // original faces
+ totalmemory += ArrayUsage( "leaves", numleafs, ENTRIES(dleafs), ENTRYSIZE(dleafs) );
+ totalmemory += ArrayUsage( "leaffaces", numleaffaces, ENTRIES(dleaffaces), ENTRYSIZE(dleaffaces) );
+ totalmemory += ArrayUsage( "leafbrushes", numleafbrushes, ENTRIES(dleafbrushes), ENTRYSIZE(dleafbrushes) );
+ totalmemory += ArrayUsage( "areas", numareas, ENTRIES(dareas), ENTRYSIZE(dareas) );
+ totalmemory += ArrayUsage( "surfedges", numsurfedges, ENTRIES(dsurfedges), ENTRYSIZE(dsurfedges) );
+ totalmemory += ArrayUsage( "edges", numedges, ENTRIES(dedges), ENTRYSIZE(dedges) );
+ totalmemory += ArrayUsage( "LDR worldlights", numworldlightsLDR, ENTRIES(dworldlightsLDR), ENTRYSIZE(dworldlightsLDR) );
+ totalmemory += ArrayUsage( "HDR worldlights", numworldlightsHDR, ENTRIES(dworldlightsHDR), ENTRYSIZE(dworldlightsHDR) );
+
+ totalmemory += ArrayUsage( "leafwaterdata", numleafwaterdata,ENTRIES(dleafwaterdata), ENTRYSIZE(dleafwaterdata) );
+ totalmemory += ArrayUsage( "waterstrips", g_numprimitives,ENTRIES(g_primitives), ENTRYSIZE(g_primitives) );
+ totalmemory += ArrayUsage( "waterverts", g_numprimverts, ENTRIES(g_primverts), ENTRYSIZE(g_primverts) );
+ totalmemory += ArrayUsage( "waterindices", g_numprimindices,ENTRIES(g_primindices),ENTRYSIZE(g_primindices) );
+ totalmemory += ArrayUsage( "cubemapsamples", g_nCubemapSamples,ENTRIES(g_CubemapSamples),ENTRYSIZE(g_CubemapSamples) );
+ totalmemory += ArrayUsage( "overlays", g_nOverlayCount, ENTRIES(g_Overlays), ENTRYSIZE(g_Overlays) );
+
+ totalmemory += GlobUsage( "LDR lightdata", dlightdataLDR.Count(), 0 );
+ totalmemory += GlobUsage( "HDR lightdata", dlightdataHDR.Count(), 0 );
+ totalmemory += GlobUsage( "visdata", visdatasize, sizeof(dvisdata) );
+ totalmemory += GlobUsage( "entdata", dentdata.Count(), 384*1024 ); // goal is <384K
+
+ totalmemory += ArrayUsage( "LDR ambient table", g_LeafAmbientIndexLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexLDR[0] ) );
+ totalmemory += ArrayUsage( "HDR ambient table", g_LeafAmbientIndexHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexHDR[0] ) );
+ totalmemory += ArrayUsage( "LDR leaf ambient lighting", g_LeafAmbientLightingLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingLDR[0] ) );
+ totalmemory += ArrayUsage( "HDR leaf ambient lighting", g_LeafAmbientLightingHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingHDR[0] ) );
+
+ totalmemory += ArrayUsage( "occluders", g_OccluderData.Count(), 0, sizeof( g_OccluderData[0] ) );
+ totalmemory += ArrayUsage( "occluder polygons", g_OccluderPolyData.Count(), 0, sizeof( g_OccluderPolyData[0] ) );
+ totalmemory += ArrayUsage( "occluder vert ind",g_OccluderVertexIndices.Count(),0, sizeof( g_OccluderVertexIndices[0] ) );
+
+ GameLumpHandle_t h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "detail props", 1, g_GameLumps.GameLumpSize(h) );
+ h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
+ h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING_HDR );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "HDR dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
+ h = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "static props", 1, g_GameLumps.GameLumpSize(h) );
+
+ totalmemory += GlobUsage( "pakfile", GetPakFile()->EstimateSize(), 0 );
+ // HACKHACK: Set physics limit at 4MB, in reality this is totally dynamic
+ totalmemory += GlobUsage( "physics", g_PhysCollideSize, 4*1024*1024 );
+ totalmemory += GlobUsage( "physics terrain", g_PhysDispSize, 1*1024*1024 );
+
+ Msg( "\nLevel flags = %x\n", g_LevelFlags );
+
+ Msg( "\n" );
+
+ int triangleCount = 0;
+
+ for ( int i = 0; i < numfaces; i++ )
+ {
+ // face tris = numedges - 2
+ triangleCount += dfaces[i].numedges - 2;
+ }
+ Msg("Total triangle count: %d\n", triangleCount );
+
+ // UNDONE:
+ // areaportals, portals, texdata, clusters, worldlights, portalverts
+}
+
+/*
+=============
+PrintBSPPackDirectory
+
+Dumps a list of files stored in the bsp pack.
+=============
+*/
+void PrintBSPPackDirectory( void )
+{
+ GetPakFile()->PrintDirectory();
+}
+
+
+//============================================
+
+int num_entities;
+entity_t entities[MAX_MAP_ENTITIES];
+
+void StripTrailing (char *e)
+{
+ char *s;
+
+ s = e + strlen(e)-1;
+ while (s >= e && *s <= 32)
+ {
+ *s = 0;
+ s--;
+ }
+}
+
+/*
+=================
+ParseEpair
+=================
+*/
+epair_t *ParseEpair (void)
+{
+ epair_t *e;
+
+ e = (epair_t*)malloc (sizeof(epair_t));
+ memset (e, 0, sizeof(epair_t));
+
+ if (strlen(token) >= MAX_KEY-1)
+ Error ("ParseEpar: token too long");
+ e->key = copystring(token);
+
+ GetToken (false);
+ if (strlen(token) >= MAX_VALUE-1)
+ Error ("ParseEpar: token too long");
+ e->value = copystring(token);
+
+ // strip trailing spaces
+ StripTrailing (e->key);
+ StripTrailing (e->value);
+
+ return e;
+}
+
+
+/*
+================
+ParseEntity
+================
+*/
+qboolean ParseEntity (void)
+{
+ epair_t *e;
+ entity_t *mapent;
+
+ if (!GetToken (true))
+ return false;
+
+ if (Q_stricmp (token, "{") )
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ mapent = &entities[num_entities];
+ num_entities++;
+
+ do
+ {
+ if (!GetToken (true))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!Q_stricmp (token, "}") )
+ break;
+ e = ParseEpair ();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } while (1);
+
+ return true;
+}
+
+/*
+================
+ParseEntities
+
+Parses the dentdata string into entities
+================
+*/
+void ParseEntities (void)
+{
+ num_entities = 0;
+ ParseFromMemory (dentdata.Base(), dentdata.Count());
+
+ while (ParseEntity ())
+ {
+ }
+}
+
+
+/*
+================
+UnparseEntities
+
+Generates the dentdata string from all the entities
+================
+*/
+void UnparseEntities (void)
+{
+ epair_t *ep;
+ char line[2048];
+ int i;
+ char key[1024], value[1024];
+
+ CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ buffer.EnsureCapacity( 256 * 1024 );
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ buffer.PutString( "{\n" );
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ strcpy (key, ep->key);
+ StripTrailing (key);
+ strcpy (value, ep->value);
+ StripTrailing (value);
+
+ sprintf(line, "\"%s\" \"%s\"\n", key, value);
+ buffer.PutString( line );
+ }
+ buffer.PutString("}\n");
+ }
+ int entdatasize = buffer.TellPut()+1;
+
+ dentdata.SetSize( entdatasize );
+ memcpy( dentdata.Base(), buffer.Base(), entdatasize-1 );
+ dentdata[entdatasize-1] = 0;
+}
+
+void PrintEntity (entity_t *ent)
+{
+ epair_t *ep;
+
+ Msg ("------- entity %p -------\n", ent);
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ {
+ Msg ("%s = %s\n", ep->key, ep->value);
+ }
+
+}
+
+void SetKeyValue(entity_t *ent, const char *key, const char *value)
+{
+ epair_t *ep;
+
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ if (!Q_stricmp (ep->key, key) )
+ {
+ free (ep->value);
+ ep->value = copystring(value);
+ return;
+ }
+ ep = (epair_t*)malloc (sizeof(*ep));
+ ep->next = ent->epairs;
+ ent->epairs = ep;
+ ep->key = copystring(key);
+ ep->value = copystring(value);
+}
+
+char *ValueForKey (entity_t *ent, char *key)
+{
+ for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
+ if (!Q_stricmp (ep->key, key) )
+ return ep->value;
+ return "";
+}
+
+vec_t FloatForKey (entity_t *ent, char *key)
+{
+ char *k = ValueForKey (ent, key);
+ return atof(k);
+}
+
+vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value)
+{
+ for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
+ if (!Q_stricmp (ep->key, key) )
+ return atof( ep->value );
+ return default_value;
+}
+
+
+
+int IntForKey (entity_t *ent, char *key)
+{
+ char *k = ValueForKey (ent, key);
+ return atol(k);
+}
+
+int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault )
+{
+ char *k = ValueForKey (ent, key);
+ if ( !k[0] )
+ return nDefault;
+ return atol(k);
+}
+
+void GetVectorForKey (entity_t *ent, char *key, Vector& vec)
+{
+
+ char *k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ double v1, v2, v3;
+ v1 = v2 = v3 = 0;
+ sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
+ vec[0] = v1;
+ vec[1] = v2;
+ vec[2] = v3;
+}
+
+void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec)
+{
+ double v1, v2;
+
+ char *k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = 0;
+ sscanf (k, "%lf %lf", &v1, &v2);
+ vec[0] = v1;
+ vec[1] = v2;
+}
+
+void GetAnglesForKey (entity_t *ent, char *key, QAngle& angle)
+{
+ char *k;
+ double v1, v2, v3;
+
+ k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = v3 = 0;
+ sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
+ angle[0] = v1;
+ angle[1] = v2;
+ angle[2] = v3;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void BuildFaceCalcWindingData( dface_t *pFace, int *points )
+{
+ for( int i = 0; i < pFace->numedges; i++ )
+ {
+ int eIndex = dsurfedges[pFace->firstedge+i];
+ if( eIndex < 0 )
+ {
+ points[i] = dedges[-eIndex].v[1];
+ }
+ else
+ {
+ points[i] = dedges[eIndex].v[0];
+ }
+ }
+}
+
+
+void TriStripToTriList(
+ unsigned short const *pTriStripIndices,
+ int nTriStripIndices,
+ unsigned short **pTriListIndices,
+ int *pnTriListIndices )
+{
+ int nMaxTriListIndices = (nTriStripIndices - 2) * 3;
+ *pTriListIndices = new unsigned short[ nMaxTriListIndices ];
+ *pnTriListIndices = 0;
+
+ for( int i=0; i < nTriStripIndices - 2; i++ )
+ {
+ if( pTriStripIndices[i] == pTriStripIndices[i+1] ||
+ pTriStripIndices[i] == pTriStripIndices[i+2] ||
+ pTriStripIndices[i+1] == pTriStripIndices[i+2] )
+ {
+ }
+ else
+ {
+ // Flip odd numbered tris..
+ if( i & 1 )
+ {
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
+ }
+ else
+ {
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
+ }
+ }
+ }
+}
+
+
+void CalcTextureCoordsAtPoints(
+ float const texelsPerWorldUnits[2][4],
+ int const subtractOffset[2],
+ Vector const *pPoints,
+ int const nPoints,
+ Vector2D *pCoords )
+{
+ for( int i=0; i < nPoints; i++ )
+ {
+ for( int iCoord=0; iCoord < 2; iCoord++ )
+ {
+ float *pDestCoord = &pCoords[i][iCoord];
+
+ *pDestCoord = 0;
+ for( int iDot=0; iDot < 3; iDot++ )
+ *pDestCoord += pPoints[i][iDot] * texelsPerWorldUnits[iCoord][iDot];
+
+ *pDestCoord += texelsPerWorldUnits[iCoord][3];
+ *pDestCoord -= subtractOffset[iCoord];
+ }
+ }
+}
+
+
+/*
+================
+CalcFaceExtents
+
+Fills in s->texmins[] and s->texsize[]
+================
+*/
+void CalcFaceExtents(dface_t *s, int lightmapTextureMinsInLuxels[2], int lightmapTextureSizeInLuxels[2])
+{
+ vec_t mins[2], maxs[2], val=0;
+ int i,j, e=0;
+ dvertex_t *v=NULL;
+ texinfo_t *tex=NULL;
+
+ mins[0] = mins[1] = 1e24;
+ maxs[0] = maxs[1] = -1e24;
+
+ tex = &texinfo[s->texinfo];
+
+ for (i=0 ; i<s->numedges ; i++)
+ {
+ e = dsurfedges[s->firstedge+i];
+ if (e >= 0)
+ v = dvertexes + dedges[e].v[0];
+ else
+ v = dvertexes + dedges[-e].v[1];
+
+ for (j=0 ; j<2 ; j++)
+ {
+ val = v->point[0] * tex->lightmapVecsLuxelsPerWorldUnits[j][0] +
+ v->point[1] * tex->lightmapVecsLuxelsPerWorldUnits[j][1] +
+ v->point[2] * tex->lightmapVecsLuxelsPerWorldUnits[j][2] +
+ tex->lightmapVecsLuxelsPerWorldUnits[j][3];
+ if (val < mins[j])
+ mins[j] = val;
+ if (val > maxs[j])
+ maxs[j] = val;
+ }
+ }
+
+ int nMaxLightmapDim = (s->dispinfo == -1) ? MAX_LIGHTMAP_DIM_WITHOUT_BORDER : MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER;
+ for (i=0 ; i<2 ; i++)
+ {
+ mins[i] = ( float )floor( mins[i] );
+ maxs[i] = ( float )ceil( maxs[i] );
+
+ lightmapTextureMinsInLuxels[i] = ( int )mins[i];
+ lightmapTextureSizeInLuxels[i] = ( int )( maxs[i] - mins[i] );
+ if( lightmapTextureSizeInLuxels[i] > nMaxLightmapDim + 1 )
+ {
+ Vector point = vec3_origin;
+ for (int j=0 ; j<s->numedges ; j++)
+ {
+ e = dsurfedges[s->firstedge+j];
+ v = (e<0)?dvertexes + dedges[-e].v[1] : dvertexes + dedges[e].v[0];
+ point += v->point;
+ Warning( "Bad surface extents point: %f %f %f\n", v->point.x, v->point.y, v->point.z );
+ }
+ point *= 1.0f/s->numedges;
+ Error( "Bad surface extents - surface is too big to have a lightmap\n\tmaterial %s around point (%.1f %.1f %.1f)\n\t(dimension: %d, %d>%d)\n",
+ TexDataStringTable_GetString( dtexdata[texinfo[s->texinfo].texdata].nameStringTableID ),
+ point.x, point.y, point.z,
+ ( int )i,
+ ( int )lightmapTextureSizeInLuxels[i],
+ ( int )( nMaxLightmapDim + 1 )
+ );
+ }
+ }
+}
+
+
+void UpdateAllFaceLightmapExtents()
+{
+ for( int i=0; i < numfaces; i++ )
+ {
+ dface_t *pFace = &dfaces[i];
+
+ if ( texinfo[pFace->texinfo].flags & (SURF_SKY|SURF_NOLIGHT) )
+ continue; // non-lit texture
+
+ CalcFaceExtents( pFace, pFace->m_LightmapTextureMinsInLuxels, pFace->m_LightmapTextureSizeInLuxels );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Helper class to iterate over leaves, used by tools
+//
+//-----------------------------------------------------------------------------
+
+#define TEST_EPSILON (0.03125)
+
+
+class CToolBSPTree : public ISpatialQuery
+{
+public:
+ // Returns the number of leaves
+ int LeafCount() const;
+
+ // Enumerates the leaves along a ray, box, etc.
+ bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context );
+ bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context );
+ bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
+ bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
+};
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of leaves
+//-----------------------------------------------------------------------------
+
+int CToolBSPTree::LeafCount() const
+{
+ return numleafs;
+}
+
+
+//-----------------------------------------------------------------------------
+// Enumerates the leaves at a point
+//-----------------------------------------------------------------------------
+
+bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt,
+ ISpatialLeafEnumerator* pEnum, int context )
+{
+ int node = 0;
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if (DotProduct( pPlane->normal, pt ) <= pPlane->dist)
+ {
+ node = pNode->children[1];
+ }
+ else
+ {
+ node = pNode->children[0];
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enumerates the leaves in a box
+//-----------------------------------------------------------------------------
+
+static bool EnumerateLeavesInBox_R( int node, Vector const& mins,
+ Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context )
+{
+ Vector cornermin, cornermax;
+
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ // Arbitrary split plane here
+ for (int i = 0; i < 3; ++i)
+ {
+ if (pPlane->normal[i] >= 0)
+ {
+ cornermin[i] = mins[i];
+ cornermax[i] = maxs[i];
+ }
+ else
+ {
+ cornermin[i] = maxs[i];
+ cornermax[i] = mins[i];
+ }
+ }
+
+ if ( (DotProduct( pPlane->normal, cornermax ) - pPlane->dist) <= -TEST_EPSILON )
+ {
+ node = pNode->children[1];
+ }
+ else if ( (DotProduct( pPlane->normal, cornermin ) - pPlane->dist) >= TEST_EPSILON )
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ if (!EnumerateLeavesInBox_R( pNode->children[0], mins, maxs, pEnum, context ))
+ {
+ return false;
+ }
+
+ return EnumerateLeavesInBox_R( pNode->children[1], mins, maxs, pEnum, context );
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs,
+ ISpatialLeafEnumerator* pEnum, int context )
+{
+ return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
+}
+
+//-----------------------------------------------------------------------------
+// Enumerate leaves within a sphere
+//-----------------------------------------------------------------------------
+
+static bool EnumerateLeavesInSphere_R( int node, Vector const& origin,
+ float radius, ISpatialLeafEnumerator* pEnum, int context )
+{
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if (DotProduct( pPlane->normal, origin ) + radius - pPlane->dist <= -TEST_EPSILON )
+ {
+ node = pNode->children[1];
+ }
+ else if (DotProduct( pPlane->normal, origin ) - radius - pPlane->dist >= TEST_EPSILON )
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ if (!EnumerateLeavesInSphere_R( pNode->children[0],
+ origin, radius, pEnum, context ))
+ {
+ return false;
+ }
+
+ return EnumerateLeavesInSphere_R( pNode->children[1],
+ origin, radius, pEnum, context );
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context )
+{
+ return EnumerateLeavesInSphere_R( 0, center, radius, pEnum, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enumerate leaves along a ray
+//-----------------------------------------------------------------------------
+
+static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray,
+ Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, int context )
+{
+ float front,back;
+
+ while (node >= 0)
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if ( pPlane->type <= PLANE_Z )
+ {
+ front = start[pPlane->type] - pPlane->dist;
+ back = end[pPlane->type] - pPlane->dist;
+ }
+ else
+ {
+ front = DotProduct(start, pPlane->normal) - pPlane->dist;
+ back = DotProduct(end, pPlane->normal) - pPlane->dist;
+ }
+
+ if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
+ {
+ node = pNode->children[1];
+ }
+ else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ // test the front side first
+ bool side = front < 0;
+
+ // Compute intersection point based on the original ray
+ float splitfrac;
+ float denom = DotProduct( ray.m_Delta, pPlane->normal );
+ if ( denom == 0.0f )
+ {
+ splitfrac = 1.0f;
+ }
+ else
+ {
+ splitfrac = ( pPlane->dist - DotProduct( ray.m_Start, pPlane->normal ) ) / denom;
+ if (splitfrac < 0)
+ splitfrac = 0;
+ else if (splitfrac > 1)
+ splitfrac = 1;
+ }
+
+ // Compute the split point
+ Vector split;
+ VectorMA( ray.m_Start, splitfrac, ray.m_Delta, split );
+
+ bool r = EnumerateLeavesAlongRay_R (pNode->children[side], ray, start, split, pEnum, context );
+ if (!r)
+ return r;
+ return EnumerateLeavesAlongRay_R (pNode->children[!side], ray, split, end, pEnum, context);
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
+{
+ if (!ray.m_IsSwept)
+ {
+ Vector mins, maxs;
+ VectorAdd( ray.m_Start, ray.m_Extents, maxs );
+ VectorSubtract( ray.m_Start, ray.m_Extents, mins );
+
+ return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
+ }
+
+ // FIXME: Extruded ray not implemented yet
+ Assert( ray.m_IsRay );
+
+ Vector end;
+ VectorAdd( ray.m_Start, ray.m_Delta, end );
+ return EnumerateLeavesAlongRay_R( 0, ray, ray.m_Start, end, pEnum, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton accessor
+//-----------------------------------------------------------------------------
+
+ISpatialQuery* ToolBSPTree()
+{
+ static CToolBSPTree s_ToolBSPTree;
+ return &s_ToolBSPTree;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Enumerates nodes in front to back order...
+//-----------------------------------------------------------------------------
+
+// FIXME: Do we want this in the IBSPTree interface?
+
+static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, float end,
+ IBSPNodeEnumerator* pEnum, int context )
+{
+ float front, back;
+ float startDotN, deltaDotN;
+
+ while (node >= 0)
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if ( pPlane->type <= PLANE_Z )
+ {
+ startDotN = ray.m_Start[pPlane->type];
+ deltaDotN = ray.m_Delta[pPlane->type];
+ }
+ else
+ {
+ startDotN = DotProduct( ray.m_Start, pPlane->normal );
+ deltaDotN = DotProduct( ray.m_Delta, pPlane->normal );
+ }
+
+ front = startDotN + start * deltaDotN - pPlane->dist;
+ back = startDotN + end * deltaDotN - pPlane->dist;
+
+ if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
+ {
+ node = pNode->children[1];
+ }
+ else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ // test the front side first
+ bool side = front < 0;
+
+ // Compute intersection point based on the original ray
+ float splitfrac;
+ if ( deltaDotN == 0.0f )
+ {
+ splitfrac = 1.0f;
+ }
+ else
+ {
+ splitfrac = ( pPlane->dist - startDotN ) / deltaDotN;
+ if (splitfrac < 0.0f)
+ splitfrac = 0.0f;
+ else if (splitfrac > 1.0f)
+ splitfrac = 1.0f;
+ }
+
+ bool r = EnumerateNodesAlongRay_R (pNode->children[side], ray, start, splitfrac, pEnum, context );
+ if (!r)
+ return r;
+
+ // Visit the node...
+ if (!pEnum->EnumerateNode( node, ray, splitfrac, context ))
+ return false;
+
+ return EnumerateNodesAlongRay_R (pNode->children[!side], ray, splitfrac, end, pEnum, context);
+ }
+ }
+
+ // Visit the leaf...
+ return pEnum->EnumerateLeaf( - node - 1, ray, start, end, context );
+}
+
+
+bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context )
+{
+ Vector end;
+ VectorAdd( ray.m_Start, ray.m_Delta, end );
+ return EnumerateNodesAlongRay_R( 0, ray, 0.0f, 1.0f, pEnum, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Helps us find all leaves associated with a particular cluster
+//-----------------------------------------------------------------------------
+CUtlVector<clusterlist_t> g_ClusterLeaves;
+
+void BuildClusterTable( void )
+{
+ int i, j;
+ int leafCount;
+ int leafList[MAX_MAP_LEAFS];
+
+ g_ClusterLeaves.SetCount( dvis->numclusters );
+ for ( i = 0; i < dvis->numclusters; i++ )
+ {
+ leafCount = 0;
+ for ( j = 0; j < numleafs; j++ )
+ {
+ if ( dleafs[j].cluster == i )
+ {
+ leafList[ leafCount ] = j;
+ leafCount++;
+ }
+ }
+
+ g_ClusterLeaves[i].leafCount = leafCount;
+ if ( leafCount )
+ {
+ g_ClusterLeaves[i].leafs.SetCount( leafCount );
+ memcpy( g_ClusterLeaves[i].leafs.Base(), leafList, sizeof(int) * leafCount );
+ }
+ }
+}
+
+// There's a version of this in host.cpp!!! Make sure that they match.
+void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int dxlevel, int maxLength )
+{
+ Q_StripExtension( pMapPath, pPlatformMapPath, maxLength );
+
+// if( dxlevel <= 60 )
+// {
+// Q_strncat( pPlatformMapPath, "_dx60", maxLength, COPY_ALL_CHARACTERS );
+// }
+
+ Q_strncat( pPlatformMapPath, ".bsp", maxLength, COPY_ALL_CHARACTERS );
+}
+
+// There's a version of this in checksum_engine.cpp!!! Make sure that they match.
+static bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
+{
+ byte chunk[1024];
+ lump_t *curLump;
+
+ FileHandle_t fp = g_pFileSystem->Open( pszFileName, "rb" );
+ if ( !fp )
+ return false;
+
+ // CRC across all lumps except for the Entities lump
+ for ( int l = 0; l < HEADER_LUMPS; ++l )
+ {
+ if (l == LUMP_ENTITIES)
+ continue;
+
+ curLump = &g_pBSPHeader->lumps[l];
+ unsigned int nSize = curLump->filelen;
+
+ g_pFileSystem->Seek( fp, curLump->fileofs, FILESYSTEM_SEEK_HEAD );
+
+ // Now read in 1K chunks
+ while ( nSize > 0 )
+ {
+ int nBytesRead = 0;
+
+ if ( nSize > 1024 )
+ nBytesRead = g_pFileSystem->Read( chunk, 1024, fp );
+ else
+ nBytesRead = g_pFileSystem->Read( chunk, nSize, fp );
+
+ // If any data was received, CRC it.
+ if ( nBytesRead > 0 )
+ {
+ nSize -= nBytesRead;
+ CRC32_ProcessBuffer( crcvalue, chunk, nBytesRead );
+ }
+ else
+ {
+ g_pFileSystem->Close( fp );
+ return false;
+ }
+ }
+ }
+
+ g_pFileSystem->Close( fp );
+ return true;
+}
+
+
+void SetHDRMode( bool bHDR )
+{
+ g_bHDR = bHDR;
+ if ( bHDR )
+ {
+ pdlightdata = &dlightdataHDR;
+ g_pLeafAmbientLighting = &g_LeafAmbientLightingHDR;
+ g_pLeafAmbientIndex = &g_LeafAmbientIndexHDR;
+ pNumworldlights = &numworldlightsHDR;
+ dworldlights = dworldlightsHDR;
+#ifdef VRAD
+ extern void VRadDetailProps_SetHDRMode( bool bHDR );
+ VRadDetailProps_SetHDRMode( bHDR );
+#endif
+ }
+ else
+ {
+ pdlightdata = &dlightdataLDR;
+ g_pLeafAmbientLighting = &g_LeafAmbientLightingLDR;
+ g_pLeafAmbientIndex = &g_LeafAmbientIndexLDR;
+ pNumworldlights = &numworldlightsLDR;
+ dworldlights = dworldlightsLDR;
+#ifdef VRAD
+ extern void VRadDetailProps_SetHDRMode( bool bHDR );
+ VRadDetailProps_SetHDRMode( bHDR );
+#endif
+ }
+}
+
+bool SwapVHV( void *pDestBase, void *pSrcBase )
+{
+ byte *pDest = (byte*)pDestBase;
+ byte *pSrc = (byte*)pSrcBase;
+
+ HardwareVerts::FileHeader_t *pHdr = (HardwareVerts::FileHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
+ g_Swap.SwapFieldsToTargetEndian<HardwareVerts::FileHeader_t>( (HardwareVerts::FileHeader_t*)pDest, (HardwareVerts::FileHeader_t*)pSrc );
+ pSrc += sizeof(HardwareVerts::FileHeader_t);
+ pDest += sizeof(HardwareVerts::FileHeader_t);
+
+ // This swap is pretty format specific
+ Assert( pHdr->m_nVersion == VHV_VERSION );
+ if ( pHdr->m_nVersion != VHV_VERSION )
+ return false;
+
+ HardwareVerts::MeshHeader_t *pSrcMesh = (HardwareVerts::MeshHeader_t*)pSrc;
+ HardwareVerts::MeshHeader_t *pDestMesh = (HardwareVerts::MeshHeader_t*)pDest;
+ HardwareVerts::MeshHeader_t *pMesh = (HardwareVerts::MeshHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
+ for ( int i = 0; i < pHdr->m_nMeshes; ++i, ++pMesh, ++pSrcMesh, ++pDestMesh )
+ {
+ g_Swap.SwapFieldsToTargetEndian( pDestMesh, pSrcMesh );
+
+ pSrc = (byte*)pSrcBase + pMesh->m_nOffset;
+ pDest = (byte*)pDestBase + pMesh->m_nOffset;
+
+ // Swap as a buffer of integers
+ // (source is bgra for an Intel swap to argb. PowerPC won't swap, so we need argb source.
+ g_Swap.SwapBufferToTargetEndian<int>( (int*)pDest, (int*)pSrc, pMesh->m_nVertexes );
+ }
+ return true;
+}
+
+const char *ResolveStaticPropToModel( const char *pPropName )
+{
+ // resolve back to static prop
+ int iProp = -1;
+
+ // filename should be sp_???.vhv or sp_hdr_???.vhv
+ if ( V_strnicmp( pPropName, "sp_", 3 ) )
+ {
+ return NULL;
+ }
+ const char *pPropNumber = V_strrchr( pPropName, '_' );
+ if ( pPropNumber )
+ {
+ sscanf( pPropNumber+1, "%d.vhv", &iProp );
+ }
+ else
+ {
+ return NULL;
+ }
+
+ // look up the prop to get to the actual model
+ if ( iProp < 0 || iProp >= g_StaticPropInstances.Count() )
+ {
+ // prop out of range
+ return NULL;
+ }
+ int iModel = g_StaticPropInstances[iProp];
+ if ( iModel < 0 || iModel >= g_StaticPropNames.Count() )
+ {
+ // model out of range
+ return NULL;
+ }
+
+ return g_StaticPropNames[iModel].String();
+}
+
+//-----------------------------------------------------------------------------
+// Iterate files in pak file, distribute to converters
+// pak file will be ready for serialization upon completion
+//-----------------------------------------------------------------------------
+void ConvertPakFileContents( const char *pInFilename )
+{
+ IZip *newPakFile = IZip::CreateZip( NULL );
+
+ CUtlBuffer sourceBuf;
+ CUtlBuffer targetBuf;
+ bool bConverted;
+ CUtlVector< CUtlString > hdrFiles;
+
+ int id = -1;
+ int fileSize;
+ while ( 1 )
+ {
+ char relativeName[MAX_PATH];
+ id = GetNextFilename( GetPakFile(), id, relativeName, sizeof( relativeName ), fileSize );
+ if ( id == -1)
+ break;
+
+ bConverted = false;
+ sourceBuf.Purge();
+ targetBuf.Purge();
+
+ const char* pExtension = V_GetFileExtension( relativeName );
+ const char* pExt = 0;
+
+ bool bOK = ReadFileFromPak( GetPakFile(), relativeName, false, sourceBuf );
+ if ( !bOK )
+ {
+ Warning( "Failed to load '%s' from lump pak for conversion or copy in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+
+ if ( pExtension && !V_stricmp( pExtension, "vtf" ) )
+ {
+ bOK = g_pVTFConvertFunc( relativeName, sourceBuf, targetBuf, g_pCompressFunc );
+ if ( !bOK )
+ {
+ Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+
+ bConverted = true;
+ pExt = ".vtf";
+ }
+ else if ( pExtension && !V_stricmp( pExtension, "vhv" ) )
+ {
+ CUtlBuffer tempBuffer;
+ if ( g_pVHVFixupFunc )
+ {
+ // caller supplied a fixup
+ const char *pModelName = ResolveStaticPropToModel( relativeName );
+ if ( !pModelName )
+ {
+ Warning( "Static Prop '%s' failed to resolve actual model in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+
+ // output temp buffer may shrink, must use TellPut() to determine size
+ bOK = g_pVHVFixupFunc( relativeName, pModelName, sourceBuf, tempBuffer );
+ if ( !bOK )
+ {
+ Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+ }
+ else
+ {
+ // use the source buffer as-is
+ tempBuffer.EnsureCapacity( sourceBuf.TellMaxPut() );
+ tempBuffer.Put( sourceBuf.Base(), sourceBuf.TellMaxPut() );
+ }
+
+ // swap the VHV
+ targetBuf.EnsureCapacity( tempBuffer.TellPut() );
+ bOK = SwapVHV( targetBuf.Base(), tempBuffer.Base() );
+ if ( !bOK )
+ {
+ Warning( "Failed to swap '%s' in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+ targetBuf.SeekPut( CUtlBuffer::SEEK_HEAD, tempBuffer.TellPut() );
+
+ if ( g_pCompressFunc )
+ {
+ CUtlBuffer compressedBuffer;
+ targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, sizeof( HardwareVerts::FileHeader_t ) );
+ bool bCompressed = g_pCompressFunc( targetBuf, compressedBuffer );
+ if ( bCompressed )
+ {
+ // copy all the header data off
+ CUtlBuffer headerBuffer;
+ headerBuffer.EnsureCapacity( sizeof( HardwareVerts::FileHeader_t ) );
+ headerBuffer.Put( targetBuf.Base(), sizeof( HardwareVerts::FileHeader_t ) );
+
+ // reform the target with the header and then the compressed data
+ targetBuf.Clear();
+ targetBuf.Put( headerBuffer.Base(), sizeof( HardwareVerts::FileHeader_t ) );
+ targetBuf.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
+ }
+
+ targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
+ }
+
+ bConverted = true;
+ pExt = ".vhv";
+ }
+
+ if ( !bConverted )
+ {
+ // straight copy
+ AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false );
+ }
+ else
+ {
+ // converted filename
+ V_StripExtension( relativeName, relativeName, sizeof( relativeName ) );
+ V_strcat( relativeName, ".360", sizeof( relativeName ) );
+ V_strcat( relativeName, pExt, sizeof( relativeName ) );
+ AddBufferToPak( newPakFile, relativeName, targetBuf.Base(), targetBuf.TellMaxPut(), false );
+ }
+
+ if ( V_stristr( relativeName, ".hdr" ) || V_stristr( relativeName, "_hdr" ) )
+ {
+ hdrFiles.AddToTail( relativeName );
+ }
+
+ DevMsg( "Created '%s' in lump pak in '%s'.\n", relativeName, pInFilename );
+ }
+
+ // strip ldr version of hdr files
+ for ( int i=0; i<hdrFiles.Count(); i++ )
+ {
+ char ldrFileName[MAX_PATH];
+
+ strcpy( ldrFileName, hdrFiles[i].String() );
+
+ char *pHDRExtension = V_stristr( ldrFileName, ".hdr" );
+ if ( !pHDRExtension )
+ {
+ pHDRExtension = V_stristr( ldrFileName, "_hdr" );
+ }
+
+ if ( pHDRExtension )
+ {
+ // strip .hdr or _hdr to get ldr filename
+ memcpy( pHDRExtension, pHDRExtension+4, strlen( pHDRExtension+4 )+1 );
+
+ DevMsg( "Stripping LDR: %s\n", ldrFileName );
+ newPakFile->RemoveFileFromZip( ldrFileName );
+ }
+ }
+
+ // discard old pak in favor of new pak
+ IZip::ReleaseZip( s_pakFile );
+ s_pakFile = newPakFile;
+}
+
+void SetAlignedLumpPosition( int lumpnum, int alignment = LUMP_ALIGNMENT )
+{
+ g_pBSPHeader->lumps[lumpnum].fileofs = AlignFilePosition( g_hBSPFile, alignment );
+}
+
+template< class T >
+int SwapLumpToDisk( int fieldType, int lumpnum )
+{
+ if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 )
+ return 0;
+
+ DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
+
+ // lump swap may expand, allocate enough expansion room
+ void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
+
+ // CopyLumpInternal will handle the swap on load case
+ unsigned int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
+ unsigned int count = CopyLumpInternal<T>( fieldType, lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
+ g_pBSPHeader->lumps[lumpnum].filelen = count * fieldSize;
+
+ if ( g_bSwapOnWrite )
+ {
+ // Swap the lump in place before writing
+ switch( lumpnum )
+ {
+ case LUMP_VISIBILITY:
+ SwapVisibilityLump( (byte*)pBuffer, (byte*)pBuffer, count );
+ break;
+
+ case LUMP_PHYSCOLLIDE:
+ // SwapPhyscollideLump may change size
+ SwapPhyscollideLump( (byte*)pBuffer, (byte*)pBuffer, count );
+ g_pBSPHeader->lumps[lumpnum].filelen = count;
+ break;
+
+ case LUMP_PHYSDISP:
+ SwapPhysdispLump( (byte*)pBuffer, (byte*)pBuffer, count );
+ break;
+
+ default:
+ g_Swap.SwapBufferToTargetEndian( (T*)pBuffer, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].filelen / sizeof(T) );
+ break;
+ }
+ }
+
+ SetAlignedLumpPosition( lumpnum );
+ SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
+
+ free( pBuffer );
+
+ return g_pBSPHeader->lumps[lumpnum].filelen;
+}
+
+template< class T >
+int SwapLumpToDisk( int lumpnum )
+{
+ if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 || g_Lumps.bLumpParsed[lumpnum] )
+ return 0;
+
+ DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
+
+ // lump swap may expand, allocate enough room
+ void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
+
+ // CopyLumpInternal will handle the swap on load case
+ int count = CopyLumpInternal<T>( lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
+ g_pBSPHeader->lumps[lumpnum].filelen = count * sizeof(T);
+
+ if ( g_bSwapOnWrite )
+ {
+ // Swap the lump in place before writing
+ g_Swap.SwapFieldsToTargetEndian( (T*)pBuffer, (T*)pBuffer, count );
+ }
+
+ SetAlignedLumpPosition( lumpnum );
+ SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
+ free( pBuffer );
+
+ return g_pBSPHeader->lumps[lumpnum].filelen;
+}
+
+void SwapLeafAmbientLightingLumpToDisk()
+{
+ if ( HasLump( LUMP_LEAF_AMBIENT_INDEX ) || HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
+ {
+ // current version, swap in place
+ if ( HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
+ {
+ // write HDR
+ SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
+ SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX_HDR );
+
+ // cull LDR
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING );
+ SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX );
+ }
+ }
+ else
+ {
+ // older ambient lighting version (before index)
+ // load older ambient lighting into memory and build ambient/index
+ // an older leaf version would have already built the new LDR leaf ambient/index
+ int numLeafs = g_pBSPHeader->lumps[LUMP_LEAFS].filelen / sizeof( dleaf_t );
+ LoadLeafAmbientLighting( numLeafs );
+
+ if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
+ {
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) );
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX_HDR ) );
+
+ // write HDR
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingHDR.Base(), g_LeafAmbientLightingHDR.Count() );
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexHDR.Base(), g_LeafAmbientIndexHDR.Count() );
+ }
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen = g_LeafAmbientLightingHDR.Count() * sizeof( dleafambientlighting_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientLightingHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen );
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX_HDR );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen = g_LeafAmbientIndexHDR.Count() * sizeof( dleafambientindex_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientIndexHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen );
+
+ // mark as processed
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
+
+ // cull LDR
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING ) );
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX ) );
+
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingLDR.Base(), g_LeafAmbientLightingLDR.Count() );
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexLDR.Base(), g_LeafAmbientIndexLDR.Count() );
+ }
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = g_LeafAmbientLightingLDR.Count() * sizeof( dleafambientlighting_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientLightingLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen );
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = g_LeafAmbientIndexLDR.Count() * sizeof( dleafambientindex_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientIndexLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen );
+
+ // mark as processed
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
+ }
+
+ g_LeafAmbientLightingLDR.Purge();
+ g_LeafAmbientIndexLDR.Purge();
+ g_LeafAmbientLightingHDR.Purge();
+ g_LeafAmbientIndexHDR.Purge();
+ }
+}
+
+void SwapLeafLumpToDisk( void )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAFS ) );
+
+ // load the leafs
+ int count = LoadLeafs();
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( dleafs, count );
+ }
+
+ bool bOldLeafVersion = ( LumpVersion( LUMP_LEAFS ) == 0 );
+ if ( bOldLeafVersion )
+ {
+ // version has been converted in the load process
+ // not updating the version ye, SwapLeafAmbientLightingLumpToDisk() can detect
+ g_pBSPHeader->lumps[LUMP_LEAFS].filelen = count * sizeof( dleaf_t );
+ }
+
+ SetAlignedLumpPosition( LUMP_LEAFS );
+ SafeWrite( g_hBSPFile, dleafs, g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
+
+ SwapLeafAmbientLightingLumpToDisk();
+
+ if ( bOldLeafVersion )
+ {
+ // version has been converted in the load process
+ // can now safely change
+ g_pBSPHeader->lumps[LUMP_LEAFS].version = 1;
+ }
+
+#if defined( BSP_USE_LESS_MEMORY )
+ if ( dleafs )
+ {
+ free( dleafs );
+ dleafs = NULL;
+ }
+#endif
+}
+
+void SwapOcclusionLumpToDisk( void )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_OCCLUSION ) );
+
+ LoadOcclusionLump();
+ SetAlignedLumpPosition( LUMP_OCCLUSION );
+ AddOcclusionLump();
+}
+
+void SwapPakfileLumpToDisk( const char *pInFilename )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_PAKFILE ) );
+
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
+ if ( paksize > 0 )
+ {
+ GetPakFile()->ActivateByteSwapping( IsX360() );
+ GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
+
+ ConvertPakFileContents( pInFilename );
+ }
+ free( pakbuffer );
+
+ SetAlignedLumpPosition( LUMP_PAKFILE, XBOX_DVD_SECTORSIZE );
+ WritePakFileLump();
+
+ ReleasePakFileLumps();
+}
+
+void SwapGameLumpsToDisk( void )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_GAME_LUMP ) );
+
+ g_GameLumps.ParseGameLump( g_pBSPHeader );
+ SetAlignedLumpPosition( LUMP_GAME_LUMP );
+ AddGameLumps();
+}
+
+//-----------------------------------------------------------------------------
+// Generate a table of all static props, used for resolving static prop lighting
+// files back to their actual mdl.
+//-----------------------------------------------------------------------------
+void BuildStaticPropNameTable()
+{
+ g_StaticPropNames.Purge();
+ g_StaticPropInstances.Purge();
+
+ g_GameLumps.ParseGameLump( g_pBSPHeader );
+
+ GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
+ if ( hGameLump != g_GameLumps.InvalidGameLump() )
+ {
+ int nVersion = g_GameLumps.GetGameLumpVersion( hGameLump );
+ if ( nVersion < 4 )
+ {
+ // old unsupported version
+ return;
+ }
+
+ if ( nVersion != 4 && nVersion != 5 && nVersion != 6 )
+ {
+ Error( "Unknown Static Prop Lump version %d!\n", nVersion );
+ }
+
+ byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
+ if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
+ {
+ // get the model dictionary
+ int count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
+ for ( int i = 0; i < count; i++ )
+ {
+ g_StaticPropNames.AddToTail( pStaticPropDictLump[i].m_Name );
+ }
+ pGameLumpData += count * sizeof( StaticPropDictLump_t );
+
+ // skip the leaf list
+ count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ pGameLumpData += count * sizeof( StaticPropLeafLump_t );
+
+ // get the instances
+ count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ for ( int i = 0; i < count; i++ )
+ {
+ int propType;
+ if ( nVersion == 4 )
+ {
+ propType = ((StaticPropLumpV4_t *)pGameLumpData)->m_PropType;
+ pGameLumpData += sizeof( StaticPropLumpV4_t );
+ }
+ else if ( nVersion == 5 )
+ {
+ propType = ((StaticPropLumpV5_t *)pGameLumpData)->m_PropType;
+ pGameLumpData += sizeof( StaticPropLumpV5_t );
+ }
+ else
+ {
+ propType = ((StaticPropLump_t *)pGameLumpData)->m_PropType;
+ pGameLumpData += sizeof( StaticPropLump_t );
+ }
+ g_StaticPropInstances.AddToTail( propType );
+ }
+ }
+ }
+
+ g_GameLumps.DestroyAllGameLumps();
+}
+
+int AlignBuffer( CUtlBuffer &buffer, int alignment )
+{
+ unsigned int newPosition = AlignValue( buffer.TellPut(), alignment );
+ int padLength = newPosition - buffer.TellPut();
+ for ( int i = 0; i<padLength; i++ )
+ {
+ buffer.PutChar( '\0' );
+ }
+ return buffer.TellPut();
+}
+
+struct SortedLump_t
+{
+ int lumpNum;
+ lump_t *pLump;
+};
+
+int SortLumpsByOffset( const SortedLump_t *pSortedLumpA, const SortedLump_t *pSortedLumpB )
+{
+ int fileOffsetA = pSortedLumpA->pLump->fileofs;
+ int fileOffsetB = pSortedLumpB->pLump->fileofs;
+
+ int fileSizeA = pSortedLumpA->pLump->filelen;
+ int fileSizeB = pSortedLumpB->pLump->filelen;
+
+ // invalid or empty lumps get sorted together
+ if ( !fileSizeA )
+ {
+ fileOffsetA = 0;
+ }
+ if ( !fileSizeB )
+ {
+ fileOffsetB = 0;
+ }
+
+ // compare by offset, want ascending
+ if ( fileOffsetA < fileOffsetB )
+ {
+ return -1;
+ }
+ else if ( fileOffsetA > fileOffsetB )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+bool CompressGameLump( dheader_t *pInBSPHeader, dheader_t *pOutBSPHeader, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
+{
+ CByteswap byteSwap;
+
+ dgamelumpheader_t* pInGameLumpHeader = (dgamelumpheader_t*)(((byte *)pInBSPHeader) + pInBSPHeader->lumps[LUMP_GAME_LUMP].fileofs);
+ dgamelump_t* pInGameLump = (dgamelump_t*)(pInGameLumpHeader + 1);
+
+ byteSwap.ActivateByteSwapping( true );
+ byteSwap.SwapFieldsToTargetEndian( pInGameLumpHeader );
+ byteSwap.SwapFieldsToTargetEndian( pInGameLump, pInGameLumpHeader->lumpCount );
+
+ unsigned int newOffset = outputBuffer.TellPut();
+ outputBuffer.Put( pInGameLumpHeader, sizeof( dgamelumpheader_t ) );
+ outputBuffer.Put( pInGameLump, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) );
+
+ dgamelumpheader_t* pOutGameLumpHeader = (dgamelumpheader_t*)((byte *)outputBuffer.Base() + newOffset);
+ dgamelump_t* pOutGameLump = (dgamelump_t*)(pOutGameLumpHeader + 1);
+
+ // add a dummy terminal gamelump
+ // purposely NOT updating the .filelen to reflect the compressed size, but leaving as original size
+ // callers use the next entry offset to determine compressed size
+ pOutGameLumpHeader->lumpCount++;
+ dgamelump_t dummyLump = { 0 };
+ outputBuffer.Put( &dummyLump, sizeof( dgamelump_t ) );
+
+ for ( int i = 0; i < pInGameLumpHeader->lumpCount; i++ )
+ {
+ CUtlBuffer inputBuffer;
+ CUtlBuffer compressedBuffer;
+
+ pOutGameLump[i].fileofs = AlignBuffer( outputBuffer, 4 );
+
+ if ( pInGameLump[i].filelen )
+ {
+ inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pInGameLump[i].fileofs, pInGameLump[i].filelen, pInGameLump[i].filelen );
+
+ bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
+ if ( bCompressed )
+ {
+ pOutGameLump[i].flags |= GAMELUMPFLAG_COMPRESSED;
+
+ outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
+ compressedBuffer.Purge();
+ }
+ else
+ {
+ // as is
+ outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
+ }
+ }
+ }
+
+ // fix the dummy terminal lump
+ int lastLump = pOutGameLumpHeader->lumpCount-1;
+ pOutGameLump[lastLump].fileofs = outputBuffer.TellPut();
+
+ // fix the output for 360, swapping it back
+ byteSwap.SwapFieldsToTargetEndian( pOutGameLump, pOutGameLumpHeader->lumpCount );
+ byteSwap.SwapFieldsToTargetEndian( pOutGameLumpHeader );
+
+ pOutBSPHeader->lumps[LUMP_GAME_LUMP].fileofs = newOffset;
+ pOutBSPHeader->lumps[LUMP_GAME_LUMP].filelen = outputBuffer.TellPut() - newOffset;
+
+ return true;
+}
+
+bool CompressBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
+{
+ CByteswap byteSwap;
+
+ dheader_t *pInBSPHeader = (dheader_t *)inputBuffer.Base();
+ if ( pInBSPHeader->ident != BigLong( IDBSPHEADER ) || !pCompressFunc )
+ {
+ // only compress 360 bsp's
+ return false;
+ }
+
+ // bsp is 360, swap the header back
+ byteSwap.ActivateByteSwapping( true );
+ byteSwap.SwapFieldsToTargetEndian( pInBSPHeader );
+
+ // output will be smaller, use input size as upper bound
+ outputBuffer.EnsureCapacity( inputBuffer.TellMaxPut() );
+ outputBuffer.Put( pInBSPHeader, sizeof( dheader_t ) );
+
+ dheader_t *pOutBSPHeader = (dheader_t *)outputBuffer.Base();
+
+ // must adhere to input lump's offset order and process according to that, NOT lump num
+ // sort by offset order
+ CUtlVector< SortedLump_t > sortedLumps;
+ for ( int i = 0; i < HEADER_LUMPS; i++ )
+ {
+ int iIndex = sortedLumps.AddToTail();
+ sortedLumps[iIndex].lumpNum = i;
+ sortedLumps[iIndex].pLump = &pInBSPHeader->lumps[i];
+ }
+ sortedLumps.Sort( SortLumpsByOffset );
+
+ // iterate in sorted order
+ for ( int i = 0; i < HEADER_LUMPS; ++i )
+ {
+ SortedLump_t *pSortedLump = &sortedLumps[i];
+ int lumpNum = pSortedLump->lumpNum;
+
+ if ( !pSortedLump->pLump->filelen )
+ {
+ // degenerate
+ pOutBSPHeader->lumps[lumpNum].fileofs = 0;
+ }
+ else
+ {
+ int alignment = 4;
+ if ( lumpNum == LUMP_PAKFILE )
+ {
+ alignment = 2048;
+ }
+ unsigned int newOffset = AlignBuffer( outputBuffer, alignment );
+
+ // only set by compressed lumps, hides the uncompressed size
+ *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = 0;
+
+ CUtlBuffer inputBuffer;
+ inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs, pSortedLump->pLump->filelen, pSortedLump->pLump->filelen );
+
+ if ( lumpNum == LUMP_GAME_LUMP )
+ {
+ // the game lump has to have each of its components individually compressed
+ CompressGameLump( pInBSPHeader, pOutBSPHeader, outputBuffer, pCompressFunc );
+ }
+ else if ( lumpNum == LUMP_PAKFILE )
+ {
+ // add as is
+ pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
+ outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
+ }
+ else
+ {
+ CUtlBuffer compressedBuffer;
+ bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
+ if ( bCompressed )
+ {
+ // placing the uncompressed size in the unused fourCC, will decode at runtime
+ *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = BigLong( inputBuffer.TellPut() );
+ pOutBSPHeader->lumps[lumpNum].filelen = compressedBuffer.TellPut();
+ pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
+ outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
+ compressedBuffer.Purge();
+ }
+ else
+ {
+ // add as is
+ pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
+ outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
+ }
+ }
+ }
+ }
+
+ // fix the output for 360, swapping it back
+ byteSwap.SetTargetBigEndian( true );
+ byteSwap.SwapFieldsToTargetEndian( pOutBSPHeader );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// For all lumps in a bsp: Loads the lump from file A, swaps it, writes it to file B.
+// This limits the memory used for the swap process which helps the Xbox 360.
+//
+// NOTE: These lumps will be written to the file in exactly the order they appear here,
+// so they can be shifted around if desired for file access optimization.
+//-----------------------------------------------------------------------------
+bool SwapBSPFile( const char *pInFilename, const char *pOutFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc )
+{
+ DevMsg( "Creating %s\n", pOutFilename );
+
+ if ( !g_pFileSystem->FileExists( pInFilename ) )
+ {
+ Warning( "Error! Couldn't open input file %s - BSP swap failed!\n", pInFilename );
+ return false;
+ }
+
+ g_hBSPFile = SafeOpenWrite( pOutFilename );
+ if ( !g_hBSPFile )
+ {
+ Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
+ return false;
+ }
+
+ if ( !pVTFConvertFunc )
+ {
+ Warning( "Error! Missing VTF Conversion function\n" );
+ return false;
+ }
+ g_pVTFConvertFunc = pVTFConvertFunc;
+
+ // optional VHV fixup
+ g_pVHVFixupFunc = pVHVFixupFunc;
+
+ // optional compression callback
+ g_pCompressFunc = pCompressFunc;
+
+ // These must be mutually exclusive
+ g_bSwapOnLoad = bSwapOnLoad;
+ g_bSwapOnWrite = !bSwapOnLoad;
+
+ g_Swap.ActivateByteSwapping( true );
+
+ OpenBSPFile( pInFilename );
+
+ // CRC the bsp first
+ CRC32_t mapCRC;
+ CRC32_Init(&mapCRC);
+ if ( !CRC_MapFile( &mapCRC, pInFilename ) )
+ {
+ Warning( "Failed to CRC the bsp\n" );
+ return false;
+ }
+
+ // hold a dictionary of all the static prop names
+ // this is needed to properly convert any VHV files inside the pak lump
+ BuildStaticPropNameTable();
+
+ // Set the output file pointer after the header
+ dheader_t dummyHeader = { 0 };
+ SafeWrite( g_hBSPFile, &dummyHeader, sizeof( dheader_t ) );
+
+ // To allow for alignment fixups, the lumps will be written to the
+ // output file in the order they appear in this function.
+
+ // NOTE: Flags for 360 !!!MUST!!! be first
+ SwapLumpToDisk< dflagslump_t >( LUMP_MAP_FLAGS );
+
+ // complex lump swaps first or for later contingent data
+ SwapLeafLumpToDisk();
+ SwapOcclusionLumpToDisk();
+ SwapGameLumpsToDisk();
+
+ // Strip dead or non relevant lumps
+ g_pBSPHeader->lumps[LUMP_DISP_LIGHTMAP_ALPHAS].filelen = 0;
+ g_pBSPHeader->lumps[LUMP_FACEIDS].filelen = 0;
+
+ // Strip obsolete LDR in favor of HDR
+ if ( SwapLumpToDisk<dface_t>( LUMP_FACES_HDR ) )
+ {
+ g_pBSPHeader->lumps[LUMP_FACES].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk<dface_t>( LUMP_FACES );
+ }
+
+ if ( SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS_HDR ) )
+ {
+ g_pBSPHeader->lumps[LUMP_WORLDLIGHTS].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS );
+ }
+
+ // Simple lump swaps
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSDISP );
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE );
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_VISIBILITY );
+ SwapLumpToDisk<dmodel_t>( LUMP_MODELS );
+ SwapLumpToDisk<dvertex_t>( LUMP_VERTEXES );
+ SwapLumpToDisk<dplane_t>( LUMP_PLANES );
+ SwapLumpToDisk<dnode_t>( LUMP_NODES );
+ SwapLumpToDisk<texinfo_t>( LUMP_TEXINFO );
+ SwapLumpToDisk<dtexdata_t>( LUMP_TEXDATA );
+ SwapLumpToDisk<ddispinfo_t>( LUMP_DISPINFO );
+ SwapLumpToDisk<CDispVert>( LUMP_DISP_VERTS );
+ SwapLumpToDisk<CDispTri>( LUMP_DISP_TRIS );
+ SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
+ SwapLumpToDisk<CFaceMacroTextureInfo>( LUMP_FACE_MACRO_TEXTURE_INFO );
+ SwapLumpToDisk<dprimitive_t>( LUMP_PRIMITIVES );
+ SwapLumpToDisk<dprimvert_t>( LUMP_PRIMVERTS );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_PRIMINDICES );
+ SwapLumpToDisk<dface_t>( LUMP_ORIGINALFACES );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFFACES );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFBRUSHES );
+ SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_SURFEDGES );
+ SwapLumpToDisk<dedge_t>( LUMP_EDGES );
+ SwapLumpToDisk<dbrush_t>( LUMP_BRUSHES );
+ SwapLumpToDisk<dbrushside_t>( LUMP_BRUSHSIDES );
+ SwapLumpToDisk<darea_t>( LUMP_AREAS );
+ SwapLumpToDisk<dareaportal_t>( LUMP_AREAPORTALS );
+ SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_ENTITIES );
+ SwapLumpToDisk<dleafwaterdata_t>( LUMP_LEAFWATERDATA );
+ SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_VERTNORMALS );
+ SwapLumpToDisk<short>( FIELD_SHORT, LUMP_VERTNORMALINDICES );
+ SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_CLIPPORTALVERTS );
+ SwapLumpToDisk<dcubemapsample_t>( LUMP_CUBEMAPS );
+ SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA );
+ SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE );
+ SwapLumpToDisk<doverlay_t>( LUMP_OVERLAYS );
+ SwapLumpToDisk<dwateroverlay_t>( LUMP_WATEROVERLAYS );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER );
+ SwapLumpToDisk<doverlayfade_t>( LUMP_OVERLAY_FADES );
+
+
+ // NOTE: this data placed at the end for the sake of 360:
+ {
+ // NOTE: lighting must be the penultimate lump
+ // (allows 360 to free this memory part-way through map loading)
+ if ( SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING_HDR ) )
+ {
+ g_pBSPHeader->lumps[LUMP_LIGHTING].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING );
+ }
+ // NOTE: Pakfile for 360 !!!MUST!!! be last
+ SwapPakfileLumpToDisk( pInFilename );
+ }
+
+
+ // Store the crc in the flags lump version field
+ g_pBSPHeader->lumps[LUMP_MAP_FLAGS].version = mapCRC;
+
+ // Pad out the end of the file to a sector boundary for optimal IO
+ AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
+
+ // Warn of any lumps that didn't get swapped
+ for ( int i = 0; i < HEADER_LUMPS; ++i )
+ {
+ if ( HasLump( i ) && !g_Lumps.bLumpParsed[i] )
+ {
+ // a new lump got added that needs to have a swap function
+ Warning( "BSP: '%s', %s has no swap or copy function. Discarding!\n", pInFilename, GetLumpName(i) );
+
+ // the data didn't get copied, so don't reference garbage
+ g_pBSPHeader->lumps[i].filelen = 0;
+ }
+ }
+
+ // Write the updated header
+ g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
+ WriteData( g_pBSPHeader );
+ g_pFileSystem->Close( g_hBSPFile );
+ g_hBSPFile = 0;
+
+ // Cleanup
+ g_Swap.ActivateByteSwapping( false );
+
+ CloseBSPFile();
+
+ g_StaticPropNames.Purge();
+ g_StaticPropInstances.Purge();
+
+ DevMsg( "Finished BSP Swap\n" );
+
+ // caller provided compress func will further compress compatible lumps
+ if ( pCompressFunc )
+ {
+ CUtlBuffer inputBuffer;
+ if ( !g_pFileSystem->ReadFile( pOutFilename, NULL, inputBuffer ) )
+ {
+ Warning( "Error! Couldn't read file %s - final BSP compression failed!\n", pOutFilename );
+ return false;
+ }
+
+ CUtlBuffer outputBuffer;
+ if ( !CompressBSP( inputBuffer, outputBuffer, pCompressFunc ) )
+ {
+ Warning( "Error! Failed to compress BSP '%s'!\n", pOutFilename );
+ return false;
+ }
+
+ g_hBSPFile = SafeOpenWrite( pOutFilename );
+ if ( !g_hBSPFile )
+ {
+ Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
+ return false;
+ }
+ SafeWrite( g_hBSPFile, outputBuffer.Base(), outputBuffer.TellPut() );
+ g_pFileSystem->Close( g_hBSPFile );
+ g_hBSPFile = 0;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Get the pak lump from a BSP
+//-----------------------------------------------------------------------------
+bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize )
+{
+ *pPakData = NULL;
+ *pPakSize = 0;
+
+ if ( !g_pFileSystem->FileExists( pBSPFilename ) )
+ {
+ Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
+ return false;
+ }
+
+ // determine endian nature
+ dheader_t *pHeader;
+ LoadFile( pBSPFilename, (void **)&pHeader );
+ bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
+ free( pHeader );
+
+ g_bSwapOnLoad = bSwap;
+ g_bSwapOnWrite = !bSwap;
+
+ OpenBSPFile( pBSPFilename );
+
+ if ( g_pBSPHeader->lumps[LUMP_PAKFILE].filelen )
+ {
+ *pPakSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, pPakData );
+ }
+
+ CloseBSPFile();
+
+ return true;
+}
+
+// compare function for qsort below
+static int LumpOffsetCompare( const void *pElem1, const void *pElem2 )
+{
+ int lump1 = *(byte *)pElem1;
+ int lump2 = *(byte *)pElem2;
+
+ if ( lump1 != lump2 )
+ {
+ // force LUMP_MAP_FLAGS to be first, always
+ if ( lump1 == LUMP_MAP_FLAGS )
+ {
+ return -1;
+ }
+ else if ( lump2 == LUMP_MAP_FLAGS )
+ {
+ return 1;
+ }
+
+ // force LUMP_PAKFILE to be last, always
+ if ( lump1 == LUMP_PAKFILE )
+ {
+ return 1;
+ }
+ else if ( lump2 == LUMP_PAKFILE )
+ {
+ return -1;
+ }
+ }
+
+ int fileOffset1 = g_pBSPHeader->lumps[lump1].fileofs;
+ int fileOffset2 = g_pBSPHeader->lumps[lump2].fileofs;
+
+ // invalid or empty lumps will get sorted together
+ if ( !g_pBSPHeader->lumps[lump1].filelen )
+ {
+ fileOffset1 = 0;
+ }
+
+ if ( !g_pBSPHeader->lumps[lump2].filelen )
+ {
+ fileOffset2 = 0;
+ }
+
+ // compare by offset
+ if ( fileOffset1 < fileOffset2 )
+ {
+ return -1;
+ }
+ else if ( fileOffset1 > fileOffset2 )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Replace the pak lump in a BSP
+//-----------------------------------------------------------------------------
+bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize )
+{
+ if ( !g_pFileSystem->FileExists( pBSPFilename ) )
+ {
+ Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
+ return false;
+ }
+
+ // determine endian nature
+ dheader_t *pHeader;
+ LoadFile( pBSPFilename, (void **)&pHeader );
+ bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
+ free( pHeader );
+
+ g_bSwapOnLoad = bSwap;
+ g_bSwapOnWrite = bSwap;
+
+ OpenBSPFile( pBSPFilename );
+
+ // save a copy of the old header
+ // generating a new bsp is a destructive operation
+ dheader_t oldHeader;
+ oldHeader = *g_pBSPHeader;
+
+ g_hBSPFile = SafeOpenWrite( pNewFilename );
+ if ( !g_hBSPFile )
+ {
+ return false;
+ }
+
+ // placeholder only, reset at conclusion
+ WriteData( &oldHeader );
+
+ // lumps must be reserialized in same relative offset order
+ // build sorted order table
+ int readOrder[HEADER_LUMPS];
+ for ( int i=0; i<HEADER_LUMPS; i++ )
+ {
+ readOrder[i] = i;
+ }
+ qsort( readOrder, HEADER_LUMPS, sizeof( int ), LumpOffsetCompare );
+
+ for ( int i = 0; i < HEADER_LUMPS; i++ )
+ {
+ int lump = readOrder[i];
+
+ if ( lump == LUMP_PAKFILE )
+ {
+ // pak lump always written last, with special alignment
+ continue;
+ }
+
+ int length = g_pBSPHeader->lumps[lump].filelen;
+ if ( length )
+ {
+ // save the lump data
+ int offset = g_pBSPHeader->lumps[lump].fileofs;
+ SetAlignedLumpPosition( lump );
+ SafeWrite( g_hBSPFile, (byte *)g_pBSPHeader + offset, length );
+ }
+ else
+ {
+ g_pBSPHeader->lumps[lump].fileofs = 0;
+ }
+ }
+
+ // Always write the pak file at the end
+ // Pad out the end of the file to a sector boundary for optimal IO
+ g_pBSPHeader->lumps[LUMP_PAKFILE].fileofs = AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
+ g_pBSPHeader->lumps[LUMP_PAKFILE].filelen = pakSize;
+ SafeWrite( g_hBSPFile, pPakData, pakSize );
+
+ // Pad out the end of the file to a sector boundary for optimal IO
+ AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
+
+ // Write the updated header
+ g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
+ WriteData( g_pBSPHeader );
+ g_pFileSystem->Close( g_hBSPFile );
+
+ CloseBSPFile();
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Build a list of files that BSP owns, world/cubemap materials, static props, etc.
+//-----------------------------------------------------------------------------
+bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList )
+{
+ if ( !g_pFileSystem->FileExists( pBSPFilename ) )
+ {
+ Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
+ return false;
+ }
+
+ // must be set, but exact hdr not critical for dependant traversal
+ SetHDRMode( false );
+
+ LoadBSPFile( pBSPFilename );
+
+ char szBspName[MAX_PATH];
+ V_FileBase( pBSPFilename, szBspName, sizeof( szBspName ) );
+ V_SetExtension( szBspName, ".bsp", sizeof( szBspName ) );
+
+ // get embedded pak files, and internals
+ char szFilename[MAX_PATH];
+ int fileSize;
+ int fileId = -1;
+ for ( ;; )
+ {
+ fileId = GetPakFile()->GetNextFilename( fileId, szFilename, sizeof( szFilename ), fileSize );
+ if ( fileId == -1 )
+ {
+ break;
+ }
+ pList->AddToTail( szFilename );
+ }
+
+ // get all the world materials
+ for ( int i=0; i<numtexdata; i++ )
+ {
+ const char *pName = TexDataStringTable_GetString( dtexdata[i].nameStringTableID );
+ V_ComposeFileName( "materials", pName, szFilename, sizeof( szFilename ) );
+ V_SetExtension( szFilename, ".vmt", sizeof( szFilename ) );
+ pList->AddToTail( szFilename );
+ }
+
+ // get all the static props
+ GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
+ if ( hGameLump != g_GameLumps.InvalidGameLump() )
+ {
+ byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
+ if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
+ {
+ int count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+
+ StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
+ for ( int i=0; i<count; i++ )
+ {
+ pList->AddToTail( pStaticPropDictLump[i].m_Name );
+ }
+ }
+ }
+
+ // get all the detail props
+ hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
+ if ( hGameLump != g_GameLumps.InvalidGameLump() )
+ {
+ byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
+ if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
+ {
+ int count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+
+ DetailObjectDictLump_t *pDetailObjectDictLump = (DetailObjectDictLump_t *)pGameLumpData;
+ for ( int i=0; i<count; i++ )
+ {
+ pList->AddToTail( pDetailObjectDictLump[i].m_Name );
+ }
+ pGameLumpData += count * sizeof( DetailObjectDictLump_t );
+
+ if ( g_GameLumps.GetGameLumpVersion( hGameLump ) == 4 )
+ {
+ count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ if ( count )
+ {
+ // All detail prop sprites must lie in the material detail/detailsprites
+ pList->AddToTail( "materials/detail/detailsprites.vmt" );
+ }
+ }
+ }
+ }
+
+ UnloadBSPFile();
+
+ return true;
+}
+
diff --git a/mp/src/utils/common/bsplib.h b/mp/src/utils/common/bsplib.h
index 83486e8b..80952ba9 100644
--- a/mp/src/utils/common/bsplib.h
+++ b/mp/src/utils/common/bsplib.h
@@ -1,404 +1,404 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef BSPLIB_H
-#define BSPLIB_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-#include "bspfile.h"
-#include "utlvector.h"
-#include "utlstring.h"
-#include "utllinkedlist.h"
-#include "byteswap.h"
-#ifdef ENGINE_DLL
-#include "zone.h"
-#endif
-
-#ifdef ENGINE_DLL
-typedef CUtlVector<unsigned char, CHunkMemory<unsigned char> > CDispLightmapSamplePositions;
-#else
-typedef CUtlVector<unsigned char> CDispLightmapSamplePositions;
-#endif
-
-class ISpatialQuery;
-struct Ray_t;
-class Vector2D;
-struct portal_t;
-class CUtlBuffer;
-class IZip;
-
-// this is only true in vrad
-extern bool g_bHDR;
-
-// default width/height of luxels in world units.
-#define DEFAULT_LUXEL_SIZE ( 16.0f )
-
-#define SINGLE_BRUSH_MAP (MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER*MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER)
-#define SINGLEMAP (MAX_LIGHTMAP_DIM_INCLUDING_BORDER*MAX_LIGHTMAP_DIM_INCLUDING_BORDER)
-
-struct entity_t
-{
- Vector origin;
- int firstbrush;
- int numbrushes;
- epair_t *epairs;
-
- // only valid for func_areaportals
- int areaportalnum;
- int portalareas[2];
- portal_t *m_pPortalsLeadingIntoAreas[2]; // portals leading into portalareas
-};
-
-extern int num_entities;
-extern entity_t entities[MAX_MAP_ENTITIES];
-
-extern int nummodels;
-extern dmodel_t dmodels[MAX_MAP_MODELS];
-
-extern int visdatasize;
-extern byte dvisdata[MAX_MAP_VISIBILITY];
-extern dvis_t *dvis;
-
-extern CUtlVector<byte> dlightdataHDR;
-extern CUtlVector<byte> dlightdataLDR;
-extern CUtlVector<byte> *pdlightdata;
-extern CUtlVector<char> dentdata;
-
-extern int numleafs;
-#if !defined( _X360 )
-extern dleaf_t dleafs[MAX_MAP_LEAFS];
-#else
-extern dleaf_t *dleafs;
-#endif
-extern CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting;
-extern CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex;
-extern unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
-
-extern int numplanes;
-extern dplane_t dplanes[MAX_MAP_PLANES];
-
-extern int numvertexes;
-extern dvertex_t dvertexes[MAX_MAP_VERTS];
-
-extern int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
-extern unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
-
-extern int g_numvertnormals;
-extern Vector g_vertnormals[MAX_MAP_VERTNORMALS];
-
-extern int numnodes;
-extern dnode_t dnodes[MAX_MAP_NODES];
-
-extern CUtlVector<texinfo_t> texinfo;
-
-extern int numtexdata;
-extern dtexdata_t dtexdata[MAX_MAP_TEXDATA];
-
-// displacement map .bsp file info
-extern CUtlVector<ddispinfo_t> g_dispinfo;
-extern CUtlVector<CDispVert> g_DispVerts;
-extern CUtlVector<CDispTri> g_DispTris;
-extern CDispLightmapSamplePositions g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
-
-extern int numorigfaces;
-extern dface_t dorigfaces[MAX_MAP_FACES];
-
-extern int g_numprimitives;
-extern dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
-
-extern int g_numprimverts;
-extern dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
-
-extern int g_numprimindices;
-extern unsigned short g_primindices[MAX_MAP_PRIMINDICES];
-
-extern int numfaces;
-extern dface_t dfaces[MAX_MAP_FACES];
-
-extern int numfaceids;
-extern CUtlVector<dfaceid_t> dfaceids;
-
-extern int numfaces_hdr;
-extern dface_t dfaces_hdr[MAX_MAP_FACES];
-
-extern int numedges;
-extern dedge_t dedges[MAX_MAP_EDGES];
-
-extern int numleaffaces;
-extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
-
-extern int numleafbrushes;
-extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
-
-extern int numsurfedges;
-extern int dsurfedges[MAX_MAP_SURFEDGES];
-
-extern int numareas;
-extern darea_t dareas[MAX_MAP_AREAS];
-
-extern int numareaportals;
-extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
-
-extern int numbrushes;
-extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
-
-extern int numbrushsides;
-extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
-
-extern int *pNumworldlights;
-extern dworldlight_t *dworldlights;
-
-extern Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
-extern int g_nClipPortalVerts;
-
-extern dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
-extern int g_nCubemapSamples;
-
-extern int g_nOverlayCount;
-extern doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
-extern doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS]; // Parallel array of fade info in a separate lump to avoid breaking backwards compat
-
-extern int g_nWaterOverlayCount;
-extern dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
-
-extern CUtlVector<char> g_TexDataStringData;
-extern CUtlVector<int> g_TexDataStringTable;
-
-extern int numleafwaterdata;
-extern dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
-
-extern CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
-
-extern CUtlVector<doccluderdata_t> g_OccluderData;
-extern CUtlVector<doccluderpolydata_t> g_OccluderPolyData;
-extern CUtlVector<int> g_OccluderVertexIndices;
-
-// level flags - see LVLFLAGS_xxx in bspfile.h
-extern uint32 g_LevelFlags;
-
-// physics collision data
-extern byte *g_pPhysCollide;
-extern int g_PhysCollideSize;
-extern byte *g_pPhysDisp;
-extern int g_PhysDispSize;
-
-// Embedded pack/pak file
-IZip *GetPakFile( void );
-IZip *GetSwapPakFile( void );
-void ClearPakFile( IZip *pak );
-void AddFileToPak( IZip *pak, const char *pRelativeName, const char *fullpath );
-void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode );
-bool FileExistsInPak( IZip *pak, const char *pRelativeName );
-bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf );
-void RemoveFileFromPak( IZip *pak, const char *pRelativeName );
-int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize );
-void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize );
-
-typedef bool (*CompressFunc_t)( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer );
-typedef bool (*VTFConvertFunc_t)( const char *pDebugName, CUtlBuffer &sourceBuf, CUtlBuffer &targetBuf, CompressFunc_t pCompressFunc );
-typedef bool (*VHVFixupFunc_t)( const char *pVhvFilename, const char *pModelName, CUtlBuffer &sourceBuf, CUtlBuffer &targetBuf );
-
-//-----------------------------------------------------------------------------
-// Game lump memory storage
-//-----------------------------------------------------------------------------
-// NOTE: This is not optimal at all; since I expect client lumps to
-// not be accessed all that often.
-
-struct GameLump_t
-{
- GameLumpId_t m_Id;
- unsigned short m_Flags;
- unsigned short m_Version;
- CUtlMemory< unsigned char > m_Memory;
-};
-
-//-----------------------------------------------------------------------------
-// Handle to a game lump
-//-----------------------------------------------------------------------------
-typedef unsigned short GameLumpHandle_t;
-
-class CGameLump
-{
-public:
- //-----------------------------------------------------------------------------
- // Convert four-CC code to a handle + back
- //-----------------------------------------------------------------------------
- GameLumpHandle_t GetGameLumpHandle( GameLumpId_t id );
- GameLumpId_t GetGameLumpId( GameLumpHandle_t handle );
- int GetGameLumpFlags( GameLumpHandle_t handle );
- int GetGameLumpVersion( GameLumpHandle_t handle );
- void ComputeGameLumpSizeAndCount( int& size, int& clumpCount );
- void ParseGameLump( dheader_t* pHeader );
- void SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int size );
-
-
- //-----------------------------------------------------------------------------
- // Game lump accessor methods
- //-----------------------------------------------------------------------------
- void* GetGameLump( GameLumpHandle_t handle );
- int GameLumpSize( GameLumpHandle_t handle );
-
-
- //-----------------------------------------------------------------------------
- // Game lump iteration methods
- //-----------------------------------------------------------------------------
- GameLumpHandle_t FirstGameLump();
- GameLumpHandle_t NextGameLump( GameLumpHandle_t handle );
- GameLumpHandle_t InvalidGameLump();
-
-
- //-----------------------------------------------------------------------------
- // Game lump creation/destruction method
- //-----------------------------------------------------------------------------
- GameLumpHandle_t CreateGameLump( GameLumpId_t id, int size, int flags, int version );
- void DestroyGameLump( GameLumpHandle_t handle );
- void DestroyAllGameLumps();
-
-private:
- CUtlLinkedList< GameLump_t, GameLumpHandle_t > m_GameLumps;
-};
-
-extern CGameLump g_GameLumps;
-extern CByteswap g_Swap;
-
-//-----------------------------------------------------------------------------
-// Helper for the bspzip tool
-//-----------------------------------------------------------------------------
-void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName );
-
-
-//-----------------------------------------------------------------------------
-// String table methods
-//-----------------------------------------------------------------------------
-const char * TexDataStringTable_GetString( int stringID );
-int TexDataStringTable_AddOrFindString( const char *pString );
-
-void DecompressVis (byte *in, byte *decompressed);
-int CompressVis (byte *vis, byte *dest);
-
-void OpenBSPFile( const char *filename );
-void CloseBSPFile(void);
-void LoadBSPFile( const char *filename );
-void LoadBSPFile_FileSystemOnly( const char *filename );
-void LoadBSPFileTexinfo( const char *filename );
-void WriteBSPFile( const char *filename, char *pUnused = NULL );
-void PrintBSPFileSizes(void);
-void PrintBSPPackDirectory(void);
-void ReleasePakFileLumps(void);
-bool SwapBSPFile( const char *filename, const char *swapFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc );
-bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize );
-bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize );
-void WriteLumpToFile( char *filename, int lump );
-void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen );
-bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList );
-void UnloadBSPFile();
-
-void ParseEntities (void);
-void UnparseEntities (void);
-void PrintEntity (entity_t *ent);
-
-void SetKeyValue (entity_t *ent, const char *key, const char *value);
-char *ValueForKey (entity_t *ent, char *key);
-// will return "" if not present
-int IntForKey (entity_t *ent, char *key);
-int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault );
-vec_t FloatForKey (entity_t *ent, char *key);
-vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value);
-void GetVectorForKey (entity_t *ent, char *key, Vector& vec);
-void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec);
-void GetAnglesForKey (entity_t *ent, char *key, QAngle& vec);
-epair_t *ParseEpair (void);
-void StripTrailing (char *e);
-
-// Build a list of the face's vertices (index into dvertexes).
-// points must be able to hold pFace->numedges indices.
-void BuildFaceCalcWindingData( dface_t *pFace, int *points );
-
-// Convert a tristrip to a trilist.
-// Removes degenerates.
-// Fills in pTriListIndices and pnTriListIndices.
-// You must free pTriListIndices with delete[].
-void TriStripToTriList(
- unsigned short const *pTriStripIndices,
- int nTriStripIndices,
- unsigned short **pTriListIndices,
- int *pnTriListIndices );
-
-// Calculates the lightmap coordinates at a given set of positions given the
-// lightmap basis information.
-void CalcTextureCoordsAtPoints(
- float const texelsPerWorldUnits[2][4],
- int const subtractOffset[2],
- Vector const *pPoints,
- int const nPoints,
- Vector2D *pCoords );
-
-// Figure out lightmap extents on all (lit) faces.
-void UpdateAllFaceLightmapExtents();
-
-
-//-----------------------------------------------------------------------------
-// Gets at an interface for the tree for enumeration of leaves in volumes.
-//-----------------------------------------------------------------------------
-ISpatialQuery* ToolBSPTree();
-
-class IBSPNodeEnumerator
-{
-public:
- // call back with a node and a context
- virtual bool EnumerateNode( int node, Ray_t const& ray, float f, int context ) = 0;
-
- // call back with a leaf and a context
- virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, int context ) = 0;
-};
-
-//-----------------------------------------------------------------------------
-// Enumerates nodes + leafs in front to back order...
-//-----------------------------------------------------------------------------
-bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context );
-
-
-//-----------------------------------------------------------------------------
-// Helps us find all leaves associated with a particular cluster
-//-----------------------------------------------------------------------------
-struct clusterlist_t
-{
- int leafCount;
- CUtlVector<int> leafs;
-};
-
-extern CUtlVector<clusterlist_t> g_ClusterLeaves;
-
-// Call this to build the mapping from cluster to leaves
-void BuildClusterTable( );
-
-void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int dxlevel, int maxLength );
-
-void SetHDRMode( bool bHDR );
-
-// ----------------------------------------------------------------------------- //
-// Helper accessors for the various structures.
-// ----------------------------------------------------------------------------- //
-
-inline ColorRGBExp32* dface_AvgLightColor( dface_t *pFace, int nLightStyleIndex )
-{
- return (ColorRGBExp32*)&(*pdlightdata)[pFace->lightofs - (nLightStyleIndex+1) * 4];
-}
-
-inline const char* TexInfo_TexName( int iTexInfo )
-{
- return TexDataStringTable_GetString( dtexdata[texinfo[iTexInfo].texdata].nameStringTableID );
-}
-
-
-#endif // BSPLIB_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BSPLIB_H
+#define BSPLIB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "bspfile.h"
+#include "utlvector.h"
+#include "utlstring.h"
+#include "utllinkedlist.h"
+#include "byteswap.h"
+#ifdef ENGINE_DLL
+#include "zone.h"
+#endif
+
+#ifdef ENGINE_DLL
+typedef CUtlVector<unsigned char, CHunkMemory<unsigned char> > CDispLightmapSamplePositions;
+#else
+typedef CUtlVector<unsigned char> CDispLightmapSamplePositions;
+#endif
+
+class ISpatialQuery;
+struct Ray_t;
+class Vector2D;
+struct portal_t;
+class CUtlBuffer;
+class IZip;
+
+// this is only true in vrad
+extern bool g_bHDR;
+
+// default width/height of luxels in world units.
+#define DEFAULT_LUXEL_SIZE ( 16.0f )
+
+#define SINGLE_BRUSH_MAP (MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER*MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER)
+#define SINGLEMAP (MAX_LIGHTMAP_DIM_INCLUDING_BORDER*MAX_LIGHTMAP_DIM_INCLUDING_BORDER)
+
+struct entity_t
+{
+ Vector origin;
+ int firstbrush;
+ int numbrushes;
+ epair_t *epairs;
+
+ // only valid for func_areaportals
+ int areaportalnum;
+ int portalareas[2];
+ portal_t *m_pPortalsLeadingIntoAreas[2]; // portals leading into portalareas
+};
+
+extern int num_entities;
+extern entity_t entities[MAX_MAP_ENTITIES];
+
+extern int nummodels;
+extern dmodel_t dmodels[MAX_MAP_MODELS];
+
+extern int visdatasize;
+extern byte dvisdata[MAX_MAP_VISIBILITY];
+extern dvis_t *dvis;
+
+extern CUtlVector<byte> dlightdataHDR;
+extern CUtlVector<byte> dlightdataLDR;
+extern CUtlVector<byte> *pdlightdata;
+extern CUtlVector<char> dentdata;
+
+extern int numleafs;
+#if !defined( _X360 )
+extern dleaf_t dleafs[MAX_MAP_LEAFS];
+#else
+extern dleaf_t *dleafs;
+#endif
+extern CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting;
+extern CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex;
+extern unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
+
+extern int numplanes;
+extern dplane_t dplanes[MAX_MAP_PLANES];
+
+extern int numvertexes;
+extern dvertex_t dvertexes[MAX_MAP_VERTS];
+
+extern int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
+extern unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
+
+extern int g_numvertnormals;
+extern Vector g_vertnormals[MAX_MAP_VERTNORMALS];
+
+extern int numnodes;
+extern dnode_t dnodes[MAX_MAP_NODES];
+
+extern CUtlVector<texinfo_t> texinfo;
+
+extern int numtexdata;
+extern dtexdata_t dtexdata[MAX_MAP_TEXDATA];
+
+// displacement map .bsp file info
+extern CUtlVector<ddispinfo_t> g_dispinfo;
+extern CUtlVector<CDispVert> g_DispVerts;
+extern CUtlVector<CDispTri> g_DispTris;
+extern CDispLightmapSamplePositions g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
+
+extern int numorigfaces;
+extern dface_t dorigfaces[MAX_MAP_FACES];
+
+extern int g_numprimitives;
+extern dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
+
+extern int g_numprimverts;
+extern dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
+
+extern int g_numprimindices;
+extern unsigned short g_primindices[MAX_MAP_PRIMINDICES];
+
+extern int numfaces;
+extern dface_t dfaces[MAX_MAP_FACES];
+
+extern int numfaceids;
+extern CUtlVector<dfaceid_t> dfaceids;
+
+extern int numfaces_hdr;
+extern dface_t dfaces_hdr[MAX_MAP_FACES];
+
+extern int numedges;
+extern dedge_t dedges[MAX_MAP_EDGES];
+
+extern int numleaffaces;
+extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
+
+extern int numleafbrushes;
+extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
+
+extern int numsurfedges;
+extern int dsurfedges[MAX_MAP_SURFEDGES];
+
+extern int numareas;
+extern darea_t dareas[MAX_MAP_AREAS];
+
+extern int numareaportals;
+extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
+
+extern int numbrushes;
+extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
+
+extern int numbrushsides;
+extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
+
+extern int *pNumworldlights;
+extern dworldlight_t *dworldlights;
+
+extern Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
+extern int g_nClipPortalVerts;
+
+extern dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
+extern int g_nCubemapSamples;
+
+extern int g_nOverlayCount;
+extern doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
+extern doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS]; // Parallel array of fade info in a separate lump to avoid breaking backwards compat
+
+extern int g_nWaterOverlayCount;
+extern dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
+
+extern CUtlVector<char> g_TexDataStringData;
+extern CUtlVector<int> g_TexDataStringTable;
+
+extern int numleafwaterdata;
+extern dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
+
+extern CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
+
+extern CUtlVector<doccluderdata_t> g_OccluderData;
+extern CUtlVector<doccluderpolydata_t> g_OccluderPolyData;
+extern CUtlVector<int> g_OccluderVertexIndices;
+
+// level flags - see LVLFLAGS_xxx in bspfile.h
+extern uint32 g_LevelFlags;
+
+// physics collision data
+extern byte *g_pPhysCollide;
+extern int g_PhysCollideSize;
+extern byte *g_pPhysDisp;
+extern int g_PhysDispSize;
+
+// Embedded pack/pak file
+IZip *GetPakFile( void );
+IZip *GetSwapPakFile( void );
+void ClearPakFile( IZip *pak );
+void AddFileToPak( IZip *pak, const char *pRelativeName, const char *fullpath );
+void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode );
+bool FileExistsInPak( IZip *pak, const char *pRelativeName );
+bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf );
+void RemoveFileFromPak( IZip *pak, const char *pRelativeName );
+int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize );
+void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize );
+
+typedef bool (*CompressFunc_t)( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer );
+typedef bool (*VTFConvertFunc_t)( const char *pDebugName, CUtlBuffer &sourceBuf, CUtlBuffer &targetBuf, CompressFunc_t pCompressFunc );
+typedef bool (*VHVFixupFunc_t)( const char *pVhvFilename, const char *pModelName, CUtlBuffer &sourceBuf, CUtlBuffer &targetBuf );
+
+//-----------------------------------------------------------------------------
+// Game lump memory storage
+//-----------------------------------------------------------------------------
+// NOTE: This is not optimal at all; since I expect client lumps to
+// not be accessed all that often.
+
+struct GameLump_t
+{
+ GameLumpId_t m_Id;
+ unsigned short m_Flags;
+ unsigned short m_Version;
+ CUtlMemory< unsigned char > m_Memory;
+};
+
+//-----------------------------------------------------------------------------
+// Handle to a game lump
+//-----------------------------------------------------------------------------
+typedef unsigned short GameLumpHandle_t;
+
+class CGameLump
+{
+public:
+ //-----------------------------------------------------------------------------
+ // Convert four-CC code to a handle + back
+ //-----------------------------------------------------------------------------
+ GameLumpHandle_t GetGameLumpHandle( GameLumpId_t id );
+ GameLumpId_t GetGameLumpId( GameLumpHandle_t handle );
+ int GetGameLumpFlags( GameLumpHandle_t handle );
+ int GetGameLumpVersion( GameLumpHandle_t handle );
+ void ComputeGameLumpSizeAndCount( int& size, int& clumpCount );
+ void ParseGameLump( dheader_t* pHeader );
+ void SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int size );
+
+
+ //-----------------------------------------------------------------------------
+ // Game lump accessor methods
+ //-----------------------------------------------------------------------------
+ void* GetGameLump( GameLumpHandle_t handle );
+ int GameLumpSize( GameLumpHandle_t handle );
+
+
+ //-----------------------------------------------------------------------------
+ // Game lump iteration methods
+ //-----------------------------------------------------------------------------
+ GameLumpHandle_t FirstGameLump();
+ GameLumpHandle_t NextGameLump( GameLumpHandle_t handle );
+ GameLumpHandle_t InvalidGameLump();
+
+
+ //-----------------------------------------------------------------------------
+ // Game lump creation/destruction method
+ //-----------------------------------------------------------------------------
+ GameLumpHandle_t CreateGameLump( GameLumpId_t id, int size, int flags, int version );
+ void DestroyGameLump( GameLumpHandle_t handle );
+ void DestroyAllGameLumps();
+
+private:
+ CUtlLinkedList< GameLump_t, GameLumpHandle_t > m_GameLumps;
+};
+
+extern CGameLump g_GameLumps;
+extern CByteswap g_Swap;
+
+//-----------------------------------------------------------------------------
+// Helper for the bspzip tool
+//-----------------------------------------------------------------------------
+void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName );
+
+
+//-----------------------------------------------------------------------------
+// String table methods
+//-----------------------------------------------------------------------------
+const char * TexDataStringTable_GetString( int stringID );
+int TexDataStringTable_AddOrFindString( const char *pString );
+
+void DecompressVis (byte *in, byte *decompressed);
+int CompressVis (byte *vis, byte *dest);
+
+void OpenBSPFile( const char *filename );
+void CloseBSPFile(void);
+void LoadBSPFile( const char *filename );
+void LoadBSPFile_FileSystemOnly( const char *filename );
+void LoadBSPFileTexinfo( const char *filename );
+void WriteBSPFile( const char *filename, char *pUnused = NULL );
+void PrintBSPFileSizes(void);
+void PrintBSPPackDirectory(void);
+void ReleasePakFileLumps(void);
+bool SwapBSPFile( const char *filename, const char *swapFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc );
+bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize );
+bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize );
+void WriteLumpToFile( char *filename, int lump );
+void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen );
+bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList );
+void UnloadBSPFile();
+
+void ParseEntities (void);
+void UnparseEntities (void);
+void PrintEntity (entity_t *ent);
+
+void SetKeyValue (entity_t *ent, const char *key, const char *value);
+char *ValueForKey (entity_t *ent, char *key);
+// will return "" if not present
+int IntForKey (entity_t *ent, char *key);
+int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault );
+vec_t FloatForKey (entity_t *ent, char *key);
+vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value);
+void GetVectorForKey (entity_t *ent, char *key, Vector& vec);
+void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec);
+void GetAnglesForKey (entity_t *ent, char *key, QAngle& vec);
+epair_t *ParseEpair (void);
+void StripTrailing (char *e);
+
+// Build a list of the face's vertices (index into dvertexes).
+// points must be able to hold pFace->numedges indices.
+void BuildFaceCalcWindingData( dface_t *pFace, int *points );
+
+// Convert a tristrip to a trilist.
+// Removes degenerates.
+// Fills in pTriListIndices and pnTriListIndices.
+// You must free pTriListIndices with delete[].
+void TriStripToTriList(
+ unsigned short const *pTriStripIndices,
+ int nTriStripIndices,
+ unsigned short **pTriListIndices,
+ int *pnTriListIndices );
+
+// Calculates the lightmap coordinates at a given set of positions given the
+// lightmap basis information.
+void CalcTextureCoordsAtPoints(
+ float const texelsPerWorldUnits[2][4],
+ int const subtractOffset[2],
+ Vector const *pPoints,
+ int const nPoints,
+ Vector2D *pCoords );
+
+// Figure out lightmap extents on all (lit) faces.
+void UpdateAllFaceLightmapExtents();
+
+
+//-----------------------------------------------------------------------------
+// Gets at an interface for the tree for enumeration of leaves in volumes.
+//-----------------------------------------------------------------------------
+ISpatialQuery* ToolBSPTree();
+
+class IBSPNodeEnumerator
+{
+public:
+ // call back with a node and a context
+ virtual bool EnumerateNode( int node, Ray_t const& ray, float f, int context ) = 0;
+
+ // call back with a leaf and a context
+ virtual bool EnumerateLeaf( int leaf, Ray_t const& ray, float start, float end, int context ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Enumerates nodes + leafs in front to back order...
+//-----------------------------------------------------------------------------
+bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context );
+
+
+//-----------------------------------------------------------------------------
+// Helps us find all leaves associated with a particular cluster
+//-----------------------------------------------------------------------------
+struct clusterlist_t
+{
+ int leafCount;
+ CUtlVector<int> leafs;
+};
+
+extern CUtlVector<clusterlist_t> g_ClusterLeaves;
+
+// Call this to build the mapping from cluster to leaves
+void BuildClusterTable( );
+
+void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int dxlevel, int maxLength );
+
+void SetHDRMode( bool bHDR );
+
+// ----------------------------------------------------------------------------- //
+// Helper accessors for the various structures.
+// ----------------------------------------------------------------------------- //
+
+inline ColorRGBExp32* dface_AvgLightColor( dface_t *pFace, int nLightStyleIndex )
+{
+ return (ColorRGBExp32*)&(*pdlightdata)[pFace->lightofs - (nLightStyleIndex+1) * 4];
+}
+
+inline const char* TexInfo_TexName( int iTexInfo )
+{
+ return TexDataStringTable_GetString( dtexdata[texinfo[iTexInfo].texdata].nameStringTableID );
+}
+
+
+#endif // BSPLIB_H
diff --git a/mp/src/utils/common/cmdlib.cpp b/mp/src/utils/common/cmdlib.cpp
index a6962380..a5f9b747 100644
--- a/mp/src/utils/common/cmdlib.cpp
+++ b/mp/src/utils/common/cmdlib.cpp
@@ -1,1007 +1,1007 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-// -----------------------
-// cmdlib.c
-// -----------------------
-#include "tier0/platform.h"
-#ifdef IS_WINDOWS_PC
-#include <windows.h>
-#endif
-#include "cmdlib.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "tier1/strtools.h"
-#ifdef _WIN32
-#include <conio.h>
-#endif
-#include "utlvector.h"
-#include "filesystem_helpers.h"
-#include "utllinkedlist.h"
-#include "tier0/icommandline.h"
-#include "KeyValues.h"
-#include "filesystem_tools.h"
-
-#if defined( MPI )
-
- #include "vmpi.h"
- #include "vmpi_tools_shared.h"
-
-#endif
-
-
-#if defined( _WIN32 ) || defined( WIN32 )
-#include <direct.h>
-#endif
-
-#if defined( _X360 )
-#include "xbox/xbox_win32stubs.h"
-#endif
-
-// set these before calling CheckParm
-int myargc;
-char **myargv;
-
-char com_token[1024];
-
-qboolean archive;
-char archivedir[1024];
-
-FileHandle_t g_pLogFile = 0;
-
-CUtlLinkedList<CleanupFn, unsigned short> g_CleanupFunctions;
-CUtlLinkedList<SpewHookFn, unsigned short> 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<char> buf;
- if ( buf.Count() == 0 )
- buf.SetCount( 1024 );
-
- va_list marker;
- va_start( marker, pFormat );
-
- while ( 1 )
- {
- int ret = Q_vsnprintf( buf.Base(), buf.Count(), pFormat, marker );
- if ( ret >= 0 )
- {
- // Write the string.
- g_pFileSystem->Write( buf.Base(), ret, hFile );
-
- break;
- }
- else
- {
- // Make the buffer larger.
- int newSize = buf.Count() * 2;
- buf.SetCount( newSize );
- if ( buf.Count() != newSize )
- {
- Error( "CmdLib_FPrintf: can't allocate space for text." );
- }
- }
- }
-
- va_end( marker );
-}
-
-char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile )
-{
- int iCur=0;
- for ( ; iCur < (outSize-1); iCur++ )
- {
- char c;
- if ( !g_pFileSystem->Read( &c, 1, hFile ) )
- {
- if ( iCur == 0 )
- return NULL;
- else
- break;
- }
-
- pOut[iCur] = c;
- if ( c == '\n' )
- break;
-
- if ( c == EOF )
- {
- if ( iCur == 0 )
- return NULL;
- else
- break;
- }
- }
-
- pOut[iCur] = 0;
- return pOut;
-}
-
-#if !defined( _X360 )
-#include <wincon.h>
-#endif
-
-// This pauses before exiting if they use -StopOnExit. Useful for debugging.
-class CExitStopper
-{
-public:
- ~CExitStopper()
- {
- if ( g_bStopOnExit )
- {
- Warning( "\nPress any key to quit.\n" );
- getch();
- }
- }
-} g_ExitStopper;
-
-
-static unsigned short g_InitialColor = 0xFFFF;
-static unsigned short g_LastColor = 0xFFFF;
-static unsigned short g_BadColor = 0xFFFF;
-static WORD g_BackgroundFlags = 0xFFFF;
-static void GetInitialColors( )
-{
-#if !defined( _X360 )
- // Get the old background attributes.
- CONSOLE_SCREEN_BUFFER_INFO oldInfo;
- GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo );
- g_InitialColor = g_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
- g_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY);
-
- g_BadColor = 0;
- if (g_BackgroundFlags & BACKGROUND_RED)
- g_BadColor |= FOREGROUND_RED;
- if (g_BackgroundFlags & BACKGROUND_GREEN)
- g_BadColor |= FOREGROUND_GREEN;
- if (g_BackgroundFlags & BACKGROUND_BLUE)
- g_BadColor |= FOREGROUND_BLUE;
- if (g_BackgroundFlags & BACKGROUND_INTENSITY)
- g_BadColor |= FOREGROUND_INTENSITY;
-#endif
-}
-
-WORD SetConsoleTextColor( int red, int green, int blue, int intensity )
-{
- WORD ret = g_LastColor;
-#if !defined( _X360 )
-
- g_LastColor = 0;
- if( red ) g_LastColor |= FOREGROUND_RED;
- if( green ) g_LastColor |= FOREGROUND_GREEN;
- if( blue ) g_LastColor |= FOREGROUND_BLUE;
- if( intensity ) g_LastColor |= FOREGROUND_INTENSITY;
-
- // Just use the initial color if there's a match...
- if (g_LastColor == g_BadColor)
- g_LastColor = g_InitialColor;
-
- SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags );
-#endif
- return ret;
-}
-
-void RestoreConsoleTextColor( WORD color )
-{
-#if !defined( _X360 )
- SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags );
- g_LastColor = color;
-#endif
-}
-
-
-#if defined( CMDLIB_NODBGLIB )
-
-// This can go away when everything is in bin.
-void Error( char const *pMsg, ... )
-{
- va_list marker;
- va_start( marker, pMsg );
- vprintf( pMsg, marker );
- va_end( marker );
-
- exit( -1 );
-}
-
-#else
-
-CRITICAL_SECTION g_SpewCS;
-bool g_bSpewCSInitted = false;
-bool g_bSuppressPrintfOutput = false;
-
-SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg )
-{
- // Hopefully two threads won't call this simultaneously right at the start!
- if ( !g_bSpewCSInitted )
- {
- InitializeCriticalSection( &g_SpewCS );
- g_bSpewCSInitted = true;
- }
-
- WORD old;
- SpewRetval_t retVal;
-
- EnterCriticalSection( &g_SpewCS );
- {
- if (( type == SPEW_MESSAGE ) || (type == SPEW_LOG ))
- {
- Color c = *GetSpewOutputColor();
- if ( c.r() != 255 || c.g() != 255 || c.b() != 255 )
- {
- // custom color
- old = SetConsoleTextColor( c.r(), c.g(), c.b(), c.a() );
- }
- else
- {
- old = SetConsoleTextColor( 1, 1, 1, 0 );
- }
- retVal = SPEW_CONTINUE;
- }
- else if( type == SPEW_WARNING )
- {
- old = SetConsoleTextColor( 1, 1, 0, 1 );
- retVal = SPEW_CONTINUE;
- }
- else if( type == SPEW_ASSERT )
- {
- old = SetConsoleTextColor( 1, 0, 0, 1 );
- retVal = SPEW_DEBUGGER;
-
-#ifdef MPI
- // VMPI workers don't want to bring up dialogs and suchlike.
- // They need to have a special function installed to handle
- // the exceptions and write the minidumps.
- // Install the function after VMPI_Init with a call:
- // SetupToolsMinidumpHandler( VMPI_ExceptionFilter );
- if ( g_bUseMPI && !g_bMPIMaster && !Plat_IsInDebugSession() )
- {
- // Generating an exception and letting the
- // installed handler handle it
- ::RaiseException
- (
- 0, // dwExceptionCode
- EXCEPTION_NONCONTINUABLE, // dwExceptionFlags
- 0, // nNumberOfArguments,
- NULL // const ULONG_PTR* lpArguments
- );
-
- // Never get here (non-continuable exception)
-
- VMPI_HandleCrash( pMsg, NULL, true );
- exit( 0 );
- }
-#endif
- }
- else if( type == SPEW_ERROR )
- {
- old = SetConsoleTextColor( 1, 0, 0, 1 );
- retVal = SPEW_ABORT; // doesn't matter.. we exit below so we can return an errorlevel (which dbg.dll doesn't do).
- }
- else
- {
- old = SetConsoleTextColor( 1, 1, 1, 1 );
- retVal = SPEW_CONTINUE;
- }
-
- if ( !g_bSuppressPrintfOutput || type == SPEW_ERROR )
- printf( "%s", pMsg );
-
- OutputDebugString( pMsg );
-
- if ( type == SPEW_ERROR )
- {
- printf( "\n" );
- OutputDebugString( "\n" );
- }
-
- if( g_pLogFile )
- {
- CmdLib_FPrintf( g_pLogFile, "%s", pMsg );
- g_pFileSystem->Flush( g_pLogFile );
- }
-
- // Dispatch to other spew hooks.
- FOR_EACH_LL( g_ExtraSpewHooks, i )
- g_ExtraSpewHooks[i]( pMsg );
-
- RestoreConsoleTextColor( old );
- }
- LeaveCriticalSection( &g_SpewCS );
-
- if ( type == SPEW_ERROR )
- {
- CmdLib_Exit( 1 );
- }
-
- return retVal;
-}
-
-
-void InstallSpewFunction()
-{
- setvbuf( stdout, NULL, _IONBF, 0 );
- setvbuf( stderr, NULL, _IONBF, 0 );
-
- SpewOutputFunc( CmdLib_SpewOutputFunc );
- GetInitialColors();
-}
-
-
-void InstallExtraSpewHook( SpewHookFn pFn )
-{
- g_ExtraSpewHooks.AddToTail( pFn );
-}
-
-#if 0
-void CmdLib_AllocError( unsigned long size )
-{
- Error( "Error trying to allocate %d bytes.\n", size );
-}
-
-
-int CmdLib_NewHandler( size_t size )
-{
- CmdLib_AllocError( size );
- return 0;
-}
-#endif
-
-void InstallAllocationFunctions()
-{
-// _set_new_mode( 1 ); // so if malloc() fails, we exit.
-// _set_new_handler( CmdLib_NewHandler );
-}
-
-void SetSpewFunctionLogFile( char const *pFilename )
-{
- Assert( (!g_pLogFile) );
- g_pLogFile = g_pFileSystem->Open( pFilename, "a" );
-
- Assert( g_pLogFile );
- if (!g_pLogFile)
- Error("Can't create LogFile:\"%s\"\n", pFilename );
-
- CmdLib_FPrintf( g_pLogFile, "\n\n\n" );
-}
-
-
-void CloseSpewFunctionLogFile()
-{
- if ( g_pFileSystem && g_pLogFile )
- {
- g_pFileSystem->Close( g_pLogFile );
- g_pLogFile = FILESYSTEM_INVALID_HANDLE;
- }
-}
-
-
-void CmdLib_AtCleanup( CleanupFn pFn )
-{
- g_CleanupFunctions.AddToTail( pFn );
-}
-
-
-void CmdLib_Cleanup()
-{
- CloseSpewFunctionLogFile();
-
- CmdLib_TermFileSystem();
-
- FOR_EACH_LL( g_CleanupFunctions, i )
- g_CleanupFunctions[i]();
-
-#if defined( MPI )
- // Unfortunately, when you call exit(), even if you have things registered with atexit(),
- // threads go into a seemingly undefined state where GetExitCodeThread gives STILL_ACTIVE
- // and WaitForSingleObject will stall forever on the thread. Because of this, we must cleanup
- // everything that uses threads before exiting.
- VMPI_Finalize();
-#endif
-}
-
-
-void CmdLib_Exit( int exitCode )
-{
- TerminateProcess( GetCurrentProcess(), 1 );
-}
-
-
-
-#endif
-
-#endif
-
-
-
-
-/*
-===================
-ExpandWildcards
-
-Mimic unix command line expansion
-===================
-*/
-#define MAX_EX_ARGC 1024
-int ex_argc;
-char *ex_argv[MAX_EX_ARGC];
-#if defined( _WIN32 ) && !defined( _X360 )
-#include "io.h"
-void ExpandWildcards (int *argc, char ***argv)
-{
- struct _finddata_t fileinfo;
- int handle;
- int i;
- char filename[1024];
- char filebase[1024];
- char *path;
-
- ex_argc = 0;
- for (i=0 ; i<*argc ; i++)
- {
- path = (*argv)[i];
- if ( path[0] == '-'
- || ( !strstr(path, "*") && !strstr(path, "?") ) )
- {
- ex_argv[ex_argc++] = path;
- continue;
- }
-
- handle = _findfirst (path, &fileinfo);
- if (handle == -1)
- return;
-
- Q_ExtractFilePath (path, filebase, sizeof( filebase ));
-
- do
- {
- sprintf (filename, "%s%s", filebase, fileinfo.name);
- ex_argv[ex_argc++] = copystring (filename);
- } while (_findnext( handle, &fileinfo ) != -1);
-
- _findclose (handle);
- }
-
- *argc = ex_argc;
- *argv = ex_argv;
-}
-#else
-void ExpandWildcards (int *argc, char ***argv)
-{
-}
-#endif
-
-
-// only printf if in verbose mode
-qboolean verbose = false;
-void qprintf (const char *format, ...)
-{
- if (!verbose)
- return;
-
- va_list argptr;
- va_start (argptr,format);
-
- char str[2048];
- Q_vsnprintf( str, sizeof(str), format, argptr );
-
-#if defined( CMDLIB_NODBGLIB )
- printf( "%s", str );
-#else
- Msg( "%s", str );
-#endif
-
- va_end (argptr);
-}
-
-
-// ---------------------------------------------------------------------------------------------------- //
-// Helpers.
-// ---------------------------------------------------------------------------------------------------- //
-
-static void CmdLib_getwd( char *out, int outSize )
-{
-#if defined( _WIN32 ) || defined( WIN32 )
- _getcwd( out, outSize );
- Q_strncat( out, "\\", outSize, COPY_ALL_CHARACTERS );
-#else
- getcwd(out, outSize);
- strcat(out, "/");
-#endif
- Q_FixSlashes( out );
-}
-
-char *ExpandArg (char *path)
-{
- static char full[1024];
-
- if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
- {
- CmdLib_getwd (full, sizeof( full ));
- Q_strncat (full, path, sizeof( full ), COPY_ALL_CHARACTERS);
- }
- else
- Q_strncpy (full, path, sizeof( full ));
- return full;
-}
-
-
-char *ExpandPath (char *path)
-{
- static char full[1024];
- if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
- return path;
- sprintf (full, "%s%s", qdir, path);
- return full;
-}
-
-
-
-char *copystring(const char *s)
-{
- char *b;
- b = (char *)malloc(strlen(s)+1);
- strcpy (b, s);
- return b;
-}
-
-
-void GetHourMinuteSeconds( int nInputSeconds, int &nHours, int &nMinutes, int &nSeconds )
-{
-}
-
-
-void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen )
-{
- int nMinutes = nInputSeconds / 60;
- int nSeconds = nInputSeconds - nMinutes * 60;
- int nHours = nMinutes / 60;
- nMinutes -= nHours * 60;
-
- const char *extra[2] = { "", "s" };
-
- if ( nHours > 0 )
- Q_snprintf( pOut, outLen, "%d hour%s, %d minute%s, %d second%s", nHours, extra[nHours != 1], nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] );
- else if ( nMinutes > 0 )
- Q_snprintf( pOut, outLen, "%d minute%s, %d second%s", nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] );
- else
- Q_snprintf( pOut, outLen, "%d second%s", nSeconds, extra[nSeconds != 1] );
-}
-
-
-void Q_mkdir (char *path)
-{
-#if defined( _WIN32 ) || defined( WIN32 )
- if (_mkdir (path) != -1)
- return;
-#else
- if (mkdir (path, 0777) != -1)
- return;
-#endif
-// if (errno != EEXIST)
- Error ("mkdir failed %s\n", path );
-}
-
-void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage )
-{
- FileSystem_Init( pFilename, maxMemoryUsage );
- if ( !g_pFileSystem )
- Error( "CmdLib_InitFileSystem failed." );
-}
-
-void CmdLib_TermFileSystem()
-{
- FileSystem_Term();
-}
-
-CreateInterfaceFn CmdLib_GetFileSystemFactory()
-{
- return FileSystem_GetFactory();
-}
-
-
-/*
-============
-FileTime
-
-returns -1 if not present
-============
-*/
-int FileTime (char *path)
-{
- struct stat buf;
-
- if (stat (path,&buf) == -1)
- return -1;
-
- return buf.st_mtime;
-}
-
-
-
-/*
-==============
-COM_Parse
-
-Parse a token out of a string
-==============
-*/
-char *COM_Parse (char *data)
-{
- return (char*)ParseFile( data, com_token, NULL );
-}
-
-
-/*
-=============================================================================
-
- MISC FUNCTIONS
-
-=============================================================================
-*/
-
-
-/*
-=================
-CheckParm
-
-Checks for the given parameter in the program's command line arguments
-Returns the argument number (1 to argc-1) or 0 if not present
-=================
-*/
-int CheckParm (char *check)
-{
- int i;
-
- for (i = 1;i<myargc;i++)
- {
- if ( !Q_strcasecmp(check, myargv[i]) )
- return i;
- }
-
- return 0;
-}
-
-
-
-/*
-================
-Q_filelength
-================
-*/
-int Q_filelength (FileHandle_t f)
-{
- return g_pFileSystem->Size( f );
-}
-
-
-FileHandle_t SafeOpenWrite ( const char *filename )
-{
- FileHandle_t f = g_pFileSystem->Open(filename, "wb");
-
- if (!f)
- {
- //Error ("Error opening %s: %s",filename,strerror(errno));
- // BUGBUG: No way to get equivalent of errno from IFileSystem!
- Error ("Error opening %s! (Check for write enable)\n",filename);
- }
-
- return f;
-}
-
-#define MAX_CMDLIB_BASE_PATHS 10
-static char g_pBasePaths[MAX_CMDLIB_BASE_PATHS][MAX_PATH];
-static int g_NumBasePaths = 0;
-
-void CmdLib_AddBasePath( const char *pPath )
-{
-// printf( "CmdLib_AddBasePath( \"%s\" )\n", pPath );
- if( g_NumBasePaths < MAX_CMDLIB_BASE_PATHS )
- {
- Q_strncpy( g_pBasePaths[g_NumBasePaths], pPath, MAX_PATH );
- Q_FixSlashes( g_pBasePaths[g_NumBasePaths] );
- g_NumBasePaths++;
- }
- else
- {
- Assert( 0 );
- }
-}
-
-bool CmdLib_HasBasePath( const char *pFileName_, int &pathLength )
-{
- char *pFileName = ( char * )_alloca( strlen( pFileName_ ) + 1 );
- strcpy( pFileName, pFileName_ );
- Q_FixSlashes( pFileName );
- pathLength = 0;
- int i;
- for( i = 0; i < g_NumBasePaths; i++ )
- {
- // see if we can rip the base off of the filename.
- if( Q_strncasecmp( g_pBasePaths[i], pFileName, strlen( g_pBasePaths[i] ) ) == 0 )
- {
- pathLength = strlen( g_pBasePaths[i] );
- return true;
- }
- }
- return false;
-}
-
-int CmdLib_GetNumBasePaths( void )
-{
- return g_NumBasePaths;
-}
-
-const char *CmdLib_GetBasePath( int i )
-{
- Assert( i >= 0 && i < g_NumBasePaths );
- return g_pBasePaths[i];
-}
-
-
-//-----------------------------------------------------------------------------
-// Like ExpandPath but expands the path for each base path like SafeOpenRead
-//-----------------------------------------------------------------------------
-int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath )
-{
- int nPathLength = 0;
-
- pszPath = ExpandPath( const_cast< char * >( pszPath ) ); // Kind of redundant but it's how CmdLib_HasBasePath needs things
-
- if ( CmdLib_HasBasePath( pszPath, nPathLength ) )
- {
- pszPath = pszPath + nPathLength;
- for ( int i = 0; i < CmdLib_GetNumBasePaths(); ++i )
- {
- CUtlString &expandedPath = expandedPathList[ expandedPathList.AddToTail( CmdLib_GetBasePath( i ) ) ];
- expandedPath += pszPath;
- }
- }
- else
- {
- expandedPathList.AddToTail( pszPath );
- }
-
- return expandedPathList.Count();
-}
-
-
-FileHandle_t SafeOpenRead( const char *filename )
-{
- int pathLength;
- FileHandle_t f = 0;
- if( CmdLib_HasBasePath( filename, pathLength ) )
- {
- filename = filename + pathLength;
- int i;
- for( i = 0; i < g_NumBasePaths; i++ )
- {
- char tmp[MAX_PATH];
- strcpy( tmp, g_pBasePaths[i] );
- strcat( tmp, filename );
- f = g_pFileSystem->Open( tmp, "rb" );
- if( f )
- {
- return f;
- }
- }
- Error ("Error opening %s\n",filename );
- return f;
- }
- else
- {
- f = g_pFileSystem->Open( filename, "rb" );
- if ( !f )
- Error ("Error opening %s",filename );
-
- return f;
- }
-}
-
-void SafeRead( FileHandle_t f, void *buffer, int count)
-{
- if ( g_pFileSystem->Read (buffer, count, f) != (size_t)count)
- Error ("File read failure");
-}
-
-
-void SafeWrite ( FileHandle_t f, void *buffer, int count)
-{
- if (g_pFileSystem->Write (buffer, count, f) != (size_t)count)
- Error ("File write failure");
-}
-
-
-/*
-==============
-FileExists
-==============
-*/
-qboolean FileExists ( const char *filename )
-{
- FileHandle_t hFile = g_pFileSystem->Open( filename, "rb" );
- if ( hFile == FILESYSTEM_INVALID_HANDLE )
- {
- return false;
- }
- else
- {
- g_pFileSystem->Close( hFile );
- return true;
- }
-}
-
-/*
-==============
-LoadFile
-==============
-*/
-int LoadFile ( const char *filename, void **bufferptr )
-{
- int length = 0;
- void *buffer;
-
- FileHandle_t f = SafeOpenRead (filename);
- if ( FILESYSTEM_INVALID_HANDLE != f )
- {
- length = Q_filelength (f);
- buffer = malloc (length+1);
- ((char *)buffer)[length] = 0;
- SafeRead (f, buffer, length);
- g_pFileSystem->Close (f);
- *bufferptr = buffer;
- }
- else
- {
- *bufferptr = NULL;
- }
- return length;
-}
-
-
-
-/*
-==============
-SaveFile
-==============
-*/
-void SaveFile ( const char *filename, void *buffer, int count )
-{
- FileHandle_t f = SafeOpenWrite (filename);
- SafeWrite (f, buffer, count);
- g_pFileSystem->Close (f);
-}
-
-/*
-====================
-Extract file parts
-====================
-*/
-// FIXME: should include the slash, otherwise
-// backing to an empty path will be wrong when appending a slash
-
-
-
-/*
-==============
-ParseNum / ParseHex
-==============
-*/
-int ParseHex (char *hex)
-{
- char *str;
- int num;
-
- num = 0;
- str = hex;
-
- while (*str)
- {
- num <<= 4;
- if (*str >= '0' && *str <= '9')
- num += *str-'0';
- else if (*str >= 'a' && *str <= 'f')
- num += 10 + *str-'a';
- else if (*str >= 'A' && *str <= 'F')
- num += 10 + *str-'A';
- else
- Error ("Bad hex number: %s",hex);
- str++;
- }
-
- return num;
-}
-
-
-int ParseNum (char *str)
-{
- if (str[0] == '$')
- return ParseHex (str+1);
- if (str[0] == '0' && str[1] == 'x')
- return ParseHex (str+2);
- return atol (str);
-}
-
-/*
-============
-CreatePath
-============
-*/
-void CreatePath (char *path)
-{
- char *ofs, c;
-
- // strip the drive
- if (path[1] == ':')
- path += 2;
-
- for (ofs = path+1 ; *ofs ; ofs++)
- {
- c = *ofs;
- if (c == '/' || c == '\\')
- { // create the directory
- *ofs = 0;
- Q_mkdir (path);
- *ofs = c;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Creates a path, path may already exist
-//-----------------------------------------------------------------------------
-#if defined( _WIN32 ) || defined( WIN32 )
-void SafeCreatePath( char *path )
-{
- char *ptr;
-
- // skip past the drive path, but don't strip
- if ( path[1] == ':' )
- {
- ptr = strchr( path, '\\' );
- }
- else
- {
- ptr = path;
- }
- while ( ptr )
- {
- ptr = strchr( ptr+1, '\\' );
- if ( ptr )
- {
- *ptr = '\0';
- _mkdir( path );
- *ptr = '\\';
- }
- }
-}
-#endif
-
-/*
-============
-QCopyFile
-
- Used to archive source files
-============
-*/
-void QCopyFile (char *from, char *to)
-{
- void *buffer;
- int length;
-
- length = LoadFile (from, &buffer);
- CreatePath (to);
- SaveFile (to, buffer, length);
- free (buffer);
-}
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// -----------------------
+// cmdlib.c
+// -----------------------
+#include "tier0/platform.h"
+#ifdef IS_WINDOWS_PC
+#include <windows.h>
+#endif
+#include "cmdlib.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "tier1/strtools.h"
+#ifdef _WIN32
+#include <conio.h>
+#endif
+#include "utlvector.h"
+#include "filesystem_helpers.h"
+#include "utllinkedlist.h"
+#include "tier0/icommandline.h"
+#include "KeyValues.h"
+#include "filesystem_tools.h"
+
+#if defined( MPI )
+
+ #include "vmpi.h"
+ #include "vmpi_tools_shared.h"
+
+#endif
+
+
+#if defined( _WIN32 ) || defined( WIN32 )
+#include <direct.h>
+#endif
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// set these before calling CheckParm
+int myargc;
+char **myargv;
+
+char com_token[1024];
+
+qboolean archive;
+char archivedir[1024];
+
+FileHandle_t g_pLogFile = 0;
+
+CUtlLinkedList<CleanupFn, unsigned short> g_CleanupFunctions;
+CUtlLinkedList<SpewHookFn, unsigned short> 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<char> buf;
+ if ( buf.Count() == 0 )
+ buf.SetCount( 1024 );
+
+ va_list marker;
+ va_start( marker, pFormat );
+
+ while ( 1 )
+ {
+ int ret = Q_vsnprintf( buf.Base(), buf.Count(), pFormat, marker );
+ if ( ret >= 0 )
+ {
+ // Write the string.
+ g_pFileSystem->Write( buf.Base(), ret, hFile );
+
+ break;
+ }
+ else
+ {
+ // Make the buffer larger.
+ int newSize = buf.Count() * 2;
+ buf.SetCount( newSize );
+ if ( buf.Count() != newSize )
+ {
+ Error( "CmdLib_FPrintf: can't allocate space for text." );
+ }
+ }
+ }
+
+ va_end( marker );
+}
+
+char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile )
+{
+ int iCur=0;
+ for ( ; iCur < (outSize-1); iCur++ )
+ {
+ char c;
+ if ( !g_pFileSystem->Read( &c, 1, hFile ) )
+ {
+ if ( iCur == 0 )
+ return NULL;
+ else
+ break;
+ }
+
+ pOut[iCur] = c;
+ if ( c == '\n' )
+ break;
+
+ if ( c == EOF )
+ {
+ if ( iCur == 0 )
+ return NULL;
+ else
+ break;
+ }
+ }
+
+ pOut[iCur] = 0;
+ return pOut;
+}
+
+#if !defined( _X360 )
+#include <wincon.h>
+#endif
+
+// This pauses before exiting if they use -StopOnExit. Useful for debugging.
+class CExitStopper
+{
+public:
+ ~CExitStopper()
+ {
+ if ( g_bStopOnExit )
+ {
+ Warning( "\nPress any key to quit.\n" );
+ getch();
+ }
+ }
+} g_ExitStopper;
+
+
+static unsigned short g_InitialColor = 0xFFFF;
+static unsigned short g_LastColor = 0xFFFF;
+static unsigned short g_BadColor = 0xFFFF;
+static WORD g_BackgroundFlags = 0xFFFF;
+static void GetInitialColors( )
+{
+#if !defined( _X360 )
+ // Get the old background attributes.
+ CONSOLE_SCREEN_BUFFER_INFO oldInfo;
+ GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo );
+ g_InitialColor = g_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
+ g_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY);
+
+ g_BadColor = 0;
+ if (g_BackgroundFlags & BACKGROUND_RED)
+ g_BadColor |= FOREGROUND_RED;
+ if (g_BackgroundFlags & BACKGROUND_GREEN)
+ g_BadColor |= FOREGROUND_GREEN;
+ if (g_BackgroundFlags & BACKGROUND_BLUE)
+ g_BadColor |= FOREGROUND_BLUE;
+ if (g_BackgroundFlags & BACKGROUND_INTENSITY)
+ g_BadColor |= FOREGROUND_INTENSITY;
+#endif
+}
+
+WORD SetConsoleTextColor( int red, int green, int blue, int intensity )
+{
+ WORD ret = g_LastColor;
+#if !defined( _X360 )
+
+ g_LastColor = 0;
+ if( red ) g_LastColor |= FOREGROUND_RED;
+ if( green ) g_LastColor |= FOREGROUND_GREEN;
+ if( blue ) g_LastColor |= FOREGROUND_BLUE;
+ if( intensity ) g_LastColor |= FOREGROUND_INTENSITY;
+
+ // Just use the initial color if there's a match...
+ if (g_LastColor == g_BadColor)
+ g_LastColor = g_InitialColor;
+
+ SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags );
+#endif
+ return ret;
+}
+
+void RestoreConsoleTextColor( WORD color )
+{
+#if !defined( _X360 )
+ SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags );
+ g_LastColor = color;
+#endif
+}
+
+
+#if defined( CMDLIB_NODBGLIB )
+
+// This can go away when everything is in bin.
+void Error( char const *pMsg, ... )
+{
+ va_list marker;
+ va_start( marker, pMsg );
+ vprintf( pMsg, marker );
+ va_end( marker );
+
+ exit( -1 );
+}
+
+#else
+
+CRITICAL_SECTION g_SpewCS;
+bool g_bSpewCSInitted = false;
+bool g_bSuppressPrintfOutput = false;
+
+SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg )
+{
+ // Hopefully two threads won't call this simultaneously right at the start!
+ if ( !g_bSpewCSInitted )
+ {
+ InitializeCriticalSection( &g_SpewCS );
+ g_bSpewCSInitted = true;
+ }
+
+ WORD old;
+ SpewRetval_t retVal;
+
+ EnterCriticalSection( &g_SpewCS );
+ {
+ if (( type == SPEW_MESSAGE ) || (type == SPEW_LOG ))
+ {
+ Color c = *GetSpewOutputColor();
+ if ( c.r() != 255 || c.g() != 255 || c.b() != 255 )
+ {
+ // custom color
+ old = SetConsoleTextColor( c.r(), c.g(), c.b(), c.a() );
+ }
+ else
+ {
+ old = SetConsoleTextColor( 1, 1, 1, 0 );
+ }
+ retVal = SPEW_CONTINUE;
+ }
+ else if( type == SPEW_WARNING )
+ {
+ old = SetConsoleTextColor( 1, 1, 0, 1 );
+ retVal = SPEW_CONTINUE;
+ }
+ else if( type == SPEW_ASSERT )
+ {
+ old = SetConsoleTextColor( 1, 0, 0, 1 );
+ retVal = SPEW_DEBUGGER;
+
+#ifdef MPI
+ // VMPI workers don't want to bring up dialogs and suchlike.
+ // They need to have a special function installed to handle
+ // the exceptions and write the minidumps.
+ // Install the function after VMPI_Init with a call:
+ // SetupToolsMinidumpHandler( VMPI_ExceptionFilter );
+ if ( g_bUseMPI && !g_bMPIMaster && !Plat_IsInDebugSession() )
+ {
+ // Generating an exception and letting the
+ // installed handler handle it
+ ::RaiseException
+ (
+ 0, // dwExceptionCode
+ EXCEPTION_NONCONTINUABLE, // dwExceptionFlags
+ 0, // nNumberOfArguments,
+ NULL // const ULONG_PTR* lpArguments
+ );
+
+ // Never get here (non-continuable exception)
+
+ VMPI_HandleCrash( pMsg, NULL, true );
+ exit( 0 );
+ }
+#endif
+ }
+ else if( type == SPEW_ERROR )
+ {
+ old = SetConsoleTextColor( 1, 0, 0, 1 );
+ retVal = SPEW_ABORT; // doesn't matter.. we exit below so we can return an errorlevel (which dbg.dll doesn't do).
+ }
+ else
+ {
+ old = SetConsoleTextColor( 1, 1, 1, 1 );
+ retVal = SPEW_CONTINUE;
+ }
+
+ if ( !g_bSuppressPrintfOutput || type == SPEW_ERROR )
+ printf( "%s", pMsg );
+
+ OutputDebugString( pMsg );
+
+ if ( type == SPEW_ERROR )
+ {
+ printf( "\n" );
+ OutputDebugString( "\n" );
+ }
+
+ if( g_pLogFile )
+ {
+ CmdLib_FPrintf( g_pLogFile, "%s", pMsg );
+ g_pFileSystem->Flush( g_pLogFile );
+ }
+
+ // Dispatch to other spew hooks.
+ FOR_EACH_LL( g_ExtraSpewHooks, i )
+ g_ExtraSpewHooks[i]( pMsg );
+
+ RestoreConsoleTextColor( old );
+ }
+ LeaveCriticalSection( &g_SpewCS );
+
+ if ( type == SPEW_ERROR )
+ {
+ CmdLib_Exit( 1 );
+ }
+
+ return retVal;
+}
+
+
+void InstallSpewFunction()
+{
+ setvbuf( stdout, NULL, _IONBF, 0 );
+ setvbuf( stderr, NULL, _IONBF, 0 );
+
+ SpewOutputFunc( CmdLib_SpewOutputFunc );
+ GetInitialColors();
+}
+
+
+void InstallExtraSpewHook( SpewHookFn pFn )
+{
+ g_ExtraSpewHooks.AddToTail( pFn );
+}
+
+#if 0
+void CmdLib_AllocError( unsigned long size )
+{
+ Error( "Error trying to allocate %d bytes.\n", size );
+}
+
+
+int CmdLib_NewHandler( size_t size )
+{
+ CmdLib_AllocError( size );
+ return 0;
+}
+#endif
+
+void InstallAllocationFunctions()
+{
+// _set_new_mode( 1 ); // so if malloc() fails, we exit.
+// _set_new_handler( CmdLib_NewHandler );
+}
+
+void SetSpewFunctionLogFile( char const *pFilename )
+{
+ Assert( (!g_pLogFile) );
+ g_pLogFile = g_pFileSystem->Open( pFilename, "a" );
+
+ Assert( g_pLogFile );
+ if (!g_pLogFile)
+ Error("Can't create LogFile:\"%s\"\n", pFilename );
+
+ CmdLib_FPrintf( g_pLogFile, "\n\n\n" );
+}
+
+
+void CloseSpewFunctionLogFile()
+{
+ if ( g_pFileSystem && g_pLogFile )
+ {
+ g_pFileSystem->Close( g_pLogFile );
+ g_pLogFile = FILESYSTEM_INVALID_HANDLE;
+ }
+}
+
+
+void CmdLib_AtCleanup( CleanupFn pFn )
+{
+ g_CleanupFunctions.AddToTail( pFn );
+}
+
+
+void CmdLib_Cleanup()
+{
+ CloseSpewFunctionLogFile();
+
+ CmdLib_TermFileSystem();
+
+ FOR_EACH_LL( g_CleanupFunctions, i )
+ g_CleanupFunctions[i]();
+
+#if defined( MPI )
+ // Unfortunately, when you call exit(), even if you have things registered with atexit(),
+ // threads go into a seemingly undefined state where GetExitCodeThread gives STILL_ACTIVE
+ // and WaitForSingleObject will stall forever on the thread. Because of this, we must cleanup
+ // everything that uses threads before exiting.
+ VMPI_Finalize();
+#endif
+}
+
+
+void CmdLib_Exit( int exitCode )
+{
+ TerminateProcess( GetCurrentProcess(), 1 );
+}
+
+
+
+#endif
+
+#endif
+
+
+
+
+/*
+===================
+ExpandWildcards
+
+Mimic unix command line expansion
+===================
+*/
+#define MAX_EX_ARGC 1024
+int ex_argc;
+char *ex_argv[MAX_EX_ARGC];
+#if defined( _WIN32 ) && !defined( _X360 )
+#include "io.h"
+void ExpandWildcards (int *argc, char ***argv)
+{
+ struct _finddata_t fileinfo;
+ int handle;
+ int i;
+ char filename[1024];
+ char filebase[1024];
+ char *path;
+
+ ex_argc = 0;
+ for (i=0 ; i<*argc ; i++)
+ {
+ path = (*argv)[i];
+ if ( path[0] == '-'
+ || ( !strstr(path, "*") && !strstr(path, "?") ) )
+ {
+ ex_argv[ex_argc++] = path;
+ continue;
+ }
+
+ handle = _findfirst (path, &fileinfo);
+ if (handle == -1)
+ return;
+
+ Q_ExtractFilePath (path, filebase, sizeof( filebase ));
+
+ do
+ {
+ sprintf (filename, "%s%s", filebase, fileinfo.name);
+ ex_argv[ex_argc++] = copystring (filename);
+ } while (_findnext( handle, &fileinfo ) != -1);
+
+ _findclose (handle);
+ }
+
+ *argc = ex_argc;
+ *argv = ex_argv;
+}
+#else
+void ExpandWildcards (int *argc, char ***argv)
+{
+}
+#endif
+
+
+// only printf if in verbose mode
+qboolean verbose = false;
+void qprintf (const char *format, ...)
+{
+ if (!verbose)
+ return;
+
+ va_list argptr;
+ va_start (argptr,format);
+
+ char str[2048];
+ Q_vsnprintf( str, sizeof(str), format, argptr );
+
+#if defined( CMDLIB_NODBGLIB )
+ printf( "%s", str );
+#else
+ Msg( "%s", str );
+#endif
+
+ va_end (argptr);
+}
+
+
+// ---------------------------------------------------------------------------------------------------- //
+// Helpers.
+// ---------------------------------------------------------------------------------------------------- //
+
+static void CmdLib_getwd( char *out, int outSize )
+{
+#if defined( _WIN32 ) || defined( WIN32 )
+ _getcwd( out, outSize );
+ Q_strncat( out, "\\", outSize, COPY_ALL_CHARACTERS );
+#else
+ getcwd(out, outSize);
+ strcat(out, "/");
+#endif
+ Q_FixSlashes( out );
+}
+
+char *ExpandArg (char *path)
+{
+ static char full[1024];
+
+ if (path[0] != '/' && path[0] != '\\' && path[1] != ':')
+ {
+ CmdLib_getwd (full, sizeof( full ));
+ Q_strncat (full, path, sizeof( full ), COPY_ALL_CHARACTERS);
+ }
+ else
+ Q_strncpy (full, path, sizeof( full ));
+ return full;
+}
+
+
+char *ExpandPath (char *path)
+{
+ static char full[1024];
+ if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
+ return path;
+ sprintf (full, "%s%s", qdir, path);
+ return full;
+}
+
+
+
+char *copystring(const char *s)
+{
+ char *b;
+ b = (char *)malloc(strlen(s)+1);
+ strcpy (b, s);
+ return b;
+}
+
+
+void GetHourMinuteSeconds( int nInputSeconds, int &nHours, int &nMinutes, int &nSeconds )
+{
+}
+
+
+void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen )
+{
+ int nMinutes = nInputSeconds / 60;
+ int nSeconds = nInputSeconds - nMinutes * 60;
+ int nHours = nMinutes / 60;
+ nMinutes -= nHours * 60;
+
+ const char *extra[2] = { "", "s" };
+
+ if ( nHours > 0 )
+ Q_snprintf( pOut, outLen, "%d hour%s, %d minute%s, %d second%s", nHours, extra[nHours != 1], nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] );
+ else if ( nMinutes > 0 )
+ Q_snprintf( pOut, outLen, "%d minute%s, %d second%s", nMinutes, extra[nMinutes != 1], nSeconds, extra[nSeconds != 1] );
+ else
+ Q_snprintf( pOut, outLen, "%d second%s", nSeconds, extra[nSeconds != 1] );
+}
+
+
+void Q_mkdir (char *path)
+{
+#if defined( _WIN32 ) || defined( WIN32 )
+ if (_mkdir (path) != -1)
+ return;
+#else
+ if (mkdir (path, 0777) != -1)
+ return;
+#endif
+// if (errno != EEXIST)
+ Error ("mkdir failed %s\n", path );
+}
+
+void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage )
+{
+ FileSystem_Init( pFilename, maxMemoryUsage );
+ if ( !g_pFileSystem )
+ Error( "CmdLib_InitFileSystem failed." );
+}
+
+void CmdLib_TermFileSystem()
+{
+ FileSystem_Term();
+}
+
+CreateInterfaceFn CmdLib_GetFileSystemFactory()
+{
+ return FileSystem_GetFactory();
+}
+
+
+/*
+============
+FileTime
+
+returns -1 if not present
+============
+*/
+int FileTime (char *path)
+{
+ struct stat buf;
+
+ if (stat (path,&buf) == -1)
+ return -1;
+
+ return buf.st_mtime;
+}
+
+
+
+/*
+==============
+COM_Parse
+
+Parse a token out of a string
+==============
+*/
+char *COM_Parse (char *data)
+{
+ return (char*)ParseFile( data, com_token, NULL );
+}
+
+
+/*
+=============================================================================
+
+ MISC FUNCTIONS
+
+=============================================================================
+*/
+
+
+/*
+=================
+CheckParm
+
+Checks for the given parameter in the program's command line arguments
+Returns the argument number (1 to argc-1) or 0 if not present
+=================
+*/
+int CheckParm (char *check)
+{
+ int i;
+
+ for (i = 1;i<myargc;i++)
+ {
+ if ( !Q_strcasecmp(check, myargv[i]) )
+ return i;
+ }
+
+ return 0;
+}
+
+
+
+/*
+================
+Q_filelength
+================
+*/
+int Q_filelength (FileHandle_t f)
+{
+ return g_pFileSystem->Size( f );
+}
+
+
+FileHandle_t SafeOpenWrite ( const char *filename )
+{
+ FileHandle_t f = g_pFileSystem->Open(filename, "wb");
+
+ if (!f)
+ {
+ //Error ("Error opening %s: %s",filename,strerror(errno));
+ // BUGBUG: No way to get equivalent of errno from IFileSystem!
+ Error ("Error opening %s! (Check for write enable)\n",filename);
+ }
+
+ return f;
+}
+
+#define MAX_CMDLIB_BASE_PATHS 10
+static char g_pBasePaths[MAX_CMDLIB_BASE_PATHS][MAX_PATH];
+static int g_NumBasePaths = 0;
+
+void CmdLib_AddBasePath( const char *pPath )
+{
+// printf( "CmdLib_AddBasePath( \"%s\" )\n", pPath );
+ if( g_NumBasePaths < MAX_CMDLIB_BASE_PATHS )
+ {
+ Q_strncpy( g_pBasePaths[g_NumBasePaths], pPath, MAX_PATH );
+ Q_FixSlashes( g_pBasePaths[g_NumBasePaths] );
+ g_NumBasePaths++;
+ }
+ else
+ {
+ Assert( 0 );
+ }
+}
+
+bool CmdLib_HasBasePath( const char *pFileName_, int &pathLength )
+{
+ char *pFileName = ( char * )_alloca( strlen( pFileName_ ) + 1 );
+ strcpy( pFileName, pFileName_ );
+ Q_FixSlashes( pFileName );
+ pathLength = 0;
+ int i;
+ for( i = 0; i < g_NumBasePaths; i++ )
+ {
+ // see if we can rip the base off of the filename.
+ if( Q_strncasecmp( g_pBasePaths[i], pFileName, strlen( g_pBasePaths[i] ) ) == 0 )
+ {
+ pathLength = strlen( g_pBasePaths[i] );
+ return true;
+ }
+ }
+ return false;
+}
+
+int CmdLib_GetNumBasePaths( void )
+{
+ return g_NumBasePaths;
+}
+
+const char *CmdLib_GetBasePath( int i )
+{
+ Assert( i >= 0 && i < g_NumBasePaths );
+ return g_pBasePaths[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Like ExpandPath but expands the path for each base path like SafeOpenRead
+//-----------------------------------------------------------------------------
+int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath )
+{
+ int nPathLength = 0;
+
+ pszPath = ExpandPath( const_cast< char * >( pszPath ) ); // Kind of redundant but it's how CmdLib_HasBasePath needs things
+
+ if ( CmdLib_HasBasePath( pszPath, nPathLength ) )
+ {
+ pszPath = pszPath + nPathLength;
+ for ( int i = 0; i < CmdLib_GetNumBasePaths(); ++i )
+ {
+ CUtlString &expandedPath = expandedPathList[ expandedPathList.AddToTail( CmdLib_GetBasePath( i ) ) ];
+ expandedPath += pszPath;
+ }
+ }
+ else
+ {
+ expandedPathList.AddToTail( pszPath );
+ }
+
+ return expandedPathList.Count();
+}
+
+
+FileHandle_t SafeOpenRead( const char *filename )
+{
+ int pathLength;
+ FileHandle_t f = 0;
+ if( CmdLib_HasBasePath( filename, pathLength ) )
+ {
+ filename = filename + pathLength;
+ int i;
+ for( i = 0; i < g_NumBasePaths; i++ )
+ {
+ char tmp[MAX_PATH];
+ strcpy( tmp, g_pBasePaths[i] );
+ strcat( tmp, filename );
+ f = g_pFileSystem->Open( tmp, "rb" );
+ if( f )
+ {
+ return f;
+ }
+ }
+ Error ("Error opening %s\n",filename );
+ return f;
+ }
+ else
+ {
+ f = g_pFileSystem->Open( filename, "rb" );
+ if ( !f )
+ Error ("Error opening %s",filename );
+
+ return f;
+ }
+}
+
+void SafeRead( FileHandle_t f, void *buffer, int count)
+{
+ if ( g_pFileSystem->Read (buffer, count, f) != (size_t)count)
+ Error ("File read failure");
+}
+
+
+void SafeWrite ( FileHandle_t f, void *buffer, int count)
+{
+ if (g_pFileSystem->Write (buffer, count, f) != (size_t)count)
+ Error ("File write failure");
+}
+
+
+/*
+==============
+FileExists
+==============
+*/
+qboolean FileExists ( const char *filename )
+{
+ FileHandle_t hFile = g_pFileSystem->Open( filename, "rb" );
+ if ( hFile == FILESYSTEM_INVALID_HANDLE )
+ {
+ return false;
+ }
+ else
+ {
+ g_pFileSystem->Close( hFile );
+ return true;
+ }
+}
+
+/*
+==============
+LoadFile
+==============
+*/
+int LoadFile ( const char *filename, void **bufferptr )
+{
+ int length = 0;
+ void *buffer;
+
+ FileHandle_t f = SafeOpenRead (filename);
+ if ( FILESYSTEM_INVALID_HANDLE != f )
+ {
+ length = Q_filelength (f);
+ buffer = malloc (length+1);
+ ((char *)buffer)[length] = 0;
+ SafeRead (f, buffer, length);
+ g_pFileSystem->Close (f);
+ *bufferptr = buffer;
+ }
+ else
+ {
+ *bufferptr = NULL;
+ }
+ return length;
+}
+
+
+
+/*
+==============
+SaveFile
+==============
+*/
+void SaveFile ( const char *filename, void *buffer, int count )
+{
+ FileHandle_t f = SafeOpenWrite (filename);
+ SafeWrite (f, buffer, count);
+ g_pFileSystem->Close (f);
+}
+
+/*
+====================
+Extract file parts
+====================
+*/
+// FIXME: should include the slash, otherwise
+// backing to an empty path will be wrong when appending a slash
+
+
+
+/*
+==============
+ParseNum / ParseHex
+==============
+*/
+int ParseHex (char *hex)
+{
+ char *str;
+ int num;
+
+ num = 0;
+ str = hex;
+
+ while (*str)
+ {
+ num <<= 4;
+ if (*str >= '0' && *str <= '9')
+ num += *str-'0';
+ else if (*str >= 'a' && *str <= 'f')
+ num += 10 + *str-'a';
+ else if (*str >= 'A' && *str <= 'F')
+ num += 10 + *str-'A';
+ else
+ Error ("Bad hex number: %s",hex);
+ str++;
+ }
+
+ return num;
+}
+
+
+int ParseNum (char *str)
+{
+ if (str[0] == '$')
+ return ParseHex (str+1);
+ if (str[0] == '0' && str[1] == 'x')
+ return ParseHex (str+2);
+ return atol (str);
+}
+
+/*
+============
+CreatePath
+============
+*/
+void CreatePath (char *path)
+{
+ char *ofs, c;
+
+ // strip the drive
+ if (path[1] == ':')
+ path += 2;
+
+ for (ofs = path+1 ; *ofs ; ofs++)
+ {
+ c = *ofs;
+ if (c == '/' || c == '\\')
+ { // create the directory
+ *ofs = 0;
+ Q_mkdir (path);
+ *ofs = c;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Creates a path, path may already exist
+//-----------------------------------------------------------------------------
+#if defined( _WIN32 ) || defined( WIN32 )
+void SafeCreatePath( char *path )
+{
+ char *ptr;
+
+ // skip past the drive path, but don't strip
+ if ( path[1] == ':' )
+ {
+ ptr = strchr( path, '\\' );
+ }
+ else
+ {
+ ptr = path;
+ }
+ while ( ptr )
+ {
+ ptr = strchr( ptr+1, '\\' );
+ if ( ptr )
+ {
+ *ptr = '\0';
+ _mkdir( path );
+ *ptr = '\\';
+ }
+ }
+}
+#endif
+
+/*
+============
+QCopyFile
+
+ Used to archive source files
+============
+*/
+void QCopyFile (char *from, char *to)
+{
+ void *buffer;
+ int length;
+
+ length = LoadFile (from, &buffer);
+ CreatePath (to);
+ SaveFile (to, buffer, length);
+ free (buffer);
+}
+
+
+
diff --git a/mp/src/utils/common/cmdlib.h b/mp/src/utils/common/cmdlib.h
index 50fa9d20..5b5b2c7c 100644
--- a/mp/src/utils/common/cmdlib.h
+++ b/mp/src/utils/common/cmdlib.h
@@ -1,178 +1,178 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef CMDLIB_H
-#define CMDLIB_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-// cmdlib.h
-
-#include "basetypes.h"
-
-// This can go away when everything is in bin.
-#if defined( CMDLIB_NODBGLIB )
- void Error( PRINTF_FORMAT_STRING char const *pMsg, ... );
-#else
- #include "tier0/dbg.h"
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <time.h>
-#include <stdarg.h>
-#include "filesystem.h"
-#include "filesystem_tools.h"
-#include "tier1/utlstring.h"
-
-
-// Tools should use this as the read path ID. It'll look into the paths specified by gameinfo.txt
-#define TOOLS_READ_PATH_ID "GAME"
-
-
-// Tools should use this to fprintf data to files.
-void CmdLib_FPrintf( FileHandle_t hFile, PRINTF_FORMAT_STRING const char *pFormat, ... );
-char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile );
-
-
-// This can be set so Msg() sends output to hook functions (like the VMPI MySQL database),
-// but doesn't actually printf the output.
-extern bool g_bSuppressPrintfOutput;
-
-extern IBaseFileSystem *g_pFileSystem;
-
-// These call right into the functions in filesystem_tools.h
-void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage = 0 );
-void CmdLib_TermFileSystem(); // GracefulExit calls this.
-CreateInterfaceFn CmdLib_GetFileSystemFactory();
-
-
-#ifdef _WIN32
-#pragma warning(disable : 4244) // MIPS
-#pragma warning(disable : 4136) // X86
-#pragma warning(disable : 4051) // ALPHA
-
-#pragma warning(disable : 4018) // signed/unsigned mismatch
-#pragma warning(disable : 4305) // truncate from double to float
-
-#pragma warning(disable : 4389) // singned/unsigned mismatch in ==
-#pragma warning(disable: 4512) // assignment operator could not be generated
-#endif
-
-
-// the dec offsetof macro doesnt work very well...
-#define myoffsetof(type,identifier) offsetof( type, identifier )
-
-
-// set these before calling CheckParm
-extern int myargc;
-extern char **myargv;
-
-int Q_filelength (FileHandle_t f);
-int FileTime (char *path);
-
-void Q_mkdir( char *path );
-
-char *ExpandArg (char *path); // expand relative to CWD
-char *ExpandPath (char *path); // expand relative to gamedir
-
-char *ExpandPathAndArchive (char *path);
-
-// Fills in pOut with "X hours, Y minutes, Z seconds". Leaves out hours or minutes if they're zero.
-void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen );
-
-
-
-int CheckParm (char *check);
-
-FileHandle_t SafeOpenWrite ( const char *filename );
-FileHandle_t SafeOpenRead ( const char *filename );
-void SafeRead( FileHandle_t f, void *buffer, int count);
-void SafeWrite( FileHandle_t f, void *buffer, int count);
-
-int LoadFile ( const char *filename, void **bufferptr );
-void SaveFile ( const char *filename, void *buffer, int count );
-qboolean FileExists ( const char *filename );
-
-int ParseNum (char *str);
-
-// Do a printf in the specified color.
-#define CP_ERROR stderr, 1, 0, 0, 1 // default colors..
-#define CP_WARNING stderr, 1, 1, 0, 1
-#define CP_STARTUP stdout, 0, 1, 1, 1
-#define CP_NOTIFY stdout, 1, 1, 1, 1
-void ColorPrintf( FILE *pFile, bool red, bool green, bool blue, bool intensity, PRINTF_FORMAT_STRING char const *pFormat, ... );
-
-// Initialize spew output.
-void InstallSpewFunction();
-
-// This registers an extra callback for spew output.
-typedef void (*SpewHookFn)( const char * );
-void InstallExtraSpewHook( SpewHookFn pFn );
-
-// Install allocation hooks so we error out if an allocation can't happen.
-void InstallAllocationFunctions();
-
-// This shuts down mgrs that use threads gracefully. If you just call exit(), the threads can
-// get in a state where you can't tell if they are shutdown or not, and it can stall forever.
-typedef void (*CleanupFn)();
-void CmdLib_AtCleanup( CleanupFn pFn ); // register a callback when Cleanup() is called.
-void CmdLib_Cleanup();
-void CmdLib_Exit( int exitCode ); // Use this to cleanup and call exit().
-
-// entrypoint if chaining spew functions
-SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg );
-unsigned short SetConsoleTextColor( int red, int green, int blue, int intensity );
-void RestoreConsoleTextColor( unsigned short color );
-
-// Append all spew output to the specified file.
-void SetSpewFunctionLogFile( char const *pFilename );
-
-char *COM_Parse (char *data);
-
-extern char com_token[1024];
-
-char *copystring(const char *s);
-
-void CreatePath( char *path );
-void QCopyFile( char *from, char *to );
-void SafeCreatePath( char *path );
-
-extern qboolean archive;
-extern char archivedir[1024];
-
-extern qboolean verbose;
-
-void qprintf( PRINTF_FORMAT_STRING const char *format, ... );
-
-void ExpandWildcards (int *argc, char ***argv);
-
-void CmdLib_AddBasePath( const char *pBasePath );
-bool CmdLib_HasBasePath( const char *pFileName, int &pathLength );
-int CmdLib_GetNumBasePaths( void );
-const char *CmdLib_GetBasePath( int i );
-// Like ExpandPath but expands the path for each base path like SafeOpenRead
-int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath );
-
-extern bool g_bStopOnExit;
-
-// for compression routines
-typedef struct
-{
- byte *data;
- int count;
-} cblock_t;
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CMDLIB_H
+#define CMDLIB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+// cmdlib.h
+
+#include "basetypes.h"
+
+// This can go away when everything is in bin.
+#if defined( CMDLIB_NODBGLIB )
+ void Error( PRINTF_FORMAT_STRING char const *pMsg, ... );
+#else
+ #include "tier0/dbg.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include "filesystem.h"
+#include "filesystem_tools.h"
+#include "tier1/utlstring.h"
+
+
+// Tools should use this as the read path ID. It'll look into the paths specified by gameinfo.txt
+#define TOOLS_READ_PATH_ID "GAME"
+
+
+// Tools should use this to fprintf data to files.
+void CmdLib_FPrintf( FileHandle_t hFile, PRINTF_FORMAT_STRING const char *pFormat, ... );
+char* CmdLib_FGets( char *pOut, int outSize, FileHandle_t hFile );
+
+
+// This can be set so Msg() sends output to hook functions (like the VMPI MySQL database),
+// but doesn't actually printf the output.
+extern bool g_bSuppressPrintfOutput;
+
+extern IBaseFileSystem *g_pFileSystem;
+
+// These call right into the functions in filesystem_tools.h
+void CmdLib_InitFileSystem( const char *pFilename, int maxMemoryUsage = 0 );
+void CmdLib_TermFileSystem(); // GracefulExit calls this.
+CreateInterfaceFn CmdLib_GetFileSystemFactory();
+
+
+#ifdef _WIN32
+#pragma warning(disable : 4244) // MIPS
+#pragma warning(disable : 4136) // X86
+#pragma warning(disable : 4051) // ALPHA
+
+#pragma warning(disable : 4018) // signed/unsigned mismatch
+#pragma warning(disable : 4305) // truncate from double to float
+
+#pragma warning(disable : 4389) // singned/unsigned mismatch in ==
+#pragma warning(disable: 4512) // assignment operator could not be generated
+#endif
+
+
+// the dec offsetof macro doesnt work very well...
+#define myoffsetof(type,identifier) offsetof( type, identifier )
+
+
+// set these before calling CheckParm
+extern int myargc;
+extern char **myargv;
+
+int Q_filelength (FileHandle_t f);
+int FileTime (char *path);
+
+void Q_mkdir( char *path );
+
+char *ExpandArg (char *path); // expand relative to CWD
+char *ExpandPath (char *path); // expand relative to gamedir
+
+char *ExpandPathAndArchive (char *path);
+
+// Fills in pOut with "X hours, Y minutes, Z seconds". Leaves out hours or minutes if they're zero.
+void GetHourMinuteSecondsString( int nInputSeconds, char *pOut, int outLen );
+
+
+
+int CheckParm (char *check);
+
+FileHandle_t SafeOpenWrite ( const char *filename );
+FileHandle_t SafeOpenRead ( const char *filename );
+void SafeRead( FileHandle_t f, void *buffer, int count);
+void SafeWrite( FileHandle_t f, void *buffer, int count);
+
+int LoadFile ( const char *filename, void **bufferptr );
+void SaveFile ( const char *filename, void *buffer, int count );
+qboolean FileExists ( const char *filename );
+
+int ParseNum (char *str);
+
+// Do a printf in the specified color.
+#define CP_ERROR stderr, 1, 0, 0, 1 // default colors..
+#define CP_WARNING stderr, 1, 1, 0, 1
+#define CP_STARTUP stdout, 0, 1, 1, 1
+#define CP_NOTIFY stdout, 1, 1, 1, 1
+void ColorPrintf( FILE *pFile, bool red, bool green, bool blue, bool intensity, PRINTF_FORMAT_STRING char const *pFormat, ... );
+
+// Initialize spew output.
+void InstallSpewFunction();
+
+// This registers an extra callback for spew output.
+typedef void (*SpewHookFn)( const char * );
+void InstallExtraSpewHook( SpewHookFn pFn );
+
+// Install allocation hooks so we error out if an allocation can't happen.
+void InstallAllocationFunctions();
+
+// This shuts down mgrs that use threads gracefully. If you just call exit(), the threads can
+// get in a state where you can't tell if they are shutdown or not, and it can stall forever.
+typedef void (*CleanupFn)();
+void CmdLib_AtCleanup( CleanupFn pFn ); // register a callback when Cleanup() is called.
+void CmdLib_Cleanup();
+void CmdLib_Exit( int exitCode ); // Use this to cleanup and call exit().
+
+// entrypoint if chaining spew functions
+SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg );
+unsigned short SetConsoleTextColor( int red, int green, int blue, int intensity );
+void RestoreConsoleTextColor( unsigned short color );
+
+// Append all spew output to the specified file.
+void SetSpewFunctionLogFile( char const *pFilename );
+
+char *COM_Parse (char *data);
+
+extern char com_token[1024];
+
+char *copystring(const char *s);
+
+void CreatePath( char *path );
+void QCopyFile( char *from, char *to );
+void SafeCreatePath( char *path );
+
+extern qboolean archive;
+extern char archivedir[1024];
+
+extern qboolean verbose;
+
+void qprintf( PRINTF_FORMAT_STRING const char *format, ... );
+
+void ExpandWildcards (int *argc, char ***argv);
+
+void CmdLib_AddBasePath( const char *pBasePath );
+bool CmdLib_HasBasePath( const char *pFileName, int &pathLength );
+int CmdLib_GetNumBasePaths( void );
+const char *CmdLib_GetBasePath( int i );
+// Like ExpandPath but expands the path for each base path like SafeOpenRead
+int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath );
+
+extern bool g_bStopOnExit;
+
+// for compression routines
+typedef struct
+{
+ byte *data;
+ int count;
+} cblock_t;
+
+
#endif // CMDLIB_H \ No newline at end of file
diff --git a/mp/src/utils/common/consolewnd.cpp b/mp/src/utils/common/consolewnd.cpp
index 8802e39e..6201409a 100644
--- a/mp/src/utils/common/consolewnd.cpp
+++ b/mp/src/utils/common/consolewnd.cpp
@@ -1,333 +1,333 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include <windows.h>
-#include "consolewnd.h"
-
-
-#pragma warning( disable : 4311 ) // warning C4311: 'reinterpret_cast' : pointer truncation from 'CConsoleWnd *const ' to 'LONG'
-#pragma warning( disable : 4312 ) // warning C4312: 'type cast' : conversion from 'LONG' to 'CConsoleWnd *' of greater size
-
-#define EDITCONTROL_BORDER_SIZE 5
-
-
-// ------------------------------------------------------------------------------------------------ //
-// Functions to manage the console window.
-// ------------------------------------------------------------------------------------------------ //
-
-class CConsoleWnd : public IConsoleWnd
-{
-public:
- CConsoleWnd();
- ~CConsoleWnd();
-
- bool Init( void *hInstance, int dialogResourceID, int editControlID, bool bVisible );
- void Term();
-
- virtual void Release();
-
- virtual void SetVisible( bool bVisible );
- virtual bool IsVisible() const;
-
- virtual void PrintToConsole( const char *pMsg );
- virtual void SetTitle( const char *pTitle );
-
- virtual void SetDeleteOnClose( bool bDelete );
-
-
-private:
-
- int WindowProc(
- HWND hwndDlg, // handle to dialog box
- UINT uMsg, // message
- WPARAM wParam, // first message parameter
- LPARAM lParam // second message parameter
- );
-
- static int CALLBACK StaticWindowProc(
- HWND hwndDlg, // handle to dialog box
- UINT uMsg, // message
- WPARAM wParam, // first message parameter
- LPARAM lParam // second message parameter
- );
-
- void RepositionEditControl();
-
-
-private:
-
- HWND m_hWnd;
- HWND m_hEditControl;
- bool m_bVisible;
- bool m_bDeleteOnClose;
- int m_nCurrentChars;
-};
-
-
-CConsoleWnd::CConsoleWnd()
-{
- m_hWnd = m_hEditControl = NULL;
- m_bVisible = false;
- m_bDeleteOnClose = false;
- m_nCurrentChars = 0;
-}
-
-
-CConsoleWnd::~CConsoleWnd()
-{
- Term();
-}
-
-bool CConsoleWnd::Init( void *hInstance, int dialogResourceID, int editControlID, bool bVisible )
-{
- // Create the window.
- m_hWnd = CreateDialog(
- (HINSTANCE)hInstance,
- MAKEINTRESOURCE( dialogResourceID ),
- NULL,
- &CConsoleWnd::StaticWindowProc );
-
- if ( !m_hWnd )
- return false;
-
- SetWindowLong( m_hWnd, GWL_USERDATA, reinterpret_cast< LONG >( this ) );
- if ( bVisible )
- ShowWindow( m_hWnd, SW_SHOW );
-
- // Get a handle to the edit control.
- m_hEditControl = GetDlgItem( m_hWnd, editControlID );
- if ( !m_hEditControl )
- return false;
-
- RepositionEditControl();
-
- m_bVisible = bVisible;
- return true;
-}
-
-
-void CConsoleWnd::Term()
-{
- if ( m_hWnd )
- {
- DestroyWindow( m_hWnd );
- m_hWnd = NULL;
- }
-}
-
-
-void CConsoleWnd::Release()
-{
- delete this;
-}
-
-
-void CConsoleWnd::SetVisible( bool bVisible )
-{
- ShowWindow( m_hWnd, bVisible ? SW_RESTORE : SW_HIDE );
-
- if ( bVisible )
- {
- ShowWindow( m_hWnd, SW_SHOW );
- SetWindowPos( m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
- UpdateWindow( m_hWnd );
-
- int nLen = (int)SendMessage( m_hEditControl, EM_GETLIMITTEXT, 0, 0 );
- SendMessage( m_hEditControl, EM_SETSEL, nLen, nLen );
- }
- else
- {
- SetWindowPos( m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOOWNERZORDER );
- }
-
- m_bVisible = bVisible;
-}
-
-
-bool CConsoleWnd::IsVisible() const
-{
- return m_bVisible;
-}
-
-
-void CConsoleWnd::PrintToConsole( const char *pMsg )
-{
- if ( m_nCurrentChars >= 16*1024 )
- {
- // Clear the edit control otherwise it'll stop outputting anything.
- m_nCurrentChars = 0;
-
- int nLen = (int)SendMessage( m_hEditControl, EM_GETLIMITTEXT, 0, 0 );
- SendMessage( m_hEditControl, EM_SETSEL, 0, nLen );
- SendMessage( m_hEditControl, EM_REPLACESEL, FALSE, (LPARAM)"" );
- }
-
- FormatAndSendToEditControl( m_hEditControl, pMsg );
- m_nCurrentChars += (int)strlen( pMsg );
-}
-
-
-void CConsoleWnd::SetTitle( const char *pTitle )
-{
- SetWindowText( m_hWnd, pTitle );
-}
-
-
-int CConsoleWnd::WindowProc(
- HWND hwndDlg, // handle to dialog box
- UINT uMsg, // message
- WPARAM wParam, // first message parameter
- LPARAM lParam // second message parameter
- )
-{
- lParam = lParam; // avoid compiler warning
-
- if ( hwndDlg != m_hWnd )
- return false;
-
- switch ( uMsg )
- {
- case WM_SYSCOMMAND:
- {
- if ( wParam == SC_CLOSE )
- {
- if ( m_bDeleteOnClose )
- {
- Release();
- }
- else
- {
- SetVisible( false );
- return true;
- }
- }
- }
- break;
-
- case WM_SHOWWINDOW:
- {
- m_bVisible = (wParam != 0);
- }
- break;
-
- case WM_SIZE:
- case WM_INITDIALOG:
- {
- RepositionEditControl();
- }
- break;
- }
-
- return false;
-}
-
-
-int CConsoleWnd::StaticWindowProc(
- HWND hwndDlg, // handle to dialog box
- UINT uMsg, // message
- WPARAM wParam, // first message parameter
- LPARAM lParam // second message parameter
- )
-{
- CConsoleWnd *pDlg = (CConsoleWnd*)GetWindowLong( hwndDlg, GWL_USERDATA );
- if ( pDlg )
- return pDlg->WindowProc( hwndDlg, uMsg, wParam, lParam );
- else
- return false;
-}
-
-
-void CConsoleWnd::RepositionEditControl()
-{
- RECT rcMain;
- GetClientRect( m_hWnd, &rcMain );
-
- RECT rcNew;
- rcNew.left = rcMain.left + EDITCONTROL_BORDER_SIZE;
- rcNew.right = rcMain.right - EDITCONTROL_BORDER_SIZE;
- rcNew.top = rcMain.top + EDITCONTROL_BORDER_SIZE;
- rcNew.bottom = rcMain.bottom - EDITCONTROL_BORDER_SIZE;
-
- SetWindowPos(
- m_hEditControl,
- NULL,
- rcNew.left,
- rcNew.top,
- rcNew.right - rcNew.left,
- rcNew.bottom - rcNew.top,
- SWP_NOZORDER );
-}
-
-
-void CConsoleWnd::SetDeleteOnClose( bool bDelete )
-{
- m_bDeleteOnClose = bDelete;
-}
-
-
-// ------------------------------------------------------------------------------------ //
-// Module interface.
-// ------------------------------------------------------------------------------------ //
-
-void SendToEditControl( HWND hEditControl, const char *pText )
-{
- int nLen = (int)SendMessage( hEditControl, EM_GETLIMITTEXT, 0, 0 );
- SendMessage( hEditControl, EM_SETSEL, nLen, nLen );
- SendMessage( hEditControl, EM_REPLACESEL, FALSE, (LPARAM)pText );
-}
-
-
-void FormatAndSendToEditControl( void *hWnd, const char *pText )
-{
- HWND hEditControl = (HWND)hWnd;
-
- // Translate \n to \r\n.
- char outMsg[1024];
- const char *pIn = pText;
- char *pOut = outMsg;
- while ( *pIn )
- {
- if ( *pIn == '\n' )
- {
- *pOut = '\r';
- pOut++;
- }
- *pOut = *pIn;
-
- ++pIn;
- ++pOut;
-
- if ( pOut - outMsg >= 1020 )
- {
- *pOut = 0;
- SendToEditControl( hEditControl, outMsg );
- pOut = outMsg;
- }
- }
- *pOut = 0;
- SendToEditControl( hEditControl, outMsg );
-}
-
-
-IConsoleWnd* CreateConsoleWnd( void *hInstance, int dialogResourceID, int editControlID, bool bVisible )
-{
- CConsoleWnd *pWnd = new CConsoleWnd;
-
- if ( pWnd->Init( hInstance, dialogResourceID, editControlID, bVisible ) )
- {
- return pWnd;
- }
- else
- {
- pWnd->Release();
- return NULL;
- }
-}
-
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <windows.h>
+#include "consolewnd.h"
+
+
+#pragma warning( disable : 4311 ) // warning C4311: 'reinterpret_cast' : pointer truncation from 'CConsoleWnd *const ' to 'LONG'
+#pragma warning( disable : 4312 ) // warning C4312: 'type cast' : conversion from 'LONG' to 'CConsoleWnd *' of greater size
+
+#define EDITCONTROL_BORDER_SIZE 5
+
+
+// ------------------------------------------------------------------------------------------------ //
+// Functions to manage the console window.
+// ------------------------------------------------------------------------------------------------ //
+
+class CConsoleWnd : public IConsoleWnd
+{
+public:
+ CConsoleWnd();
+ ~CConsoleWnd();
+
+ bool Init( void *hInstance, int dialogResourceID, int editControlID, bool bVisible );
+ void Term();
+
+ virtual void Release();
+
+ virtual void SetVisible( bool bVisible );
+ virtual bool IsVisible() const;
+
+ virtual void PrintToConsole( const char *pMsg );
+ virtual void SetTitle( const char *pTitle );
+
+ virtual void SetDeleteOnClose( bool bDelete );
+
+
+private:
+
+ int WindowProc(
+ HWND hwndDlg, // handle to dialog box
+ UINT uMsg, // message
+ WPARAM wParam, // first message parameter
+ LPARAM lParam // second message parameter
+ );
+
+ static int CALLBACK StaticWindowProc(
+ HWND hwndDlg, // handle to dialog box
+ UINT uMsg, // message
+ WPARAM wParam, // first message parameter
+ LPARAM lParam // second message parameter
+ );
+
+ void RepositionEditControl();
+
+
+private:
+
+ HWND m_hWnd;
+ HWND m_hEditControl;
+ bool m_bVisible;
+ bool m_bDeleteOnClose;
+ int m_nCurrentChars;
+};
+
+
+CConsoleWnd::CConsoleWnd()
+{
+ m_hWnd = m_hEditControl = NULL;
+ m_bVisible = false;
+ m_bDeleteOnClose = false;
+ m_nCurrentChars = 0;
+}
+
+
+CConsoleWnd::~CConsoleWnd()
+{
+ Term();
+}
+
+bool CConsoleWnd::Init( void *hInstance, int dialogResourceID, int editControlID, bool bVisible )
+{
+ // Create the window.
+ m_hWnd = CreateDialog(
+ (HINSTANCE)hInstance,
+ MAKEINTRESOURCE( dialogResourceID ),
+ NULL,
+ &CConsoleWnd::StaticWindowProc );
+
+ if ( !m_hWnd )
+ return false;
+
+ SetWindowLong( m_hWnd, GWL_USERDATA, reinterpret_cast< LONG >( this ) );
+ if ( bVisible )
+ ShowWindow( m_hWnd, SW_SHOW );
+
+ // Get a handle to the edit control.
+ m_hEditControl = GetDlgItem( m_hWnd, editControlID );
+ if ( !m_hEditControl )
+ return false;
+
+ RepositionEditControl();
+
+ m_bVisible = bVisible;
+ return true;
+}
+
+
+void CConsoleWnd::Term()
+{
+ if ( m_hWnd )
+ {
+ DestroyWindow( m_hWnd );
+ m_hWnd = NULL;
+ }
+}
+
+
+void CConsoleWnd::Release()
+{
+ delete this;
+}
+
+
+void CConsoleWnd::SetVisible( bool bVisible )
+{
+ ShowWindow( m_hWnd, bVisible ? SW_RESTORE : SW_HIDE );
+
+ if ( bVisible )
+ {
+ ShowWindow( m_hWnd, SW_SHOW );
+ SetWindowPos( m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
+ UpdateWindow( m_hWnd );
+
+ int nLen = (int)SendMessage( m_hEditControl, EM_GETLIMITTEXT, 0, 0 );
+ SendMessage( m_hEditControl, EM_SETSEL, nLen, nLen );
+ }
+ else
+ {
+ SetWindowPos( m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOOWNERZORDER );
+ }
+
+ m_bVisible = bVisible;
+}
+
+
+bool CConsoleWnd::IsVisible() const
+{
+ return m_bVisible;
+}
+
+
+void CConsoleWnd::PrintToConsole( const char *pMsg )
+{
+ if ( m_nCurrentChars >= 16*1024 )
+ {
+ // Clear the edit control otherwise it'll stop outputting anything.
+ m_nCurrentChars = 0;
+
+ int nLen = (int)SendMessage( m_hEditControl, EM_GETLIMITTEXT, 0, 0 );
+ SendMessage( m_hEditControl, EM_SETSEL, 0, nLen );
+ SendMessage( m_hEditControl, EM_REPLACESEL, FALSE, (LPARAM)"" );
+ }
+
+ FormatAndSendToEditControl( m_hEditControl, pMsg );
+ m_nCurrentChars += (int)strlen( pMsg );
+}
+
+
+void CConsoleWnd::SetTitle( const char *pTitle )
+{
+ SetWindowText( m_hWnd, pTitle );
+}
+
+
+int CConsoleWnd::WindowProc(
+ HWND hwndDlg, // handle to dialog box
+ UINT uMsg, // message
+ WPARAM wParam, // first message parameter
+ LPARAM lParam // second message parameter
+ )
+{
+ lParam = lParam; // avoid compiler warning
+
+ if ( hwndDlg != m_hWnd )
+ return false;
+
+ switch ( uMsg )
+ {
+ case WM_SYSCOMMAND:
+ {
+ if ( wParam == SC_CLOSE )
+ {
+ if ( m_bDeleteOnClose )
+ {
+ Release();
+ }
+ else
+ {
+ SetVisible( false );
+ return true;
+ }
+ }
+ }
+ break;
+
+ case WM_SHOWWINDOW:
+ {
+ m_bVisible = (wParam != 0);
+ }
+ break;
+
+ case WM_SIZE:
+ case WM_INITDIALOG:
+ {
+ RepositionEditControl();
+ }
+ break;
+ }
+
+ return false;
+}
+
+
+int CConsoleWnd::StaticWindowProc(
+ HWND hwndDlg, // handle to dialog box
+ UINT uMsg, // message
+ WPARAM wParam, // first message parameter
+ LPARAM lParam // second message parameter
+ )
+{
+ CConsoleWnd *pDlg = (CConsoleWnd*)GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( pDlg )
+ return pDlg->WindowProc( hwndDlg, uMsg, wParam, lParam );
+ else
+ return false;
+}
+
+
+void CConsoleWnd::RepositionEditControl()
+{
+ RECT rcMain;
+ GetClientRect( m_hWnd, &rcMain );
+
+ RECT rcNew;
+ rcNew.left = rcMain.left + EDITCONTROL_BORDER_SIZE;
+ rcNew.right = rcMain.right - EDITCONTROL_BORDER_SIZE;
+ rcNew.top = rcMain.top + EDITCONTROL_BORDER_SIZE;
+ rcNew.bottom = rcMain.bottom - EDITCONTROL_BORDER_SIZE;
+
+ SetWindowPos(
+ m_hEditControl,
+ NULL,
+ rcNew.left,
+ rcNew.top,
+ rcNew.right - rcNew.left,
+ rcNew.bottom - rcNew.top,
+ SWP_NOZORDER );
+}
+
+
+void CConsoleWnd::SetDeleteOnClose( bool bDelete )
+{
+ m_bDeleteOnClose = bDelete;
+}
+
+
+// ------------------------------------------------------------------------------------ //
+// Module interface.
+// ------------------------------------------------------------------------------------ //
+
+void SendToEditControl( HWND hEditControl, const char *pText )
+{
+ int nLen = (int)SendMessage( hEditControl, EM_GETLIMITTEXT, 0, 0 );
+ SendMessage( hEditControl, EM_SETSEL, nLen, nLen );
+ SendMessage( hEditControl, EM_REPLACESEL, FALSE, (LPARAM)pText );
+}
+
+
+void FormatAndSendToEditControl( void *hWnd, const char *pText )
+{
+ HWND hEditControl = (HWND)hWnd;
+
+ // Translate \n to \r\n.
+ char outMsg[1024];
+ const char *pIn = pText;
+ char *pOut = outMsg;
+ while ( *pIn )
+ {
+ if ( *pIn == '\n' )
+ {
+ *pOut = '\r';
+ pOut++;
+ }
+ *pOut = *pIn;
+
+ ++pIn;
+ ++pOut;
+
+ if ( pOut - outMsg >= 1020 )
+ {
+ *pOut = 0;
+ SendToEditControl( hEditControl, outMsg );
+ pOut = outMsg;
+ }
+ }
+ *pOut = 0;
+ SendToEditControl( hEditControl, outMsg );
+}
+
+
+IConsoleWnd* CreateConsoleWnd( void *hInstance, int dialogResourceID, int editControlID, bool bVisible )
+{
+ CConsoleWnd *pWnd = new CConsoleWnd;
+
+ if ( pWnd->Init( hInstance, dialogResourceID, editControlID, bVisible ) )
+ {
+ return pWnd;
+ }
+ else
+ {
+ pWnd->Release();
+ return NULL;
+ }
+}
+
+
+
+
diff --git a/mp/src/utils/common/consolewnd.h b/mp/src/utils/common/consolewnd.h
index 4572ff57..92649e2f 100644
--- a/mp/src/utils/common/consolewnd.h
+++ b/mp/src/utils/common/consolewnd.h
@@ -1,45 +1,45 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef CONSOLEWND_H
-#define CONSOLEWND_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-class IConsoleWnd
-{
-public:
- virtual void Release() = 0;
-
- // Print a message to the console.
- virtual void PrintToConsole( const char *pMsg ) = 0;
-
- // Set the window title.
- virtual void SetTitle( const char *pTitle ) = 0;
-
- // Show and hide the console window.
- virtual void SetVisible( bool bVisible ) = 0;
- virtual bool IsVisible() const = 0;
-
- // Normally, the window just hides itself when closed. You can use this to make the window
- // automatically go away when they close it.
- virtual void SetDeleteOnClose( bool bDelete ) = 0;
-};
-
-
-// Utility functions.
-
-// This converts adds \r's where necessary and sends the text to the edit control.
-void FormatAndSendToEditControl( void *hWnd, const char *pText );
-
-
-IConsoleWnd* CreateConsoleWnd( void *hInstance, int dialogResourceID, int editControlID, bool bVisible );
-
-
-#endif // CONSOLEWND_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CONSOLEWND_H
+#define CONSOLEWND_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+class IConsoleWnd
+{
+public:
+ virtual void Release() = 0;
+
+ // Print a message to the console.
+ virtual void PrintToConsole( const char *pMsg ) = 0;
+
+ // Set the window title.
+ virtual void SetTitle( const char *pTitle ) = 0;
+
+ // Show and hide the console window.
+ virtual void SetVisible( bool bVisible ) = 0;
+ virtual bool IsVisible() const = 0;
+
+ // Normally, the window just hides itself when closed. You can use this to make the window
+ // automatically go away when they close it.
+ virtual void SetDeleteOnClose( bool bDelete ) = 0;
+};
+
+
+// Utility functions.
+
+// This converts adds \r's where necessary and sends the text to the edit control.
+void FormatAndSendToEditControl( void *hWnd, const char *pText );
+
+
+IConsoleWnd* CreateConsoleWnd( void *hInstance, int dialogResourceID, int editControlID, bool bVisible );
+
+
+#endif // CONSOLEWND_H
diff --git a/mp/src/utils/common/filesystem_tools.cpp b/mp/src/utils/common/filesystem_tools.cpp
index 9714c57a..b1306c59 100644
--- a/mp/src/utils/common/filesystem_tools.cpp
+++ b/mp/src/utils/common/filesystem_tools.cpp
@@ -1,209 +1,209 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//===========================================================================//
-
-#if defined( _WIN32 ) && !defined( _X360 )
-#include <windows.h>
-#include <direct.h>
-#include <io.h> // _chmod
-#elif _LINUX
-#include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include "tier1/strtools.h"
-#include "filesystem_tools.h"
-#include "tier0/icommandline.h"
-#include "KeyValues.h"
-#include "tier2/tier2.h"
-
-#ifdef MPI
- #include "vmpi.h"
- #include "vmpi_tools_shared.h"
- #include "vmpi_filesystem.h"
-#endif
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include <tier0/memdbgon.h>
-
-
-// ---------------------------------------------------------------------------------------------------- //
-// Module interface.
-// ---------------------------------------------------------------------------------------------------- //
-
-IBaseFileSystem *g_pFileSystem = NULL;
-
-// These are only used for tools that need the search paths that the engine's file system provides.
-CSysModule *g_pFullFileSystemModule = NULL;
-
-// ---------------------------------------------------------------------------
-//
-// These are the base paths that everything will be referenced relative to (textures especially)
-// All of these directories include the trailing slash
-//
-// ---------------------------------------------------------------------------
-
-// This is the the path of the initial source file (relative to the cwd)
-char qdir[1024];
-
-// This is the base engine + mod-specific game dir (e.g. "c:\tf2\mytfmod\")
-char gamedir[1024];
-
-void FileSystem_SetupStandardDirectories( const char *pFilename, const char *pGameInfoPath )
-{
- // Set qdir.
- if ( !pFilename )
- {
- pFilename = ".";
- }
-
- Q_MakeAbsolutePath( qdir, sizeof( qdir ), pFilename, NULL );
- Q_StripFilename( qdir );
- Q_strlower( qdir );
- if ( qdir[0] != 0 )
- {
- Q_AppendSlash( qdir, sizeof( qdir ) );
- }
-
- // Set gamedir.
- Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), pGameInfoPath );
- Q_AppendSlash( gamedir, sizeof( gamedir ) );
-}
-
-
-bool FileSystem_Init_Normal( const char *pFilename, FSInitType_t initType, bool bOnlyUseDirectoryName )
-{
- if ( initType == FS_INIT_FULL )
- {
- // First, get the name of the module
- char fileSystemDLLName[MAX_PATH];
- bool bSteam;
- if ( FileSystem_GetFileSystemDLLName( fileSystemDLLName, MAX_PATH, bSteam ) != FS_OK )
- return false;
-
- // If we're under Steam we need extra setup to let us find the proper modules
- FileSystem_SetupSteamInstallPath();
-
- // Next, load the module, call Connect/Init.
- CFSLoadModuleInfo loadModuleInfo;
- loadModuleInfo.m_pFileSystemDLLName = fileSystemDLLName;
- loadModuleInfo.m_pDirectoryName = pFilename;
- loadModuleInfo.m_bOnlyUseDirectoryName = bOnlyUseDirectoryName;
- loadModuleInfo.m_ConnectFactory = Sys_GetFactoryThis();
- loadModuleInfo.m_bSteam = bSteam;
- loadModuleInfo.m_bToolsMode = true;
- if ( FileSystem_LoadFileSystemModule( loadModuleInfo ) != FS_OK )
- return false;
-
- // Next, mount the content
- CFSMountContentInfo mountContentInfo;
- mountContentInfo.m_pDirectoryName= loadModuleInfo.m_GameInfoPath;
- mountContentInfo.m_pFileSystem = loadModuleInfo.m_pFileSystem;
- mountContentInfo.m_bToolsMode = true;
- if ( FileSystem_MountContent( mountContentInfo ) != FS_OK )
- return false;
-
- // Finally, load the search paths.
- CFSSearchPathsInit searchPathsInit;
- searchPathsInit.m_pDirectoryName = loadModuleInfo.m_GameInfoPath;
- searchPathsInit.m_pFileSystem = loadModuleInfo.m_pFileSystem;
- if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
- return false;
-
- // Store the data we got from filesystem_init.
- g_pFileSystem = g_pFullFileSystem = loadModuleInfo.m_pFileSystem;
- g_pFullFileSystemModule = loadModuleInfo.m_pModule;
-
- FileSystem_AddSearchPath_Platform( g_pFullFileSystem, loadModuleInfo.m_GameInfoPath );
-
- FileSystem_SetupStandardDirectories( pFilename, loadModuleInfo.m_GameInfoPath );
- }
- else
- {
- if ( !Sys_LoadInterface(
- "filesystem_stdio",
- FILESYSTEM_INTERFACE_VERSION,
- &g_pFullFileSystemModule,
- (void**)&g_pFullFileSystem ) )
- {
- return false;
- }
-
- if ( g_pFullFileSystem->Init() != INIT_OK )
- return false;
-
- g_pFullFileSystem->RemoveAllSearchPaths();
- g_pFullFileSystem->AddSearchPath( "../platform", "PLATFORM" );
- g_pFullFileSystem->AddSearchPath( ".", "GAME" );
-
- g_pFileSystem = g_pFullFileSystem;
- }
-
- return true;
-}
-
-
-bool FileSystem_Init( const char *pBSPFilename, int maxMemoryUsage, FSInitType_t initType, bool bOnlyUseFilename )
-{
- Assert( CommandLine()->GetCmdLine() != NULL ); // Should have called CreateCmdLine by now.
-
- // If this app uses VMPI, then let VMPI intercept all filesystem calls.
-#if defined( MPI )
- if ( g_bUseMPI )
- {
- if ( g_bMPIMaster )
- {
- if ( !FileSystem_Init_Normal( pBSPFilename, initType, bOnlyUseFilename ) )
- return false;
-
- g_pFileSystem = g_pFullFileSystem = VMPI_FileSystem_Init( maxMemoryUsage, g_pFullFileSystem );
- SendQDirInfo();
- }
- else
- {
- g_pFileSystem = g_pFullFileSystem = VMPI_FileSystem_Init( maxMemoryUsage, NULL );
- RecvQDirInfo();
- }
- return true;
- }
-#endif
-
- return FileSystem_Init_Normal( pBSPFilename, initType, bOnlyUseFilename );
-}
-
-
-void FileSystem_Term()
-{
-#if defined( MPI )
- if ( g_bUseMPI )
- {
- g_pFileSystem = g_pFullFileSystem = VMPI_FileSystem_Term();
- }
-#endif
-
- if ( g_pFullFileSystem )
- {
- g_pFullFileSystem->Shutdown();
- g_pFullFileSystem = NULL;
- g_pFileSystem = NULL;
- }
-
- if ( g_pFullFileSystemModule )
- {
- Sys_UnloadModule( g_pFullFileSystemModule );
- g_pFullFileSystemModule = NULL;
- }
-}
-
-
-CreateInterfaceFn FileSystem_GetFactory()
-{
-#if defined( MPI )
- if ( g_bUseMPI )
- return VMPI_FileSystem_GetFactory();
-#endif
- return Sys_GetFactory( g_pFullFileSystemModule );
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#if defined( _WIN32 ) && !defined( _X360 )
+#include <windows.h>
+#include <direct.h>
+#include <io.h> // _chmod
+#elif _LINUX
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include "tier1/strtools.h"
+#include "filesystem_tools.h"
+#include "tier0/icommandline.h"
+#include "KeyValues.h"
+#include "tier2/tier2.h"
+
+#ifdef MPI
+ #include "vmpi.h"
+ #include "vmpi_tools_shared.h"
+ #include "vmpi_filesystem.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+// ---------------------------------------------------------------------------------------------------- //
+// Module interface.
+// ---------------------------------------------------------------------------------------------------- //
+
+IBaseFileSystem *g_pFileSystem = NULL;
+
+// These are only used for tools that need the search paths that the engine's file system provides.
+CSysModule *g_pFullFileSystemModule = NULL;
+
+// ---------------------------------------------------------------------------
+//
+// These are the base paths that everything will be referenced relative to (textures especially)
+// All of these directories include the trailing slash
+//
+// ---------------------------------------------------------------------------
+
+// This is the the path of the initial source file (relative to the cwd)
+char qdir[1024];
+
+// This is the base engine + mod-specific game dir (e.g. "c:\tf2\mytfmod\")
+char gamedir[1024];
+
+void FileSystem_SetupStandardDirectories( const char *pFilename, const char *pGameInfoPath )
+{
+ // Set qdir.
+ if ( !pFilename )
+ {
+ pFilename = ".";
+ }
+
+ Q_MakeAbsolutePath( qdir, sizeof( qdir ), pFilename, NULL );
+ Q_StripFilename( qdir );
+ Q_strlower( qdir );
+ if ( qdir[0] != 0 )
+ {
+ Q_AppendSlash( qdir, sizeof( qdir ) );
+ }
+
+ // Set gamedir.
+ Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), pGameInfoPath );
+ Q_AppendSlash( gamedir, sizeof( gamedir ) );
+}
+
+
+bool FileSystem_Init_Normal( const char *pFilename, FSInitType_t initType, bool bOnlyUseDirectoryName )
+{
+ if ( initType == FS_INIT_FULL )
+ {
+ // First, get the name of the module
+ char fileSystemDLLName[MAX_PATH];
+ bool bSteam;
+ if ( FileSystem_GetFileSystemDLLName( fileSystemDLLName, MAX_PATH, bSteam ) != FS_OK )
+ return false;
+
+ // If we're under Steam we need extra setup to let us find the proper modules
+ FileSystem_SetupSteamInstallPath();
+
+ // Next, load the module, call Connect/Init.
+ CFSLoadModuleInfo loadModuleInfo;
+ loadModuleInfo.m_pFileSystemDLLName = fileSystemDLLName;
+ loadModuleInfo.m_pDirectoryName = pFilename;
+ loadModuleInfo.m_bOnlyUseDirectoryName = bOnlyUseDirectoryName;
+ loadModuleInfo.m_ConnectFactory = Sys_GetFactoryThis();
+ loadModuleInfo.m_bSteam = bSteam;
+ loadModuleInfo.m_bToolsMode = true;
+ if ( FileSystem_LoadFileSystemModule( loadModuleInfo ) != FS_OK )
+ return false;
+
+ // Next, mount the content
+ CFSMountContentInfo mountContentInfo;
+ mountContentInfo.m_pDirectoryName= loadModuleInfo.m_GameInfoPath;
+ mountContentInfo.m_pFileSystem = loadModuleInfo.m_pFileSystem;
+ mountContentInfo.m_bToolsMode = true;
+ if ( FileSystem_MountContent( mountContentInfo ) != FS_OK )
+ return false;
+
+ // Finally, load the search paths.
+ CFSSearchPathsInit searchPathsInit;
+ searchPathsInit.m_pDirectoryName = loadModuleInfo.m_GameInfoPath;
+ searchPathsInit.m_pFileSystem = loadModuleInfo.m_pFileSystem;
+ if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
+ return false;
+
+ // Store the data we got from filesystem_init.
+ g_pFileSystem = g_pFullFileSystem = loadModuleInfo.m_pFileSystem;
+ g_pFullFileSystemModule = loadModuleInfo.m_pModule;
+
+ FileSystem_AddSearchPath_Platform( g_pFullFileSystem, loadModuleInfo.m_GameInfoPath );
+
+ FileSystem_SetupStandardDirectories( pFilename, loadModuleInfo.m_GameInfoPath );
+ }
+ else
+ {
+ if ( !Sys_LoadInterface(
+ "filesystem_stdio",
+ FILESYSTEM_INTERFACE_VERSION,
+ &g_pFullFileSystemModule,
+ (void**)&g_pFullFileSystem ) )
+ {
+ return false;
+ }
+
+ if ( g_pFullFileSystem->Init() != INIT_OK )
+ return false;
+
+ g_pFullFileSystem->RemoveAllSearchPaths();
+ g_pFullFileSystem->AddSearchPath( "../platform", "PLATFORM" );
+ g_pFullFileSystem->AddSearchPath( ".", "GAME" );
+
+ g_pFileSystem = g_pFullFileSystem;
+ }
+
+ return true;
+}
+
+
+bool FileSystem_Init( const char *pBSPFilename, int maxMemoryUsage, FSInitType_t initType, bool bOnlyUseFilename )
+{
+ Assert( CommandLine()->GetCmdLine() != NULL ); // Should have called CreateCmdLine by now.
+
+ // If this app uses VMPI, then let VMPI intercept all filesystem calls.
+#if defined( MPI )
+ if ( g_bUseMPI )
+ {
+ if ( g_bMPIMaster )
+ {
+ if ( !FileSystem_Init_Normal( pBSPFilename, initType, bOnlyUseFilename ) )
+ return false;
+
+ g_pFileSystem = g_pFullFileSystem = VMPI_FileSystem_Init( maxMemoryUsage, g_pFullFileSystem );
+ SendQDirInfo();
+ }
+ else
+ {
+ g_pFileSystem = g_pFullFileSystem = VMPI_FileSystem_Init( maxMemoryUsage, NULL );
+ RecvQDirInfo();
+ }
+ return true;
+ }
+#endif
+
+ return FileSystem_Init_Normal( pBSPFilename, initType, bOnlyUseFilename );
+}
+
+
+void FileSystem_Term()
+{
+#if defined( MPI )
+ if ( g_bUseMPI )
+ {
+ g_pFileSystem = g_pFullFileSystem = VMPI_FileSystem_Term();
+ }
+#endif
+
+ if ( g_pFullFileSystem )
+ {
+ g_pFullFileSystem->Shutdown();
+ g_pFullFileSystem = NULL;
+ g_pFileSystem = NULL;
+ }
+
+ if ( g_pFullFileSystemModule )
+ {
+ Sys_UnloadModule( g_pFullFileSystemModule );
+ g_pFullFileSystemModule = NULL;
+ }
+}
+
+
+CreateInterfaceFn FileSystem_GetFactory()
+{
+#if defined( MPI )
+ if ( g_bUseMPI )
+ return VMPI_FileSystem_GetFactory();
+#endif
+ return Sys_GetFactory( g_pFullFileSystemModule );
+}
diff --git a/mp/src/utils/common/filesystem_tools.h b/mp/src/utils/common/filesystem_tools.h
index 09db7b3e..ada82ad5 100644
--- a/mp/src/utils/common/filesystem_tools.h
+++ b/mp/src/utils/common/filesystem_tools.h
@@ -1,59 +1,59 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//===========================================================================//
-
-#ifndef FILESYSTEM_TOOLS_H
-#define FILESYSTEM_TOOLS_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-#include "filesystem.h"
-#include "filesystem_init.h"
-
-
-// This is the the path of the initial source file
-extern char qdir[1024];
-
-// This is the base engine + mod-specific game dir (e.g. "d:\tf2\mytfmod\")
-extern char gamedir[1024];
-
-
-// ---------------------------------------------------------------------------------------- //
-// Filesystem initialization.
-// ---------------------------------------------------------------------------------------- //
-
-enum FSInitType_t
-{
- FS_INIT_FULL, // Load gameinfo.txt, maybe use filesystem_steam, and setup search paths.
- FS_INIT_COMPATIBILITY_MODE // Load filesystem_stdio and that's it.
-};
-
-//
-// Initializes qdir, and gamedir. Also initializes the VMPI filesystem if MPI is defined.
-//
-// pFilename can be NULL if you want to rely on vproject and qproject. If it's specified, FileSystem_Init
-// will go up directories from pFilename looking for gameinfo.txt (if vproject isn't specified).
-//
-// If bOnlyUseFilename is true, then it won't use any alternative methods of finding the vproject dir
-// (ie: it won't use -game or -vproject or the vproject env var or qproject).
-//
-bool FileSystem_Init( const char *pFilename, int maxMemoryUsage=0, FSInitType_t initType=FS_INIT_FULL, bool bOnlyUseFilename=false );
-void FileSystem_Term();
-
-// Used to connect app-framework based console apps to the filesystem tools
-void FileSystem_SetupStandardDirectories( const char *pFilename, const char *pGameInfoPath );
-
-CreateInterfaceFn FileSystem_GetFactory( void );
-
-
-extern IBaseFileSystem *g_pFileSystem;
-extern IFileSystem *g_pFullFileSystem; // NOTE: this is here when VMPI is being used, but a VMPI app can
- // ONLY use LoadModule/UnloadModule.
-
-
-#endif // FILESYSTEM_TOOLS_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef FILESYSTEM_TOOLS_H
+#define FILESYSTEM_TOOLS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "filesystem.h"
+#include "filesystem_init.h"
+
+
+// This is the the path of the initial source file
+extern char qdir[1024];
+
+// This is the base engine + mod-specific game dir (e.g. "d:\tf2\mytfmod\")
+extern char gamedir[1024];
+
+
+// ---------------------------------------------------------------------------------------- //
+// Filesystem initialization.
+// ---------------------------------------------------------------------------------------- //
+
+enum FSInitType_t
+{
+ FS_INIT_FULL, // Load gameinfo.txt, maybe use filesystem_steam, and setup search paths.
+ FS_INIT_COMPATIBILITY_MODE // Load filesystem_stdio and that's it.
+};
+
+//
+// Initializes qdir, and gamedir. Also initializes the VMPI filesystem if MPI is defined.
+//
+// pFilename can be NULL if you want to rely on vproject and qproject. If it's specified, FileSystem_Init
+// will go up directories from pFilename looking for gameinfo.txt (if vproject isn't specified).
+//
+// If bOnlyUseFilename is true, then it won't use any alternative methods of finding the vproject dir
+// (ie: it won't use -game or -vproject or the vproject env var or qproject).
+//
+bool FileSystem_Init( const char *pFilename, int maxMemoryUsage=0, FSInitType_t initType=FS_INIT_FULL, bool bOnlyUseFilename=false );
+void FileSystem_Term();
+
+// Used to connect app-framework based console apps to the filesystem tools
+void FileSystem_SetupStandardDirectories( const char *pFilename, const char *pGameInfoPath );
+
+CreateInterfaceFn FileSystem_GetFactory( void );
+
+
+extern IBaseFileSystem *g_pFileSystem;
+extern IFileSystem *g_pFullFileSystem; // NOTE: this is here when VMPI is being used, but a VMPI app can
+ // ONLY use LoadModule/UnloadModule.
+
+
+#endif // FILESYSTEM_TOOLS_H
diff --git a/mp/src/utils/common/map_shared.cpp b/mp/src/utils/common/map_shared.cpp
index f1e970c0..e33e20cb 100644
--- a/mp/src/utils/common/map_shared.cpp
+++ b/mp/src/utils/common/map_shared.cpp
@@ -1,136 +1,136 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "map_shared.h"
-#include "bsplib.h"
-#include "cmdlib.h"
-
-
-CMapError g_MapError;
-int g_nMapFileVersion;
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *szKey -
-// *szValue -
-// *pLoadEntity -
-// Output : ChunkFileResult_t
-//-----------------------------------------------------------------------------
-ChunkFileResult_t LoadEntityKeyCallback(const char *szKey, const char *szValue, LoadEntity_t *pLoadEntity)
-{
- if (!stricmp(szKey, "classname"))
- {
- if (!stricmp(szValue, "func_detail"))
- {
- pLoadEntity->nBaseContents = CONTENTS_DETAIL;
- }
- else if (!stricmp(szValue, "func_ladder"))
- {
- pLoadEntity->nBaseContents = CONTENTS_LADDER;
- }
- else if (!stricmp(szValue, "func_water"))
- {
- pLoadEntity->nBaseContents = CONTENTS_WATER;
- }
- }
- else if (!stricmp(szKey, "id"))
- {
- // UNDONE: flag entity errors by ID instead of index
- //g_MapError.EntityState( atoi( szValue ) );
- // rename this field since DME code uses this name
- SetKeyValue( pLoadEntity->pEntity, "hammerid", szValue );
- return(ChunkFile_Ok);
- }
- else if( !stricmp( szKey, "mapversion" ) )
- {
- // .vmf map revision number
- g_MapRevision = atoi( szValue );
- SetKeyValue( pLoadEntity->pEntity, szKey, szValue );
- return ( ChunkFile_Ok );
- }
-
- SetKeyValue( pLoadEntity->pEntity, szKey, szValue );
-
- return(ChunkFile_Ok);
-}
-
-
-static ChunkFileResult_t LoadEntityCallback( CChunkFile *pFile, int nParam )
-{
- if (num_entities == MAX_MAP_ENTITIES)
- {
- // Exits.
- g_MapError.ReportError ("num_entities == MAX_MAP_ENTITIES");
- }
-
- entity_t *mapent = &entities[num_entities];
- num_entities++;
- memset(mapent, 0, sizeof(*mapent));
- mapent->numbrushes = 0;
-
- LoadEntity_t LoadEntity;
- LoadEntity.pEntity = mapent;
-
- // No default flags/contents
- LoadEntity.nBaseFlags = 0;
- LoadEntity.nBaseContents = 0;
-
- //
- // Read the entity chunk.
- //
- ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadEntityKeyCallback, &LoadEntity);
-
- return eResult;
-}
-
-
-bool LoadEntsFromMapFile( char const *pFilename )
-{
- //
- // Dummy this up for the texture handling. This can be removed when old .MAP file
- // support is removed.
- //
- g_nMapFileVersion = 400;
-
- //
- // Open the file.
- //
- CChunkFile File;
- ChunkFileResult_t eResult = File.Open( pFilename, ChunkFile_Read );
-
- if(eResult == ChunkFile_Ok)
- {
- num_entities = 0;
-
- //
- // Set up handlers for the subchunks that we are interested in.
- //
- CChunkHandlerMap Handlers;
- Handlers.AddHandler("entity", (ChunkHandler_t)LoadEntityCallback, 0);
-
- File.PushHandlers(&Handlers);
-
- //
- // Read the sub-chunks. We ignore keys in the root of the file.
- //
- while (eResult == ChunkFile_Ok)
- {
- eResult = File.ReadChunk();
- }
-
- File.PopHandlers();
- return true;
- }
- else
- {
- Error("Error in LoadEntsFromMapFile (in-memory file): %s.\n", File.GetErrorText(eResult));
- return false;
- }
-}
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "map_shared.h"
+#include "bsplib.h"
+#include "cmdlib.h"
+
+
+CMapError g_MapError;
+int g_nMapFileVersion;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *szKey -
+// *szValue -
+// *pLoadEntity -
+// Output : ChunkFileResult_t
+//-----------------------------------------------------------------------------
+ChunkFileResult_t LoadEntityKeyCallback(const char *szKey, const char *szValue, LoadEntity_t *pLoadEntity)
+{
+ if (!stricmp(szKey, "classname"))
+ {
+ if (!stricmp(szValue, "func_detail"))
+ {
+ pLoadEntity->nBaseContents = CONTENTS_DETAIL;
+ }
+ else if (!stricmp(szValue, "func_ladder"))
+ {
+ pLoadEntity->nBaseContents = CONTENTS_LADDER;
+ }
+ else if (!stricmp(szValue, "func_water"))
+ {
+ pLoadEntity->nBaseContents = CONTENTS_WATER;
+ }
+ }
+ else if (!stricmp(szKey, "id"))
+ {
+ // UNDONE: flag entity errors by ID instead of index
+ //g_MapError.EntityState( atoi( szValue ) );
+ // rename this field since DME code uses this name
+ SetKeyValue( pLoadEntity->pEntity, "hammerid", szValue );
+ return(ChunkFile_Ok);
+ }
+ else if( !stricmp( szKey, "mapversion" ) )
+ {
+ // .vmf map revision number
+ g_MapRevision = atoi( szValue );
+ SetKeyValue( pLoadEntity->pEntity, szKey, szValue );
+ return ( ChunkFile_Ok );
+ }
+
+ SetKeyValue( pLoadEntity->pEntity, szKey, szValue );
+
+ return(ChunkFile_Ok);
+}
+
+
+static ChunkFileResult_t LoadEntityCallback( CChunkFile *pFile, int nParam )
+{
+ if (num_entities == MAX_MAP_ENTITIES)
+ {
+ // Exits.
+ g_MapError.ReportError ("num_entities == MAX_MAP_ENTITIES");
+ }
+
+ entity_t *mapent = &entities[num_entities];
+ num_entities++;
+ memset(mapent, 0, sizeof(*mapent));
+ mapent->numbrushes = 0;
+
+ LoadEntity_t LoadEntity;
+ LoadEntity.pEntity = mapent;
+
+ // No default flags/contents
+ LoadEntity.nBaseFlags = 0;
+ LoadEntity.nBaseContents = 0;
+
+ //
+ // Read the entity chunk.
+ //
+ ChunkFileResult_t eResult = pFile->ReadChunk((KeyHandler_t)LoadEntityKeyCallback, &LoadEntity);
+
+ return eResult;
+}
+
+
+bool LoadEntsFromMapFile( char const *pFilename )
+{
+ //
+ // Dummy this up for the texture handling. This can be removed when old .MAP file
+ // support is removed.
+ //
+ g_nMapFileVersion = 400;
+
+ //
+ // Open the file.
+ //
+ CChunkFile File;
+ ChunkFileResult_t eResult = File.Open( pFilename, ChunkFile_Read );
+
+ if(eResult == ChunkFile_Ok)
+ {
+ num_entities = 0;
+
+ //
+ // Set up handlers for the subchunks that we are interested in.
+ //
+ CChunkHandlerMap Handlers;
+ Handlers.AddHandler("entity", (ChunkHandler_t)LoadEntityCallback, 0);
+
+ File.PushHandlers(&Handlers);
+
+ //
+ // Read the sub-chunks. We ignore keys in the root of the file.
+ //
+ while (eResult == ChunkFile_Ok)
+ {
+ eResult = File.ReadChunk();
+ }
+
+ File.PopHandlers();
+ return true;
+ }
+ else
+ {
+ Error("Error in LoadEntsFromMapFile (in-memory file): %s.\n", File.GetErrorText(eResult));
+ return false;
+ }
+}
+
+
diff --git a/mp/src/utils/common/map_shared.h b/mp/src/utils/common/map_shared.h
index 08e443a0..5f2b2b62 100644
--- a/mp/src/utils/common/map_shared.h
+++ b/mp/src/utils/common/map_shared.h
@@ -1,91 +1,91 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#ifndef MAP_SHARED_H
-#define MAP_SHARED_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-#include "ChunkFile.h"
-#include "bsplib.h"
-#include "cmdlib.h"
-
-
-struct LoadEntity_t
-{
- entity_t *pEntity;
- int nID;
- int nBaseFlags;
- int nBaseContents;
-};
-
-
-class CMapError
-{
-public:
-
- void BrushState( int brushID )
- {
- m_brushID = brushID;
- }
-
- void BrushSide( int side )
- {
- m_sideIndex = side;
- }
-
- void TextureState( const char *pTextureName )
- {
- Q_strncpy( m_textureName, pTextureName, sizeof( m_textureName ) );
- }
-
- void ClearState( void )
- {
- BrushState( 0 );
- BrushSide( 0 );
- TextureState( "Not a Parse error!" );
- }
-
- //-----------------------------------------------------------------------------
- // Purpose: Hook the map parse errors and report brush/ent/texture state
- // Input : *pErrorString -
- //-----------------------------------------------------------------------------
- void ReportError( const char *pErrorString )
- {
- Error( "Brush %i: %s\nSide %i\nTexture: %s\n", m_brushID, pErrorString, m_sideIndex, m_textureName );
- }
-
- //-----------------------------------------------------------------------------
- // Purpose: Hook the map parse errors and report brush/ent/texture state without exiting.
- // Input : pWarningString -
- //-----------------------------------------------------------------------------
- void ReportWarning( const char *pWarningString )
- {
- printf( "Brush %i, Side %i: %s\n", m_brushID, m_sideIndex, pWarningString );
- }
-
-private:
-
- int m_brushID;
- int m_sideIndex;
- char m_textureName[80];
-};
-
-
-extern CMapError g_MapError;
-extern int g_nMapFileVersion;
-
-
-// Shared mapload code.
-ChunkFileResult_t LoadEntityKeyCallback( const char *szKey, const char *szValue, LoadEntity_t *pLoadEntity );
-
-// Used by VRAD incremental lighting - only load ents from the file and
-// fill in the global entities/num_entities array.
-bool LoadEntsFromMapFile( char const *pFilename );
-
-#endif // MAP_SHARED_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef MAP_SHARED_H
+#define MAP_SHARED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "ChunkFile.h"
+#include "bsplib.h"
+#include "cmdlib.h"
+
+
+struct LoadEntity_t
+{
+ entity_t *pEntity;
+ int nID;
+ int nBaseFlags;
+ int nBaseContents;
+};
+
+
+class CMapError
+{
+public:
+
+ void BrushState( int brushID )
+ {
+ m_brushID = brushID;
+ }
+
+ void BrushSide( int side )
+ {
+ m_sideIndex = side;
+ }
+
+ void TextureState( const char *pTextureName )
+ {
+ Q_strncpy( m_textureName, pTextureName, sizeof( m_textureName ) );
+ }
+
+ void ClearState( void )
+ {
+ BrushState( 0 );
+ BrushSide( 0 );
+ TextureState( "Not a Parse error!" );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Hook the map parse errors and report brush/ent/texture state
+ // Input : *pErrorString -
+ //-----------------------------------------------------------------------------
+ void ReportError( const char *pErrorString )
+ {
+ Error( "Brush %i: %s\nSide %i\nTexture: %s\n", m_brushID, pErrorString, m_sideIndex, m_textureName );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Hook the map parse errors and report brush/ent/texture state without exiting.
+ // Input : pWarningString -
+ //-----------------------------------------------------------------------------
+ void ReportWarning( const char *pWarningString )
+ {
+ printf( "Brush %i, Side %i: %s\n", m_brushID, m_sideIndex, pWarningString );
+ }
+
+private:
+
+ int m_brushID;
+ int m_sideIndex;
+ char m_textureName[80];
+};
+
+
+extern CMapError g_MapError;
+extern int g_nMapFileVersion;
+
+
+// Shared mapload code.
+ChunkFileResult_t LoadEntityKeyCallback( const char *szKey, const char *szValue, LoadEntity_t *pLoadEntity );
+
+// Used by VRAD incremental lighting - only load ents from the file and
+// fill in the global entities/num_entities array.
+bool LoadEntsFromMapFile( char const *pFilename );
+
+#endif // MAP_SHARED_H
diff --git a/mp/src/utils/common/movie.h b/mp/src/utils/common/movie.h
index 78ba92fb..f9055296 100644
--- a/mp/src/utils/common/movie.h
+++ b/mp/src/utils/common/movie.h
@@ -1,34 +1,34 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-#ifndef _MOVIE_H_
-#define _MOVIE_H_
-
-/*
- movie.h
-
- definitions and such for dumping screen shots to make a movie
-*/
-
-typedef struct
-{
- unsigned long tag;
- unsigned long size;
-} movieblockheader_t;
-
-
-typedef struct
-{
- short width;
- short height;
- short depth;
-} movieframe_t;
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef _MOVIE_H_
+#define _MOVIE_H_
+
+/*
+ movie.h
+
+ definitions and such for dumping screen shots to make a movie
+*/
+
+typedef struct
+{
+ unsigned long tag;
+ unsigned long size;
+} movieblockheader_t;
+
+
+typedef struct
+{
+ short width;
+ short height;
+ short depth;
+} movieframe_t;
+
+
+
#endif _MOVIE_H_ \ No newline at end of file
diff --git a/mp/src/utils/common/mpi_stats.cpp b/mp/src/utils/common/mpi_stats.cpp
index 8d9cc5e7..f5840cea 100644
--- a/mp/src/utils/common/mpi_stats.cpp
+++ b/mp/src/utils/common/mpi_stats.cpp
@@ -1,839 +1,839 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-// Nasty headers!
-#include "MySqlDatabase.h"
-#include "tier1/strtools.h"
-#include "vmpi.h"
-#include "vmpi_dispatch.h"
-#include "mpi_stats.h"
-#include "cmdlib.h"
-#include "imysqlwrapper.h"
-#include "threadhelpers.h"
-#include "vmpi_tools_shared.h"
-#include "tier0/icommandline.h"
-
-/*
-
--- MySQL code to create the databases, create the users, and set access privileges.
--- You only need to ever run this once.
-
-create database vrad;
-
-use mysql;
-
-create user vrad_worker;
-create user vmpi_browser;
-
--- This updates the "user" table, which is checked when someone tries to connect to the database.
-grant select,insert,update on vrad.* to vrad_worker;
-grant select on vrad.* to vmpi_browser;
-flush privileges;
-
-/*
-
--- SQL code to (re)create the tables.
-
--- Master generates a unique job ID (in job_master_start) and sends it to workers.
--- Each worker (and the master) make a job_worker_start, link it to the primary job ID,
--- get their own unique ID, which represents that process in that job.
--- All JobWorkerID fields link to the JobWorkerID field in job_worker_start.
-
--- NOTE: do a "use vrad" or "use vvis" first, depending on the DB you want to create.
-
-
-use vrad;
-
-
-drop table job_master_start;
-create table job_master_start (
- JobID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, index id( JobID, MachineName(5) ),
- BSPFilename TINYTEXT NOT NULL,
- StartTime TIMESTAMP NOT NULL,
- MachineName TEXT NOT NULL,
- RunningTimeMS INTEGER UNSIGNED NOT NULL,
- NumWorkers INTEGER UNSIGNED NOT NULL default 0
- );
-
-drop table job_master_end;
-create table job_master_end (
- JobID INTEGER UNSIGNED NOT NULL, PRIMARY KEY ( JobID ),
- NumWorkersConnected SMALLINT UNSIGNED NOT NULL,
- NumWorkersDisconnected SMALLINT UNSIGNED NOT NULL,
- ErrorText TEXT NOT NULL
- );
-
-drop table job_worker_start;
-create table job_worker_start (
- JobWorkerID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
- index index_jobid( JobID ),
- index index_jobworkerid( JobWorkerID ),
-
- JobID INTEGER UNSIGNED NOT NULL, -- links to job_master_start::JobID
- IsMaster BOOL NOT NULL, -- Set to 1 if this "worker" is the master process.
- RunningTimeMS INTEGER UNSIGNED NOT NULL default 0,
- MachineName TEXT NOT NULL,
- WorkerState SMALLINT UNSIGNED NOT NULL default 0, -- 0 = disconnected, 1 = connected
- NumWorkUnits INTEGER UNSIGNED NOT NULL default 0, -- how many work units this worker has completed
- CurrentStage TINYTEXT NOT NULL, -- which compile stage is it on
- Thread0WU INTEGER NOT NULL default 0, -- which WU thread 0 is on
- Thread1WU INTEGER NOT NULL default 0, -- which WU thread 1 is on
- Thread2WU INTEGER NOT NULL default 0, -- which WU thread 2 is on
- Thread3WU INTEGER NOT NULL default 0 -- which WU thread 3 is on
- );
-
-drop table text_messages;
-create table text_messages (
- JobWorkerID INTEGER UNSIGNED NOT NULL, index id( JobWorkerID, MessageIndex ),
- MessageIndex INTEGER UNSIGNED NOT NULL,
- Text TEXT NOT NULL
- );
-
-drop table graph_entry;
-create table graph_entry (
- JobWorkerID INTEGER UNSIGNED NOT NULL, index id( JobWorkerID ),
- MSSinceJobStart INTEGER UNSIGNED NOT NULL,
- BytesSent INTEGER UNSIGNED NOT NULL,
- BytesReceived INTEGER UNSIGNED NOT NULL
- );
-
-drop table events;
-create table events (
- JobWorkerID INTEGER UNSIGNED NOT NULL, index id( JobWorkerID ),
- Text TEXT NOT NULL
- );
-*/
-
-
-
-// Stats set by the app.
-int g_nWorkersConnected = 0;
-int g_nWorkersDisconnected = 0;
-
-
-DWORD g_StatsStartTime;
-
-CMySqlDatabase *g_pDB = NULL;
-
-IMySQL *g_pSQL = NULL;
-CSysModule *g_hMySQLDLL = NULL;
-
-char g_BSPFilename[256];
-
-bool g_bMaster = false;
-unsigned long g_JobPrimaryID = 0; // This represents this job, but doesn't link to a particular machine.
-unsigned long g_JobWorkerID = 0; // A unique key in the DB that represents this machine in this job.
-char g_MachineName[MAX_COMPUTERNAME_LENGTH+1] = {0};
-
-unsigned long g_CurrentMessageIndex = 0;
-
-
-HANDLE g_hPerfThread = NULL;
-DWORD g_PerfThreadID = 0xFEFEFEFE;
-HANDLE g_hPerfThreadExitEvent = NULL;
-
-// These are set by the app and they go into the database.
-extern uint64 g_ThreadWUs[4];
-
-extern uint64 VMPI_GetNumWorkUnitsCompleted( int iProc );
-
-
-// ---------------------------------------------------------------------------------------------------- //
-// This is a helper class to build queries like the stream IO.
-// ---------------------------------------------------------------------------------------------------- //
-
-class CMySQLQuery
-{
-friend class CMySQL;
-
-public:
- // This is like a sprintf, but it will grow the string as necessary.
- void Format( const char *pFormat, ... );
-
- int Execute( IMySQL *pDB );
-
-private:
- CUtlVector<char> m_QueryText;
-};
-
-
-void CMySQLQuery::Format( const char *pFormat, ... )
-{
- #define QUERYTEXT_GROWSIZE 1024
-
- // This keeps growing the buffer and calling _vsnprintf until the buffer is
- // large enough to hold all the data.
- m_QueryText.SetSize( QUERYTEXT_GROWSIZE );
- while ( 1 )
- {
- va_list marker;
- va_start( marker, pFormat );
- int ret = _vsnprintf( m_QueryText.Base(), m_QueryText.Count(), pFormat, marker );
- va_end( marker );
-
- if ( ret < 0 )
- {
- m_QueryText.SetSize( m_QueryText.Count() + QUERYTEXT_GROWSIZE );
- }
- else
- {
- m_QueryText[ m_QueryText.Count() - 1 ] = 0;
- break;
- }
- }
-}
-
-
-int CMySQLQuery::Execute( IMySQL *pDB )
-{
- int ret = pDB->Execute( m_QueryText.Base() );
- m_QueryText.Purge();
- return ret;
-}
-
-
-
-// ---------------------------------------------------------------------------------------------------- //
-// This inserts the necessary backslashes in front of backslashes or quote characters.
-// ---------------------------------------------------------------------------------------------------- //
-
-char* FormatStringForSQL( const char *pText )
-{
- // First, count the quotes in the string. We need to put a backslash in front of each one.
- int nChars = 0;
- const char *pCur = pText;
- while ( *pCur != 0 )
- {
- if ( *pCur == '\"' || *pCur == '\\' )
- ++nChars;
-
- ++pCur;
- ++nChars;
- }
-
- pCur = pText;
- char *pRetVal = new char[nChars+1];
- for ( int i=0; i < nChars; )
- {
- if ( *pCur == '\"' || *pCur == '\\' )
- pRetVal[i++] = '\\';
-
- pRetVal[i++] = *pCur;
- ++pCur;
- }
- pRetVal[nChars] = 0;
-
- return pRetVal;
-}
-
-
-
-// -------------------------------------------------------------------------------- //
-// Commands to add data to the database.
-// -------------------------------------------------------------------------------- //
-class CSQLDBCommandBase : public ISQLDBCommand
-{
-public:
- virtual ~CSQLDBCommandBase()
- {
- }
-
- virtual void deleteThis()
- {
- delete this;
- }
-};
-
-class CSQLDBCommand_WorkerStats : public CSQLDBCommandBase
-{
-public:
- virtual int RunCommand()
- {
- int nCurConnections = VMPI_GetCurrentNumberOfConnections();
-
-
- // Update the NumWorkers entry.
- char query[2048];
- Q_snprintf( query, sizeof( query ), "update job_master_start set NumWorkers=%d where JobID=%lu",
- nCurConnections,
- g_JobPrimaryID );
- g_pSQL->Execute( query );
-
-
- // Update the job_master_worker_stats stuff.
- for ( int i=1; i < nCurConnections; i++ )
- {
- unsigned long jobWorkerID = VMPI_GetJobWorkerID( i );
-
- if ( jobWorkerID != 0xFFFFFFFF )
- {
- Q_snprintf( query, sizeof( query ), "update "
- "job_worker_start set WorkerState=%d, NumWorkUnits=%d where JobWorkerID=%lu",
- VMPI_IsProcConnected( i ),
- (int) VMPI_GetNumWorkUnitsCompleted( i ),
- VMPI_GetJobWorkerID( i )
- );
- g_pSQL->Execute( query );
- }
- }
- return 1;
- }
-};
-
-class CSQLDBCommand_JobMasterEnd : public CSQLDBCommandBase
-{
-public:
-
- virtual int RunCommand()
- {
- CMySQLQuery query;
- query.Format( "insert into job_master_end values ( %lu, %d, %d, \"no errors\" )", g_JobPrimaryID, g_nWorkersConnected, g_nWorkersDisconnected );
- query.Execute( g_pSQL );
-
- // Now set RunningTimeMS.
- unsigned long runningTimeMS = GetTickCount() - g_StatsStartTime;
- query.Format( "update job_master_start set RunningTimeMS=%lu where JobID=%lu", runningTimeMS, g_JobPrimaryID );
- query.Execute( g_pSQL );
- return 1;
- }
-};
-
-
-void UpdateJobWorkerRunningTime()
-{
- unsigned long runningTimeMS = GetTickCount() - g_StatsStartTime;
-
- char curStage[256];
- VMPI_GetCurrentStage( curStage, sizeof( curStage ) );
-
- CMySQLQuery query;
- query.Format( "update job_worker_start set RunningTimeMS=%lu, CurrentStage=\"%s\", "
- "Thread0WU=%d, Thread1WU=%d, Thread2WU=%d, Thread3WU=%d where JobWorkerID=%lu",
- runningTimeMS,
- curStage,
- (int) g_ThreadWUs[0],
- (int) g_ThreadWUs[1],
- (int) g_ThreadWUs[2],
- (int) g_ThreadWUs[3],
- g_JobWorkerID );
- query.Execute( g_pSQL );
-}
-
-
-class CSQLDBCommand_GraphEntry : public CSQLDBCommandBase
-{
-public:
-
- CSQLDBCommand_GraphEntry( DWORD msTime, DWORD nBytesSent, DWORD nBytesReceived )
- {
- m_msTime = msTime;
- m_nBytesSent = nBytesSent;
- m_nBytesReceived = nBytesReceived;
- }
-
- virtual int RunCommand()
- {
- CMySQLQuery query;
- query.Format( "insert into graph_entry (JobWorkerID, MSSinceJobStart, BytesSent, BytesReceived) "
- "values ( %lu, %lu, %lu, %lu )",
- g_JobWorkerID,
- m_msTime,
- m_nBytesSent,
- m_nBytesReceived );
-
- query.Execute( g_pSQL );
-
- UpdateJobWorkerRunningTime();
-
- ++g_CurrentMessageIndex;
- return 1;
- }
-
- DWORD m_nBytesSent;
- DWORD m_nBytesReceived;
- DWORD m_msTime;
-};
-
-
-
-class CSQLDBCommand_TextMessage : public CSQLDBCommandBase
-{
-public:
-
- CSQLDBCommand_TextMessage( const char *pText )
- {
- m_pText = FormatStringForSQL( pText );
- }
-
- virtual ~CSQLDBCommand_TextMessage()
- {
- delete [] m_pText;
- }
-
- virtual int RunCommand()
- {
- CMySQLQuery query;
- query.Format( "insert into text_messages (JobWorkerID, MessageIndex, Text) values ( %lu, %lu, \"%s\" )", g_JobWorkerID, g_CurrentMessageIndex, m_pText );
- query.Execute( g_pSQL );
-
- ++g_CurrentMessageIndex;
- return 1;
- }
-
- char *m_pText;
-};
-
-
-// -------------------------------------------------------------------------------- //
-// Internal helpers.
-// -------------------------------------------------------------------------------- //
-
-// This is the spew output before it has connected to the MySQL database.
-CCriticalSection g_SpewTextCS;
-CUtlVector<char> g_SpewText( 1024 );
-
-
-void VMPI_Stats_SpewHook( const char *pMsg )
-{
- CCriticalSectionLock csLock( &g_SpewTextCS );
- csLock.Lock();
-
- // Queue the text up so we can send it to the DB right away when we connect.
- g_SpewText.AddMultipleToTail( strlen( pMsg ), pMsg );
-}
-
-
-void PerfThread_SendSpewText()
-{
- // Send the spew text to the database.
- CCriticalSectionLock csLock( &g_SpewTextCS );
- csLock.Lock();
-
- if ( g_SpewText.Count() > 0 )
- {
- g_SpewText.AddToTail( 0 );
-
- if ( g_bMPI_StatsTextOutput )
- {
- g_pDB->AddCommandToQueue( new CSQLDBCommand_TextMessage( g_SpewText.Base() ), NULL );
- }
- else
- {
- // Just show one message in the vmpi_job_watch window to let them know that they need
- // to use a command line option to get the output.
- static bool bFirst = true;
- if ( bFirst )
- {
- char msg[512];
- V_snprintf( msg, sizeof( msg ), "%s not enabled", VMPI_GetParamString( mpi_Stats_TextOutput ) );
- bFirst = false;
- g_pDB->AddCommandToQueue( new CSQLDBCommand_TextMessage( msg ), NULL );
- }
- }
-
- g_SpewText.RemoveAll();
- }
-
- csLock.Unlock();
-}
-
-
-void PerfThread_AddGraphEntry( DWORD startTicks, DWORD &lastSent, DWORD &lastReceived )
-{
- // Send the graph entry with data transmission info.
- DWORD curSent = g_nBytesSent + g_nMulticastBytesSent;
- DWORD curReceived = g_nBytesReceived + g_nMulticastBytesReceived;
-
- g_pDB->AddCommandToQueue(
- new CSQLDBCommand_GraphEntry(
- GetTickCount() - startTicks,
- curSent - lastSent,
- curReceived - lastReceived ),
- NULL );
-
- lastSent = curSent;
- lastReceived = curReceived;
-}
-
-
-// This function adds a graph_entry into the database periodically.
-DWORD WINAPI PerfThreadFn( LPVOID pParameter )
-{
- DWORD lastSent = 0;
- DWORD lastReceived = 0;
- DWORD startTicks = GetTickCount();
-
- while ( WaitForSingleObject( g_hPerfThreadExitEvent, 1000 ) != WAIT_OBJECT_0 )
- {
- PerfThread_AddGraphEntry( startTicks, lastSent, lastReceived );
-
- // Send updates for text output.
- PerfThread_SendSpewText();
-
- // If we're the master, update all the worker stats.
- if ( g_bMaster )
- {
- g_pDB->AddCommandToQueue(
- new CSQLDBCommand_WorkerStats,
- NULL );
- }
- }
-
- // Add the remaining text and one last graph entry (which will include the current stage info).
- PerfThread_SendSpewText();
- PerfThread_AddGraphEntry( startTicks, lastSent, lastReceived );
-
- SetEvent( g_hPerfThreadExitEvent );
- return 0;
-}
-
-
-// -------------------------------------------------------------------------------- //
-// VMPI_Stats interface.
-// -------------------------------------------------------------------------------- //
-
-void VMPI_Stats_InstallSpewHook()
-{
- InstallExtraSpewHook( VMPI_Stats_SpewHook );
-}
-
-
-void UnloadMySQLWrapper()
-{
- if ( g_hMySQLDLL )
- {
- if ( g_pSQL )
- {
- g_pSQL->Release();
- g_pSQL = NULL;
- }
-
- Sys_UnloadModule( g_hMySQLDLL );
- g_hMySQLDLL = NULL;
- }
-}
-
-
-bool LoadMySQLWrapper(
- const char *pHostName,
- const char *pDBName,
- const char *pUserName
- )
-{
- UnloadMySQLWrapper();
-
- // Load the DLL and the interface.
- if ( !Sys_LoadInterface( "mysql_wrapper", MYSQL_WRAPPER_VERSION_NAME, &g_hMySQLDLL, (void**)&g_pSQL ) )
- return false;
-
- // Try to init the database.
- if ( !g_pSQL->InitMySQL( pDBName, pHostName, pUserName ) )
- {
- UnloadMySQLWrapper();
- return false;
- }
-
- return true;
-}
-
-
-bool VMPI_Stats_Init_Master(
- const char *pHostName,
- const char *pDBName,
- const char *pUserName,
- const char *pBSPFilename,
- unsigned long *pDBJobID )
-{
- Assert( !g_pDB );
-
- g_bMaster = true;
-
- // Connect the database.
- g_pDB = new CMySqlDatabase;
- if ( !g_pDB || !g_pDB->Initialize() || !LoadMySQLWrapper( pHostName, pDBName, pUserName ) )
- {
- delete g_pDB;
- g_pDB = NULL;
- return false;
- }
-
- DWORD size = sizeof( g_MachineName );
- GetComputerName( g_MachineName, &size );
-
- // Create the job_master_start row.
- Q_FileBase( pBSPFilename, g_BSPFilename, sizeof( g_BSPFilename ) );
-
- g_JobPrimaryID = 0;
- CMySQLQuery query;
- query.Format( "insert into job_master_start ( BSPFilename, StartTime, MachineName, RunningTimeMS ) values ( \"%s\", null, \"%s\", %lu )", g_BSPFilename, g_MachineName, RUNNINGTIME_MS_SENTINEL );
- query.Execute( g_pSQL );
-
- g_JobPrimaryID = g_pSQL->InsertID();
- if ( g_JobPrimaryID == 0 )
- {
- delete g_pDB;
- g_pDB = NULL;
- return false;
- }
-
-
- // Now init the worker portion.
- *pDBJobID = g_JobPrimaryID;
- return VMPI_Stats_Init_Worker( NULL, NULL, NULL, g_JobPrimaryID );
-}
-
-
-
-bool VMPI_Stats_Init_Worker( const char *pHostName, const char *pDBName, const char *pUserName, unsigned long DBJobID )
-{
- g_StatsStartTime = GetTickCount();
-
- // If pDBServerName is null, then we're the master and we just want to make the job_worker_start entry.
- if ( pHostName )
- {
- Assert( !g_pDB );
-
- // Connect the database.
- g_pDB = new CMySqlDatabase;
- if ( !g_pDB || !g_pDB->Initialize() || !LoadMySQLWrapper( pHostName, pDBName, pUserName ) )
- {
- delete g_pDB;
- g_pDB = NULL;
- return false;
- }
-
- // Get our machine name to store in the database.
- DWORD size = sizeof( g_MachineName );
- GetComputerName( g_MachineName, &size );
- }
-
-
- g_JobPrimaryID = DBJobID;
- g_JobWorkerID = 0;
-
- CMySQLQuery query;
- query.Format( "insert into job_worker_start ( JobID, CurrentStage, IsMaster, MachineName ) values ( %lu, \"none\", %d, \"%s\" )",
- g_JobPrimaryID, g_bMaster, g_MachineName );
- query.Execute( g_pSQL );
-
- g_JobWorkerID = g_pSQL->InsertID();
- if ( g_JobWorkerID == 0 )
- {
- delete g_pDB;
- g_pDB = NULL;
- return false;
- }
-
- // Now create a thread that samples perf data and stores it in the database.
- g_hPerfThreadExitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- g_hPerfThread = CreateThread(
- NULL,
- 0,
- PerfThreadFn,
- NULL,
- 0,
- &g_PerfThreadID );
-
- return true;
-}
-
-
-void VMPI_Stats_Term()
-{
- if ( !g_pDB )
- return;
-
- // Stop the thread.
- SetEvent( g_hPerfThreadExitEvent );
- WaitForSingleObject( g_hPerfThread, INFINITE );
-
- CloseHandle( g_hPerfThreadExitEvent );
- g_hPerfThreadExitEvent = NULL;
-
- CloseHandle( g_hPerfThread );
- g_hPerfThread = NULL;
-
- if ( g_bMaster )
- {
- // (Write a job_master_end entry here).
- g_pDB->AddCommandToQueue( new CSQLDBCommand_JobMasterEnd, NULL );
- }
-
- // Wait for up to a second for the DB to finish writing its data.
- DWORD startTime = GetTickCount();
- while ( GetTickCount() - startTime < 1000 )
- {
- if ( g_pDB->QueriesInOutQueue() == 0 )
- break;
- }
-
- delete g_pDB;
- g_pDB = NULL;
-
- UnloadMySQLWrapper();
-}
-
-
-static bool ReadStringFromFile( FILE *fp, char *pStr, int strSize )
-{
- int i=0;
- for ( i; i < strSize-2; i++ )
- {
- if ( fread( &pStr[i], 1, 1, fp ) != 1 ||
- pStr[i] == '\n' )
- {
- break;
- }
- }
-
- pStr[i] = 0;
- return i != 0;
-}
-
-
-// This looks for pDBInfoFilename in the same path as pBaseExeFilename.
-// The file has 3 lines: machine name (with database), database name, username
-void GetDBInfo( const char *pDBInfoFilename, CDBInfo *pInfo )
-{
- char baseExeFilename[512];
- if ( !GetModuleFileName( GetModuleHandle( NULL ), baseExeFilename, sizeof( baseExeFilename ) ) )
- Error( "GetModuleFileName failed." );
-
- // Look for the info file in the same directory as the exe.
- char dbInfoFilename[512];
- Q_strncpy( dbInfoFilename, baseExeFilename, sizeof( dbInfoFilename ) );
- Q_StripFilename( dbInfoFilename );
-
- if ( dbInfoFilename[0] == 0 )
- Q_strncpy( dbInfoFilename, ".", sizeof( dbInfoFilename ) );
-
- Q_strncat( dbInfoFilename, "/", sizeof( dbInfoFilename ), COPY_ALL_CHARACTERS );
- Q_strncat( dbInfoFilename, pDBInfoFilename, sizeof( dbInfoFilename ), COPY_ALL_CHARACTERS );
-
- FILE *fp = fopen( dbInfoFilename, "rt" );
- if ( !fp )
- {
- Error( "Can't open %s for database info.\n", dbInfoFilename );
- }
-
- if ( !ReadStringFromFile( fp, pInfo->m_HostName, sizeof( pInfo->m_HostName ) ) ||
- !ReadStringFromFile( fp, pInfo->m_DBName, sizeof( pInfo->m_DBName ) ) ||
- !ReadStringFromFile( fp, pInfo->m_UserName, sizeof( pInfo->m_UserName ) )
- )
- {
- Error( "%s is not a valid database info file.\n", dbInfoFilename );
- }
-
- fclose( fp );
-}
-
-
-void RunJobWatchApp( char *pCmdLine )
-{
- STARTUPINFO si;
- memset( &si, 0, sizeof( si ) );
- si.cb = sizeof( si );
-
- PROCESS_INFORMATION pi;
- memset( &pi, 0, sizeof( pi ) );
-
- // Working directory should be the same as our exe's directory.
- char dirName[512];
- if ( GetModuleFileName( NULL, dirName, sizeof( dirName ) ) != 0 )
- {
- char *s1 = V_strrchr( dirName, '\\' );
- char *s2 = V_strrchr( dirName, '/' );
- if ( s1 || s2 )
- {
- // Get rid of the last slash.
- s1 = max( s1, s2 );
- s1[0] = 0;
-
- if ( !CreateProcess(
- NULL,
- pCmdLine,
- NULL, // security
- NULL,
- TRUE,
- 0, // flags
- NULL, // environment
- dirName, // current directory
- &si,
- &pi ) )
- {
- Warning( "%s - error launching '%s'\n", VMPI_GetParamString( mpi_Job_Watch ), pCmdLine );
- }
- }
- }
-}
-
-
-void StatsDB_InitStatsDatabase(
- int argc,
- char **argv,
- const char *pDBInfoFilename )
-{
- // Did they disable the stats database?
- if ( !g_bMPI_Stats && !VMPI_IsParamUsed( mpi_Job_Watch ) )
- return;
-
- unsigned long jobPrimaryID;
-
- // Now open the DB.
- if ( g_bMPIMaster )
- {
- CDBInfo dbInfo;
- GetDBInfo( pDBInfoFilename, &dbInfo );
-
- if ( !VMPI_Stats_Init_Master( dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName, argv[argc-1], &jobPrimaryID ) )
- {
- Warning( "VMPI_Stats_Init_Master( %s, %s, %s ) failed.\n", dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName );
-
- // Tell the workers not to use stats.
- dbInfo.m_HostName[0] = 0;
- }
-
- char cmdLine[2048];
- Q_snprintf( cmdLine, sizeof( cmdLine ), "vmpi_job_watch -JobID %d", jobPrimaryID );
-
- Msg( "\nTo watch this job, run this command line:\n%s\n\n", cmdLine );
-
- if ( VMPI_IsParamUsed( mpi_Job_Watch ) )
- {
- // Convenience thing to automatically launch the job watch for this job.
- RunJobWatchApp( cmdLine );
- }
-
- // Send the database info to all the workers.
- SendDBInfo( &dbInfo, jobPrimaryID );
- }
- else
- {
- // Wait to get DB info so we can connect to the MySQL database.
- CDBInfo dbInfo;
- unsigned long jobPrimaryID;
- RecvDBInfo( &dbInfo, &jobPrimaryID );
-
- if ( dbInfo.m_HostName[0] != 0 )
- {
- if ( !VMPI_Stats_Init_Worker( dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName, jobPrimaryID ) )
- Error( "VMPI_Stats_Init_Worker( %s, %s, %s, %d ) failed.\n", dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName, jobPrimaryID );
- }
- }
-}
-
-
-unsigned long StatsDB_GetUniqueJobID()
-{
- return g_JobPrimaryID;
-}
-
-
-unsigned long VMPI_Stats_GetJobWorkerID()
-{
- return g_JobWorkerID;
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+// Nasty headers!
+#include "MySqlDatabase.h"
+#include "tier1/strtools.h"
+#include "vmpi.h"
+#include "vmpi_dispatch.h"
+#include "mpi_stats.h"
+#include "cmdlib.h"
+#include "imysqlwrapper.h"
+#include "threadhelpers.h"
+#include "vmpi_tools_shared.h"
+#include "tier0/icommandline.h"
+
+/*
+
+-- MySQL code to create the databases, create the users, and set access privileges.
+-- You only need to ever run this once.
+
+create database vrad;
+
+use mysql;
+
+create user vrad_worker;
+create user vmpi_browser;
+
+-- This updates the "user" table, which is checked when someone tries to connect to the database.
+grant select,insert,update on vrad.* to vrad_worker;
+grant select on vrad.* to vmpi_browser;
+flush privileges;
+
+/*
+
+-- SQL code to (re)create the tables.
+
+-- Master generates a unique job ID (in job_master_start) and sends it to workers.
+-- Each worker (and the master) make a job_worker_start, link it to the primary job ID,
+-- get their own unique ID, which represents that process in that job.
+-- All JobWorkerID fields link to the JobWorkerID field in job_worker_start.
+
+-- NOTE: do a "use vrad" or "use vvis" first, depending on the DB you want to create.
+
+
+use vrad;
+
+
+drop table job_master_start;
+create table job_master_start (
+ JobID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, index id( JobID, MachineName(5) ),
+ BSPFilename TINYTEXT NOT NULL,
+ StartTime TIMESTAMP NOT NULL,
+ MachineName TEXT NOT NULL,
+ RunningTimeMS INTEGER UNSIGNED NOT NULL,
+ NumWorkers INTEGER UNSIGNED NOT NULL default 0
+ );
+
+drop table job_master_end;
+create table job_master_end (
+ JobID INTEGER UNSIGNED NOT NULL, PRIMARY KEY ( JobID ),
+ NumWorkersConnected SMALLINT UNSIGNED NOT NULL,
+ NumWorkersDisconnected SMALLINT UNSIGNED NOT NULL,
+ ErrorText TEXT NOT NULL
+ );
+
+drop table job_worker_start;
+create table job_worker_start (
+ JobWorkerID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+ index index_jobid( JobID ),
+ index index_jobworkerid( JobWorkerID ),
+
+ JobID INTEGER UNSIGNED NOT NULL, -- links to job_master_start::JobID
+ IsMaster BOOL NOT NULL, -- Set to 1 if this "worker" is the master process.
+ RunningTimeMS INTEGER UNSIGNED NOT NULL default 0,
+ MachineName TEXT NOT NULL,
+ WorkerState SMALLINT UNSIGNED NOT NULL default 0, -- 0 = disconnected, 1 = connected
+ NumWorkUnits INTEGER UNSIGNED NOT NULL default 0, -- how many work units this worker has completed
+ CurrentStage TINYTEXT NOT NULL, -- which compile stage is it on
+ Thread0WU INTEGER NOT NULL default 0, -- which WU thread 0 is on
+ Thread1WU INTEGER NOT NULL default 0, -- which WU thread 1 is on
+ Thread2WU INTEGER NOT NULL default 0, -- which WU thread 2 is on
+ Thread3WU INTEGER NOT NULL default 0 -- which WU thread 3 is on
+ );
+
+drop table text_messages;
+create table text_messages (
+ JobWorkerID INTEGER UNSIGNED NOT NULL, index id( JobWorkerID, MessageIndex ),
+ MessageIndex INTEGER UNSIGNED NOT NULL,
+ Text TEXT NOT NULL
+ );
+
+drop table graph_entry;
+create table graph_entry (
+ JobWorkerID INTEGER UNSIGNED NOT NULL, index id( JobWorkerID ),
+ MSSinceJobStart INTEGER UNSIGNED NOT NULL,
+ BytesSent INTEGER UNSIGNED NOT NULL,
+ BytesReceived INTEGER UNSIGNED NOT NULL
+ );
+
+drop table events;
+create table events (
+ JobWorkerID INTEGER UNSIGNED NOT NULL, index id( JobWorkerID ),
+ Text TEXT NOT NULL
+ );
+*/
+
+
+
+// Stats set by the app.
+int g_nWorkersConnected = 0;
+int g_nWorkersDisconnected = 0;
+
+
+DWORD g_StatsStartTime;
+
+CMySqlDatabase *g_pDB = NULL;
+
+IMySQL *g_pSQL = NULL;
+CSysModule *g_hMySQLDLL = NULL;
+
+char g_BSPFilename[256];
+
+bool g_bMaster = false;
+unsigned long g_JobPrimaryID = 0; // This represents this job, but doesn't link to a particular machine.
+unsigned long g_JobWorkerID = 0; // A unique key in the DB that represents this machine in this job.
+char g_MachineName[MAX_COMPUTERNAME_LENGTH+1] = {0};
+
+unsigned long g_CurrentMessageIndex = 0;
+
+
+HANDLE g_hPerfThread = NULL;
+DWORD g_PerfThreadID = 0xFEFEFEFE;
+HANDLE g_hPerfThreadExitEvent = NULL;
+
+// These are set by the app and they go into the database.
+extern uint64 g_ThreadWUs[4];
+
+extern uint64 VMPI_GetNumWorkUnitsCompleted( int iProc );
+
+
+// ---------------------------------------------------------------------------------------------------- //
+// This is a helper class to build queries like the stream IO.
+// ---------------------------------------------------------------------------------------------------- //
+
+class CMySQLQuery
+{
+friend class CMySQL;
+
+public:
+ // This is like a sprintf, but it will grow the string as necessary.
+ void Format( const char *pFormat, ... );
+
+ int Execute( IMySQL *pDB );
+
+private:
+ CUtlVector<char> m_QueryText;
+};
+
+
+void CMySQLQuery::Format( const char *pFormat, ... )
+{
+ #define QUERYTEXT_GROWSIZE 1024
+
+ // This keeps growing the buffer and calling _vsnprintf until the buffer is
+ // large enough to hold all the data.
+ m_QueryText.SetSize( QUERYTEXT_GROWSIZE );
+ while ( 1 )
+ {
+ va_list marker;
+ va_start( marker, pFormat );
+ int ret = _vsnprintf( m_QueryText.Base(), m_QueryText.Count(), pFormat, marker );
+ va_end( marker );
+
+ if ( ret < 0 )
+ {
+ m_QueryText.SetSize( m_QueryText.Count() + QUERYTEXT_GROWSIZE );
+ }
+ else
+ {
+ m_QueryText[ m_QueryText.Count() - 1 ] = 0;
+ break;
+ }
+ }
+}
+
+
+int CMySQLQuery::Execute( IMySQL *pDB )
+{
+ int ret = pDB->Execute( m_QueryText.Base() );
+ m_QueryText.Purge();
+ return ret;
+}
+
+
+
+// ---------------------------------------------------------------------------------------------------- //
+// This inserts the necessary backslashes in front of backslashes or quote characters.
+// ---------------------------------------------------------------------------------------------------- //
+
+char* FormatStringForSQL( const char *pText )
+{
+ // First, count the quotes in the string. We need to put a backslash in front of each one.
+ int nChars = 0;
+ const char *pCur = pText;
+ while ( *pCur != 0 )
+ {
+ if ( *pCur == '\"' || *pCur == '\\' )
+ ++nChars;
+
+ ++pCur;
+ ++nChars;
+ }
+
+ pCur = pText;
+ char *pRetVal = new char[nChars+1];
+ for ( int i=0; i < nChars; )
+ {
+ if ( *pCur == '\"' || *pCur == '\\' )
+ pRetVal[i++] = '\\';
+
+ pRetVal[i++] = *pCur;
+ ++pCur;
+ }
+ pRetVal[nChars] = 0;
+
+ return pRetVal;
+}
+
+
+
+// -------------------------------------------------------------------------------- //
+// Commands to add data to the database.
+// -------------------------------------------------------------------------------- //
+class CSQLDBCommandBase : public ISQLDBCommand
+{
+public:
+ virtual ~CSQLDBCommandBase()
+ {
+ }
+
+ virtual void deleteThis()
+ {
+ delete this;
+ }
+};
+
+class CSQLDBCommand_WorkerStats : public CSQLDBCommandBase
+{
+public:
+ virtual int RunCommand()
+ {
+ int nCurConnections = VMPI_GetCurrentNumberOfConnections();
+
+
+ // Update the NumWorkers entry.
+ char query[2048];
+ Q_snprintf( query, sizeof( query ), "update job_master_start set NumWorkers=%d where JobID=%lu",
+ nCurConnections,
+ g_JobPrimaryID );
+ g_pSQL->Execute( query );
+
+
+ // Update the job_master_worker_stats stuff.
+ for ( int i=1; i < nCurConnections; i++ )
+ {
+ unsigned long jobWorkerID = VMPI_GetJobWorkerID( i );
+
+ if ( jobWorkerID != 0xFFFFFFFF )
+ {
+ Q_snprintf( query, sizeof( query ), "update "
+ "job_worker_start set WorkerState=%d, NumWorkUnits=%d where JobWorkerID=%lu",
+ VMPI_IsProcConnected( i ),
+ (int) VMPI_GetNumWorkUnitsCompleted( i ),
+ VMPI_GetJobWorkerID( i )
+ );
+ g_pSQL->Execute( query );
+ }
+ }
+ return 1;
+ }
+};
+
+class CSQLDBCommand_JobMasterEnd : public CSQLDBCommandBase
+{
+public:
+
+ virtual int RunCommand()
+ {
+ CMySQLQuery query;
+ query.Format( "insert into job_master_end values ( %lu, %d, %d, \"no errors\" )", g_JobPrimaryID, g_nWorkersConnected, g_nWorkersDisconnected );
+ query.Execute( g_pSQL );
+
+ // Now set RunningTimeMS.
+ unsigned long runningTimeMS = GetTickCount() - g_StatsStartTime;
+ query.Format( "update job_master_start set RunningTimeMS=%lu where JobID=%lu", runningTimeMS, g_JobPrimaryID );
+ query.Execute( g_pSQL );
+ return 1;
+ }
+};
+
+
+void UpdateJobWorkerRunningTime()
+{
+ unsigned long runningTimeMS = GetTickCount() - g_StatsStartTime;
+
+ char curStage[256];
+ VMPI_GetCurrentStage( curStage, sizeof( curStage ) );
+
+ CMySQLQuery query;
+ query.Format( "update job_worker_start set RunningTimeMS=%lu, CurrentStage=\"%s\", "
+ "Thread0WU=%d, Thread1WU=%d, Thread2WU=%d, Thread3WU=%d where JobWorkerID=%lu",
+ runningTimeMS,
+ curStage,
+ (int) g_ThreadWUs[0],
+ (int) g_ThreadWUs[1],
+ (int) g_ThreadWUs[2],
+ (int) g_ThreadWUs[3],
+ g_JobWorkerID );
+ query.Execute( g_pSQL );
+}
+
+
+class CSQLDBCommand_GraphEntry : public CSQLDBCommandBase
+{
+public:
+
+ CSQLDBCommand_GraphEntry( DWORD msTime, DWORD nBytesSent, DWORD nBytesReceived )
+ {
+ m_msTime = msTime;
+ m_nBytesSent = nBytesSent;
+ m_nBytesReceived = nBytesReceived;
+ }
+
+ virtual int RunCommand()
+ {
+ CMySQLQuery query;
+ query.Format( "insert into graph_entry (JobWorkerID, MSSinceJobStart, BytesSent, BytesReceived) "
+ "values ( %lu, %lu, %lu, %lu )",
+ g_JobWorkerID,
+ m_msTime,
+ m_nBytesSent,
+ m_nBytesReceived );
+
+ query.Execute( g_pSQL );
+
+ UpdateJobWorkerRunningTime();
+
+ ++g_CurrentMessageIndex;
+ return 1;
+ }
+
+ DWORD m_nBytesSent;
+ DWORD m_nBytesReceived;
+ DWORD m_msTime;
+};
+
+
+
+class CSQLDBCommand_TextMessage : public CSQLDBCommandBase
+{
+public:
+
+ CSQLDBCommand_TextMessage( const char *pText )
+ {
+ m_pText = FormatStringForSQL( pText );
+ }
+
+ virtual ~CSQLDBCommand_TextMessage()
+ {
+ delete [] m_pText;
+ }
+
+ virtual int RunCommand()
+ {
+ CMySQLQuery query;
+ query.Format( "insert into text_messages (JobWorkerID, MessageIndex, Text) values ( %lu, %lu, \"%s\" )", g_JobWorkerID, g_CurrentMessageIndex, m_pText );
+ query.Execute( g_pSQL );
+
+ ++g_CurrentMessageIndex;
+ return 1;
+ }
+
+ char *m_pText;
+};
+
+
+// -------------------------------------------------------------------------------- //
+// Internal helpers.
+// -------------------------------------------------------------------------------- //
+
+// This is the spew output before it has connected to the MySQL database.
+CCriticalSection g_SpewTextCS;
+CUtlVector<char> g_SpewText( 1024 );
+
+
+void VMPI_Stats_SpewHook( const char *pMsg )
+{
+ CCriticalSectionLock csLock( &g_SpewTextCS );
+ csLock.Lock();
+
+ // Queue the text up so we can send it to the DB right away when we connect.
+ g_SpewText.AddMultipleToTail( strlen( pMsg ), pMsg );
+}
+
+
+void PerfThread_SendSpewText()
+{
+ // Send the spew text to the database.
+ CCriticalSectionLock csLock( &g_SpewTextCS );
+ csLock.Lock();
+
+ if ( g_SpewText.Count() > 0 )
+ {
+ g_SpewText.AddToTail( 0 );
+
+ if ( g_bMPI_StatsTextOutput )
+ {
+ g_pDB->AddCommandToQueue( new CSQLDBCommand_TextMessage( g_SpewText.Base() ), NULL );
+ }
+ else
+ {
+ // Just show one message in the vmpi_job_watch window to let them know that they need
+ // to use a command line option to get the output.
+ static bool bFirst = true;
+ if ( bFirst )
+ {
+ char msg[512];
+ V_snprintf( msg, sizeof( msg ), "%s not enabled", VMPI_GetParamString( mpi_Stats_TextOutput ) );
+ bFirst = false;
+ g_pDB->AddCommandToQueue( new CSQLDBCommand_TextMessage( msg ), NULL );
+ }
+ }
+
+ g_SpewText.RemoveAll();
+ }
+
+ csLock.Unlock();
+}
+
+
+void PerfThread_AddGraphEntry( DWORD startTicks, DWORD &lastSent, DWORD &lastReceived )
+{
+ // Send the graph entry with data transmission info.
+ DWORD curSent = g_nBytesSent + g_nMulticastBytesSent;
+ DWORD curReceived = g_nBytesReceived + g_nMulticastBytesReceived;
+
+ g_pDB->AddCommandToQueue(
+ new CSQLDBCommand_GraphEntry(
+ GetTickCount() - startTicks,
+ curSent - lastSent,
+ curReceived - lastReceived ),
+ NULL );
+
+ lastSent = curSent;
+ lastReceived = curReceived;
+}
+
+
+// This function adds a graph_entry into the database periodically.
+DWORD WINAPI PerfThreadFn( LPVOID pParameter )
+{
+ DWORD lastSent = 0;
+ DWORD lastReceived = 0;
+ DWORD startTicks = GetTickCount();
+
+ while ( WaitForSingleObject( g_hPerfThreadExitEvent, 1000 ) != WAIT_OBJECT_0 )
+ {
+ PerfThread_AddGraphEntry( startTicks, lastSent, lastReceived );
+
+ // Send updates for text output.
+ PerfThread_SendSpewText();
+
+ // If we're the master, update all the worker stats.
+ if ( g_bMaster )
+ {
+ g_pDB->AddCommandToQueue(
+ new CSQLDBCommand_WorkerStats,
+ NULL );
+ }
+ }
+
+ // Add the remaining text and one last graph entry (which will include the current stage info).
+ PerfThread_SendSpewText();
+ PerfThread_AddGraphEntry( startTicks, lastSent, lastReceived );
+
+ SetEvent( g_hPerfThreadExitEvent );
+ return 0;
+}
+
+
+// -------------------------------------------------------------------------------- //
+// VMPI_Stats interface.
+// -------------------------------------------------------------------------------- //
+
+void VMPI_Stats_InstallSpewHook()
+{
+ InstallExtraSpewHook( VMPI_Stats_SpewHook );
+}
+
+
+void UnloadMySQLWrapper()
+{
+ if ( g_hMySQLDLL )
+ {
+ if ( g_pSQL )
+ {
+ g_pSQL->Release();
+ g_pSQL = NULL;
+ }
+
+ Sys_UnloadModule( g_hMySQLDLL );
+ g_hMySQLDLL = NULL;
+ }
+}
+
+
+bool LoadMySQLWrapper(
+ const char *pHostName,
+ const char *pDBName,
+ const char *pUserName
+ )
+{
+ UnloadMySQLWrapper();
+
+ // Load the DLL and the interface.
+ if ( !Sys_LoadInterface( "mysql_wrapper", MYSQL_WRAPPER_VERSION_NAME, &g_hMySQLDLL, (void**)&g_pSQL ) )
+ return false;
+
+ // Try to init the database.
+ if ( !g_pSQL->InitMySQL( pDBName, pHostName, pUserName ) )
+ {
+ UnloadMySQLWrapper();
+ return false;
+ }
+
+ return true;
+}
+
+
+bool VMPI_Stats_Init_Master(
+ const char *pHostName,
+ const char *pDBName,
+ const char *pUserName,
+ const char *pBSPFilename,
+ unsigned long *pDBJobID )
+{
+ Assert( !g_pDB );
+
+ g_bMaster = true;
+
+ // Connect the database.
+ g_pDB = new CMySqlDatabase;
+ if ( !g_pDB || !g_pDB->Initialize() || !LoadMySQLWrapper( pHostName, pDBName, pUserName ) )
+ {
+ delete g_pDB;
+ g_pDB = NULL;
+ return false;
+ }
+
+ DWORD size = sizeof( g_MachineName );
+ GetComputerName( g_MachineName, &size );
+
+ // Create the job_master_start row.
+ Q_FileBase( pBSPFilename, g_BSPFilename, sizeof( g_BSPFilename ) );
+
+ g_JobPrimaryID = 0;
+ CMySQLQuery query;
+ query.Format( "insert into job_master_start ( BSPFilename, StartTime, MachineName, RunningTimeMS ) values ( \"%s\", null, \"%s\", %lu )", g_BSPFilename, g_MachineName, RUNNINGTIME_MS_SENTINEL );
+ query.Execute( g_pSQL );
+
+ g_JobPrimaryID = g_pSQL->InsertID();
+ if ( g_JobPrimaryID == 0 )
+ {
+ delete g_pDB;
+ g_pDB = NULL;
+ return false;
+ }
+
+
+ // Now init the worker portion.
+ *pDBJobID = g_JobPrimaryID;
+ return VMPI_Stats_Init_Worker( NULL, NULL, NULL, g_JobPrimaryID );
+}
+
+
+
+bool VMPI_Stats_Init_Worker( const char *pHostName, const char *pDBName, const char *pUserName, unsigned long DBJobID )
+{
+ g_StatsStartTime = GetTickCount();
+
+ // If pDBServerName is null, then we're the master and we just want to make the job_worker_start entry.
+ if ( pHostName )
+ {
+ Assert( !g_pDB );
+
+ // Connect the database.
+ g_pDB = new CMySqlDatabase;
+ if ( !g_pDB || !g_pDB->Initialize() || !LoadMySQLWrapper( pHostName, pDBName, pUserName ) )
+ {
+ delete g_pDB;
+ g_pDB = NULL;
+ return false;
+ }
+
+ // Get our machine name to store in the database.
+ DWORD size = sizeof( g_MachineName );
+ GetComputerName( g_MachineName, &size );
+ }
+
+
+ g_JobPrimaryID = DBJobID;
+ g_JobWorkerID = 0;
+
+ CMySQLQuery query;
+ query.Format( "insert into job_worker_start ( JobID, CurrentStage, IsMaster, MachineName ) values ( %lu, \"none\", %d, \"%s\" )",
+ g_JobPrimaryID, g_bMaster, g_MachineName );
+ query.Execute( g_pSQL );
+
+ g_JobWorkerID = g_pSQL->InsertID();
+ if ( g_JobWorkerID == 0 )
+ {
+ delete g_pDB;
+ g_pDB = NULL;
+ return false;
+ }
+
+ // Now create a thread that samples perf data and stores it in the database.
+ g_hPerfThreadExitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ g_hPerfThread = CreateThread(
+ NULL,
+ 0,
+ PerfThreadFn,
+ NULL,
+ 0,
+ &g_PerfThreadID );
+
+ return true;
+}
+
+
+void VMPI_Stats_Term()
+{
+ if ( !g_pDB )
+ return;
+
+ // Stop the thread.
+ SetEvent( g_hPerfThreadExitEvent );
+ WaitForSingleObject( g_hPerfThread, INFINITE );
+
+ CloseHandle( g_hPerfThreadExitEvent );
+ g_hPerfThreadExitEvent = NULL;
+
+ CloseHandle( g_hPerfThread );
+ g_hPerfThread = NULL;
+
+ if ( g_bMaster )
+ {
+ // (Write a job_master_end entry here).
+ g_pDB->AddCommandToQueue( new CSQLDBCommand_JobMasterEnd, NULL );
+ }
+
+ // Wait for up to a second for the DB to finish writing its data.
+ DWORD startTime = GetTickCount();
+ while ( GetTickCount() - startTime < 1000 )
+ {
+ if ( g_pDB->QueriesInOutQueue() == 0 )
+ break;
+ }
+
+ delete g_pDB;
+ g_pDB = NULL;
+
+ UnloadMySQLWrapper();
+}
+
+
+static bool ReadStringFromFile( FILE *fp, char *pStr, int strSize )
+{
+ int i=0;
+ for ( i; i < strSize-2; i++ )
+ {
+ if ( fread( &pStr[i], 1, 1, fp ) != 1 ||
+ pStr[i] == '\n' )
+ {
+ break;
+ }
+ }
+
+ pStr[i] = 0;
+ return i != 0;
+}
+
+
+// This looks for pDBInfoFilename in the same path as pBaseExeFilename.
+// The file has 3 lines: machine name (with database), database name, username
+void GetDBInfo( const char *pDBInfoFilename, CDBInfo *pInfo )
+{
+ char baseExeFilename[512];
+ if ( !GetModuleFileName( GetModuleHandle( NULL ), baseExeFilename, sizeof( baseExeFilename ) ) )
+ Error( "GetModuleFileName failed." );
+
+ // Look for the info file in the same directory as the exe.
+ char dbInfoFilename[512];
+ Q_strncpy( dbInfoFilename, baseExeFilename, sizeof( dbInfoFilename ) );
+ Q_StripFilename( dbInfoFilename );
+
+ if ( dbInfoFilename[0] == 0 )
+ Q_strncpy( dbInfoFilename, ".", sizeof( dbInfoFilename ) );
+
+ Q_strncat( dbInfoFilename, "/", sizeof( dbInfoFilename ), COPY_ALL_CHARACTERS );
+ Q_strncat( dbInfoFilename, pDBInfoFilename, sizeof( dbInfoFilename ), COPY_ALL_CHARACTERS );
+
+ FILE *fp = fopen( dbInfoFilename, "rt" );
+ if ( !fp )
+ {
+ Error( "Can't open %s for database info.\n", dbInfoFilename );
+ }
+
+ if ( !ReadStringFromFile( fp, pInfo->m_HostName, sizeof( pInfo->m_HostName ) ) ||
+ !ReadStringFromFile( fp, pInfo->m_DBName, sizeof( pInfo->m_DBName ) ) ||
+ !ReadStringFromFile( fp, pInfo->m_UserName, sizeof( pInfo->m_UserName ) )
+ )
+ {
+ Error( "%s is not a valid database info file.\n", dbInfoFilename );
+ }
+
+ fclose( fp );
+}
+
+
+void RunJobWatchApp( char *pCmdLine )
+{
+ STARTUPINFO si;
+ memset( &si, 0, sizeof( si ) );
+ si.cb = sizeof( si );
+
+ PROCESS_INFORMATION pi;
+ memset( &pi, 0, sizeof( pi ) );
+
+ // Working directory should be the same as our exe's directory.
+ char dirName[512];
+ if ( GetModuleFileName( NULL, dirName, sizeof( dirName ) ) != 0 )
+ {
+ char *s1 = V_strrchr( dirName, '\\' );
+ char *s2 = V_strrchr( dirName, '/' );
+ if ( s1 || s2 )
+ {
+ // Get rid of the last slash.
+ s1 = max( s1, s2 );
+ s1[0] = 0;
+
+ if ( !CreateProcess(
+ NULL,
+ pCmdLine,
+ NULL, // security
+ NULL,
+ TRUE,
+ 0, // flags
+ NULL, // environment
+ dirName, // current directory
+ &si,
+ &pi ) )
+ {
+ Warning( "%s - error launching '%s'\n", VMPI_GetParamString( mpi_Job_Watch ), pCmdLine );
+ }
+ }
+ }
+}
+
+
+void StatsDB_InitStatsDatabase(
+ int argc,
+ char **argv,
+ const char *pDBInfoFilename )
+{
+ // Did they disable the stats database?
+ if ( !g_bMPI_Stats && !VMPI_IsParamUsed( mpi_Job_Watch ) )
+ return;
+
+ unsigned long jobPrimaryID;
+
+ // Now open the DB.
+ if ( g_bMPIMaster )
+ {
+ CDBInfo dbInfo;
+ GetDBInfo( pDBInfoFilename, &dbInfo );
+
+ if ( !VMPI_Stats_Init_Master( dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName, argv[argc-1], &jobPrimaryID ) )
+ {
+ Warning( "VMPI_Stats_Init_Master( %s, %s, %s ) failed.\n", dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName );
+
+ // Tell the workers not to use stats.
+ dbInfo.m_HostName[0] = 0;
+ }
+
+ char cmdLine[2048];
+ Q_snprintf( cmdLine, sizeof( cmdLine ), "vmpi_job_watch -JobID %d", jobPrimaryID );
+
+ Msg( "\nTo watch this job, run this command line:\n%s\n\n", cmdLine );
+
+ if ( VMPI_IsParamUsed( mpi_Job_Watch ) )
+ {
+ // Convenience thing to automatically launch the job watch for this job.
+ RunJobWatchApp( cmdLine );
+ }
+
+ // Send the database info to all the workers.
+ SendDBInfo( &dbInfo, jobPrimaryID );
+ }
+ else
+ {
+ // Wait to get DB info so we can connect to the MySQL database.
+ CDBInfo dbInfo;
+ unsigned long jobPrimaryID;
+ RecvDBInfo( &dbInfo, &jobPrimaryID );
+
+ if ( dbInfo.m_HostName[0] != 0 )
+ {
+ if ( !VMPI_Stats_Init_Worker( dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName, jobPrimaryID ) )
+ Error( "VMPI_Stats_Init_Worker( %s, %s, %s, %d ) failed.\n", dbInfo.m_HostName, dbInfo.m_DBName, dbInfo.m_UserName, jobPrimaryID );
+ }
+ }
+}
+
+
+unsigned long StatsDB_GetUniqueJobID()
+{
+ return g_JobPrimaryID;
+}
+
+
+unsigned long VMPI_Stats_GetJobWorkerID()
+{
+ return g_JobWorkerID;
} \ No newline at end of file
diff --git a/mp/src/utils/common/mpi_stats.h b/mp/src/utils/common/mpi_stats.h
index 10aa6162..841db3a2 100644
--- a/mp/src/utils/common/mpi_stats.h
+++ b/mp/src/utils/common/mpi_stats.h
@@ -1,59 +1,59 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef MPI_STATS_H
-#define MPI_STATS_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-// The VMPI stats module reports a bunch of statistics to a MySQL server, and the
-// stats can be used to trace and graph a compile session.
-//
-
-// Call this as soon as possible to initialize spew hooks.
-void VMPI_Stats_InstallSpewHook();
-
-//
-// pDBServerName is the hostname (or dotted IP address) of the MySQL server to connect to.
-// pBSPFilename is the last argument on the command line.
-// pMachineIP is the dotted IP address of this machine.
-// jobID is an 8-byte unique identifier for this job.
-//
-bool VMPI_Stats_Init_Master( const char *pHostName, const char *pDBName, const char *pUserName, const char *pBSPFilename, unsigned long *pDBJobID );
-bool VMPI_Stats_Init_Worker( const char *pHostName, const char *pDBName, const char *pUserName, unsigned long DBJobID );
-void VMPI_Stats_Term();
-
-// Add a generic text event to the database.
-void VMPI_Stats_AddEventText( const char *pText );
-
-class CDBInfo
-{
-public:
- char m_HostName[128];
- char m_DBName[128];
- char m_UserName[128];
-};
-
-// If you're the master, this loads pDBInfoFilename, sends that info to the workers, and
-// connects to the database.
-//
-// If you're a worker, this waits for the DB info, then connects to the database.
-void StatsDB_InitStatsDatabase(
- int argc,
- char **argv,
- const char *pDBInfoFilename );
-
-// The database gives back a unique ID for the job.
-unsigned long StatsDB_GetUniqueJobID();
-
-// Get the worker ID (used for the JobWorkerID fields in the database).
-unsigned long VMPI_Stats_GetJobWorkerID();
-
-
-#endif // MPI_STATS_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MPI_STATS_H
+#define MPI_STATS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// The VMPI stats module reports a bunch of statistics to a MySQL server, and the
+// stats can be used to trace and graph a compile session.
+//
+
+// Call this as soon as possible to initialize spew hooks.
+void VMPI_Stats_InstallSpewHook();
+
+//
+// pDBServerName is the hostname (or dotted IP address) of the MySQL server to connect to.
+// pBSPFilename is the last argument on the command line.
+// pMachineIP is the dotted IP address of this machine.
+// jobID is an 8-byte unique identifier for this job.
+//
+bool VMPI_Stats_Init_Master( const char *pHostName, const char *pDBName, const char *pUserName, const char *pBSPFilename, unsigned long *pDBJobID );
+bool VMPI_Stats_Init_Worker( const char *pHostName, const char *pDBName, const char *pUserName, unsigned long DBJobID );
+void VMPI_Stats_Term();
+
+// Add a generic text event to the database.
+void VMPI_Stats_AddEventText( const char *pText );
+
+class CDBInfo
+{
+public:
+ char m_HostName[128];
+ char m_DBName[128];
+ char m_UserName[128];
+};
+
+// If you're the master, this loads pDBInfoFilename, sends that info to the workers, and
+// connects to the database.
+//
+// If you're a worker, this waits for the DB info, then connects to the database.
+void StatsDB_InitStatsDatabase(
+ int argc,
+ char **argv,
+ const char *pDBInfoFilename );
+
+// The database gives back a unique ID for the job.
+unsigned long StatsDB_GetUniqueJobID();
+
+// Get the worker ID (used for the JobWorkerID fields in the database).
+unsigned long VMPI_Stats_GetJobWorkerID();
+
+
+#endif // MPI_STATS_H
diff --git a/mp/src/utils/common/mstristrip.cpp b/mp/src/utils/common/mstristrip.cpp
index 9e611f94..ad6ebdc8 100644
--- a/mp/src/utils/common/mstristrip.cpp
+++ b/mp/src/utils/common/mstristrip.cpp
@@ -1,930 +1,930 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-//-----------------------------------------------------------------------------
-// FILE: TRISTRIP.CPP
-//
-// Desc: Xbox tristripper
-//
-// Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-
-// identifier was truncated to '255' characters in the debug information
-#pragma warning(disable: 4786)
-// conversion from 'double' to 'float'
-#pragma warning(disable: 4244)
-#pragma warning(disable: 4530)
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <algorithm>
-#include <list>
-#include <vector>
-
-#include <assert.h>
-#ifdef _DEBUG
-#include <crtdbg.h>
-#endif
-
-#include "mstristrip.h"
-
-using namespace std;
-
-//=========================================================================
-// structs
-//=========================================================================
-typedef vector<WORD> STRIPVERTS;
-typedef list<STRIPVERTS *> STRIPLIST;
-typedef WORD (*TRIANGLELIST)[3];
-
-struct TRIANGLEINFO
-{
- int neighbortri[3];
- int neighboredge[3];
-};
-
-// return true if strip starts clockwise
-inline bool FIsStripCW(const STRIPVERTS &stripvertices)
-{
- // last index should have cw/ccw bool
- return !!stripvertices[stripvertices.size() - 1];
-}
-
-// return length of strip
-inline int StripLen(const STRIPVERTS &stripvertices)
-{
- return (int)stripvertices.size() - 1;
-}
-
-// free all stripverts and clear the striplist
-inline void FreeStripListVerts(STRIPLIST *pstriplist)
-{
- STRIPLIST::iterator istriplist = pstriplist->begin();
- while(istriplist != pstriplist->end())
- {
- STRIPVERTS *pstripverts = *istriplist;
- delete pstripverts;
- pstriplist->erase(istriplist++);
- }
-}
-
-//=========================================================================
-// main stripper class
-//=========================================================================
-class CStripper
-{
-public:
- // ctors/dtors
- CStripper(int numtris, TRIANGLELIST ptriangles);
- ~CStripper();
-
- // initialize tri info
- void InitTriangleInfo(int tri, int vert);
-
- // get maximum length strip from tri/vert
- int CreateStrip(int tri, int vert, int maxlen, int *pswaps,
- bool flookahead, bool fstartcw, int *pstriptris, int *pstripverts);
-
- // stripify entire mesh
- void BuildStrips(STRIPLIST *pstriplist, int maxlen, bool flookahead);
-
- // blast strip indices to ppstripindices
- int CreateManyStrips(STRIPLIST *pstriplist, WORD **ppstripindices);
- int CreateLongStrip(STRIPLIST *pstriplist, WORD **ppstripindices);
-
- inline int GetNeighborCount(int tri)
- {
- int count = 0;
- for(int vert = 0; vert < 3; vert++)
- {
- int neighbortri = m_ptriinfo[tri].neighbortri[vert];
- count += (neighbortri != -1) && !m_pused[neighbortri];
- }
- return count;
- }
-
- // from callee
- int m_numtris; // # tris
- TRIANGLELIST m_ptriangles; // trilist
-
- TRIANGLEINFO *m_ptriinfo; // tri edge, neighbor info
- int *m_pused; // tri used flag
-};
-
-//=========================================================================
-// vertex cache class
-//=========================================================================
-class CVertCache
-{
-public:
- CVertCache()
- { Reset(); }
- ~CVertCache()
- {};
-
- // reset cache
- void Reset()
- {
- m_iCachePtr = 0;
- m_cachehits = 0;
- memset(m_rgCache, 0xff, sizeof(m_rgCache));
- }
-
- // add vertindex to cache
- bool Add(int strip, int vertindex);
-
- int NumCacheHits() const
- { return m_cachehits; }
-
-// enum { CACHE_SIZE = 10 };
- enum { CACHE_SIZE = 18 };
-
-private:
- int m_cachehits; // current # of cache hits
- WORD m_rgCache[CACHE_SIZE]; // vertex cache
- int m_rgCacheStrip[CACHE_SIZE]; // strip # which added vert
- int m_iCachePtr; // fifo ptr
-};
-
-//=========================================================================
-// Get maximum length of strip starting at tri/vert
-//=========================================================================
-int CStripper::CreateStrip(int tri, int vert, int maxlen, int *pswaps,
- bool flookahead, bool fstartcw, int *pstriptris, int *pstripverts)
-{
- *pswaps = 0;
-
- // this guy has already been used?
- if(m_pused[tri])
- return 0;
-
- // mark tri as used
- m_pused[tri] = 1;
-
- int swaps = 0;
-
- // add first tri info
- pstriptris[0] = tri;
- pstriptris[1] = tri;
- pstriptris[2] = tri;
-
- if(fstartcw)
- {
- pstripverts[0] = (vert) % 3;
- pstripverts[1] = (vert + 1) % 3;
- pstripverts[2] = (vert + 2) % 3;
- }
- else
- {
- pstripverts[0] = (vert + 1) % 3;
- pstripverts[1] = (vert + 0) % 3;
- pstripverts[2] = (vert + 2) % 3;
- }
- fstartcw = !fstartcw;
-
- // get next tri information
- int edge = (fstartcw ? vert + 2 : vert + 1) % 3;
- int nexttri = m_ptriinfo[tri].neighbortri[edge];
- int nextvert = m_ptriinfo[tri].neighboredge[edge];
-
- // start building the strip until we run out of room or indices
- int stripcount;
- for( stripcount = 3; stripcount < maxlen; stripcount++)
- {
- // dead end?
- if(nexttri == -1 || m_pused[nexttri])
- break;
-
- // move to next tri
- tri = nexttri;
- vert = nextvert;
-
- // toggle orientation
- fstartcw = !fstartcw;
-
- // find the next natural edge
- int edge = (fstartcw ? vert + 2 : vert + 1) % 3;
- nexttri = m_ptriinfo[tri].neighbortri[edge];
- nextvert = m_ptriinfo[tri].neighboredge[edge];
-
- bool fswap = false;
- if(nexttri == -1 || m_pused[nexttri])
- {
- // if the next tri is a dead end - try swapping orientation
- fswap = true;
- }
- else if(flookahead)
- {
- // try a swap and see who our new neighbor would be
- int edgeswap = (fstartcw ? vert + 1 : vert + 2) % 3;
- int nexttriswap = m_ptriinfo[tri].neighbortri[edgeswap];
- int nextvertswap = m_ptriinfo[tri].neighboredge[edgeswap];
-
- if(nexttriswap != -1 && !m_pused[nexttriswap])
- {
- assert(nexttri != -1);
-
- // if the swap neighbor has a lower count, change directions
- if(GetNeighborCount(nexttriswap) < GetNeighborCount(nexttri))
- {
- fswap = true;
- }
- else if(GetNeighborCount(nexttriswap) == GetNeighborCount(nexttri))
- {
- // if they have the same number of neighbors - check their neighbors
- edgeswap = (fstartcw ? nextvertswap + 2 : nextvertswap + 1) % 3;
- nexttriswap = m_ptriinfo[nexttriswap].neighbortri[edgeswap];
-
- int edge1 = (fstartcw ? nextvert + 1 : nextvert + 2) % 3;
- int nexttri1 = m_ptriinfo[nexttri].neighbortri[edge1];
-
- if(nexttri1 == -1 || m_pused[nexttri1])
- {
- // natural winding order leads us to a dead end so turn
- fswap = true;
- }
- else if(nexttriswap != -1 && !m_pused[nexttriswap])
- {
- // check neighbor counts on both directions and swap if it's better
- if(GetNeighborCount(nexttriswap) < GetNeighborCount(nexttri1))
- fswap = true;
- }
- }
- }
- }
-
- if(fswap)
- {
- // we've been told to change directions so make sure we actually can
- // and then add the swap vertex
- int edgeswap = (fstartcw ? vert + 1 : vert + 2) % 3;
- nexttri = m_ptriinfo[tri].neighbortri[edgeswap];
- nextvert = m_ptriinfo[tri].neighboredge[edgeswap];
-
- if(nexttri != -1 && !m_pused[nexttri])
- {
- pstriptris[stripcount] = pstriptris[stripcount - 2];
- pstripverts[stripcount] = pstripverts[stripcount - 2];
- stripcount++;
- swaps++;
- fstartcw = !fstartcw;
- }
- }
-
- // record index information
- pstriptris[stripcount] = tri;
- pstripverts[stripcount] = (vert + 2) % 3;
-
- // mark triangle as used
- m_pused[tri] = 1;
- }
-
- // clear the used flags
- for(int j = 2; j < stripcount; j++)
- m_pused[pstriptris[j]] = 0;
-
- // return swap count and striplen
- *pswaps = swaps;
- return stripcount;
-}
-
-//=========================================================================
-// Given a striplist and current cache state, pick the best next strip
-//=========================================================================
-STRIPLIST::iterator FindBestCachedStrip(STRIPLIST *pstriplist,
- const CVertCache &vertcachestate)
-{
- if(pstriplist->empty())
- return pstriplist->end();
-
- bool fFlipStrip = false;
- int maxcachehits = -1;
- STRIPLIST::iterator istriplistbest = pstriplist->begin();
-
- int striplen = StripLen(**istriplistbest);
- bool fstartcw = FIsStripCW(**istriplistbest);
-
- // go through all the other strips looking for the best caching
- for(STRIPLIST::iterator istriplist = pstriplist->begin();
- istriplist != pstriplist->end();
- ++istriplist)
- {
- bool fFlip = false;
- const STRIPVERTS &stripverts = **istriplist;
- int striplennew = StripLen(stripverts);
-
- // check cache if this strip is the same type as us (ie: cw/odd)
- if((FIsStripCW(stripverts) == fstartcw) &&
- ((striplen & 0x1) == (striplennew & 0x1)))
- {
- // copy current state of cache
- CVertCache vertcachenew = vertcachestate;
-
- // figure out what this guy would do to our cache
- for(int ivert = 0; ivert < striplennew; ivert++)
- vertcachenew.Add(2, stripverts[ivert]);
-
- // even length strip - see if better cache hits reversed
- if(!(striplennew & 0x1))
- {
- CVertCache vertcacheflipped = vertcachestate;
-
- for(int ivert = StripLen(stripverts) - 1; ivert >= 0; ivert--)
- vertcacheflipped.Add(2, stripverts[ivert]);
-
- if(vertcacheflipped.NumCacheHits() > vertcachenew.NumCacheHits())
- {
- vertcachenew = vertcacheflipped;
- fFlip = true;
- }
- }
-
- // record the best number of cache hits to date
- int numcachehits = vertcachenew.NumCacheHits() - vertcachestate.NumCacheHits();
- if(numcachehits > maxcachehits)
- {
- maxcachehits = numcachehits;
- istriplistbest = istriplist;
- fFlipStrip = fFlip;
- }
- }
- }
-
- if(fFlipStrip)
- {
- STRIPVERTS &stripverts = **istriplistbest;
- STRIPVERTS::iterator vend = stripverts.end();
-
- reverse(stripverts.begin(), --vend);
- }
-
- // make sure we keep the list in order and always pull off
- // the first dude.
- if(istriplistbest != pstriplist->begin())
- swap(*istriplistbest, *pstriplist->begin());
-
- return pstriplist->begin();
-}
-
-
-//=========================================================================
-// Don't merge the strips - just blast em into the stripbuffer one by one
-// (useful for debugging)
-//=========================================================================
-int CStripper::CreateManyStrips(STRIPLIST *pstriplist, WORD **ppstripindices)
-{
- // allow room for each of the strips size plus the final 0
- int indexcount = (int)pstriplist->size() + 1;
-
- // we're storing the strips in [size1 i1 i2 i3][size2 i4 i5 i6][0] format
- STRIPLIST::iterator istriplist;
- for( istriplist = pstriplist->begin(); istriplist != pstriplist->end(); ++istriplist)
- {
- // add striplength plus potential degenerate to swap ccw --> cw
- indexcount += StripLen(**istriplist) + 1;
- }
-
- // alloc the space for all this stuff
- WORD *pstripindices = new WORD [indexcount];
- assert(pstripindices);
-
- CVertCache vertcache;
- int numstripindices = 0;
-
- for(istriplist = pstriplist->begin();
- !pstriplist->empty();
- istriplist = FindBestCachedStrip(pstriplist, vertcache))
- {
- const STRIPVERTS &stripverts = **istriplist;
-
- if(!FIsStripCW(stripverts))
- {
- // add an extra index if it's ccw
- pstripindices[numstripindices++] = StripLen(stripverts) + 1;
- pstripindices[numstripindices++] = stripverts[0];
- }
- else
- {
- // add the strip length
- pstripindices[numstripindices++] = StripLen(stripverts);
- }
-
- // add all the strip indices
- for(int i = 0; i < StripLen(stripverts); i++)
- {
- pstripindices[numstripindices++] = stripverts[i];
- vertcache.Add(1, stripverts[i]);
- }
-
- // free this guy and pop him off the list
- delete &stripverts;
- pstriplist->pop_front();
- }
-
- // add terminating zero
- pstripindices[numstripindices++] = 0;
- *ppstripindices = pstripindices;
-
- return numstripindices;
-}
-
-//=========================================================================
-// Merge striplist into one big uberlist with (hopefully) optimal caching
-//=========================================================================
-int CStripper::CreateLongStrip(STRIPLIST *pstriplist, WORD **ppstripindices)
-{
- // allow room for one strip length plus a possible 3 extra indices per
- // concatenated strip list plus the final 0
- int indexcount = ((int)pstriplist->size() * 3) + 2;
-
- // we're storing the strips in [size1 i1 i2 i3][size2 i4 i5 i6][0] format
- STRIPLIST::iterator istriplist;
- for( istriplist = pstriplist->begin(); istriplist != pstriplist->end(); ++istriplist)
- {
- indexcount += StripLen(**istriplist);
- }
-
- // alloc the space for all this stuff
- WORD *pstripindices = new WORD [indexcount];
- assert(pstripindices);
-
- CVertCache vertcache;
- int numstripindices = 0;
-
- // add first strip
- istriplist = pstriplist->begin();
- const STRIPVERTS &stripverts = **istriplist;
-
- // first strip should be cw
- assert(FIsStripCW(stripverts));
-
- for(int ivert = 0; ivert < StripLen(stripverts); ivert++)
- {
- pstripindices[numstripindices++] = stripverts[ivert];
- vertcache.Add(1, stripverts[ivert]);
- }
-
- // kill first dude
- delete &stripverts;
- pstriplist->erase(istriplist);
-
- // add all the others
- while(pstriplist->size())
- {
- istriplist = FindBestCachedStrip(pstriplist, vertcache);
- STRIPVERTS &stripverts = **istriplist;
- short lastvert = pstripindices[numstripindices - 1];
- short firstvert = stripverts[0];
-
- if(firstvert != lastvert)
- {
- // add degenerate from last strip
- pstripindices[numstripindices++] = lastvert;
-
- // add degenerate from our strip
- pstripindices[numstripindices++] = firstvert;
- }
-
- // if we're not orientated correctly, we need to add a degenerate
- if(FIsStripCW(stripverts) != !(numstripindices & 0x1))
- {
- // This shouldn't happen - we're currently trying very hard
- // to keep everything oriented correctly.
- assert(false);
- pstripindices[numstripindices++] = firstvert;
- }
-
- // add these verts
- for(int ivert = 0; ivert < StripLen(stripverts); ivert++)
- {
- pstripindices[numstripindices++] = stripverts[ivert];
- vertcache.Add(1, stripverts[ivert]);
- }
-
- // free these guys
- delete &stripverts;
- pstriplist->erase(istriplist);
- }
-
- *ppstripindices = pstripindices;
- return numstripindices;
-}
-
-//=========================================================================
-// Build a (hopefully) optimal set of strips from a trilist
-//=========================================================================
-void CStripper::BuildStrips(STRIPLIST *pstriplist, int maxlen, bool flookahead)
-{
- // temp indices storage
- const int ctmpverts = 1024;
- int pstripverts[ctmpverts + 1];
- int pstriptris[ctmpverts + 1];
-
- assert(maxlen <= ctmpverts);
-
- // clear all the used flags for the tris
- memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
-
- bool fstartcw = true;
- for(;;)
- {
- int besttri = 0;
- int bestvert = 0;
- float bestratio = 2.0f;
- int bestneighborcount = INT_MAX;
-
- int tri;
- for( tri = 0; tri < m_numtris; tri++)
- {
- // if used the continue
- if(m_pused[tri])
- continue;
-
- // get the neighbor count
- int curneightborcount = GetNeighborCount(tri);
- assert(curneightborcount >= 0 && curneightborcount <= 3);
-
- // push all the singletons to the very end
- if(!curneightborcount)
- curneightborcount = 4;
-
- // if this guy has more neighbors than the current best - bail
- if(curneightborcount > bestneighborcount)
- continue;
-
- // try starting the strip with each of this tris verts
- for(int vert = 0; vert < 3; vert++)
- {
- int swaps;
- int len = CreateStrip(tri, vert, maxlen, &swaps, flookahead,
- fstartcw, pstriptris, pstripverts);
- assert(len);
-
- float ratio = (len == 3) ? 1.0f : (float)swaps / len;
-
- // check if this ratio is better than what we've already got for
- // this neighborcount
- if((curneightborcount < bestneighborcount) ||
- ((curneightborcount == bestneighborcount) && (ratio < bestratio)))
- {
- bestneighborcount = curneightborcount;
-
- besttri = tri;
- bestvert = vert;
- bestratio = ratio;
- }
-
- }
- }
-
- // no strips found?
- if(bestneighborcount == INT_MAX)
- break;
-
- // recreate this strip
- int swaps;
- int len = CreateStrip(besttri, bestvert, maxlen,
- &swaps, flookahead, fstartcw, pstriptris, pstripverts);
- assert(len);
-
- // mark the tris on the best strip as used
- for(tri = 0; tri < len; tri++)
- m_pused[pstriptris[tri]] = 1;
-
- // create a new STRIPVERTS and stuff in the indices
- STRIPVERTS *pstripvertices = new STRIPVERTS(len + 1);
- assert(pstripvertices);
-
- // store orientation in first entry
- for(tri = 0; tri < len; tri++)
- (*pstripvertices)[tri] = m_ptriangles[pstriptris[tri]][pstripverts[tri]];
- (*pstripvertices)[len] = fstartcw;
-
- // store the STRIPVERTS
- pstriplist->push_back(pstripvertices);
-
- // if strip was odd - swap orientation
- if((len & 0x1))
- fstartcw = !fstartcw;
- }
-
-#ifdef _DEBUG
- // make sure all tris are used
- for(int t = 0; t < m_numtris; t++)
- assert(m_pused[t]);
-#endif
-}
-
-//=========================================================================
-// Guesstimate on the total index count for this list of strips
-//=========================================================================
-int EstimateStripCost(STRIPLIST *pstriplist)
-{
- int count = 0;
-
- for(STRIPLIST::iterator istriplist = pstriplist->begin();
- istriplist != pstriplist->end();
- ++istriplist)
- {
- // add count of indices
- count += StripLen(**istriplist);
- }
-
- // assume 2 indices per strip to tack all these guys together
- return count + ((int)pstriplist->size() - 1) * 2;
-}
-
-//=========================================================================
-// Initialize triangle information (edges, #neighbors, etc.)
-//=========================================================================
-void CStripper::InitTriangleInfo(int tri, int vert)
-{
- WORD *ptriverts = &m_ptriangles[tri + 1][0];
- int vert1 = m_ptriangles[tri][(vert + 1) % 3];
- int vert2 = m_ptriangles[tri][vert];
-
- for(int itri = tri + 1; itri < m_numtris; itri++, ptriverts += 3)
- {
- if(m_pused[itri] != 0x7)
- {
- for(int ivert = 0; ivert < 3; ivert++)
- {
- if((ptriverts[ivert] == vert1) &&
- (ptriverts[(ivert + 1) % 3] == vert2))
- {
- // add the triangle info
- m_ptriinfo[tri].neighbortri[vert] = itri;
- m_ptriinfo[tri].neighboredge[vert] = ivert;
- m_pused[tri] |= (1 << vert);
-
- m_ptriinfo[itri].neighbortri[ivert] = tri;
- m_ptriinfo[itri].neighboredge[ivert] = vert;
- m_pused[itri] |= (1 << ivert);
- return;
- }
- }
- }
- }
-}
-
-//=========================================================================
-// CStripper ctor
-//=========================================================================
-CStripper::CStripper(int numtris, TRIANGLELIST ptriangles)
-{
- // store trilist info
- m_numtris = numtris;
- m_ptriangles = ptriangles;
-
- m_pused = new int[numtris];
- assert(m_pused);
- m_ptriinfo = new TRIANGLEINFO[numtris];
- assert(m_ptriinfo);
-
- // init triinfo
- int itri;
- for( itri = 0; itri < numtris; itri++)
- {
- m_ptriinfo[itri].neighbortri[0] = -1;
- m_ptriinfo[itri].neighbortri[1] = -1;
- m_ptriinfo[itri].neighbortri[2] = -1;
- }
-
- // clear the used flag
- memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
-
- // go through all the triangles and find edges, neighbor counts
- for(itri = 0; itri < numtris; itri++)
- {
- for(int ivert = 0; ivert < 3; ivert++)
- {
- if(!(m_pused[itri] & (1 << ivert)))
- InitTriangleInfo(itri, ivert);
- }
- }
-
- // clear the used flags from InitTriangleInfo
- memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
-}
-
-//=========================================================================
-// CStripper dtor
-//=========================================================================
-CStripper::~CStripper()
-{
- // free stuff
- delete [] m_pused;
- m_pused = NULL;
-
- delete [] m_ptriinfo;
- m_ptriinfo = NULL;
-}
-
-//=========================================================================
-// Add an index to the cache - returns true if it was added, false otherwise
-//=========================================================================
-bool CVertCache::Add(int strip, int vertindex)
-{
- // find index in cache
- for(int iCache = 0; iCache < CACHE_SIZE; iCache++)
- {
- if(vertindex == m_rgCache[iCache])
- {
- // if it's in the cache and it's from a different strip
- // change the strip to the new one and count the cache hit
- if(strip != m_rgCacheStrip[iCache])
- {
- m_cachehits++;
- m_rgCacheStrip[iCache] = strip;
- return true;
- }
-
- // we added this item to the cache earlier - carry on
- return false;
- }
- }
-
- // not in cache, add vert and strip
- m_rgCache[m_iCachePtr] = vertindex;
- m_rgCacheStrip[m_iCachePtr] = strip;
- m_iCachePtr = (m_iCachePtr + 1) % CACHE_SIZE;
- return true;
-}
-
-#ifdef _DEBUG
-//=========================================================================
-// Turn on c runtime leak checking, etc.
-//=========================================================================
-void EnableLeakChecking()
-{
- int flCrtDbgFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
-
- flCrtDbgFlags &=
- ~(_CRTDBG_LEAK_CHECK_DF |
- _CRTDBG_CHECK_ALWAYS_DF |
- _CRTDBG_DELAY_FREE_MEM_DF);
-
- // always check for memory leaks
- flCrtDbgFlags |= _CRTDBG_LEAK_CHECK_DF;
-
- // others you may / may not want to set
- flCrtDbgFlags |= _CRTDBG_CHECK_ALWAYS_DF;
- flCrtDbgFlags |= _CRTDBG_DELAY_FREE_MEM_DF;
-
- _CrtSetDbgFlag(flCrtDbgFlags);
-
- // all types of reports go via OutputDebugString
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
-
- // big errors and asserts get their own assert window
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
- _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW);
-
- // _CrtSetBreakAlloc(0);
-}
-#endif
-
-//=========================================================================
-// Main Stripify routine
-//=========================================================================
-int Stripify(int numtris, WORD *ptriangles, int *pnumindices, WORD **ppstripindices)
-{
- if(!numtris || !ptriangles)
- return 0;
-
-#ifdef _DEBUG
-// EnableLeakChecking();
-#endif
-
- CStripper stripper(numtris, (TRIANGLELIST)ptriangles);
-
- // map of various args to try stripifying mesh with
- struct ARGMAP
- {
- int maxlen; // maximum length of strips
- bool flookahead; // use sgi greedy lookahead (or not)
- } rgargmap[] =
- {
- { 1024, true },
- { 1024, false },
- };
- static const int cargmaps = sizeof(rgargmap) / sizeof(rgargmap[0]);
- STRIPLIST striplistbest;
- int bestlistcost = 0;
-
- for(int imap = 0; imap < cargmaps; imap++)
- {
- STRIPLIST striplist;
-
- // build the strip with the various args
- stripper.BuildStrips(&striplist, rgargmap[imap].maxlen,
- rgargmap[imap].flookahead);
-
- // guesstimate the list cost and store it if it's good
- int listcost = EstimateStripCost(&striplist);
- if(!bestlistcost || (listcost < bestlistcost))
- {
- // free the old best list
- FreeStripListVerts(&striplistbest);
-
- // store the new best list
- striplistbest = striplist;
- bestlistcost = listcost;
- assert(bestlistcost > 0);
- }
- else
- {
- FreeStripListVerts(&striplist);
- }
- }
-
-#ifdef NEVER
- // Return the strips in [size1 i1 i2 i3][size2 i4 i5 i6]...[0] format
- // Very useful for debugging...
- return stripper.CreateManyStrips(&striplistbest, ppstripindices);
-#endif // NEVER
-
- // return one big long strip
- int numindices = stripper.CreateLongStrip(&striplistbest, ppstripindices);
-
- if(pnumindices)
- *pnumindices = numindices;
- return numindices;
-}
-
-//=========================================================================
-// Class used to vertices for locality of access.
-//=========================================================================
-struct SortEntry
-{
-public:
- int iFirstUsed;
- int iOrigIndex;
-
- bool operator<(const SortEntry& rhs) const
- {
- return iFirstUsed < rhs.iFirstUsed;
- }
-};
-
-//=========================================================================
-// Reorder the vertices
-//=========================================================================
-void ComputeVertexPermutation(int numstripindices, WORD* pstripindices,
- int* pnumverts, WORD** ppvertexpermutation)
-{
- // Sort verts to maximize locality.
- SortEntry* pSortTable = new SortEntry[*pnumverts];
-
- // Fill in original index.
- int i;
- for( i = 0; i < *pnumverts; i++)
- {
- pSortTable[i].iOrigIndex = i;
- pSortTable[i].iFirstUsed = -1;
- }
-
- // Fill in first used flag.
- for(i = 0; i < numstripindices; i++)
- {
- int index = pstripindices[i];
-
- if(pSortTable[index].iFirstUsed == -1)
- pSortTable[index].iFirstUsed = i;
- }
-
- // Sort the table.
- sort(pSortTable, pSortTable + *pnumverts);
-
- // Copy re-mapped to orignal vertex permutaion into output array.
- *ppvertexpermutation = new WORD[*pnumverts];
-
- for(i = 0; i < *pnumverts; i++)
- {
- (*ppvertexpermutation)[i] = pSortTable[i].iOrigIndex;
- }
-
- // Build original to re-mapped permutation.
- WORD* pInversePermutation = new WORD[numstripindices];
-
- for(i = 0; i < *pnumverts; i++)
- {
- pInversePermutation[pSortTable[i].iOrigIndex] = i;
- }
-
- // We need to remap indices as well.
- for(i = 0; i < numstripindices; i++)
- {
- pstripindices[i] = pInversePermutation[pstripindices[i]];
- }
-
- delete[] pSortTable;
- delete[] pInversePermutation;
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+//-----------------------------------------------------------------------------
+// FILE: TRISTRIP.CPP
+//
+// Desc: Xbox tristripper
+//
+// Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+// identifier was truncated to '255' characters in the debug information
+#pragma warning(disable: 4786)
+// conversion from 'double' to 'float'
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4530)
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <algorithm>
+#include <list>
+#include <vector>
+
+#include <assert.h>
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#include "mstristrip.h"
+
+using namespace std;
+
+//=========================================================================
+// structs
+//=========================================================================
+typedef vector<WORD> STRIPVERTS;
+typedef list<STRIPVERTS *> STRIPLIST;
+typedef WORD (*TRIANGLELIST)[3];
+
+struct TRIANGLEINFO
+{
+ int neighbortri[3];
+ int neighboredge[3];
+};
+
+// return true if strip starts clockwise
+inline bool FIsStripCW(const STRIPVERTS &stripvertices)
+{
+ // last index should have cw/ccw bool
+ return !!stripvertices[stripvertices.size() - 1];
+}
+
+// return length of strip
+inline int StripLen(const STRIPVERTS &stripvertices)
+{
+ return (int)stripvertices.size() - 1;
+}
+
+// free all stripverts and clear the striplist
+inline void FreeStripListVerts(STRIPLIST *pstriplist)
+{
+ STRIPLIST::iterator istriplist = pstriplist->begin();
+ while(istriplist != pstriplist->end())
+ {
+ STRIPVERTS *pstripverts = *istriplist;
+ delete pstripverts;
+ pstriplist->erase(istriplist++);
+ }
+}
+
+//=========================================================================
+// main stripper class
+//=========================================================================
+class CStripper
+{
+public:
+ // ctors/dtors
+ CStripper(int numtris, TRIANGLELIST ptriangles);
+ ~CStripper();
+
+ // initialize tri info
+ void InitTriangleInfo(int tri, int vert);
+
+ // get maximum length strip from tri/vert
+ int CreateStrip(int tri, int vert, int maxlen, int *pswaps,
+ bool flookahead, bool fstartcw, int *pstriptris, int *pstripverts);
+
+ // stripify entire mesh
+ void BuildStrips(STRIPLIST *pstriplist, int maxlen, bool flookahead);
+
+ // blast strip indices to ppstripindices
+ int CreateManyStrips(STRIPLIST *pstriplist, WORD **ppstripindices);
+ int CreateLongStrip(STRIPLIST *pstriplist, WORD **ppstripindices);
+
+ inline int GetNeighborCount(int tri)
+ {
+ int count = 0;
+ for(int vert = 0; vert < 3; vert++)
+ {
+ int neighbortri = m_ptriinfo[tri].neighbortri[vert];
+ count += (neighbortri != -1) && !m_pused[neighbortri];
+ }
+ return count;
+ }
+
+ // from callee
+ int m_numtris; // # tris
+ TRIANGLELIST m_ptriangles; // trilist
+
+ TRIANGLEINFO *m_ptriinfo; // tri edge, neighbor info
+ int *m_pused; // tri used flag
+};
+
+//=========================================================================
+// vertex cache class
+//=========================================================================
+class CVertCache
+{
+public:
+ CVertCache()
+ { Reset(); }
+ ~CVertCache()
+ {};
+
+ // reset cache
+ void Reset()
+ {
+ m_iCachePtr = 0;
+ m_cachehits = 0;
+ memset(m_rgCache, 0xff, sizeof(m_rgCache));
+ }
+
+ // add vertindex to cache
+ bool Add(int strip, int vertindex);
+
+ int NumCacheHits() const
+ { return m_cachehits; }
+
+// enum { CACHE_SIZE = 10 };
+ enum { CACHE_SIZE = 18 };
+
+private:
+ int m_cachehits; // current # of cache hits
+ WORD m_rgCache[CACHE_SIZE]; // vertex cache
+ int m_rgCacheStrip[CACHE_SIZE]; // strip # which added vert
+ int m_iCachePtr; // fifo ptr
+};
+
+//=========================================================================
+// Get maximum length of strip starting at tri/vert
+//=========================================================================
+int CStripper::CreateStrip(int tri, int vert, int maxlen, int *pswaps,
+ bool flookahead, bool fstartcw, int *pstriptris, int *pstripverts)
+{
+ *pswaps = 0;
+
+ // this guy has already been used?
+ if(m_pused[tri])
+ return 0;
+
+ // mark tri as used
+ m_pused[tri] = 1;
+
+ int swaps = 0;
+
+ // add first tri info
+ pstriptris[0] = tri;
+ pstriptris[1] = tri;
+ pstriptris[2] = tri;
+
+ if(fstartcw)
+ {
+ pstripverts[0] = (vert) % 3;
+ pstripverts[1] = (vert + 1) % 3;
+ pstripverts[2] = (vert + 2) % 3;
+ }
+ else
+ {
+ pstripverts[0] = (vert + 1) % 3;
+ pstripverts[1] = (vert + 0) % 3;
+ pstripverts[2] = (vert + 2) % 3;
+ }
+ fstartcw = !fstartcw;
+
+ // get next tri information
+ int edge = (fstartcw ? vert + 2 : vert + 1) % 3;
+ int nexttri = m_ptriinfo[tri].neighbortri[edge];
+ int nextvert = m_ptriinfo[tri].neighboredge[edge];
+
+ // start building the strip until we run out of room or indices
+ int stripcount;
+ for( stripcount = 3; stripcount < maxlen; stripcount++)
+ {
+ // dead end?
+ if(nexttri == -1 || m_pused[nexttri])
+ break;
+
+ // move to next tri
+ tri = nexttri;
+ vert = nextvert;
+
+ // toggle orientation
+ fstartcw = !fstartcw;
+
+ // find the next natural edge
+ int edge = (fstartcw ? vert + 2 : vert + 1) % 3;
+ nexttri = m_ptriinfo[tri].neighbortri[edge];
+ nextvert = m_ptriinfo[tri].neighboredge[edge];
+
+ bool fswap = false;
+ if(nexttri == -1 || m_pused[nexttri])
+ {
+ // if the next tri is a dead end - try swapping orientation
+ fswap = true;
+ }
+ else if(flookahead)
+ {
+ // try a swap and see who our new neighbor would be
+ int edgeswap = (fstartcw ? vert + 1 : vert + 2) % 3;
+ int nexttriswap = m_ptriinfo[tri].neighbortri[edgeswap];
+ int nextvertswap = m_ptriinfo[tri].neighboredge[edgeswap];
+
+ if(nexttriswap != -1 && !m_pused[nexttriswap])
+ {
+ assert(nexttri != -1);
+
+ // if the swap neighbor has a lower count, change directions
+ if(GetNeighborCount(nexttriswap) < GetNeighborCount(nexttri))
+ {
+ fswap = true;
+ }
+ else if(GetNeighborCount(nexttriswap) == GetNeighborCount(nexttri))
+ {
+ // if they have the same number of neighbors - check their neighbors
+ edgeswap = (fstartcw ? nextvertswap + 2 : nextvertswap + 1) % 3;
+ nexttriswap = m_ptriinfo[nexttriswap].neighbortri[edgeswap];
+
+ int edge1 = (fstartcw ? nextvert + 1 : nextvert + 2) % 3;
+ int nexttri1 = m_ptriinfo[nexttri].neighbortri[edge1];
+
+ if(nexttri1 == -1 || m_pused[nexttri1])
+ {
+ // natural winding order leads us to a dead end so turn
+ fswap = true;
+ }
+ else if(nexttriswap != -1 && !m_pused[nexttriswap])
+ {
+ // check neighbor counts on both directions and swap if it's better
+ if(GetNeighborCount(nexttriswap) < GetNeighborCount(nexttri1))
+ fswap = true;
+ }
+ }
+ }
+ }
+
+ if(fswap)
+ {
+ // we've been told to change directions so make sure we actually can
+ // and then add the swap vertex
+ int edgeswap = (fstartcw ? vert + 1 : vert + 2) % 3;
+ nexttri = m_ptriinfo[tri].neighbortri[edgeswap];
+ nextvert = m_ptriinfo[tri].neighboredge[edgeswap];
+
+ if(nexttri != -1 && !m_pused[nexttri])
+ {
+ pstriptris[stripcount] = pstriptris[stripcount - 2];
+ pstripverts[stripcount] = pstripverts[stripcount - 2];
+ stripcount++;
+ swaps++;
+ fstartcw = !fstartcw;
+ }
+ }
+
+ // record index information
+ pstriptris[stripcount] = tri;
+ pstripverts[stripcount] = (vert + 2) % 3;
+
+ // mark triangle as used
+ m_pused[tri] = 1;
+ }
+
+ // clear the used flags
+ for(int j = 2; j < stripcount; j++)
+ m_pused[pstriptris[j]] = 0;
+
+ // return swap count and striplen
+ *pswaps = swaps;
+ return stripcount;
+}
+
+//=========================================================================
+// Given a striplist and current cache state, pick the best next strip
+//=========================================================================
+STRIPLIST::iterator FindBestCachedStrip(STRIPLIST *pstriplist,
+ const CVertCache &vertcachestate)
+{
+ if(pstriplist->empty())
+ return pstriplist->end();
+
+ bool fFlipStrip = false;
+ int maxcachehits = -1;
+ STRIPLIST::iterator istriplistbest = pstriplist->begin();
+
+ int striplen = StripLen(**istriplistbest);
+ bool fstartcw = FIsStripCW(**istriplistbest);
+
+ // go through all the other strips looking for the best caching
+ for(STRIPLIST::iterator istriplist = pstriplist->begin();
+ istriplist != pstriplist->end();
+ ++istriplist)
+ {
+ bool fFlip = false;
+ const STRIPVERTS &stripverts = **istriplist;
+ int striplennew = StripLen(stripverts);
+
+ // check cache if this strip is the same type as us (ie: cw/odd)
+ if((FIsStripCW(stripverts) == fstartcw) &&
+ ((striplen & 0x1) == (striplennew & 0x1)))
+ {
+ // copy current state of cache
+ CVertCache vertcachenew = vertcachestate;
+
+ // figure out what this guy would do to our cache
+ for(int ivert = 0; ivert < striplennew; ivert++)
+ vertcachenew.Add(2, stripverts[ivert]);
+
+ // even length strip - see if better cache hits reversed
+ if(!(striplennew & 0x1))
+ {
+ CVertCache vertcacheflipped = vertcachestate;
+
+ for(int ivert = StripLen(stripverts) - 1; ivert >= 0; ivert--)
+ vertcacheflipped.Add(2, stripverts[ivert]);
+
+ if(vertcacheflipped.NumCacheHits() > vertcachenew.NumCacheHits())
+ {
+ vertcachenew = vertcacheflipped;
+ fFlip = true;
+ }
+ }
+
+ // record the best number of cache hits to date
+ int numcachehits = vertcachenew.NumCacheHits() - vertcachestate.NumCacheHits();
+ if(numcachehits > maxcachehits)
+ {
+ maxcachehits = numcachehits;
+ istriplistbest = istriplist;
+ fFlipStrip = fFlip;
+ }
+ }
+ }
+
+ if(fFlipStrip)
+ {
+ STRIPVERTS &stripverts = **istriplistbest;
+ STRIPVERTS::iterator vend = stripverts.end();
+
+ reverse(stripverts.begin(), --vend);
+ }
+
+ // make sure we keep the list in order and always pull off
+ // the first dude.
+ if(istriplistbest != pstriplist->begin())
+ swap(*istriplistbest, *pstriplist->begin());
+
+ return pstriplist->begin();
+}
+
+
+//=========================================================================
+// Don't merge the strips - just blast em into the stripbuffer one by one
+// (useful for debugging)
+//=========================================================================
+int CStripper::CreateManyStrips(STRIPLIST *pstriplist, WORD **ppstripindices)
+{
+ // allow room for each of the strips size plus the final 0
+ int indexcount = (int)pstriplist->size() + 1;
+
+ // we're storing the strips in [size1 i1 i2 i3][size2 i4 i5 i6][0] format
+ STRIPLIST::iterator istriplist;
+ for( istriplist = pstriplist->begin(); istriplist != pstriplist->end(); ++istriplist)
+ {
+ // add striplength plus potential degenerate to swap ccw --> cw
+ indexcount += StripLen(**istriplist) + 1;
+ }
+
+ // alloc the space for all this stuff
+ WORD *pstripindices = new WORD [indexcount];
+ assert(pstripindices);
+
+ CVertCache vertcache;
+ int numstripindices = 0;
+
+ for(istriplist = pstriplist->begin();
+ !pstriplist->empty();
+ istriplist = FindBestCachedStrip(pstriplist, vertcache))
+ {
+ const STRIPVERTS &stripverts = **istriplist;
+
+ if(!FIsStripCW(stripverts))
+ {
+ // add an extra index if it's ccw
+ pstripindices[numstripindices++] = StripLen(stripverts) + 1;
+ pstripindices[numstripindices++] = stripverts[0];
+ }
+ else
+ {
+ // add the strip length
+ pstripindices[numstripindices++] = StripLen(stripverts);
+ }
+
+ // add all the strip indices
+ for(int i = 0; i < StripLen(stripverts); i++)
+ {
+ pstripindices[numstripindices++] = stripverts[i];
+ vertcache.Add(1, stripverts[i]);
+ }
+
+ // free this guy and pop him off the list
+ delete &stripverts;
+ pstriplist->pop_front();
+ }
+
+ // add terminating zero
+ pstripindices[numstripindices++] = 0;
+ *ppstripindices = pstripindices;
+
+ return numstripindices;
+}
+
+//=========================================================================
+// Merge striplist into one big uberlist with (hopefully) optimal caching
+//=========================================================================
+int CStripper::CreateLongStrip(STRIPLIST *pstriplist, WORD **ppstripindices)
+{
+ // allow room for one strip length plus a possible 3 extra indices per
+ // concatenated strip list plus the final 0
+ int indexcount = ((int)pstriplist->size() * 3) + 2;
+
+ // we're storing the strips in [size1 i1 i2 i3][size2 i4 i5 i6][0] format
+ STRIPLIST::iterator istriplist;
+ for( istriplist = pstriplist->begin(); istriplist != pstriplist->end(); ++istriplist)
+ {
+ indexcount += StripLen(**istriplist);
+ }
+
+ // alloc the space for all this stuff
+ WORD *pstripindices = new WORD [indexcount];
+ assert(pstripindices);
+
+ CVertCache vertcache;
+ int numstripindices = 0;
+
+ // add first strip
+ istriplist = pstriplist->begin();
+ const STRIPVERTS &stripverts = **istriplist;
+
+ // first strip should be cw
+ assert(FIsStripCW(stripverts));
+
+ for(int ivert = 0; ivert < StripLen(stripverts); ivert++)
+ {
+ pstripindices[numstripindices++] = stripverts[ivert];
+ vertcache.Add(1, stripverts[ivert]);
+ }
+
+ // kill first dude
+ delete &stripverts;
+ pstriplist->erase(istriplist);
+
+ // add all the others
+ while(pstriplist->size())
+ {
+ istriplist = FindBestCachedStrip(pstriplist, vertcache);
+ STRIPVERTS &stripverts = **istriplist;
+ short lastvert = pstripindices[numstripindices - 1];
+ short firstvert = stripverts[0];
+
+ if(firstvert != lastvert)
+ {
+ // add degenerate from last strip
+ pstripindices[numstripindices++] = lastvert;
+
+ // add degenerate from our strip
+ pstripindices[numstripindices++] = firstvert;
+ }
+
+ // if we're not orientated correctly, we need to add a degenerate
+ if(FIsStripCW(stripverts) != !(numstripindices & 0x1))
+ {
+ // This shouldn't happen - we're currently trying very hard
+ // to keep everything oriented correctly.
+ assert(false);
+ pstripindices[numstripindices++] = firstvert;
+ }
+
+ // add these verts
+ for(int ivert = 0; ivert < StripLen(stripverts); ivert++)
+ {
+ pstripindices[numstripindices++] = stripverts[ivert];
+ vertcache.Add(1, stripverts[ivert]);
+ }
+
+ // free these guys
+ delete &stripverts;
+ pstriplist->erase(istriplist);
+ }
+
+ *ppstripindices = pstripindices;
+ return numstripindices;
+}
+
+//=========================================================================
+// Build a (hopefully) optimal set of strips from a trilist
+//=========================================================================
+void CStripper::BuildStrips(STRIPLIST *pstriplist, int maxlen, bool flookahead)
+{
+ // temp indices storage
+ const int ctmpverts = 1024;
+ int pstripverts[ctmpverts + 1];
+ int pstriptris[ctmpverts + 1];
+
+ assert(maxlen <= ctmpverts);
+
+ // clear all the used flags for the tris
+ memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
+
+ bool fstartcw = true;
+ for(;;)
+ {
+ int besttri = 0;
+ int bestvert = 0;
+ float bestratio = 2.0f;
+ int bestneighborcount = INT_MAX;
+
+ int tri;
+ for( tri = 0; tri < m_numtris; tri++)
+ {
+ // if used the continue
+ if(m_pused[tri])
+ continue;
+
+ // get the neighbor count
+ int curneightborcount = GetNeighborCount(tri);
+ assert(curneightborcount >= 0 && curneightborcount <= 3);
+
+ // push all the singletons to the very end
+ if(!curneightborcount)
+ curneightborcount = 4;
+
+ // if this guy has more neighbors than the current best - bail
+ if(curneightborcount > bestneighborcount)
+ continue;
+
+ // try starting the strip with each of this tris verts
+ for(int vert = 0; vert < 3; vert++)
+ {
+ int swaps;
+ int len = CreateStrip(tri, vert, maxlen, &swaps, flookahead,
+ fstartcw, pstriptris, pstripverts);
+ assert(len);
+
+ float ratio = (len == 3) ? 1.0f : (float)swaps / len;
+
+ // check if this ratio is better than what we've already got for
+ // this neighborcount
+ if((curneightborcount < bestneighborcount) ||
+ ((curneightborcount == bestneighborcount) && (ratio < bestratio)))
+ {
+ bestneighborcount = curneightborcount;
+
+ besttri = tri;
+ bestvert = vert;
+ bestratio = ratio;
+ }
+
+ }
+ }
+
+ // no strips found?
+ if(bestneighborcount == INT_MAX)
+ break;
+
+ // recreate this strip
+ int swaps;
+ int len = CreateStrip(besttri, bestvert, maxlen,
+ &swaps, flookahead, fstartcw, pstriptris, pstripverts);
+ assert(len);
+
+ // mark the tris on the best strip as used
+ for(tri = 0; tri < len; tri++)
+ m_pused[pstriptris[tri]] = 1;
+
+ // create a new STRIPVERTS and stuff in the indices
+ STRIPVERTS *pstripvertices = new STRIPVERTS(len + 1);
+ assert(pstripvertices);
+
+ // store orientation in first entry
+ for(tri = 0; tri < len; tri++)
+ (*pstripvertices)[tri] = m_ptriangles[pstriptris[tri]][pstripverts[tri]];
+ (*pstripvertices)[len] = fstartcw;
+
+ // store the STRIPVERTS
+ pstriplist->push_back(pstripvertices);
+
+ // if strip was odd - swap orientation
+ if((len & 0x1))
+ fstartcw = !fstartcw;
+ }
+
+#ifdef _DEBUG
+ // make sure all tris are used
+ for(int t = 0; t < m_numtris; t++)
+ assert(m_pused[t]);
+#endif
+}
+
+//=========================================================================
+// Guesstimate on the total index count for this list of strips
+//=========================================================================
+int EstimateStripCost(STRIPLIST *pstriplist)
+{
+ int count = 0;
+
+ for(STRIPLIST::iterator istriplist = pstriplist->begin();
+ istriplist != pstriplist->end();
+ ++istriplist)
+ {
+ // add count of indices
+ count += StripLen(**istriplist);
+ }
+
+ // assume 2 indices per strip to tack all these guys together
+ return count + ((int)pstriplist->size() - 1) * 2;
+}
+
+//=========================================================================
+// Initialize triangle information (edges, #neighbors, etc.)
+//=========================================================================
+void CStripper::InitTriangleInfo(int tri, int vert)
+{
+ WORD *ptriverts = &m_ptriangles[tri + 1][0];
+ int vert1 = m_ptriangles[tri][(vert + 1) % 3];
+ int vert2 = m_ptriangles[tri][vert];
+
+ for(int itri = tri + 1; itri < m_numtris; itri++, ptriverts += 3)
+ {
+ if(m_pused[itri] != 0x7)
+ {
+ for(int ivert = 0; ivert < 3; ivert++)
+ {
+ if((ptriverts[ivert] == vert1) &&
+ (ptriverts[(ivert + 1) % 3] == vert2))
+ {
+ // add the triangle info
+ m_ptriinfo[tri].neighbortri[vert] = itri;
+ m_ptriinfo[tri].neighboredge[vert] = ivert;
+ m_pused[tri] |= (1 << vert);
+
+ m_ptriinfo[itri].neighbortri[ivert] = tri;
+ m_ptriinfo[itri].neighboredge[ivert] = vert;
+ m_pused[itri] |= (1 << ivert);
+ return;
+ }
+ }
+ }
+ }
+}
+
+//=========================================================================
+// CStripper ctor
+//=========================================================================
+CStripper::CStripper(int numtris, TRIANGLELIST ptriangles)
+{
+ // store trilist info
+ m_numtris = numtris;
+ m_ptriangles = ptriangles;
+
+ m_pused = new int[numtris];
+ assert(m_pused);
+ m_ptriinfo = new TRIANGLEINFO[numtris];
+ assert(m_ptriinfo);
+
+ // init triinfo
+ int itri;
+ for( itri = 0; itri < numtris; itri++)
+ {
+ m_ptriinfo[itri].neighbortri[0] = -1;
+ m_ptriinfo[itri].neighbortri[1] = -1;
+ m_ptriinfo[itri].neighbortri[2] = -1;
+ }
+
+ // clear the used flag
+ memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
+
+ // go through all the triangles and find edges, neighbor counts
+ for(itri = 0; itri < numtris; itri++)
+ {
+ for(int ivert = 0; ivert < 3; ivert++)
+ {
+ if(!(m_pused[itri] & (1 << ivert)))
+ InitTriangleInfo(itri, ivert);
+ }
+ }
+
+ // clear the used flags from InitTriangleInfo
+ memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
+}
+
+//=========================================================================
+// CStripper dtor
+//=========================================================================
+CStripper::~CStripper()
+{
+ // free stuff
+ delete [] m_pused;
+ m_pused = NULL;
+
+ delete [] m_ptriinfo;
+ m_ptriinfo = NULL;
+}
+
+//=========================================================================
+// Add an index to the cache - returns true if it was added, false otherwise
+//=========================================================================
+bool CVertCache::Add(int strip, int vertindex)
+{
+ // find index in cache
+ for(int iCache = 0; iCache < CACHE_SIZE; iCache++)
+ {
+ if(vertindex == m_rgCache[iCache])
+ {
+ // if it's in the cache and it's from a different strip
+ // change the strip to the new one and count the cache hit
+ if(strip != m_rgCacheStrip[iCache])
+ {
+ m_cachehits++;
+ m_rgCacheStrip[iCache] = strip;
+ return true;
+ }
+
+ // we added this item to the cache earlier - carry on
+ return false;
+ }
+ }
+
+ // not in cache, add vert and strip
+ m_rgCache[m_iCachePtr] = vertindex;
+ m_rgCacheStrip[m_iCachePtr] = strip;
+ m_iCachePtr = (m_iCachePtr + 1) % CACHE_SIZE;
+ return true;
+}
+
+#ifdef _DEBUG
+//=========================================================================
+// Turn on c runtime leak checking, etc.
+//=========================================================================
+void EnableLeakChecking()
+{
+ int flCrtDbgFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+
+ flCrtDbgFlags &=
+ ~(_CRTDBG_LEAK_CHECK_DF |
+ _CRTDBG_CHECK_ALWAYS_DF |
+ _CRTDBG_DELAY_FREE_MEM_DF);
+
+ // always check for memory leaks
+ flCrtDbgFlags |= _CRTDBG_LEAK_CHECK_DF;
+
+ // others you may / may not want to set
+ flCrtDbgFlags |= _CRTDBG_CHECK_ALWAYS_DF;
+ flCrtDbgFlags |= _CRTDBG_DELAY_FREE_MEM_DF;
+
+ _CrtSetDbgFlag(flCrtDbgFlags);
+
+ // all types of reports go via OutputDebugString
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+
+ // big errors and asserts get their own assert window
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW);
+
+ // _CrtSetBreakAlloc(0);
+}
+#endif
+
+//=========================================================================
+// Main Stripify routine
+//=========================================================================
+int Stripify(int numtris, WORD *ptriangles, int *pnumindices, WORD **ppstripindices)
+{
+ if(!numtris || !ptriangles)
+ return 0;
+
+#ifdef _DEBUG
+// EnableLeakChecking();
+#endif
+
+ CStripper stripper(numtris, (TRIANGLELIST)ptriangles);
+
+ // map of various args to try stripifying mesh with
+ struct ARGMAP
+ {
+ int maxlen; // maximum length of strips
+ bool flookahead; // use sgi greedy lookahead (or not)
+ } rgargmap[] =
+ {
+ { 1024, true },
+ { 1024, false },
+ };
+ static const int cargmaps = sizeof(rgargmap) / sizeof(rgargmap[0]);
+ STRIPLIST striplistbest;
+ int bestlistcost = 0;
+
+ for(int imap = 0; imap < cargmaps; imap++)
+ {
+ STRIPLIST striplist;
+
+ // build the strip with the various args
+ stripper.BuildStrips(&striplist, rgargmap[imap].maxlen,
+ rgargmap[imap].flookahead);
+
+ // guesstimate the list cost and store it if it's good
+ int listcost = EstimateStripCost(&striplist);
+ if(!bestlistcost || (listcost < bestlistcost))
+ {
+ // free the old best list
+ FreeStripListVerts(&striplistbest);
+
+ // store the new best list
+ striplistbest = striplist;
+ bestlistcost = listcost;
+ assert(bestlistcost > 0);
+ }
+ else
+ {
+ FreeStripListVerts(&striplist);
+ }
+ }
+
+#ifdef NEVER
+ // Return the strips in [size1 i1 i2 i3][size2 i4 i5 i6]...[0] format
+ // Very useful for debugging...
+ return stripper.CreateManyStrips(&striplistbest, ppstripindices);
+#endif // NEVER
+
+ // return one big long strip
+ int numindices = stripper.CreateLongStrip(&striplistbest, ppstripindices);
+
+ if(pnumindices)
+ *pnumindices = numindices;
+ return numindices;
+}
+
+//=========================================================================
+// Class used to vertices for locality of access.
+//=========================================================================
+struct SortEntry
+{
+public:
+ int iFirstUsed;
+ int iOrigIndex;
+
+ bool operator<(const SortEntry& rhs) const
+ {
+ return iFirstUsed < rhs.iFirstUsed;
+ }
+};
+
+//=========================================================================
+// Reorder the vertices
+//=========================================================================
+void ComputeVertexPermutation(int numstripindices, WORD* pstripindices,
+ int* pnumverts, WORD** ppvertexpermutation)
+{
+ // Sort verts to maximize locality.
+ SortEntry* pSortTable = new SortEntry[*pnumverts];
+
+ // Fill in original index.
+ int i;
+ for( i = 0; i < *pnumverts; i++)
+ {
+ pSortTable[i].iOrigIndex = i;
+ pSortTable[i].iFirstUsed = -1;
+ }
+
+ // Fill in first used flag.
+ for(i = 0; i < numstripindices; i++)
+ {
+ int index = pstripindices[i];
+
+ if(pSortTable[index].iFirstUsed == -1)
+ pSortTable[index].iFirstUsed = i;
+ }
+
+ // Sort the table.
+ sort(pSortTable, pSortTable + *pnumverts);
+
+ // Copy re-mapped to orignal vertex permutaion into output array.
+ *ppvertexpermutation = new WORD[*pnumverts];
+
+ for(i = 0; i < *pnumverts; i++)
+ {
+ (*ppvertexpermutation)[i] = pSortTable[i].iOrigIndex;
+ }
+
+ // Build original to re-mapped permutation.
+ WORD* pInversePermutation = new WORD[numstripindices];
+
+ for(i = 0; i < *pnumverts; i++)
+ {
+ pInversePermutation[pSortTable[i].iOrigIndex] = i;
+ }
+
+ // We need to remap indices as well.
+ for(i = 0; i < numstripindices; i++)
+ {
+ pstripindices[i] = pInversePermutation[pstripindices[i]];
+ }
+
+ delete[] pSortTable;
+ delete[] pInversePermutation;
+}
+
diff --git a/mp/src/utils/common/mstristrip.h b/mp/src/utils/common/mstristrip.h
index 626a0062..55c93198 100644
--- a/mp/src/utils/common/mstristrip.h
+++ b/mp/src/utils/common/mstristrip.h
@@ -1,43 +1,43 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-//-----------------------------------------------------------------------------
-// FILE: TRISTRIP.H
-//
-// Desc: tristrip header file
-//
-// Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-
-typedef unsigned short WORD;
-
-//
-// Main Stripify routine. Returns number of strip indices contained
-// in ppstripindices. Caller must delete [] ppstripindices.
-//
-int Stripify(
- int numtris, // Number of triangles
- WORD *ptriangles, // triangle indices pointer
- int *pnumindices, // number of indices in ppstripindices (out)
- WORD **ppstripindices // triangle strip indices
-);
-
-//
-// Re-arrange vertices so that they occur in the order that they are first
-// used. This function doesn't actually move vertex data around, it returns
-// an array that specifies where in the new vertex array each old vertex
-// should go. It also re-maps the strip indices to use the new vertex
-// locations. Caller must delete [] pVertexPermutation.
-//
-void ComputeVertexPermutation
-(
- int numstripindices, // Number of strip indices
- WORD *pstripindices, // Strip indices
- int *pnumverts, // Number of verts (in and out)
- WORD **ppvertexpermutation // Map from orignal index to remapped index
-);
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+//-----------------------------------------------------------------------------
+// FILE: TRISTRIP.H
+//
+// Desc: tristrip header file
+//
+// Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+typedef unsigned short WORD;
+
+//
+// Main Stripify routine. Returns number of strip indices contained
+// in ppstripindices. Caller must delete [] ppstripindices.
+//
+int Stripify(
+ int numtris, // Number of triangles
+ WORD *ptriangles, // triangle indices pointer
+ int *pnumindices, // number of indices in ppstripindices (out)
+ WORD **ppstripindices // triangle strip indices
+);
+
+//
+// Re-arrange vertices so that they occur in the order that they are first
+// used. This function doesn't actually move vertex data around, it returns
+// an array that specifies where in the new vertex array each old vertex
+// should go. It also re-maps the strip indices to use the new vertex
+// locations. Caller must delete [] pVertexPermutation.
+//
+void ComputeVertexPermutation
+(
+ int numstripindices, // Number of strip indices
+ WORD *pstripindices, // Strip indices
+ int *pnumverts, // Number of verts (in and out)
+ WORD **ppvertexpermutation // Map from orignal index to remapped index
+);
+
diff --git a/mp/src/utils/common/pacifier.cpp b/mp/src/utils/common/pacifier.cpp
index 6d9c73f2..41a10184 100644
--- a/mp/src/utils/common/pacifier.cpp
+++ b/mp/src/utils/common/pacifier.cpp
@@ -1,63 +1,63 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include <stdio.h>
-#include "basetypes.h"
-#include "pacifier.h"
-#include "tier0/dbg.h"
-
-
-static int g_LastPacifierDrawn = -1;
-static bool g_bPacifierSuppressed = false;
-
-#define clamp(a,b,c) ( (a) > (c) ? (c) : ( (a) < (b) ? (b) : (a) ) )
-
-void StartPacifier( char const *pPrefix )
-{
- Msg( "%s", pPrefix );
- g_LastPacifierDrawn = -1;
- UpdatePacifier( 0.001f );
-}
-
-void UpdatePacifier( float flPercent )
-{
- int iCur = (int)(flPercent * 40.0f);
- iCur = clamp( iCur, g_LastPacifierDrawn, 40 );
-
- if( iCur != g_LastPacifierDrawn && !g_bPacifierSuppressed )
- {
- for( int i=g_LastPacifierDrawn+1; i <= iCur; i++ )
- {
- if ( !( i % 4 ) )
- {
- Msg("%d", i/4);
- }
- else
- {
- if( i != 40 )
- {
- Msg(".");
- }
- }
- }
-
- g_LastPacifierDrawn = iCur;
- }
-}
-
-void EndPacifier( bool bCarriageReturn )
-{
- UpdatePacifier(1);
-
- if( bCarriageReturn && !g_bPacifierSuppressed )
- Msg("\n");
-}
-
-void SuppressPacifier( bool bSuppress )
-{
- g_bPacifierSuppressed = bSuppress;
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+#include "basetypes.h"
+#include "pacifier.h"
+#include "tier0/dbg.h"
+
+
+static int g_LastPacifierDrawn = -1;
+static bool g_bPacifierSuppressed = false;
+
+#define clamp(a,b,c) ( (a) > (c) ? (c) : ( (a) < (b) ? (b) : (a) ) )
+
+void StartPacifier( char const *pPrefix )
+{
+ Msg( "%s", pPrefix );
+ g_LastPacifierDrawn = -1;
+ UpdatePacifier( 0.001f );
+}
+
+void UpdatePacifier( float flPercent )
+{
+ int iCur = (int)(flPercent * 40.0f);
+ iCur = clamp( iCur, g_LastPacifierDrawn, 40 );
+
+ if( iCur != g_LastPacifierDrawn && !g_bPacifierSuppressed )
+ {
+ for( int i=g_LastPacifierDrawn+1; i <= iCur; i++ )
+ {
+ if ( !( i % 4 ) )
+ {
+ Msg("%d", i/4);
+ }
+ else
+ {
+ if( i != 40 )
+ {
+ Msg(".");
+ }
+ }
+ }
+
+ g_LastPacifierDrawn = iCur;
+ }
+}
+
+void EndPacifier( bool bCarriageReturn )
+{
+ UpdatePacifier(1);
+
+ if( bCarriageReturn && !g_bPacifierSuppressed )
+ Msg("\n");
+}
+
+void SuppressPacifier( bool bSuppress )
+{
+ g_bPacifierSuppressed = bSuppress;
+}
diff --git a/mp/src/utils/common/pacifier.h b/mp/src/utils/common/pacifier.h
index 42ecd6ec..d64d6cda 100644
--- a/mp/src/utils/common/pacifier.h
+++ b/mp/src/utils/common/pacifier.h
@@ -1,23 +1,23 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef PACIFIER_H
-#define PACIFIER_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-// Use these to display a pacifier like:
-// ProcessBlock_Thread: 0...1...2...3...4...5...6...7...8...9... (0)
-void StartPacifier( char const *pPrefix ); // Prints the prefix and resets the pacifier
-void UpdatePacifier( float flPercent ); // percent value between 0 and 1.
-void EndPacifier( bool bCarriageReturn = true ); // Completes pacifier as if 100% was done
-void SuppressPacifier( bool bSuppress = true ); // Suppresses pacifier updates if another thread might still be firing them
-
-
-#endif // PACIFIER_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef PACIFIER_H
+#define PACIFIER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// Use these to display a pacifier like:
+// ProcessBlock_Thread: 0...1...2...3...4...5...6...7...8...9... (0)
+void StartPacifier( char const *pPrefix ); // Prints the prefix and resets the pacifier
+void UpdatePacifier( float flPercent ); // percent value between 0 and 1.
+void EndPacifier( bool bCarriageReturn = true ); // Completes pacifier as if 100% was done
+void SuppressPacifier( bool bSuppress = true ); // Suppresses pacifier updates if another thread might still be firing them
+
+
+#endif // PACIFIER_H
diff --git a/mp/src/utils/common/physdll.cpp b/mp/src/utils/common/physdll.cpp
index fae9810a..3df4b964 100644
--- a/mp/src/utils/common/physdll.cpp
+++ b/mp/src/utils/common/physdll.cpp
@@ -1,31 +1,31 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-#include <stdio.h>
-#include "physdll.h"
-#include "filesystem_tools.h"
-
-static CSysModule *pPhysicsModule = NULL;
-CreateInterfaceFn GetPhysicsFactory( void )
-{
- if ( !pPhysicsModule )
- {
- pPhysicsModule = g_pFullFileSystem->LoadModule( "VPHYSICS.DLL" );
- if ( !pPhysicsModule )
- return NULL;
- }
-
- return Sys_GetFactory( pPhysicsModule );
-}
-
-void PhysicsDLLPath( const char *pPathname )
-{
- if ( !pPhysicsModule )
- {
- pPhysicsModule = g_pFullFileSystem->LoadModule( pPathname );
- }
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include <stdio.h>
+#include "physdll.h"
+#include "filesystem_tools.h"
+
+static CSysModule *pPhysicsModule = NULL;
+CreateInterfaceFn GetPhysicsFactory( void )
+{
+ if ( !pPhysicsModule )
+ {
+ pPhysicsModule = g_pFullFileSystem->LoadModule( "VPHYSICS.DLL" );
+ if ( !pPhysicsModule )
+ return NULL;
+ }
+
+ return Sys_GetFactory( pPhysicsModule );
+}
+
+void PhysicsDLLPath( const char *pPathname )
+{
+ if ( !pPhysicsModule )
+ {
+ pPhysicsModule = g_pFullFileSystem->LoadModule( pPathname );
+ }
+}
diff --git a/mp/src/utils/common/physdll.h b/mp/src/utils/common/physdll.h
index 151a9e50..f6faf2d8 100644
--- a/mp/src/utils/common/physdll.h
+++ b/mp/src/utils/common/physdll.h
@@ -1,30 +1,30 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef PHYSDLL_H
-#define PHYSDLL_H
-#pragma once
-
-
-#ifdef __cplusplus
-#include "vphysics_interface.h"
-class IPhysics;
-class IPhysicsCollision;
-
-extern CreateInterfaceFn GetPhysicsFactory( void );
-
-extern "C" {
-#endif
-
-// tools need to force the path
-void PhysicsDLLPath( const char *pPathname );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // PHYSDLL_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef PHYSDLL_H
+#define PHYSDLL_H
+#pragma once
+
+
+#ifdef __cplusplus
+#include "vphysics_interface.h"
+class IPhysics;
+class IPhysicsCollision;
+
+extern CreateInterfaceFn GetPhysicsFactory( void );
+
+extern "C" {
+#endif
+
+// tools need to force the path
+void PhysicsDLLPath( const char *pPathname );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PHYSDLL_H
diff --git a/mp/src/utils/common/polylib.cpp b/mp/src/utils/common/polylib.cpp
index 36690a27..63c91449 100644
--- a/mp/src/utils/common/polylib.cpp
+++ b/mp/src/utils/common/polylib.cpp
@@ -1,915 +1,915 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cmdlib.h"
-#include "mathlib/mathlib.h"
-#include "polylib.h"
-#include "worldsize.h"
-#include "threads.h"
-#include "tier0/dbg.h"
-
-// doesn't seem to need to be here? -- in threads.h
-//extern int numthreads;
-
-// counters are only bumped when running single threaded,
-// because they are an awefull coherence problem
-int c_active_windings;
-int c_peak_windings;
-int c_winding_allocs;
-int c_winding_points;
-
-void pw(winding_t *w)
-{
- int i;
- for (i=0 ; i<w->numpoints ; i++)
- printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
-}
-
-winding_t *winding_pool[MAX_POINTS_ON_WINDING+4];
-
-/*
-=============
-AllocWinding
-=============
-*/
-winding_t *AllocWinding (int points)
-{
- winding_t *w;
-
- if (numthreads == 1)
- {
- c_winding_allocs++;
- c_winding_points += points;
- c_active_windings++;
- if (c_active_windings > c_peak_windings)
- c_peak_windings = c_active_windings;
- }
- ThreadLock();
- if (winding_pool[points])
- {
- w = winding_pool[points];
- winding_pool[points] = w->next;
- }
- else
- {
- w = (winding_t *)malloc(sizeof(*w));
- w->p = (Vector *)calloc( points, sizeof(Vector) );
- }
- ThreadUnlock();
- w->numpoints = 0; // None are occupied yet even though allocated.
- w->maxpoints = points;
- w->next = NULL;
- return w;
-}
-
-void FreeWinding (winding_t *w)
-{
- if (w->numpoints == 0xdeaddead)
- Error ("FreeWinding: freed a freed winding");
-
- ThreadLock();
- w->numpoints = 0xdeaddead; // flag as freed
- w->next = winding_pool[w->maxpoints];
- winding_pool[w->maxpoints] = w;
- ThreadUnlock();
-}
-
-/*
-============
-RemoveColinearPoints
-============
-*/
-int c_removed;
-
-void RemoveColinearPoints (winding_t *w)
-{
- int i, j, k;
- Vector v1, v2;
- int nump;
- Vector p[MAX_POINTS_ON_WINDING];
-
- nump = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- j = (i+1)%w->numpoints;
- k = (i+w->numpoints-1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[i], v1);
- VectorSubtract (w->p[i], w->p[k], v2);
- VectorNormalize(v1);
- VectorNormalize(v2);
- if (DotProduct(v1, v2) < 0.999)
- {
- VectorCopy (w->p[i], p[nump]);
- nump++;
- }
- }
-
- if (nump == w->numpoints)
- return;
-
- if (numthreads == 1)
- c_removed += w->numpoints - nump;
- w->numpoints = nump;
- memcpy (w->p, p, nump*sizeof(p[0]));
-}
-
-/*
-============
-WindingPlane
-============
-*/
-void WindingPlane (winding_t *w, Vector &normal, vec_t *dist)
-{
- Vector v1, v2;
-
- VectorSubtract (w->p[1], w->p[0], v1);
-
- // HACKHACK: Avoid potentially collinear verts
- if ( w->numpoints > 3 )
- {
- VectorSubtract (w->p[3], w->p[0], v2);
- }
- else
- {
- VectorSubtract (w->p[2], w->p[0], v2);
- }
- CrossProduct (v2, v1, normal);
- VectorNormalize (normal);
- *dist = DotProduct (w->p[0], normal);
-
-}
-
-
-/*
-=============
-WindingArea
-=============
-*/
-vec_t WindingArea(winding_t *w)
-{
- int i;
- Vector d1, d2, cross;
- vec_t total;
-
- total = 0;
- for (i=2 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->p[i-1], w->p[0], d1);
- VectorSubtract (w->p[i], w->p[0], d2);
- CrossProduct (d1, d2, cross);
- total += VectorLength ( cross );
- }
- return total * 0.5;
-}
-
-void WindingBounds (winding_t *w, Vector &mins, Vector &maxs)
-{
- vec_t v;
- int i,j;
-
- mins[0] = mins[1] = mins[2] = 99999;
- maxs[0] = maxs[1] = maxs[2] = -99999;
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- v = w->p[i][j];
- if (v < mins[j])
- mins[j] = v;
- if (v > maxs[j])
- maxs[j] = v;
- }
- }
-}
-
-/*
-=============
-WindingCenter
-=============
-*/
-void WindingCenter (winding_t *w, Vector &center)
-{
- int i;
- float scale;
-
- VectorCopy (vec3_origin, center);
- for (i=0 ; i<w->numpoints ; i++)
- VectorAdd (w->p[i], center, center);
-
- scale = 1.0/w->numpoints;
- VectorScale (center, scale, center);
-}
-
-
-
-/*
-=============
-WindingCenter
-=============
-*/
-vec_t WindingAreaAndBalancePoint( winding_t *w, Vector &center )
-{
- int i;
- Vector d1, d2, cross;
- vec_t total;
-
- VectorCopy (vec3_origin, center);
- if ( !w )
- return 0.0f;
-
- total = 0;
- for (i=2 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->p[i-1], w->p[0], d1);
- VectorSubtract (w->p[i], w->p[0], d2);
- CrossProduct (d1, d2, cross);
- float area = VectorLength ( cross );
- total += area;
-
- // center of triangle, weighed by area
- VectorMA( center, area / 3.0, w->p[i-1], center );
- VectorMA( center, area / 3.0, w->p[i], center );
- VectorMA( center, area / 3.0, w->p[0], center );
- }
- if (total)
- {
- VectorScale( center, 1.0 / total, center );
- }
- return total * 0.5;
-}
-
-/*
-=================
-BaseWindingForPlane
-=================
-*/
-winding_t *BaseWindingForPlane (const Vector &normal, vec_t dist)
-{
- int i, x;
- vec_t max, v;
- Vector org, vright, vup;
- winding_t *w;
-
-// find the major axis
-
- max = -1;
- x = -1;
- for (i=0 ; i<3; i++)
- {
- v = fabs(normal[i]);
- if (v > max)
- {
- x = i;
- max = v;
- }
- }
- if (x==-1)
- Error ("BaseWindingForPlane: no axis found");
-
- VectorCopy (vec3_origin, vup);
- switch (x)
- {
- case 0:
- case 1:
- vup[2] = 1;
- break;
- case 2:
- vup[0] = 1;
- break;
- }
-
- v = DotProduct (vup, normal);
- VectorMA (vup, -v, normal, vup);
- VectorNormalize (vup);
-
- VectorScale (normal, dist, org);
-
- CrossProduct (vup, normal, vright);
-
- VectorScale (vup, (MAX_COORD_INTEGER*4), vup);
- VectorScale (vright, (MAX_COORD_INTEGER*4), vright);
-
-// project a really big axis aligned box onto the plane
- w = AllocWinding (4);
-
- VectorSubtract (org, vright, w->p[0]);
- VectorAdd (w->p[0], vup, w->p[0]);
-
- VectorAdd (org, vright, w->p[1]);
- VectorAdd (w->p[1], vup, w->p[1]);
-
- VectorAdd (org, vright, w->p[2]);
- VectorSubtract (w->p[2], vup, w->p[2]);
-
- VectorSubtract (org, vright, w->p[3]);
- VectorSubtract (w->p[3], vup, w->p[3]);
-
- w->numpoints = 4;
-
- return w;
-}
-
-/*
-==================
-CopyWinding
-==================
-*/
-winding_t *CopyWinding (winding_t *w)
-{
- int size;
- winding_t *c;
-
- c = AllocWinding (w->numpoints);
- c->numpoints = w->numpoints;
- size = w->numpoints*sizeof(w->p[0]);
- memcpy (c->p, w->p, size);
- return c;
-}
-
-/*
-==================
-ReverseWinding
-==================
-*/
-winding_t *ReverseWinding (winding_t *w)
-{
- int i;
- winding_t *c;
-
- c = AllocWinding (w->numpoints);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
- }
- c->numpoints = w->numpoints;
- return c;
-}
-
-
-// BUGBUG: Hunt this down - it's causing CSG errors
-#pragma optimize("g", off)
-/*
-=============
-ClipWindingEpsilon
-=============
-*/
-
-void ClipWindingEpsilon (winding_t *in, const Vector &normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back)
-{
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- vec_t dot;
- int i, j;
- Vector mid = vec3_origin;
- winding_t *f, *b;
- int maxpts;
-
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *front = *back = NULL;
-
- if (!counts[0])
- {
- *back = CopyWinding (in);
- return;
- }
- if (!counts[1])
- {
- *front = CopyWinding (in);
- return;
- }
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- *front = f = AllocWinding (maxpts);
- *back = b = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- Vector& p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- Vector& p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (mid, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (f->numpoints > maxpts || b->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
- Error ("ClipWinding: MAX_POINTS_ON_WINDING");
-}
-#pragma optimize("", on)
-
-
-// NOTE: This is identical to ClipWindingEpsilon, but it does a pre/post translation to improve precision
-void ClipWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, const Vector &offset )
-{
- TranslateWinding( in, offset );
- ClipWindingEpsilon( in, normal, dist+DotProduct(offset,normal), epsilon, front, back );
- TranslateWinding( in, -offset );
- if ( front && *front )
- {
- TranslateWinding( *front, -offset );
- }
- if ( back && *back )
- {
- TranslateWinding( *back, -offset );
- }
-}
-
-void ClassifyWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, winding_t **on, const Vector &offset)
-{
- TranslateWinding( in, offset );
- ClassifyWindingEpsilon( in, normal, dist+DotProduct(offset,normal), epsilon, front, back, on );
- TranslateWinding( in, -offset );
- if ( front && *front )
- {
- TranslateWinding( *front, -offset );
- }
- if ( back && *back )
- {
- TranslateWinding( *back, -offset );
- }
- if ( on && *on )
- {
- TranslateWinding( *on, -offset );
- }
-}
-
-/*
-=============
-ClassifyWindingEpsilon
-=============
-*/
-// This version returns the winding as "on" if all verts lie in the plane
-void ClassifyWindingEpsilon( winding_t *in, const Vector &normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back, winding_t **on)
-{
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- vec_t dot;
- int i, j;
- Vector mid = vec3_origin;
- winding_t *f, *b;
- int maxpts;
-
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- *front = *back = *on = NULL;
-
- if ( !counts[0] && !counts[1] )
- {
- *on = CopyWinding(in);
- return;
- }
-
- if (!counts[0])
- {
- *back = CopyWinding(in);
- return;
- }
- if (!counts[1])
- {
- *front = CopyWinding(in);
- return;
- }
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- *front = f = AllocWinding (maxpts);
- *back = b = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- Vector& p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- Vector& p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- VectorCopy (mid, b->p[b->numpoints]);
- b->numpoints++;
- }
-
- if (f->numpoints > maxpts || b->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
- Error ("ClipWinding: MAX_POINTS_ON_WINDING");
-}
-
-/*
-=============
-ChopWindingInPlace
-=============
-*/
-void ChopWindingInPlace (winding_t **inout, const Vector &normal, vec_t dist, vec_t epsilon)
-{
- winding_t *in;
- vec_t dists[MAX_POINTS_ON_WINDING+4];
- int sides[MAX_POINTS_ON_WINDING+4];
- int counts[3];
- vec_t dot;
- int i, j;
- Vector mid = vec3_origin;
- winding_t *f;
- int maxpts;
-
- in = *inout;
- counts[0] = counts[1] = counts[2] = 0;
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->p[i], normal);
- dot -= dist;
- dists[i] = dot;
- if (dot > epsilon)
- {
- sides[i] = SIDE_FRONT;
- }
- else if (dot < -epsilon)
- {
- sides[i] = SIDE_BACK;
- }
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- if (!counts[0])
- {
- FreeWinding (in);
- *inout = NULL;
- return;
- }
- if (!counts[1])
- return; // inout stays the same
-
- maxpts = in->numpoints+4; // cant use counts[0]+2 because
- // of fp grouping errors
-
- f = AllocWinding (maxpts);
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- Vector& p1 = in->p[i];
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f->p[f->numpoints]);
- f->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- // generate a split point
- Vector& p2 = in->p[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (normal[j] == 1)
- mid[j] = dist;
- else if (normal[j] == -1)
- mid[j] = -dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f->p[f->numpoints]);
- f->numpoints++;
- }
-
- if (f->numpoints > maxpts)
- Error ("ClipWinding: points exceeded estimate");
- if (f->numpoints > MAX_POINTS_ON_WINDING)
- Error ("ClipWinding: MAX_POINTS_ON_WINDING");
-
- FreeWinding (in);
- *inout = f;
-}
-
-
-/*
-=================
-ChopWinding
-
-Returns the fragment of in that is on the front side
-of the cliping plane. The original is freed.
-=================
-*/
-winding_t *ChopWinding (winding_t *in, const Vector &normal, vec_t dist)
-{
- winding_t *f, *b;
-
- ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
- FreeWinding (in);
- if (b)
- FreeWinding (b);
- return f;
-}
-
-
-/*
-=================
-CheckWinding
-
-=================
-*/
-void CheckWinding (winding_t *w)
-{
- int i, j;
- vec_t d, edgedist;
- Vector dir, edgenormal, facenormal;
- vec_t area;
- vec_t facedist;
-
- if (w->numpoints < 3)
- Error ("CheckWinding: %i points",w->numpoints);
-
- area = WindingArea(w);
- if (area < 1)
- Error ("CheckWinding: %f area", area);
-
- WindingPlane (w, facenormal, &facedist);
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- Vector& p1 = w->p[i];
-
- for (j=0 ; j<3 ; j++)
- {
- if (p1[j] > MAX_COORD_INTEGER || p1[j] < MIN_COORD_INTEGER)
- Error ("CheckFace: out of range: %f",p1[j]);
- }
-
- j = i+1 == w->numpoints ? 0 : i+1;
-
- // check the point is on the face plane
- d = DotProduct (p1, facenormal) - facedist;
- if (d < -ON_EPSILON || d > ON_EPSILON)
- Error ("CheckWinding: point off plane");
-
- // check the edge isnt degenerate
- Vector& p2 = w->p[j];
- VectorSubtract (p2, p1, dir);
-
- if (VectorLength (dir) < ON_EPSILON)
- Error ("CheckWinding: degenerate edge");
-
- CrossProduct (facenormal, dir, edgenormal);
- VectorNormalize (edgenormal);
- edgedist = DotProduct (p1, edgenormal);
- edgedist += ON_EPSILON;
-
- // all other points must be on front side
- for (j=0 ; j<w->numpoints ; j++)
- {
- if (j == i)
- continue;
- d = DotProduct (w->p[j], edgenormal);
- if (d > edgedist)
- Error ("CheckWinding: non-convex");
- }
- }
-}
-
-
-/*
-============
-WindingOnPlaneSide
-============
-*/
-int WindingOnPlaneSide (winding_t *w, const Vector &normal, vec_t dist)
-{
- qboolean front, back;
- int i;
- vec_t d;
-
- front = false;
- back = false;
- for (i=0 ; i<w->numpoints ; i++)
- {
- d = DotProduct (w->p[i], normal) - dist;
- if (d < -ON_EPSILON)
- {
- if (front)
- return SIDE_CROSS;
- back = true;
- continue;
- }
- if (d > ON_EPSILON)
- {
- if (back)
- return SIDE_CROSS;
- front = true;
- continue;
- }
- }
-
- if (back)
- return SIDE_BACK;
- if (front)
- return SIDE_FRONT;
- return SIDE_ON;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: 2d point inside of winding test (assumes the point resides in the
-// winding plane)
-//-----------------------------------------------------------------------------
-bool PointInWinding( const Vector &pt, winding_t *pWinding )
-{
- if( !pWinding )
- return false;
-
-#if 0
- //
- // NOTE: this will be a quicker way to calculate this, however I don't
- // know the trick off hand (post dot product tests??)
- // TODO: look in graphics gems!!!! (cab)
- //
-
- Vector edge1, edge2;
- for( int ndxPt = 0; ndxPt < pWinding->numpoints; ndxPt++ )
- {
- edge1 = pWinding->p[ndxPt] - pt;
- edge2 = pWinding->p[(ndxPt+1)%pWinding->numpoints] - pt;
-
- VectorNormalize( edge1 );
- VectorNormalize( edge2 );
-
- if( edge2.Dot( edge1 ) < 0.0f )
- return false;
- }
-
- return true;
-
-#else
- Vector edge, toPt, cross, testCross;
-
- //
- // get the first normal to test
- //
- toPt = pt - pWinding->p[0];
- edge = pWinding->p[1] - pWinding->p[0];
- testCross = edge.Cross( toPt );
- VectorNormalize( testCross );
-
- for( int ndxPt = 1; ndxPt < pWinding->numpoints; ndxPt++ )
- {
- toPt = pt - pWinding->p[ndxPt];
- edge = pWinding->p[(ndxPt+1)%pWinding->numpoints] - pWinding->p[ndxPt];
- cross = edge.Cross( toPt );
- VectorNormalize( cross );
-
- if( cross.Dot( testCross ) < 0.0f )
- return false;
- }
-
- return true;
-#endif
-}
-
-void TranslateWinding( winding_t *pWinding, const Vector &offset )
-{
- for ( int i = 0; i < pWinding->numpoints; i++ )
- {
- pWinding->p[i] += offset;
- }
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cmdlib.h"
+#include "mathlib/mathlib.h"
+#include "polylib.h"
+#include "worldsize.h"
+#include "threads.h"
+#include "tier0/dbg.h"
+
+// doesn't seem to need to be here? -- in threads.h
+//extern int numthreads;
+
+// counters are only bumped when running single threaded,
+// because they are an awefull coherence problem
+int c_active_windings;
+int c_peak_windings;
+int c_winding_allocs;
+int c_winding_points;
+
+void pw(winding_t *w)
+{
+ int i;
+ for (i=0 ; i<w->numpoints ; i++)
+ printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
+}
+
+winding_t *winding_pool[MAX_POINTS_ON_WINDING+4];
+
+/*
+=============
+AllocWinding
+=============
+*/
+winding_t *AllocWinding (int points)
+{
+ winding_t *w;
+
+ if (numthreads == 1)
+ {
+ c_winding_allocs++;
+ c_winding_points += points;
+ c_active_windings++;
+ if (c_active_windings > c_peak_windings)
+ c_peak_windings = c_active_windings;
+ }
+ ThreadLock();
+ if (winding_pool[points])
+ {
+ w = winding_pool[points];
+ winding_pool[points] = w->next;
+ }
+ else
+ {
+ w = (winding_t *)malloc(sizeof(*w));
+ w->p = (Vector *)calloc( points, sizeof(Vector) );
+ }
+ ThreadUnlock();
+ w->numpoints = 0; // None are occupied yet even though allocated.
+ w->maxpoints = points;
+ w->next = NULL;
+ return w;
+}
+
+void FreeWinding (winding_t *w)
+{
+ if (w->numpoints == 0xdeaddead)
+ Error ("FreeWinding: freed a freed winding");
+
+ ThreadLock();
+ w->numpoints = 0xdeaddead; // flag as freed
+ w->next = winding_pool[w->maxpoints];
+ winding_pool[w->maxpoints] = w;
+ ThreadUnlock();
+}
+
+/*
+============
+RemoveColinearPoints
+============
+*/
+int c_removed;
+
+void RemoveColinearPoints (winding_t *w)
+{
+ int i, j, k;
+ Vector v1, v2;
+ int nump;
+ Vector p[MAX_POINTS_ON_WINDING];
+
+ nump = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ j = (i+1)%w->numpoints;
+ k = (i+w->numpoints-1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[i], v1);
+ VectorSubtract (w->p[i], w->p[k], v2);
+ VectorNormalize(v1);
+ VectorNormalize(v2);
+ if (DotProduct(v1, v2) < 0.999)
+ {
+ VectorCopy (w->p[i], p[nump]);
+ nump++;
+ }
+ }
+
+ if (nump == w->numpoints)
+ return;
+
+ if (numthreads == 1)
+ c_removed += w->numpoints - nump;
+ w->numpoints = nump;
+ memcpy (w->p, p, nump*sizeof(p[0]));
+}
+
+/*
+============
+WindingPlane
+============
+*/
+void WindingPlane (winding_t *w, Vector &normal, vec_t *dist)
+{
+ Vector v1, v2;
+
+ VectorSubtract (w->p[1], w->p[0], v1);
+
+ // HACKHACK: Avoid potentially collinear verts
+ if ( w->numpoints > 3 )
+ {
+ VectorSubtract (w->p[3], w->p[0], v2);
+ }
+ else
+ {
+ VectorSubtract (w->p[2], w->p[0], v2);
+ }
+ CrossProduct (v2, v1, normal);
+ VectorNormalize (normal);
+ *dist = DotProduct (w->p[0], normal);
+
+}
+
+
+/*
+=============
+WindingArea
+=============
+*/
+vec_t WindingArea(winding_t *w)
+{
+ int i;
+ Vector d1, d2, cross;
+ vec_t total;
+
+ total = 0;
+ for (i=2 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->p[i-1], w->p[0], d1);
+ VectorSubtract (w->p[i], w->p[0], d2);
+ CrossProduct (d1, d2, cross);
+ total += VectorLength ( cross );
+ }
+ return total * 0.5;
+}
+
+void WindingBounds (winding_t *w, Vector &mins, Vector &maxs)
+{
+ vec_t v;
+ int i,j;
+
+ mins[0] = mins[1] = mins[2] = 99999;
+ maxs[0] = maxs[1] = maxs[2] = -99999;
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ v = w->p[i][j];
+ if (v < mins[j])
+ mins[j] = v;
+ if (v > maxs[j])
+ maxs[j] = v;
+ }
+ }
+}
+
+/*
+=============
+WindingCenter
+=============
+*/
+void WindingCenter (winding_t *w, Vector &center)
+{
+ int i;
+ float scale;
+
+ VectorCopy (vec3_origin, center);
+ for (i=0 ; i<w->numpoints ; i++)
+ VectorAdd (w->p[i], center, center);
+
+ scale = 1.0/w->numpoints;
+ VectorScale (center, scale, center);
+}
+
+
+
+/*
+=============
+WindingCenter
+=============
+*/
+vec_t WindingAreaAndBalancePoint( winding_t *w, Vector &center )
+{
+ int i;
+ Vector d1, d2, cross;
+ vec_t total;
+
+ VectorCopy (vec3_origin, center);
+ if ( !w )
+ return 0.0f;
+
+ total = 0;
+ for (i=2 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->p[i-1], w->p[0], d1);
+ VectorSubtract (w->p[i], w->p[0], d2);
+ CrossProduct (d1, d2, cross);
+ float area = VectorLength ( cross );
+ total += area;
+
+ // center of triangle, weighed by area
+ VectorMA( center, area / 3.0, w->p[i-1], center );
+ VectorMA( center, area / 3.0, w->p[i], center );
+ VectorMA( center, area / 3.0, w->p[0], center );
+ }
+ if (total)
+ {
+ VectorScale( center, 1.0 / total, center );
+ }
+ return total * 0.5;
+}
+
+/*
+=================
+BaseWindingForPlane
+=================
+*/
+winding_t *BaseWindingForPlane (const Vector &normal, vec_t dist)
+{
+ int i, x;
+ vec_t max, v;
+ Vector org, vright, vup;
+ winding_t *w;
+
+// find the major axis
+
+ max = -1;
+ x = -1;
+ for (i=0 ; i<3; i++)
+ {
+ v = fabs(normal[i]);
+ if (v > max)
+ {
+ x = i;
+ max = v;
+ }
+ }
+ if (x==-1)
+ Error ("BaseWindingForPlane: no axis found");
+
+ VectorCopy (vec3_origin, vup);
+ switch (x)
+ {
+ case 0:
+ case 1:
+ vup[2] = 1;
+ break;
+ case 2:
+ vup[0] = 1;
+ break;
+ }
+
+ v = DotProduct (vup, normal);
+ VectorMA (vup, -v, normal, vup);
+ VectorNormalize (vup);
+
+ VectorScale (normal, dist, org);
+
+ CrossProduct (vup, normal, vright);
+
+ VectorScale (vup, (MAX_COORD_INTEGER*4), vup);
+ VectorScale (vright, (MAX_COORD_INTEGER*4), vright);
+
+// project a really big axis aligned box onto the plane
+ w = AllocWinding (4);
+
+ VectorSubtract (org, vright, w->p[0]);
+ VectorAdd (w->p[0], vup, w->p[0]);
+
+ VectorAdd (org, vright, w->p[1]);
+ VectorAdd (w->p[1], vup, w->p[1]);
+
+ VectorAdd (org, vright, w->p[2]);
+ VectorSubtract (w->p[2], vup, w->p[2]);
+
+ VectorSubtract (org, vright, w->p[3]);
+ VectorSubtract (w->p[3], vup, w->p[3]);
+
+ w->numpoints = 4;
+
+ return w;
+}
+
+/*
+==================
+CopyWinding
+==================
+*/
+winding_t *CopyWinding (winding_t *w)
+{
+ int size;
+ winding_t *c;
+
+ c = AllocWinding (w->numpoints);
+ c->numpoints = w->numpoints;
+ size = w->numpoints*sizeof(w->p[0]);
+ memcpy (c->p, w->p, size);
+ return c;
+}
+
+/*
+==================
+ReverseWinding
+==================
+*/
+winding_t *ReverseWinding (winding_t *w)
+{
+ int i;
+ winding_t *c;
+
+ c = AllocWinding (w->numpoints);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
+ }
+ c->numpoints = w->numpoints;
+ return c;
+}
+
+
+// BUGBUG: Hunt this down - it's causing CSG errors
+#pragma optimize("g", off)
+/*
+=============
+ClipWindingEpsilon
+=============
+*/
+
+void ClipWindingEpsilon (winding_t *in, const Vector &normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back)
+{
+ vec_t dists[MAX_POINTS_ON_WINDING+4];
+ int sides[MAX_POINTS_ON_WINDING+4];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ Vector mid = vec3_origin;
+ winding_t *f, *b;
+ int maxpts;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ *front = *back = NULL;
+
+ if (!counts[0])
+ {
+ *back = CopyWinding (in);
+ return;
+ }
+ if (!counts[1])
+ {
+ *front = CopyWinding (in);
+ return;
+ }
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ *front = f = AllocWinding (maxpts);
+ *back = b = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ Vector& p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ Vector& p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (mid, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (f->numpoints > maxpts || b->numpoints > maxpts)
+ Error ("ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
+ Error ("ClipWinding: MAX_POINTS_ON_WINDING");
+}
+#pragma optimize("", on)
+
+
+// NOTE: This is identical to ClipWindingEpsilon, but it does a pre/post translation to improve precision
+void ClipWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, const Vector &offset )
+{
+ TranslateWinding( in, offset );
+ ClipWindingEpsilon( in, normal, dist+DotProduct(offset,normal), epsilon, front, back );
+ TranslateWinding( in, -offset );
+ if ( front && *front )
+ {
+ TranslateWinding( *front, -offset );
+ }
+ if ( back && *back )
+ {
+ TranslateWinding( *back, -offset );
+ }
+}
+
+void ClassifyWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, winding_t **on, const Vector &offset)
+{
+ TranslateWinding( in, offset );
+ ClassifyWindingEpsilon( in, normal, dist+DotProduct(offset,normal), epsilon, front, back, on );
+ TranslateWinding( in, -offset );
+ if ( front && *front )
+ {
+ TranslateWinding( *front, -offset );
+ }
+ if ( back && *back )
+ {
+ TranslateWinding( *back, -offset );
+ }
+ if ( on && *on )
+ {
+ TranslateWinding( *on, -offset );
+ }
+}
+
+/*
+=============
+ClassifyWindingEpsilon
+=============
+*/
+// This version returns the winding as "on" if all verts lie in the plane
+void ClassifyWindingEpsilon( winding_t *in, const Vector &normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back, winding_t **on)
+{
+ vec_t dists[MAX_POINTS_ON_WINDING+4];
+ int sides[MAX_POINTS_ON_WINDING+4];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ Vector mid = vec3_origin;
+ winding_t *f, *b;
+ int maxpts;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ *front = *back = *on = NULL;
+
+ if ( !counts[0] && !counts[1] )
+ {
+ *on = CopyWinding(in);
+ return;
+ }
+
+ if (!counts[0])
+ {
+ *back = CopyWinding(in);
+ return;
+ }
+ if (!counts[1])
+ {
+ *front = CopyWinding(in);
+ return;
+ }
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ *front = f = AllocWinding (maxpts);
+ *back = b = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ Vector& p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ Vector& p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ VectorCopy (mid, b->p[b->numpoints]);
+ b->numpoints++;
+ }
+
+ if (f->numpoints > maxpts || b->numpoints > maxpts)
+ Error ("ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
+ Error ("ClipWinding: MAX_POINTS_ON_WINDING");
+}
+
+/*
+=============
+ChopWindingInPlace
+=============
+*/
+void ChopWindingInPlace (winding_t **inout, const Vector &normal, vec_t dist, vec_t epsilon)
+{
+ winding_t *in;
+ vec_t dists[MAX_POINTS_ON_WINDING+4];
+ int sides[MAX_POINTS_ON_WINDING+4];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ Vector mid = vec3_origin;
+ winding_t *f;
+ int maxpts;
+
+ in = *inout;
+ counts[0] = counts[1] = counts[2] = 0;
+// determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->p[i], normal);
+ dot -= dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ {
+ sides[i] = SIDE_FRONT;
+ }
+ else if (dot < -epsilon)
+ {
+ sides[i] = SIDE_BACK;
+ }
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ if (!counts[0])
+ {
+ FreeWinding (in);
+ *inout = NULL;
+ return;
+ }
+ if (!counts[1])
+ return; // inout stays the same
+
+ maxpts = in->numpoints+4; // cant use counts[0]+2 because
+ // of fp grouping errors
+
+ f = AllocWinding (maxpts);
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ Vector& p1 = in->p[i];
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ // generate a split point
+ Vector& p2 = in->p[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (normal[j] == 1)
+ mid[j] = dist;
+ else if (normal[j] == -1)
+ mid[j] = -dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f->p[f->numpoints]);
+ f->numpoints++;
+ }
+
+ if (f->numpoints > maxpts)
+ Error ("ClipWinding: points exceeded estimate");
+ if (f->numpoints > MAX_POINTS_ON_WINDING)
+ Error ("ClipWinding: MAX_POINTS_ON_WINDING");
+
+ FreeWinding (in);
+ *inout = f;
+}
+
+
+/*
+=================
+ChopWinding
+
+Returns the fragment of in that is on the front side
+of the cliping plane. The original is freed.
+=================
+*/
+winding_t *ChopWinding (winding_t *in, const Vector &normal, vec_t dist)
+{
+ winding_t *f, *b;
+
+ ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
+ FreeWinding (in);
+ if (b)
+ FreeWinding (b);
+ return f;
+}
+
+
+/*
+=================
+CheckWinding
+
+=================
+*/
+void CheckWinding (winding_t *w)
+{
+ int i, j;
+ vec_t d, edgedist;
+ Vector dir, edgenormal, facenormal;
+ vec_t area;
+ vec_t facedist;
+
+ if (w->numpoints < 3)
+ Error ("CheckWinding: %i points",w->numpoints);
+
+ area = WindingArea(w);
+ if (area < 1)
+ Error ("CheckWinding: %f area", area);
+
+ WindingPlane (w, facenormal, &facedist);
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ Vector& p1 = w->p[i];
+
+ for (j=0 ; j<3 ; j++)
+ {
+ if (p1[j] > MAX_COORD_INTEGER || p1[j] < MIN_COORD_INTEGER)
+ Error ("CheckFace: out of range: %f",p1[j]);
+ }
+
+ j = i+1 == w->numpoints ? 0 : i+1;
+
+ // check the point is on the face plane
+ d = DotProduct (p1, facenormal) - facedist;
+ if (d < -ON_EPSILON || d > ON_EPSILON)
+ Error ("CheckWinding: point off plane");
+
+ // check the edge isnt degenerate
+ Vector& p2 = w->p[j];
+ VectorSubtract (p2, p1, dir);
+
+ if (VectorLength (dir) < ON_EPSILON)
+ Error ("CheckWinding: degenerate edge");
+
+ CrossProduct (facenormal, dir, edgenormal);
+ VectorNormalize (edgenormal);
+ edgedist = DotProduct (p1, edgenormal);
+ edgedist += ON_EPSILON;
+
+ // all other points must be on front side
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct (w->p[j], edgenormal);
+ if (d > edgedist)
+ Error ("CheckWinding: non-convex");
+ }
+ }
+}
+
+
+/*
+============
+WindingOnPlaneSide
+============
+*/
+int WindingOnPlaneSide (winding_t *w, const Vector &normal, vec_t dist)
+{
+ qboolean front, back;
+ int i;
+ vec_t d;
+
+ front = false;
+ back = false;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ d = DotProduct (w->p[i], normal) - dist;
+ if (d < -ON_EPSILON)
+ {
+ if (front)
+ return SIDE_CROSS;
+ back = true;
+ continue;
+ }
+ if (d > ON_EPSILON)
+ {
+ if (back)
+ return SIDE_CROSS;
+ front = true;
+ continue;
+ }
+ }
+
+ if (back)
+ return SIDE_BACK;
+ if (front)
+ return SIDE_FRONT;
+ return SIDE_ON;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: 2d point inside of winding test (assumes the point resides in the
+// winding plane)
+//-----------------------------------------------------------------------------
+bool PointInWinding( const Vector &pt, winding_t *pWinding )
+{
+ if( !pWinding )
+ return false;
+
+#if 0
+ //
+ // NOTE: this will be a quicker way to calculate this, however I don't
+ // know the trick off hand (post dot product tests??)
+ // TODO: look in graphics gems!!!! (cab)
+ //
+
+ Vector edge1, edge2;
+ for( int ndxPt = 0; ndxPt < pWinding->numpoints; ndxPt++ )
+ {
+ edge1 = pWinding->p[ndxPt] - pt;
+ edge2 = pWinding->p[(ndxPt+1)%pWinding->numpoints] - pt;
+
+ VectorNormalize( edge1 );
+ VectorNormalize( edge2 );
+
+ if( edge2.Dot( edge1 ) < 0.0f )
+ return false;
+ }
+
+ return true;
+
+#else
+ Vector edge, toPt, cross, testCross;
+
+ //
+ // get the first normal to test
+ //
+ toPt = pt - pWinding->p[0];
+ edge = pWinding->p[1] - pWinding->p[0];
+ testCross = edge.Cross( toPt );
+ VectorNormalize( testCross );
+
+ for( int ndxPt = 1; ndxPt < pWinding->numpoints; ndxPt++ )
+ {
+ toPt = pt - pWinding->p[ndxPt];
+ edge = pWinding->p[(ndxPt+1)%pWinding->numpoints] - pWinding->p[ndxPt];
+ cross = edge.Cross( toPt );
+ VectorNormalize( cross );
+
+ if( cross.Dot( testCross ) < 0.0f )
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+void TranslateWinding( winding_t *pWinding, const Vector &offset )
+{
+ for ( int i = 0; i < pWinding->numpoints; i++ )
+ {
+ pWinding->p[i] += offset;
+ }
+}
diff --git a/mp/src/utils/common/polylib.h b/mp/src/utils/common/polylib.h
index 1750a82a..8753dccc 100644
--- a/mp/src/utils/common/polylib.h
+++ b/mp/src/utils/common/polylib.h
@@ -1,78 +1,78 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-//
-//-----------------------------------------------------------------------------
-// $Log: $
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef POLYLIB_H
-#define POLYLIB_H
-#pragma once
-
-#ifndef MATHLIB_H
-#include "mathlib/mathlib.h"
-#endif
-
-struct winding_t
-{
- int numpoints;
- Vector *p; // variable sized
- int maxpoints;
- winding_t *next;
-};
-
-#define MAX_POINTS_ON_WINDING 64
-
-// you can define on_epsilon in the makefile as tighter
-// point on plane side epsilon
-// todo: need a world-space epsilon, a lightmap-space epsilon, and a texture space epsilon
-// or at least convert from a world-space epsilon to lightmap and texture space epsilons
-#ifndef ON_EPSILON
-#define ON_EPSILON 0.1
-#endif
-
-
-winding_t *AllocWinding (int points);
-vec_t WindingArea (winding_t *w);
-void WindingCenter (winding_t *w, Vector &center);
-vec_t WindingAreaAndBalancePoint( winding_t *w, Vector &center );
-void ClipWindingEpsilon (winding_t *in, const Vector &normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back);
-
-// translates everything by offset, then does the clip, then translates back (to keep precision)
-void ClipWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, const Vector &offset );
-
-void ClassifyWindingEpsilon( winding_t *in, const Vector &normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back, winding_t **on);
-void ClassifyWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back, winding_t **on, const Vector &offset);
-
-winding_t *ChopWinding (winding_t *in, const Vector &normal, vec_t dist);
-winding_t *CopyWinding (winding_t *w);
-winding_t *ReverseWinding (winding_t *w);
-winding_t *BaseWindingForPlane (const Vector &normal, vec_t dist);
-void CheckWinding (winding_t *w);
-void WindingPlane (winding_t *w, Vector &normal, vec_t *dist);
-void RemoveColinearPoints (winding_t *w);
-int WindingOnPlaneSide (winding_t *w, const Vector &normal, vec_t dist);
-void FreeWinding (winding_t *w);
-void WindingBounds (winding_t *w, Vector &mins, Vector &maxs);
-
-void ChopWindingInPlace (winding_t **w, const Vector &normal, vec_t dist, vec_t epsilon);
-// frees the original if clipped
-
-bool PointInWinding( Vector const &pt, winding_t *pWinding );
-
-// translates a winding by offset
-void TranslateWinding( winding_t *pWinding, const Vector &offset );
-
-void pw(winding_t *w);
-
-
-#endif // POLYLIB_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef POLYLIB_H
+#define POLYLIB_H
+#pragma once
+
+#ifndef MATHLIB_H
+#include "mathlib/mathlib.h"
+#endif
+
+struct winding_t
+{
+ int numpoints;
+ Vector *p; // variable sized
+ int maxpoints;
+ winding_t *next;
+};
+
+#define MAX_POINTS_ON_WINDING 64
+
+// you can define on_epsilon in the makefile as tighter
+// point on plane side epsilon
+// todo: need a world-space epsilon, a lightmap-space epsilon, and a texture space epsilon
+// or at least convert from a world-space epsilon to lightmap and texture space epsilons
+#ifndef ON_EPSILON
+#define ON_EPSILON 0.1
+#endif
+
+
+winding_t *AllocWinding (int points);
+vec_t WindingArea (winding_t *w);
+void WindingCenter (winding_t *w, Vector &center);
+vec_t WindingAreaAndBalancePoint( winding_t *w, Vector &center );
+void ClipWindingEpsilon (winding_t *in, const Vector &normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back);
+
+// translates everything by offset, then does the clip, then translates back (to keep precision)
+void ClipWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back, const Vector &offset );
+
+void ClassifyWindingEpsilon( winding_t *in, const Vector &normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back, winding_t **on);
+void ClassifyWindingEpsilon_Offset( winding_t *in, const Vector &normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back, winding_t **on, const Vector &offset);
+
+winding_t *ChopWinding (winding_t *in, const Vector &normal, vec_t dist);
+winding_t *CopyWinding (winding_t *w);
+winding_t *ReverseWinding (winding_t *w);
+winding_t *BaseWindingForPlane (const Vector &normal, vec_t dist);
+void CheckWinding (winding_t *w);
+void WindingPlane (winding_t *w, Vector &normal, vec_t *dist);
+void RemoveColinearPoints (winding_t *w);
+int WindingOnPlaneSide (winding_t *w, const Vector &normal, vec_t dist);
+void FreeWinding (winding_t *w);
+void WindingBounds (winding_t *w, Vector &mins, Vector &maxs);
+
+void ChopWindingInPlace (winding_t **w, const Vector &normal, vec_t dist, vec_t epsilon);
+// frees the original if clipped
+
+bool PointInWinding( Vector const &pt, winding_t *pWinding );
+
+// translates a winding by offset
+void TranslateWinding( winding_t *pWinding, const Vector &offset );
+
+void pw(winding_t *w);
+
+
+#endif // POLYLIB_H
diff --git a/mp/src/utils/common/qfiles.h b/mp/src/utils/common/qfiles.h
index b1d2232f..fc122c33 100644
--- a/mp/src/utils/common/qfiles.h
+++ b/mp/src/utils/common/qfiles.h
@@ -1,42 +1,42 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-//
-//-----------------------------------------------------------------------------
-// $Log: $
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef QFILES_H
-#define QFILES_H
-#pragma once
-
-
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-#include "basetypes.h"
-#include "commonmacros.h"
-#include "worldsize.h"
-#include "bspfile.h"
-
-#define MAX_OSPATH 260
-#define MAX_QPATH 64
-
-/*
-========================================================================
-
-The .pak files are just a linear collapse of a directory tree
-
-========================================================================
-*/
-
-#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
-
-#endif // QFILES_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef QFILES_H
+#define QFILES_H
+#pragma once
+
+
+//
+// qfiles.h: quake file formats
+// This file must be identical in the quake and utils directories
+//
+
+#include "basetypes.h"
+#include "commonmacros.h"
+#include "worldsize.h"
+#include "bspfile.h"
+
+#define MAX_OSPATH 260
+#define MAX_QPATH 64
+
+/*
+========================================================================
+
+The .pak files are just a linear collapse of a directory tree
+
+========================================================================
+*/
+
+#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
+
+#endif // QFILES_H
diff --git a/mp/src/utils/common/scratchpad_helpers.cpp b/mp/src/utils/common/scratchpad_helpers.cpp
index 9a3c2d74..ecab731b 100644
--- a/mp/src/utils/common/scratchpad_helpers.cpp
+++ b/mp/src/utils/common/scratchpad_helpers.cpp
@@ -1,103 +1,103 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include "scratchpad_helpers.h"
-#include "bspfile.h"
-#include "bsplib.h"
-
-
-void ScratchPad_DrawWinding(
- IScratchPad3D *pPad,
- int nPoints,
- Vector *pPoints,
- Vector vColor,
- Vector vOffset )
-{
- for ( int i=0; i < nPoints; i++ )
- {
- pPad->DrawLine( CSPVert( pPoints[i]+vOffset, vColor ), CSPVert( pPoints[(i+1)%nPoints]+vOffset, vColor ) );
- }
-}
-
-
-void ScratchPad_DrawFace( IScratchPad3D *pPad, dface_t *f, int iFaceNumber, const CSPColor &faceColor, const Vector &vOffset )
-{
- // Draw the face's outline, then put text for its face index on it too.
- CUtlVector<Vector> points;
- for ( int iEdge = 0; iEdge < f->numedges; iEdge++ )
- {
- int v;
- int se = dsurfedges[f->firstedge + iEdge];
- if ( se < 0 )
- v = dedges[-se].v[1];
- else
- v = dedges[se].v[0];
-
- dvertex_t *dv = &dvertexes[v];
- points.AddToTail( dv->point );
- }
-
- // Draw the outline.
- Vector vCenter( 0, 0, 0 );
- for ( int iEdge=0; iEdge < points.Count(); iEdge++ )
- {
- pPad->DrawLine( CSPVert( points[iEdge]+vOffset, faceColor ), CSPVert( points[(iEdge+1)%points.Count()]+vOffset, faceColor ) );
- vCenter += points[iEdge];
- }
- vCenter /= points.Count();
- vCenter += vOffset;
-
- // Draw the text.
- if ( iFaceNumber != -1 )
- {
- char str[64];
- Q_snprintf( str, sizeof( str ), "%d", iFaceNumber );
-
- CTextParams params;
-
- params.m_bCentered = true;
- params.m_bOutline = true;
- params.m_flLetterWidth = 2;
- params.m_vColor.Init( 1, 0, 0 );
-
- VectorAngles( dplanes[f->planenum].normal, params.m_vAngles );
- params.m_bTwoSided = true;
-
- params.m_vPos = vCenter;
-
- pPad->DrawText( str, params );
- }
-}
-
-
-void ScratchPad_DrawWorld( IScratchPad3D *pPad, bool bDrawFaceNumbers, const CSPColor &faceColor )
-{
- bool bAutoFlush = pPad->GetAutoFlush();
- pPad->SetAutoFlush( false );
-
- for ( int i=0; i < numleafs; i++ )
- {
- dleaf_t *l = &dleafs[i];
- if ( l->contents & CONTENTS_DETAIL )
- continue;
-
- for ( int z=0; z < l->numleaffaces; z++ )
- {
- int iFace = dleaffaces[l->firstleafface+z];
- dface_t *f = &dfaces[iFace];
- ScratchPad_DrawFace( pPad, f, bDrawFaceNumbers ? i : -1 );
- }
- }
-
- pPad->SetAutoFlush( bAutoFlush );
-}
-
-
-void ScratchPad_DrawWorld( bool bDrawFaceNumbers, const CSPColor &faceColor )
-{
- IScratchPad3D *pPad = ScratchPad3D_Create();
- ScratchPad_DrawWorld( pPad, bDrawFaceNumbers );
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "scratchpad_helpers.h"
+#include "bspfile.h"
+#include "bsplib.h"
+
+
+void ScratchPad_DrawWinding(
+ IScratchPad3D *pPad,
+ int nPoints,
+ Vector *pPoints,
+ Vector vColor,
+ Vector vOffset )
+{
+ for ( int i=0; i < nPoints; i++ )
+ {
+ pPad->DrawLine( CSPVert( pPoints[i]+vOffset, vColor ), CSPVert( pPoints[(i+1)%nPoints]+vOffset, vColor ) );
+ }
+}
+
+
+void ScratchPad_DrawFace( IScratchPad3D *pPad, dface_t *f, int iFaceNumber, const CSPColor &faceColor, const Vector &vOffset )
+{
+ // Draw the face's outline, then put text for its face index on it too.
+ CUtlVector<Vector> points;
+ for ( int iEdge = 0; iEdge < f->numedges; iEdge++ )
+ {
+ int v;
+ int se = dsurfedges[f->firstedge + iEdge];
+ if ( se < 0 )
+ v = dedges[-se].v[1];
+ else
+ v = dedges[se].v[0];
+
+ dvertex_t *dv = &dvertexes[v];
+ points.AddToTail( dv->point );
+ }
+
+ // Draw the outline.
+ Vector vCenter( 0, 0, 0 );
+ for ( int iEdge=0; iEdge < points.Count(); iEdge++ )
+ {
+ pPad->DrawLine( CSPVert( points[iEdge]+vOffset, faceColor ), CSPVert( points[(iEdge+1)%points.Count()]+vOffset, faceColor ) );
+ vCenter += points[iEdge];
+ }
+ vCenter /= points.Count();
+ vCenter += vOffset;
+
+ // Draw the text.
+ if ( iFaceNumber != -1 )
+ {
+ char str[64];
+ Q_snprintf( str, sizeof( str ), "%d", iFaceNumber );
+
+ CTextParams params;
+
+ params.m_bCentered = true;
+ params.m_bOutline = true;
+ params.m_flLetterWidth = 2;
+ params.m_vColor.Init( 1, 0, 0 );
+
+ VectorAngles( dplanes[f->planenum].normal, params.m_vAngles );
+ params.m_bTwoSided = true;
+
+ params.m_vPos = vCenter;
+
+ pPad->DrawText( str, params );
+ }
+}
+
+
+void ScratchPad_DrawWorld( IScratchPad3D *pPad, bool bDrawFaceNumbers, const CSPColor &faceColor )
+{
+ bool bAutoFlush = pPad->GetAutoFlush();
+ pPad->SetAutoFlush( false );
+
+ for ( int i=0; i < numleafs; i++ )
+ {
+ dleaf_t *l = &dleafs[i];
+ if ( l->contents & CONTENTS_DETAIL )
+ continue;
+
+ for ( int z=0; z < l->numleaffaces; z++ )
+ {
+ int iFace = dleaffaces[l->firstleafface+z];
+ dface_t *f = &dfaces[iFace];
+ ScratchPad_DrawFace( pPad, f, bDrawFaceNumbers ? i : -1 );
+ }
+ }
+
+ pPad->SetAutoFlush( bAutoFlush );
+}
+
+
+void ScratchPad_DrawWorld( bool bDrawFaceNumbers, const CSPColor &faceColor )
+{
+ IScratchPad3D *pPad = ScratchPad3D_Create();
+ ScratchPad_DrawWorld( pPad, bDrawFaceNumbers );
+}
diff --git a/mp/src/utils/common/scratchpad_helpers.h b/mp/src/utils/common/scratchpad_helpers.h
index 8f409fca..29e5a122 100644
--- a/mp/src/utils/common/scratchpad_helpers.h
+++ b/mp/src/utils/common/scratchpad_helpers.h
@@ -1,25 +1,25 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#ifndef SCRATCHPAD_HELPERS_H
-#define SCRATCHPAD_HELPERS_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-#include "iscratchpad3d.h"
-#include "bspfile.h"
-
-
-void ScratchPad_DrawWinding( IScratchPad3D *pPad, int nPoints, Vector *pPoints, Vector vColor, Vector vOffset = Vector(0,0,0) );
-
-void ScratchPad_DrawFace( IScratchPad3D *pPad, dface_t *f, int iFaceNumber = -1, const CSPColor &faceColor=CSPColor(1,1,1,1), const Vector &vOffset=Vector(0,0,0) );
-void ScratchPad_DrawWorld( IScratchPad3D *pPad, bool bDrawFaceNumbers, const CSPColor &faceColor=CSPColor(1,1,1,1) );
-void ScratchPad_DrawWorld( bool bDrawFaceNumbers, const CSPColor &faceColor=CSPColor(1,1,1,1) );
-
-
-#endif // SCRATCHPAD_HELPERS_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SCRATCHPAD_HELPERS_H
+#define SCRATCHPAD_HELPERS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "iscratchpad3d.h"
+#include "bspfile.h"
+
+
+void ScratchPad_DrawWinding( IScratchPad3D *pPad, int nPoints, Vector *pPoints, Vector vColor, Vector vOffset = Vector(0,0,0) );
+
+void ScratchPad_DrawFace( IScratchPad3D *pPad, dface_t *f, int iFaceNumber = -1, const CSPColor &faceColor=CSPColor(1,1,1,1), const Vector &vOffset=Vector(0,0,0) );
+void ScratchPad_DrawWorld( IScratchPad3D *pPad, bool bDrawFaceNumbers, const CSPColor &faceColor=CSPColor(1,1,1,1) );
+void ScratchPad_DrawWorld( bool bDrawFaceNumbers, const CSPColor &faceColor=CSPColor(1,1,1,1) );
+
+
+#endif // SCRATCHPAD_HELPERS_H
diff --git a/mp/src/utils/common/scriplib.cpp b/mp/src/utils/common/scriplib.cpp
index 469c7885..1c8b47f8 100644
--- a/mp/src/utils/common/scriplib.cpp
+++ b/mp/src/utils/common/scriplib.cpp
@@ -1,1349 +1,1349 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//===========================================================================//
-
-// scriplib.c
-
-#include "tier1/strtools.h"
-#include "tier2/tier2.h"
-#include "cmdlib.h"
-#include "scriplib.h"
-#if defined( _X360 )
-#include "xbox\xbox_win32stubs.h"
-#endif
-#if defined(POSIX)
-#include "../../filesystem/linux_support.h"
-#include <sys/stat.h>
-#endif
-/*
-=============================================================================
-
- PARSING STUFF
-
-=============================================================================
-*/
-
-typedef struct
-{
- char filename[1024];
- char *buffer,*script_p,*end_p;
- int line;
-
- char macrobuffer[4096];
- char *macroparam[64];
- char *macrovalue[64];
- int nummacroparams;
-
-} script_t;
-
-#define MAX_INCLUDES 64
-script_t scriptstack[MAX_INCLUDES];
-script_t *script = NULL;
-int scriptline;
-
-char token[MAXTOKEN];
-qboolean endofscript;
-qboolean tokenready; // only true if UnGetToken was just called
-
-typedef struct
-{
- char *param;
- char *value;
-} variable_t;
-
-CUtlVector<variable_t> g_definevariable;
-
-/*
-Callback stuff
-*/
-
-void DefaultScriptLoadedCallback( char const *pFilenameLoaded, char const *pIncludedFromFileName, int nIncludeLineNumber )
-{
- NULL;
-}
-
-SCRIPT_LOADED_CALLBACK g_pfnCallback = DefaultScriptLoadedCallback;
-
-SCRIPT_LOADED_CALLBACK SetScriptLoadedCallback( SCRIPT_LOADED_CALLBACK pfnNewScriptLoadedCallback )
-{
- SCRIPT_LOADED_CALLBACK pfnCallback = g_pfnCallback;
- g_pfnCallback = pfnNewScriptLoadedCallback;
- return pfnCallback;
-}
-
-/*
-==============
-AddScriptToStack
-==============
-*/
-void AddScriptToStack (char *filename, ScriptPathMode_t pathMode = SCRIPT_USE_ABSOLUTE_PATH)
-{
- int size;
-
- script++;
- if (script == &scriptstack[MAX_INCLUDES])
- Error ("script file exceeded MAX_INCLUDES");
-
- if ( pathMode == SCRIPT_USE_RELATIVE_PATH )
- Q_strncpy( script->filename, filename, sizeof( script->filename ) );
- else
- Q_strncpy (script->filename, ExpandPath (filename), sizeof( script->filename ) );
-
- size = LoadFile (script->filename, (void **)&script->buffer);
-
- // printf ("entering %s\n", script->filename);
- if ( g_pfnCallback )
- {
- if ( script == scriptstack + 1 )
- g_pfnCallback( script->filename, NULL, 0 );
- else
- g_pfnCallback( script->filename, script[-1].filename, script[-1].line );
- }
-
- script->line = 1;
-
- script->script_p = script->buffer;
- script->end_p = script->buffer + size;
-}
-
-
-/*
-==============
-LoadScriptFile
-==============
-*/
-void LoadScriptFile (char *filename, ScriptPathMode_t pathMode)
-{
- script = scriptstack;
- AddScriptToStack (filename, pathMode);
-
- endofscript = false;
- tokenready = false;
-}
-
-
-/*
-==============
-==============
-*/
-
-script_t *macrolist[256];
-int nummacros;
-
-void DefineMacro( char *macroname )
-{
- script_t *pmacro = (script_t *)malloc( sizeof( script_t ) );
-
- strcpy( pmacro->filename, macroname );
- pmacro->line = script->line;
- pmacro->nummacroparams = 0;
-
- char *mp = pmacro->macrobuffer;
- char *cp = script->script_p;
-
- while (TokenAvailable( ))
- {
- GetToken( false );
-
- if (token[0] == '\\' && token[1] == '\\')
- {
- break;
- }
- cp = script->script_p;
-
- pmacro->macroparam[pmacro->nummacroparams++] = mp;
-
- strcpy( mp, token );
- mp += strlen( token ) + 1;
-
- if (mp >= pmacro->macrobuffer + sizeof( pmacro->macrobuffer ))
- Error("Macro buffer overflow\n");
- }
- // roll back script_p to previous valid location
- script->script_p = cp;
-
- // find end of macro def
- while (*cp && *cp != '\n')
- {
- //Msg("%d ", *cp );
- if (*cp == '\\' && *(cp+1) == '\\')
- {
- // skip till end of line
- while (*cp && *cp != '\n')
- {
- *cp = ' '; // replace with spaces
- cp++;
- }
-
- if (*cp)
- {
- cp++;
- }
- }
- else
- {
- cp++;
- }
- }
-
- int size = (cp - script->script_p);
-
- pmacro->buffer = (char *)malloc( size + 1);
- memcpy( pmacro->buffer, script->script_p, size );
- pmacro->buffer[size] = '\0';
- pmacro->end_p = &pmacro->buffer[size];
-
- macrolist[nummacros++] = pmacro;
-
- script->script_p = cp;
-}
-
-
-void DefineVariable( char *variablename )
-{
- variable_t v;
-
- v.param = strdup( variablename );
-
- GetToken( false );
-
- v.value = strdup( token );
-
- g_definevariable.AddToTail( v );
-}
-
-
-
-/*
-==============
-==============
-*/
-bool AddMacroToStack( char *macroname )
-{
- // lookup macro
- if (macroname[0] != '$')
- return false;
-
- int i;
- for (i = 0; i < nummacros; i++)
- {
- if (strcmpi( macrolist[i]->filename, &macroname[1] ) == 0)
- {
- break;
- }
- }
- if (i == nummacros)
- return false;
-
- script_t *pmacro = macrolist[i];
-
- // get tokens
- script_t *pnext = script + 1;
-
- pnext++;
- if (pnext == &scriptstack[MAX_INCLUDES])
- Error ("script file exceeded MAX_INCLUDES");
-
- // get tokens
- char *cp = pnext->macrobuffer;
-
- pnext->nummacroparams = pmacro->nummacroparams;
-
- for (i = 0; i < pnext->nummacroparams; i++)
- {
- GetToken(false);
-
- strcpy( cp, token );
- pnext->macroparam[i] = pmacro->macroparam[i];
- pnext->macrovalue[i] = cp;
-
- cp += strlen( token ) + 1;
-
- if (cp >= pnext->macrobuffer + sizeof( pnext->macrobuffer ))
- Error("Macro buffer overflow\n");
- }
-
- script = pnext;
- strcpy( script->filename, pmacro->filename );
-
- int size = pmacro->end_p - pmacro->buffer;
- script->buffer = (char *)malloc( size + 1 );
- memcpy( script->buffer, pmacro->buffer, size );
- pmacro->buffer[size] = '\0';
- script->script_p = script->buffer;
- script->end_p = script->buffer + size;
- script->line = pmacro->line;
-
- return true;
-}
-
-
-
-bool ExpandMacroToken( char *&token_p )
-{
- if ( script->nummacroparams && *script->script_p == '$' )
- {
- char *cp = script->script_p + 1;
-
- while ( *cp > 32 && *cp != '$' )
- {
- cp++;
- }
-
- // found a word with $'s on either end?
- if (*cp != '$')
- return false;
-
- // get token pointer
- char *tp = script->script_p + 1;
- int len = (cp - tp);
- *(tp + len) = '\0';
-
- // lookup macro parameter
- int index = 0;
- for (index = 0; index < script->nummacroparams; index++)
- {
- if (stricmp( script->macroparam[index], tp ) == 0)
- break;
- }
- if (index >= script->nummacroparams)
- {
- Error("unknown macro token \"%s\" in %s\n", tp, script->filename );
- }
-
- // paste token into
- len = strlen( script->macrovalue[index] );
- strcpy( token_p, script->macrovalue[index] );
- token_p += len;
-
- script->script_p = cp + 1;
-
- if (script->script_p >= script->end_p)
- Error ("Macro expand overflow\n");
-
- if (token_p >= &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
-
- return true;
- }
- return false;
-}
-
-
-
-/*
-==============
-==============
-*/
-// FIXME: this should create a new script context so the individual tokens in the variable can be parsed
-bool ExpandVariableToken( char *&token_p )
-{
- if ( *script->script_p == '$' )
- {
- char *cp = script->script_p + 1;
-
- while ( *cp > 32 && *cp != '$' )
- {
- cp++;
- }
-
- // found a word with $'s on either end?
- if (*cp != '$')
- return false;
-
- // get token pointer
- char *tp = script->script_p + 1;
- int len = (cp - tp);
- *(tp + len) = '\0';
-
- // lookup macro parameter
-
- int index;
- for (index = 0; index < g_definevariable.Count(); index++)
- {
- if (Q_strnicmp( g_definevariable[index].param, tp, len ) == 0)
- break;
- }
-
- if (index >= g_definevariable.Count() )
- {
- Error("unknown variable token \"%s\" in %s\n", tp, script->filename );
- }
-
- // paste token into
- len = strlen( g_definevariable[index].value );
- strcpy( token_p, g_definevariable[index].value );
- token_p += len;
-
- script->script_p = cp + 1;
-
- if (script->script_p >= script->end_p)
- Error ("Macro expand overflow\n");
-
- if (token_p >= &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
-
- return true;
- }
- return false;
-}
-
-
-
-/*
-==============
-ParseFromMemory
-==============
-*/
-void ParseFromMemory (char *buffer, int size)
-{
- script = scriptstack;
- script++;
- if (script == &scriptstack[MAX_INCLUDES])
- Error ("script file exceeded MAX_INCLUDES");
- strcpy (script->filename, "memory buffer" );
-
- script->buffer = buffer;
- script->line = 1;
- script->script_p = script->buffer;
- script->end_p = script->buffer + size;
-
- endofscript = false;
- tokenready = false;
-}
-
-
-//-----------------------------------------------------------------------------
-// Used instead of ParseFromMemory to temporarily add a memory buffer
-// to the script stack. ParseFromMemory just blows away the stack.
-//-----------------------------------------------------------------------------
-void PushMemoryScript( char *pszBuffer, const int nSize )
-{
- if ( script == NULL )
- {
- script = scriptstack;
- }
- script++;
- if ( script == &scriptstack[MAX_INCLUDES] )
- {
- Error ( "script file exceeded MAX_INCLUDES" );
- }
- strcpy (script->filename, "memory buffer" );
-
- script->buffer = pszBuffer;
- script->line = 1;
- script->script_p = script->buffer;
- script->end_p = script->buffer + nSize;
-
- endofscript = false;
- tokenready = false;
-}
-
-
-//-----------------------------------------------------------------------------
-// Used after calling PushMemoryScript to clean up the memory buffer
-// added to the script stack. The normal end of script terminates
-// all parsing at the end of a memory buffer even if there are more scripts
-// remaining on the script stack
-//-----------------------------------------------------------------------------
-bool PopMemoryScript()
-{
- if ( V_stricmp( script->filename, "memory buffer" ) )
- return false;
-
- if ( script == scriptstack )
- {
- endofscript = true;
- return false;
- }
- script--;
- scriptline = script->line;
-
- endofscript = false;
-
- return true;
-}
-
-
-/*
-==============
-UnGetToken
-
-Signals that the current token was not used, and should be reported
-for the next GetToken. Note that
-
-GetToken (true);
-UnGetToken ();
-GetToken (false);
-
-could cross a line boundary.
-==============
-*/
-void UnGetToken (void)
-{
- tokenready = true;
-}
-
-
-qboolean EndOfScript (qboolean crossline)
-{
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline);
-
- if (!strcmp (script->filename, "memory buffer"))
- {
- endofscript = true;
- return false;
- }
-
- free (script->buffer);
- script->buffer = NULL;
- if (script == scriptstack+1)
- {
- endofscript = true;
- return false;
- }
- script--;
- scriptline = script->line;
- // printf ("returning to %s\n", script->filename);
- return GetToken (crossline);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Given an absolute path, do a find first find next on it and build
-// a list of files. Physical file system only
-//-----------------------------------------------------------------------------
-static void FindFileAbsoluteList( CUtlVector< CUtlString > &outAbsolutePathNames, const char *pszFindName )
-{
- char szPath[MAX_PATH];
- V_strncpy( szPath, pszFindName, sizeof( szPath ) );
- V_StripFilename( szPath );
-
- char szResult[MAX_PATH];
- FileFindHandle_t hFile = FILESYSTEM_INVALID_FIND_HANDLE;
-
- for ( const char *pszFoundFile = g_pFullFileSystem->FindFirst( pszFindName, &hFile ); pszFoundFile && hFile != FILESYSTEM_INVALID_FIND_HANDLE; pszFoundFile = g_pFullFileSystem->FindNext( hFile ) )
- {
- V_ComposeFileName( szPath, pszFoundFile, szResult, sizeof( szResult ) );
- outAbsolutePathNames.AddToTail( szResult );
- }
-
- g_pFullFileSystem->FindClose( hFile );
-}
-
-
-//-----------------------------------------------------------------------------
-// Data for checking for single character tokens while parsing
-//-----------------------------------------------------------------------------
-bool g_bCheckSingleCharTokens = false;
-CUtlString g_sSingleCharTokens;
-
-
-//-----------------------------------------------------------------------------
-// Sets whether the scriplib parser will do a special check for single
-// character tokens. Returns previous state of whether single character
-// tokens will be checked.
-//-----------------------------------------------------------------------------
-bool SetCheckSingleCharTokens( bool bCheck )
-{
- const bool bRetVal = g_bCheckSingleCharTokens;
-
- g_bCheckSingleCharTokens = bCheck;
-
- return bRetVal;
-}
-
-
-//-----------------------------------------------------------------------------
-// Sets the list of single character tokens to check if SetCheckSingleCharTokens
-// is turned on.
-//-----------------------------------------------------------------------------
-CUtlString SetSingleCharTokenList( const char *pszSingleCharTokenList )
-{
- const CUtlString sRetVal = g_sSingleCharTokens;
-
- if ( pszSingleCharTokenList )
- {
- g_sSingleCharTokens = pszSingleCharTokenList;
- }
-
- return sRetVal;
-}
-
-
-/*
-==============
-GetToken
-==============
-*/
-qboolean GetToken (qboolean crossline)
-{
- char *token_p;
-
- if (tokenready) // is a token allready waiting?
- {
- tokenready = false;
- return true;
- }
-
- // printf("script_p %x (%x)\n", script->script_p, script->end_p ); fflush( stdout );
-
- if (script->script_p >= script->end_p)
- {
- return EndOfScript (crossline);
- }
-
- tokenready = false;
-
- // skip space, ctrl chars
-skipspace:
- while (*script->script_p <= 32)
- {
- if (script->script_p >= script->end_p)
- {
- return EndOfScript (crossline);
- }
- if (*(script->script_p++) == '\n')
- {
- if (!crossline)
- {
- Error ("Line %i is incomplete\n",scriptline);
- }
- scriptline = ++script->line;
- }
- }
-
- if (script->script_p >= script->end_p)
- {
- return EndOfScript (crossline);
- }
-
- // strip single line comments
- if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
- (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
- {
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline);
- while (*script->script_p++ != '\n')
- {
- if (script->script_p >= script->end_p)
- {
- return EndOfScript (crossline);
- }
- }
- scriptline = ++script->line;
- goto skipspace;
- }
-
- // strip out matching /* */ comments
- if (*script->script_p == '/' && *((script->script_p)+1) == '*')
- {
- script->script_p += 2;
- while (*script->script_p != '*' || *((script->script_p)+1) != '/')
- {
- if (*script->script_p++ != '\n')
- {
- if (script->script_p >= script->end_p)
- {
- return EndOfScript (crossline);
- }
-
- scriptline = ++script->line;
- }
- }
- script->script_p += 2;
- goto skipspace;
- }
-
- // copy token to buffer
- token_p = token;
-
- if (*script->script_p == '"')
- {
- // quoted token
- script->script_p++;
- while (*script->script_p != '"')
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
- }
- script->script_p++;
- }
- else if ( g_bCheckSingleCharTokens && !g_sSingleCharTokens.IsEmpty() && strchr( g_sSingleCharTokens.String(), *script->script_p ) != NULL )
- {
- *token_p++ = *script->script_p++;
- }
- else // regular token
- while ( *script->script_p > 32 && *script->script_p != ';')
- {
- if ( !ExpandMacroToken( token_p ) )
- {
- if ( !ExpandVariableToken( token_p ) )
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
-
- }
- }
- }
-
- // add null to end of token
- *token_p = 0;
-
- // check for other commands
- if ( !stricmp( token, "$include" ) )
- {
- GetToken( false );
-
- bool bFallbackToToken = true;
-
- CUtlVector< CUtlString > expandedPathList;
-
- if ( CmdLib_ExpandWithBasePaths( expandedPathList, token ) > 0 )
- {
- for ( int i = 0; i < expandedPathList.Count(); ++i )
- {
- CUtlVector< CUtlString > findFileList;
- FindFileAbsoluteList( findFileList, expandedPathList[i].String() );
-
- if ( findFileList.Count() > 0 )
- {
- bFallbackToToken = false;
-
- // Only add the first set of glob matches from the first base path
- for ( int j = 0; j < findFileList.Count(); ++j )
- {
- AddScriptToStack( const_cast< char * >( findFileList[j].String() ) );
- }
-
- break;
- }
- }
- }
-
- if ( bFallbackToToken )
- {
- AddScriptToStack( token );
- }
-
- return GetToken( crossline );
- }
- else if (!stricmp (token, "$definemacro"))
- {
- GetToken (false);
- DefineMacro(token);
- return GetToken (crossline);
- }
- else if (!stricmp (token, "$definevariable"))
- {
- GetToken (false);
- DefineVariable(token);
- return GetToken (crossline);
- }
- else if (AddMacroToStack( token ))
- {
- return GetToken (crossline);
- }
-
- return true;
-}
-
-
-/*
-==============
-GetExprToken - use C mathematical operator parsing rules to split tokens instead of whitespace
-==============
-*/
-qboolean GetExprToken (qboolean crossline)
-{
- char *token_p;
-
- if (tokenready) // is a token allready waiting?
- {
- tokenready = false;
- return true;
- }
-
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
-
- tokenready = false;
-
-//
-// skip space
-//
-skipspace:
- while (*script->script_p <= 32)
- {
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
- if (*script->script_p++ == '\n')
- {
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline);
- scriptline = ++script->line;
- }
- }
-
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
-
- if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
- (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
- {
- if (!crossline)
- Error ("Line %i is incomplete\n",scriptline);
- while (*script->script_p++ != '\n')
- if (script->script_p >= script->end_p)
- return EndOfScript (crossline);
- goto skipspace;
- }
-
-//
-// copy token
-//
- token_p = token;
-
- if (*script->script_p == '"')
- {
- // quoted token
- script->script_p++;
- while (*script->script_p != '"')
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
- }
- script->script_p++;
- }
- else
- {
- if ( V_isalpha( *script->script_p ) || *script->script_p == '_' )
- {
- // regular token
- while ( V_isalnum( *script->script_p ) || *script->script_p == '_' )
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
- }
- }
- else if ( V_isdigit( *script->script_p ) || *script->script_p == '.' )
- {
- // regular token
- while ( V_isdigit( *script->script_p ) || *script->script_p == '.' )
- {
- *token_p++ = *script->script_p++;
- if (script->script_p == script->end_p)
- break;
- if (token_p == &token[MAXTOKEN])
- Error ("Token too large on line %i\n",scriptline);
- }
- }
- else
- {
- // single char
- *token_p++ = *script->script_p++;
- }
- }
-
- *token_p = 0;
-
- if (!stricmp (token, "$include"))
- {
- GetToken (false);
- AddScriptToStack (token);
- return GetToken (crossline);
- }
-
- return true;
-}
-
-
-/*
-==============
-TokenAvailable
-
-Returns true if there is another token on the line
-==============
-*/
-qboolean TokenAvailable (void)
-{
- char *search_p;
-
- if (tokenready) // is a token allready waiting?
- {
- return true;
- }
-
- search_p = script->script_p;
-
- if (search_p >= script->end_p)
- return false;
-
- while ( *search_p <= 32)
- {
- if (*search_p == '\n')
- return false;
- search_p++;
- if (search_p == script->end_p)
- return false;
-
- }
-
- if (*search_p == ';' || *search_p == '#' || // semicolon and # is comment field
- (*search_p == '/' && *((search_p)+1) == '/')) // also make // a comment field
- return false;
-
- return true;
-}
-
-qboolean GetTokenizerStatus( char **pFilename, int *pLine )
-{
- // is this the default state?
- if (!script)
- return false;
-
- if (script->script_p >= script->end_p)
- return false;
-
- if (pFilename)
- {
- *pFilename = script->filename;
- }
- if (pLine)
- {
- *pLine = script->line;
- }
- return true;
-}
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef WIN32
-#include <direct.h>
-#include <io.h>
-#include <sys/utime.h>
-#endif
-#include <time.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include "tier1/utlbuffer.h"
-
-class CScriptLib : public IScriptLib
-{
-public:
- virtual bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText = false, bool bNoOpenFailureWarning = false );
- virtual bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode );
- virtual int FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList );
- virtual char *MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize );
- virtual void DeleteTemporaryFiles( const char *pFileMask );
- virtual int CompareFileTime( const char *pFilenameA, const char *pFilenameB );
- virtual bool DoesFileExist( const char *pFilename );
-
-private:
-
- int GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< fileList_t > &fileList );
- void RecurseFileTree_r( const char* pDirPath, int depth, CUtlVector< CUtlString > &dirList );
-};
-
-static CScriptLib g_ScriptLib;
-IScriptLib *scriptlib = &g_ScriptLib;
-IScriptLib *g_pScriptLib = &g_ScriptLib;
-
-//-----------------------------------------------------------------------------
-// Existence check
-//-----------------------------------------------------------------------------
-bool CScriptLib::DoesFileExist( const char *pFilename )
-{
- return g_pFullFileSystem->FileExists( pFilename );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Helper utility, read file into buffer
-//-----------------------------------------------------------------------------
-bool CScriptLib::ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning )
-{
- bool bSuccess = true;
-
- if ( !g_pFullFileSystem->ReadFile( pSourceName, NULL, buffer ) )
- {
- if ( !bNoOpenFailureWarning )
- {
- Msg( "ReadFileToBuffer(): Error opening %s: %s\n", pSourceName, strerror( errno ) );
- }
- return false;
- }
-
- if ( bText )
- {
- // force it into text mode
- buffer.SetBufferType( true, true );
- }
- else
- {
- buffer.SetBufferType( false, false );
- }
-
- return bSuccess;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Helper utility, Write buffer to file
-//-----------------------------------------------------------------------------
-bool CScriptLib::WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode )
-{
- char* ptr;
- char dirPath[MAX_PATH];
-
- bool bSuccess = true;
-
- // create path
- // prime and skip to first seperator
- strcpy( dirPath, pTargetName );
- ptr = strchr( dirPath, '\\' );
- while ( ptr )
- {
- ptr = strchr( ptr+1, '\\' );
- if ( ptr )
- {
- *ptr = '\0';
- _mkdir( dirPath );
- *ptr = '\\';
- }
- }
-
- bool bDoWrite = false;
- if ( writeMode == WRITE_TO_DISK_ALWAYS )
- {
- bDoWrite = true;
- }
- else if ( writeMode == WRITE_TO_DISK_UPDATE )
- {
- if ( DoesFileExist( pTargetName ) )
- {
- bDoWrite = true;
- }
- }
-
- if ( bDoWrite )
- {
- bSuccess = g_pFullFileSystem->WriteFile( pTargetName, NULL, buffer );
- }
-
- return bSuccess;
-}
-
-//-----------------------------------------------------------------------------
-// Returns -1, 0, or 1.
-//-----------------------------------------------------------------------------
-int CScriptLib::CompareFileTime( const char *pFilenameA, const char *pFilenameB )
-{
- int timeA = g_pFullFileSystem->GetFileTime( (char *)pFilenameA );
- int timeB = g_pFullFileSystem->GetFileTime( (char *)pFilenameB );
-
- if ( timeA == -1)
- {
- // file a not exist
- timeA = 0;
- }
- if ( timeB == -1 )
- {
- // file b not exist
- timeB = 0;
- }
-
- if ( (unsigned int)timeA < (unsigned int)timeB )
- {
- return -1;
- }
- else if ( (unsigned int)timeA > (unsigned int)timeB )
- {
- return 1;
- }
-
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Make a temporary filename
-//-----------------------------------------------------------------------------
-char *CScriptLib::MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize )
-{
- char *pBuffer = _tempnam( pchModPath, "mgd_" );
- if ( pBuffer[0] == '\\' )
- {
- pBuffer++;
- }
- if ( pBuffer[strlen( pBuffer )-1] == '.' )
- {
- pBuffer[strlen( pBuffer )-1] = '\0';
- }
- V_snprintf( pPath, pathSize, "%s.tmp", pBuffer );
-
- free( pBuffer );
-
- return pPath;
-}
-
-//-----------------------------------------------------------------------------
-// Delete temporary files
-//-----------------------------------------------------------------------------
-void CScriptLib::DeleteTemporaryFiles( const char *pFileMask )
-{
-#if !defined( _X360 )
- const char *pEnv = getenv( "temp" );
- if ( !pEnv )
- {
- pEnv = getenv( "tmp" );
- }
-
- if ( pEnv )
- {
- char tempPath[MAX_PATH];
- strcpy( tempPath, pEnv );
- V_AppendSlash( tempPath, sizeof( tempPath ) );
- strcat( tempPath, pFileMask );
-
- CUtlVector<fileList_t> fileList;
- FindFiles( tempPath, false, fileList );
- for ( int i=0; i<fileList.Count(); i++ )
- {
- _unlink( fileList[i].fileName.String() );
- }
- }
-#else
- AssertOnce( !"CScriptLib::DeleteTemporaryFiles: Not avail on 360\n" );
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get list of files from current path that match pattern
-//-----------------------------------------------------------------------------
-int CScriptLib::GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< fileList_t > &fileList )
-{
- char sourcePath[MAX_PATH];
- char fullPath[MAX_PATH];
- bool bFindDirs;
-
- fileList.Purge();
-
- strcpy( sourcePath, pDirPath );
- int len = (int)strlen( sourcePath );
- if ( !len )
- {
- strcpy( sourcePath, ".\\" );
- }
- else if ( sourcePath[len-1] != '\\' )
- {
- sourcePath[len] = '\\';
- sourcePath[len+1] = '\0';
- }
-
- strcpy( fullPath, sourcePath );
- if ( pPattern[0] == '\\' && pPattern[1] == '\0' )
- {
- // find directories only
- bFindDirs = true;
- strcat( fullPath, "*" );
- }
- else
- {
- // find files, use provided pattern
- bFindDirs = false;
- strcat( fullPath, pPattern );
- }
-
-#ifdef WIN32
- struct _finddata_t findData;
- intptr_t h = _findfirst( fullPath, &findData );
- if ( h == -1 )
- {
- return 0;
- }
-
- do
- {
- // dos attribute complexities i.e. _A_NORMAL is 0
- if ( bFindDirs )
- {
- // skip non dirs
- if ( !( findData.attrib & _A_SUBDIR ) )
- continue;
- }
- else
- {
- // skip dirs
- if ( findData.attrib & _A_SUBDIR )
- continue;
- }
-
- if ( !stricmp( findData.name, "." ) )
- continue;
-
- if ( !stricmp( findData.name, ".." ) )
- continue;
-
- char fileName[MAX_PATH];
- strcpy( fileName, sourcePath );
- strcat( fileName, findData.name );
-
- int j = fileList.AddToTail();
- fileList[j].fileName.Set( fileName );
- fileList[j].timeWrite = findData.time_write;
- }
- while ( !_findnext( h, &findData ) );
-
- _findclose( h );
-#elif defined(POSIX)
- FIND_DATA findData;
- Q_FixSlashes( fullPath );
- void *h = FindFirstFile( fullPath, &findData );
- if ( (int)h == -1 )
- {
- return 0;
- }
-
- do
- {
- // dos attribute complexities i.e. _A_NORMAL is 0
- if ( bFindDirs )
- {
- // skip non dirs
- if ( !( findData.dwFileAttributes & S_IFDIR ) )
- continue;
- }
- else
- {
- // skip dirs
- if ( findData.dwFileAttributes & S_IFDIR )
- continue;
- }
-
- if ( !stricmp( findData.cFileName, "." ) )
- continue;
-
- if ( !stricmp( findData.cFileName, ".." ) )
- continue;
-
- char fileName[MAX_PATH];
- strcpy( fileName, sourcePath );
- strcat( fileName, findData.cFileName );
-
- int j = fileList.AddToTail();
- fileList[j].fileName.Set( fileName );
- struct stat statbuf;
- if ( stat( fileName, &statbuf ) )
-#ifdef OSX
- fileList[j].timeWrite = statbuf.st_mtimespec.tv_sec;
-#else
- fileList[j].timeWrite = statbuf.st_mtime;
-#endif
- else
- fileList[j].timeWrite = 0;
- }
- while ( !FindNextFile( h, &findData ) );
-
- FindClose( h );
-
-#else
-#error
-#endif
-
-
- return fileList.Count();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Recursively determine directory tree
-//-----------------------------------------------------------------------------
-void CScriptLib::RecurseFileTree_r( const char* pDirPath, int depth, CUtlVector< CUtlString > &dirList )
-{
- // recurse from source directory, get directories only
- CUtlVector< fileList_t > fileList;
- int dirCount = GetFileList( pDirPath, "\\", fileList );
- if ( !dirCount )
- {
- // add directory name to search tree
- int j = dirList.AddToTail();
- dirList[j].Set( pDirPath );
- return;
- }
-
- for ( int i=0; i<dirCount; i++ )
- {
- // form new path name, recurse into
- RecurseFileTree_r( fileList[i].fileName.String(), depth+1, dirList );
- }
-
- int j = dirList.AddToTail();
- dirList[j].Set( pDirPath );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Generate a list of file matching mask
-//-----------------------------------------------------------------------------
-int CScriptLib::FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList )
-{
- char dirPath[MAX_PATH];
- char pattern[MAX_PATH];
- char extension[MAX_PATH];
-
- // get path only
- strcpy( dirPath, pFileMask );
- V_StripFilename( dirPath );
-
- // get pattern only
- V_FileBase( pFileMask, pattern, sizeof( pattern ) );
- V_ExtractFileExtension( pFileMask, extension, sizeof( extension ) );
- if ( extension[0] )
- {
- strcat( pattern, "." );
- strcat( pattern, extension );
- }
-
- if ( !bRecurse )
- {
- GetFileList( dirPath, pattern, fileList );
- }
- else
- {
- // recurse and get the tree
- CUtlVector< fileList_t > tempList;
- CUtlVector< CUtlString > dirList;
- RecurseFileTree_r( dirPath, 0, dirList );
- for ( int i=0; i<dirList.Count(); i++ )
- {
- // iterate each directory found
- tempList.Purge();
- tempList.EnsureCapacity( dirList.Count() );
-
- GetFileList( dirList[i].String(), pattern, tempList );
-
- int start = fileList.AddMultipleToTail( tempList.Count() );
- for ( int j=0; j<tempList.Count(); j++ )
- {
- fileList[start+j] = tempList[j];
- }
- }
- }
-
- return fileList.Count();
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+// scriplib.c
+
+#include "tier1/strtools.h"
+#include "tier2/tier2.h"
+#include "cmdlib.h"
+#include "scriplib.h"
+#if defined( _X360 )
+#include "xbox\xbox_win32stubs.h"
+#endif
+#if defined(POSIX)
+#include "../../filesystem/linux_support.h"
+#include <sys/stat.h>
+#endif
+/*
+=============================================================================
+
+ PARSING STUFF
+
+=============================================================================
+*/
+
+typedef struct
+{
+ char filename[1024];
+ char *buffer,*script_p,*end_p;
+ int line;
+
+ char macrobuffer[4096];
+ char *macroparam[64];
+ char *macrovalue[64];
+ int nummacroparams;
+
+} script_t;
+
+#define MAX_INCLUDES 64
+script_t scriptstack[MAX_INCLUDES];
+script_t *script = NULL;
+int scriptline;
+
+char token[MAXTOKEN];
+qboolean endofscript;
+qboolean tokenready; // only true if UnGetToken was just called
+
+typedef struct
+{
+ char *param;
+ char *value;
+} variable_t;
+
+CUtlVector<variable_t> g_definevariable;
+
+/*
+Callback stuff
+*/
+
+void DefaultScriptLoadedCallback( char const *pFilenameLoaded, char const *pIncludedFromFileName, int nIncludeLineNumber )
+{
+ NULL;
+}
+
+SCRIPT_LOADED_CALLBACK g_pfnCallback = DefaultScriptLoadedCallback;
+
+SCRIPT_LOADED_CALLBACK SetScriptLoadedCallback( SCRIPT_LOADED_CALLBACK pfnNewScriptLoadedCallback )
+{
+ SCRIPT_LOADED_CALLBACK pfnCallback = g_pfnCallback;
+ g_pfnCallback = pfnNewScriptLoadedCallback;
+ return pfnCallback;
+}
+
+/*
+==============
+AddScriptToStack
+==============
+*/
+void AddScriptToStack (char *filename, ScriptPathMode_t pathMode = SCRIPT_USE_ABSOLUTE_PATH)
+{
+ int size;
+
+ script++;
+ if (script == &scriptstack[MAX_INCLUDES])
+ Error ("script file exceeded MAX_INCLUDES");
+
+ if ( pathMode == SCRIPT_USE_RELATIVE_PATH )
+ Q_strncpy( script->filename, filename, sizeof( script->filename ) );
+ else
+ Q_strncpy (script->filename, ExpandPath (filename), sizeof( script->filename ) );
+
+ size = LoadFile (script->filename, (void **)&script->buffer);
+
+ // printf ("entering %s\n", script->filename);
+ if ( g_pfnCallback )
+ {
+ if ( script == scriptstack + 1 )
+ g_pfnCallback( script->filename, NULL, 0 );
+ else
+ g_pfnCallback( script->filename, script[-1].filename, script[-1].line );
+ }
+
+ script->line = 1;
+
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+}
+
+
+/*
+==============
+LoadScriptFile
+==============
+*/
+void LoadScriptFile (char *filename, ScriptPathMode_t pathMode)
+{
+ script = scriptstack;
+ AddScriptToStack (filename, pathMode);
+
+ endofscript = false;
+ tokenready = false;
+}
+
+
+/*
+==============
+==============
+*/
+
+script_t *macrolist[256];
+int nummacros;
+
+void DefineMacro( char *macroname )
+{
+ script_t *pmacro = (script_t *)malloc( sizeof( script_t ) );
+
+ strcpy( pmacro->filename, macroname );
+ pmacro->line = script->line;
+ pmacro->nummacroparams = 0;
+
+ char *mp = pmacro->macrobuffer;
+ char *cp = script->script_p;
+
+ while (TokenAvailable( ))
+ {
+ GetToken( false );
+
+ if (token[0] == '\\' && token[1] == '\\')
+ {
+ break;
+ }
+ cp = script->script_p;
+
+ pmacro->macroparam[pmacro->nummacroparams++] = mp;
+
+ strcpy( mp, token );
+ mp += strlen( token ) + 1;
+
+ if (mp >= pmacro->macrobuffer + sizeof( pmacro->macrobuffer ))
+ Error("Macro buffer overflow\n");
+ }
+ // roll back script_p to previous valid location
+ script->script_p = cp;
+
+ // find end of macro def
+ while (*cp && *cp != '\n')
+ {
+ //Msg("%d ", *cp );
+ if (*cp == '\\' && *(cp+1) == '\\')
+ {
+ // skip till end of line
+ while (*cp && *cp != '\n')
+ {
+ *cp = ' '; // replace with spaces
+ cp++;
+ }
+
+ if (*cp)
+ {
+ cp++;
+ }
+ }
+ else
+ {
+ cp++;
+ }
+ }
+
+ int size = (cp - script->script_p);
+
+ pmacro->buffer = (char *)malloc( size + 1);
+ memcpy( pmacro->buffer, script->script_p, size );
+ pmacro->buffer[size] = '\0';
+ pmacro->end_p = &pmacro->buffer[size];
+
+ macrolist[nummacros++] = pmacro;
+
+ script->script_p = cp;
+}
+
+
+void DefineVariable( char *variablename )
+{
+ variable_t v;
+
+ v.param = strdup( variablename );
+
+ GetToken( false );
+
+ v.value = strdup( token );
+
+ g_definevariable.AddToTail( v );
+}
+
+
+
+/*
+==============
+==============
+*/
+bool AddMacroToStack( char *macroname )
+{
+ // lookup macro
+ if (macroname[0] != '$')
+ return false;
+
+ int i;
+ for (i = 0; i < nummacros; i++)
+ {
+ if (strcmpi( macrolist[i]->filename, &macroname[1] ) == 0)
+ {
+ break;
+ }
+ }
+ if (i == nummacros)
+ return false;
+
+ script_t *pmacro = macrolist[i];
+
+ // get tokens
+ script_t *pnext = script + 1;
+
+ pnext++;
+ if (pnext == &scriptstack[MAX_INCLUDES])
+ Error ("script file exceeded MAX_INCLUDES");
+
+ // get tokens
+ char *cp = pnext->macrobuffer;
+
+ pnext->nummacroparams = pmacro->nummacroparams;
+
+ for (i = 0; i < pnext->nummacroparams; i++)
+ {
+ GetToken(false);
+
+ strcpy( cp, token );
+ pnext->macroparam[i] = pmacro->macroparam[i];
+ pnext->macrovalue[i] = cp;
+
+ cp += strlen( token ) + 1;
+
+ if (cp >= pnext->macrobuffer + sizeof( pnext->macrobuffer ))
+ Error("Macro buffer overflow\n");
+ }
+
+ script = pnext;
+ strcpy( script->filename, pmacro->filename );
+
+ int size = pmacro->end_p - pmacro->buffer;
+ script->buffer = (char *)malloc( size + 1 );
+ memcpy( script->buffer, pmacro->buffer, size );
+ pmacro->buffer[size] = '\0';
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+ script->line = pmacro->line;
+
+ return true;
+}
+
+
+
+bool ExpandMacroToken( char *&token_p )
+{
+ if ( script->nummacroparams && *script->script_p == '$' )
+ {
+ char *cp = script->script_p + 1;
+
+ while ( *cp > 32 && *cp != '$' )
+ {
+ cp++;
+ }
+
+ // found a word with $'s on either end?
+ if (*cp != '$')
+ return false;
+
+ // get token pointer
+ char *tp = script->script_p + 1;
+ int len = (cp - tp);
+ *(tp + len) = '\0';
+
+ // lookup macro parameter
+ int index = 0;
+ for (index = 0; index < script->nummacroparams; index++)
+ {
+ if (stricmp( script->macroparam[index], tp ) == 0)
+ break;
+ }
+ if (index >= script->nummacroparams)
+ {
+ Error("unknown macro token \"%s\" in %s\n", tp, script->filename );
+ }
+
+ // paste token into
+ len = strlen( script->macrovalue[index] );
+ strcpy( token_p, script->macrovalue[index] );
+ token_p += len;
+
+ script->script_p = cp + 1;
+
+ if (script->script_p >= script->end_p)
+ Error ("Macro expand overflow\n");
+
+ if (token_p >= &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+
+ return true;
+ }
+ return false;
+}
+
+
+
+/*
+==============
+==============
+*/
+// FIXME: this should create a new script context so the individual tokens in the variable can be parsed
+bool ExpandVariableToken( char *&token_p )
+{
+ if ( *script->script_p == '$' )
+ {
+ char *cp = script->script_p + 1;
+
+ while ( *cp > 32 && *cp != '$' )
+ {
+ cp++;
+ }
+
+ // found a word with $'s on either end?
+ if (*cp != '$')
+ return false;
+
+ // get token pointer
+ char *tp = script->script_p + 1;
+ int len = (cp - tp);
+ *(tp + len) = '\0';
+
+ // lookup macro parameter
+
+ int index;
+ for (index = 0; index < g_definevariable.Count(); index++)
+ {
+ if (Q_strnicmp( g_definevariable[index].param, tp, len ) == 0)
+ break;
+ }
+
+ if (index >= g_definevariable.Count() )
+ {
+ Error("unknown variable token \"%s\" in %s\n", tp, script->filename );
+ }
+
+ // paste token into
+ len = strlen( g_definevariable[index].value );
+ strcpy( token_p, g_definevariable[index].value );
+ token_p += len;
+
+ script->script_p = cp + 1;
+
+ if (script->script_p >= script->end_p)
+ Error ("Macro expand overflow\n");
+
+ if (token_p >= &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+
+ return true;
+ }
+ return false;
+}
+
+
+
+/*
+==============
+ParseFromMemory
+==============
+*/
+void ParseFromMemory (char *buffer, int size)
+{
+ script = scriptstack;
+ script++;
+ if (script == &scriptstack[MAX_INCLUDES])
+ Error ("script file exceeded MAX_INCLUDES");
+ strcpy (script->filename, "memory buffer" );
+
+ script->buffer = buffer;
+ script->line = 1;
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+
+ endofscript = false;
+ tokenready = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used instead of ParseFromMemory to temporarily add a memory buffer
+// to the script stack. ParseFromMemory just blows away the stack.
+//-----------------------------------------------------------------------------
+void PushMemoryScript( char *pszBuffer, const int nSize )
+{
+ if ( script == NULL )
+ {
+ script = scriptstack;
+ }
+ script++;
+ if ( script == &scriptstack[MAX_INCLUDES] )
+ {
+ Error ( "script file exceeded MAX_INCLUDES" );
+ }
+ strcpy (script->filename, "memory buffer" );
+
+ script->buffer = pszBuffer;
+ script->line = 1;
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + nSize;
+
+ endofscript = false;
+ tokenready = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used after calling PushMemoryScript to clean up the memory buffer
+// added to the script stack. The normal end of script terminates
+// all parsing at the end of a memory buffer even if there are more scripts
+// remaining on the script stack
+//-----------------------------------------------------------------------------
+bool PopMemoryScript()
+{
+ if ( V_stricmp( script->filename, "memory buffer" ) )
+ return false;
+
+ if ( script == scriptstack )
+ {
+ endofscript = true;
+ return false;
+ }
+ script--;
+ scriptline = script->line;
+
+ endofscript = false;
+
+ return true;
+}
+
+
+/*
+==============
+UnGetToken
+
+Signals that the current token was not used, and should be reported
+for the next GetToken. Note that
+
+GetToken (true);
+UnGetToken ();
+GetToken (false);
+
+could cross a line boundary.
+==============
+*/
+void UnGetToken (void)
+{
+ tokenready = true;
+}
+
+
+qboolean EndOfScript (qboolean crossline)
+{
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+
+ if (!strcmp (script->filename, "memory buffer"))
+ {
+ endofscript = true;
+ return false;
+ }
+
+ free (script->buffer);
+ script->buffer = NULL;
+ if (script == scriptstack+1)
+ {
+ endofscript = true;
+ return false;
+ }
+ script--;
+ scriptline = script->line;
+ // printf ("returning to %s\n", script->filename);
+ return GetToken (crossline);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Given an absolute path, do a find first find next on it and build
+// a list of files. Physical file system only
+//-----------------------------------------------------------------------------
+static void FindFileAbsoluteList( CUtlVector< CUtlString > &outAbsolutePathNames, const char *pszFindName )
+{
+ char szPath[MAX_PATH];
+ V_strncpy( szPath, pszFindName, sizeof( szPath ) );
+ V_StripFilename( szPath );
+
+ char szResult[MAX_PATH];
+ FileFindHandle_t hFile = FILESYSTEM_INVALID_FIND_HANDLE;
+
+ for ( const char *pszFoundFile = g_pFullFileSystem->FindFirst( pszFindName, &hFile ); pszFoundFile && hFile != FILESYSTEM_INVALID_FIND_HANDLE; pszFoundFile = g_pFullFileSystem->FindNext( hFile ) )
+ {
+ V_ComposeFileName( szPath, pszFoundFile, szResult, sizeof( szResult ) );
+ outAbsolutePathNames.AddToTail( szResult );
+ }
+
+ g_pFullFileSystem->FindClose( hFile );
+}
+
+
+//-----------------------------------------------------------------------------
+// Data for checking for single character tokens while parsing
+//-----------------------------------------------------------------------------
+bool g_bCheckSingleCharTokens = false;
+CUtlString g_sSingleCharTokens;
+
+
+//-----------------------------------------------------------------------------
+// Sets whether the scriplib parser will do a special check for single
+// character tokens. Returns previous state of whether single character
+// tokens will be checked.
+//-----------------------------------------------------------------------------
+bool SetCheckSingleCharTokens( bool bCheck )
+{
+ const bool bRetVal = g_bCheckSingleCharTokens;
+
+ g_bCheckSingleCharTokens = bCheck;
+
+ return bRetVal;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the list of single character tokens to check if SetCheckSingleCharTokens
+// is turned on.
+//-----------------------------------------------------------------------------
+CUtlString SetSingleCharTokenList( const char *pszSingleCharTokenList )
+{
+ const CUtlString sRetVal = g_sSingleCharTokens;
+
+ if ( pszSingleCharTokenList )
+ {
+ g_sSingleCharTokens = pszSingleCharTokenList;
+ }
+
+ return sRetVal;
+}
+
+
+/*
+==============
+GetToken
+==============
+*/
+qboolean GetToken (qboolean crossline)
+{
+ char *token_p;
+
+ if (tokenready) // is a token allready waiting?
+ {
+ tokenready = false;
+ return true;
+ }
+
+ // printf("script_p %x (%x)\n", script->script_p, script->end_p ); fflush( stdout );
+
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+
+ tokenready = false;
+
+ // skip space, ctrl chars
+skipspace:
+ while (*script->script_p <= 32)
+ {
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+ if (*(script->script_p++) == '\n')
+ {
+ if (!crossline)
+ {
+ Error ("Line %i is incomplete\n",scriptline);
+ }
+ scriptline = ++script->line;
+ }
+ }
+
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+
+ // strip single line comments
+ if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
+ (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
+ {
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+ while (*script->script_p++ != '\n')
+ {
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+ }
+ scriptline = ++script->line;
+ goto skipspace;
+ }
+
+ // strip out matching /* */ comments
+ if (*script->script_p == '/' && *((script->script_p)+1) == '*')
+ {
+ script->script_p += 2;
+ while (*script->script_p != '*' || *((script->script_p)+1) != '/')
+ {
+ if (*script->script_p++ != '\n')
+ {
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+
+ scriptline = ++script->line;
+ }
+ }
+ script->script_p += 2;
+ goto skipspace;
+ }
+
+ // copy token to buffer
+ token_p = token;
+
+ if (*script->script_p == '"')
+ {
+ // quoted token
+ script->script_p++;
+ while (*script->script_p != '"')
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ script->script_p++;
+ }
+ else if ( g_bCheckSingleCharTokens && !g_sSingleCharTokens.IsEmpty() && strchr( g_sSingleCharTokens.String(), *script->script_p ) != NULL )
+ {
+ *token_p++ = *script->script_p++;
+ }
+ else // regular token
+ while ( *script->script_p > 32 && *script->script_p != ';')
+ {
+ if ( !ExpandMacroToken( token_p ) )
+ {
+ if ( !ExpandVariableToken( token_p ) )
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+
+ }
+ }
+ }
+
+ // add null to end of token
+ *token_p = 0;
+
+ // check for other commands
+ if ( !stricmp( token, "$include" ) )
+ {
+ GetToken( false );
+
+ bool bFallbackToToken = true;
+
+ CUtlVector< CUtlString > expandedPathList;
+
+ if ( CmdLib_ExpandWithBasePaths( expandedPathList, token ) > 0 )
+ {
+ for ( int i = 0; i < expandedPathList.Count(); ++i )
+ {
+ CUtlVector< CUtlString > findFileList;
+ FindFileAbsoluteList( findFileList, expandedPathList[i].String() );
+
+ if ( findFileList.Count() > 0 )
+ {
+ bFallbackToToken = false;
+
+ // Only add the first set of glob matches from the first base path
+ for ( int j = 0; j < findFileList.Count(); ++j )
+ {
+ AddScriptToStack( const_cast< char * >( findFileList[j].String() ) );
+ }
+
+ break;
+ }
+ }
+ }
+
+ if ( bFallbackToToken )
+ {
+ AddScriptToStack( token );
+ }
+
+ return GetToken( crossline );
+ }
+ else if (!stricmp (token, "$definemacro"))
+ {
+ GetToken (false);
+ DefineMacro(token);
+ return GetToken (crossline);
+ }
+ else if (!stricmp (token, "$definevariable"))
+ {
+ GetToken (false);
+ DefineVariable(token);
+ return GetToken (crossline);
+ }
+ else if (AddMacroToStack( token ))
+ {
+ return GetToken (crossline);
+ }
+
+ return true;
+}
+
+
+/*
+==============
+GetExprToken - use C mathematical operator parsing rules to split tokens instead of whitespace
+==============
+*/
+qboolean GetExprToken (qboolean crossline)
+{
+ char *token_p;
+
+ if (tokenready) // is a token allready waiting?
+ {
+ tokenready = false;
+ return true;
+ }
+
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+
+ tokenready = false;
+
+//
+// skip space
+//
+skipspace:
+ while (*script->script_p <= 32)
+ {
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+ if (*script->script_p++ == '\n')
+ {
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+ scriptline = ++script->line;
+ }
+ }
+
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+
+ if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
+ (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
+ {
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+ while (*script->script_p++ != '\n')
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+ goto skipspace;
+ }
+
+//
+// copy token
+//
+ token_p = token;
+
+ if (*script->script_p == '"')
+ {
+ // quoted token
+ script->script_p++;
+ while (*script->script_p != '"')
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ script->script_p++;
+ }
+ else
+ {
+ if ( V_isalpha( *script->script_p ) || *script->script_p == '_' )
+ {
+ // regular token
+ while ( V_isalnum( *script->script_p ) || *script->script_p == '_' )
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ }
+ else if ( V_isdigit( *script->script_p ) || *script->script_p == '.' )
+ {
+ // regular token
+ while ( V_isdigit( *script->script_p ) || *script->script_p == '.' )
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ }
+ else
+ {
+ // single char
+ *token_p++ = *script->script_p++;
+ }
+ }
+
+ *token_p = 0;
+
+ if (!stricmp (token, "$include"))
+ {
+ GetToken (false);
+ AddScriptToStack (token);
+ return GetToken (crossline);
+ }
+
+ return true;
+}
+
+
+/*
+==============
+TokenAvailable
+
+Returns true if there is another token on the line
+==============
+*/
+qboolean TokenAvailable (void)
+{
+ char *search_p;
+
+ if (tokenready) // is a token allready waiting?
+ {
+ return true;
+ }
+
+ search_p = script->script_p;
+
+ if (search_p >= script->end_p)
+ return false;
+
+ while ( *search_p <= 32)
+ {
+ if (*search_p == '\n')
+ return false;
+ search_p++;
+ if (search_p == script->end_p)
+ return false;
+
+ }
+
+ if (*search_p == ';' || *search_p == '#' || // semicolon and # is comment field
+ (*search_p == '/' && *((search_p)+1) == '/')) // also make // a comment field
+ return false;
+
+ return true;
+}
+
+qboolean GetTokenizerStatus( char **pFilename, int *pLine )
+{
+ // is this the default state?
+ if (!script)
+ return false;
+
+ if (script->script_p >= script->end_p)
+ return false;
+
+ if (pFilename)
+ {
+ *pFilename = script->filename;
+ }
+ if (pLine)
+ {
+ *pLine = script->line;
+ }
+ return true;
+}
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef WIN32
+#include <direct.h>
+#include <io.h>
+#include <sys/utime.h>
+#endif
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "tier1/utlbuffer.h"
+
+class CScriptLib : public IScriptLib
+{
+public:
+ virtual bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText = false, bool bNoOpenFailureWarning = false );
+ virtual bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode );
+ virtual int FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList );
+ virtual char *MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize );
+ virtual void DeleteTemporaryFiles( const char *pFileMask );
+ virtual int CompareFileTime( const char *pFilenameA, const char *pFilenameB );
+ virtual bool DoesFileExist( const char *pFilename );
+
+private:
+
+ int GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< fileList_t > &fileList );
+ void RecurseFileTree_r( const char* pDirPath, int depth, CUtlVector< CUtlString > &dirList );
+};
+
+static CScriptLib g_ScriptLib;
+IScriptLib *scriptlib = &g_ScriptLib;
+IScriptLib *g_pScriptLib = &g_ScriptLib;
+
+//-----------------------------------------------------------------------------
+// Existence check
+//-----------------------------------------------------------------------------
+bool CScriptLib::DoesFileExist( const char *pFilename )
+{
+ return g_pFullFileSystem->FileExists( pFilename );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper utility, read file into buffer
+//-----------------------------------------------------------------------------
+bool CScriptLib::ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning )
+{
+ bool bSuccess = true;
+
+ if ( !g_pFullFileSystem->ReadFile( pSourceName, NULL, buffer ) )
+ {
+ if ( !bNoOpenFailureWarning )
+ {
+ Msg( "ReadFileToBuffer(): Error opening %s: %s\n", pSourceName, strerror( errno ) );
+ }
+ return false;
+ }
+
+ if ( bText )
+ {
+ // force it into text mode
+ buffer.SetBufferType( true, true );
+ }
+ else
+ {
+ buffer.SetBufferType( false, false );
+ }
+
+ return bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper utility, Write buffer to file
+//-----------------------------------------------------------------------------
+bool CScriptLib::WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode )
+{
+ char* ptr;
+ char dirPath[MAX_PATH];
+
+ bool bSuccess = true;
+
+ // create path
+ // prime and skip to first seperator
+ strcpy( dirPath, pTargetName );
+ ptr = strchr( dirPath, '\\' );
+ while ( ptr )
+ {
+ ptr = strchr( ptr+1, '\\' );
+ if ( ptr )
+ {
+ *ptr = '\0';
+ _mkdir( dirPath );
+ *ptr = '\\';
+ }
+ }
+
+ bool bDoWrite = false;
+ if ( writeMode == WRITE_TO_DISK_ALWAYS )
+ {
+ bDoWrite = true;
+ }
+ else if ( writeMode == WRITE_TO_DISK_UPDATE )
+ {
+ if ( DoesFileExist( pTargetName ) )
+ {
+ bDoWrite = true;
+ }
+ }
+
+ if ( bDoWrite )
+ {
+ bSuccess = g_pFullFileSystem->WriteFile( pTargetName, NULL, buffer );
+ }
+
+ return bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Returns -1, 0, or 1.
+//-----------------------------------------------------------------------------
+int CScriptLib::CompareFileTime( const char *pFilenameA, const char *pFilenameB )
+{
+ int timeA = g_pFullFileSystem->GetFileTime( (char *)pFilenameA );
+ int timeB = g_pFullFileSystem->GetFileTime( (char *)pFilenameB );
+
+ if ( timeA == -1)
+ {
+ // file a not exist
+ timeA = 0;
+ }
+ if ( timeB == -1 )
+ {
+ // file b not exist
+ timeB = 0;
+ }
+
+ if ( (unsigned int)timeA < (unsigned int)timeB )
+ {
+ return -1;
+ }
+ else if ( (unsigned int)timeA > (unsigned int)timeB )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Make a temporary filename
+//-----------------------------------------------------------------------------
+char *CScriptLib::MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize )
+{
+ char *pBuffer = _tempnam( pchModPath, "mgd_" );
+ if ( pBuffer[0] == '\\' )
+ {
+ pBuffer++;
+ }
+ if ( pBuffer[strlen( pBuffer )-1] == '.' )
+ {
+ pBuffer[strlen( pBuffer )-1] = '\0';
+ }
+ V_snprintf( pPath, pathSize, "%s.tmp", pBuffer );
+
+ free( pBuffer );
+
+ return pPath;
+}
+
+//-----------------------------------------------------------------------------
+// Delete temporary files
+//-----------------------------------------------------------------------------
+void CScriptLib::DeleteTemporaryFiles( const char *pFileMask )
+{
+#if !defined( _X360 )
+ const char *pEnv = getenv( "temp" );
+ if ( !pEnv )
+ {
+ pEnv = getenv( "tmp" );
+ }
+
+ if ( pEnv )
+ {
+ char tempPath[MAX_PATH];
+ strcpy( tempPath, pEnv );
+ V_AppendSlash( tempPath, sizeof( tempPath ) );
+ strcat( tempPath, pFileMask );
+
+ CUtlVector<fileList_t> fileList;
+ FindFiles( tempPath, false, fileList );
+ for ( int i=0; i<fileList.Count(); i++ )
+ {
+ _unlink( fileList[i].fileName.String() );
+ }
+ }
+#else
+ AssertOnce( !"CScriptLib::DeleteTemporaryFiles: Not avail on 360\n" );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get list of files from current path that match pattern
+//-----------------------------------------------------------------------------
+int CScriptLib::GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< fileList_t > &fileList )
+{
+ char sourcePath[MAX_PATH];
+ char fullPath[MAX_PATH];
+ bool bFindDirs;
+
+ fileList.Purge();
+
+ strcpy( sourcePath, pDirPath );
+ int len = (int)strlen( sourcePath );
+ if ( !len )
+ {
+ strcpy( sourcePath, ".\\" );
+ }
+ else if ( sourcePath[len-1] != '\\' )
+ {
+ sourcePath[len] = '\\';
+ sourcePath[len+1] = '\0';
+ }
+
+ strcpy( fullPath, sourcePath );
+ if ( pPattern[0] == '\\' && pPattern[1] == '\0' )
+ {
+ // find directories only
+ bFindDirs = true;
+ strcat( fullPath, "*" );
+ }
+ else
+ {
+ // find files, use provided pattern
+ bFindDirs = false;
+ strcat( fullPath, pPattern );
+ }
+
+#ifdef WIN32
+ struct _finddata_t findData;
+ intptr_t h = _findfirst( fullPath, &findData );
+ if ( h == -1 )
+ {
+ return 0;
+ }
+
+ do
+ {
+ // dos attribute complexities i.e. _A_NORMAL is 0
+ if ( bFindDirs )
+ {
+ // skip non dirs
+ if ( !( findData.attrib & _A_SUBDIR ) )
+ continue;
+ }
+ else
+ {
+ // skip dirs
+ if ( findData.attrib & _A_SUBDIR )
+ continue;
+ }
+
+ if ( !stricmp( findData.name, "." ) )
+ continue;
+
+ if ( !stricmp( findData.name, ".." ) )
+ continue;
+
+ char fileName[MAX_PATH];
+ strcpy( fileName, sourcePath );
+ strcat( fileName, findData.name );
+
+ int j = fileList.AddToTail();
+ fileList[j].fileName.Set( fileName );
+ fileList[j].timeWrite = findData.time_write;
+ }
+ while ( !_findnext( h, &findData ) );
+
+ _findclose( h );
+#elif defined(POSIX)
+ FIND_DATA findData;
+ Q_FixSlashes( fullPath );
+ void *h = FindFirstFile( fullPath, &findData );
+ if ( (int)h == -1 )
+ {
+ return 0;
+ }
+
+ do
+ {
+ // dos attribute complexities i.e. _A_NORMAL is 0
+ if ( bFindDirs )
+ {
+ // skip non dirs
+ if ( !( findData.dwFileAttributes & S_IFDIR ) )
+ continue;
+ }
+ else
+ {
+ // skip dirs
+ if ( findData.dwFileAttributes & S_IFDIR )
+ continue;
+ }
+
+ if ( !stricmp( findData.cFileName, "." ) )
+ continue;
+
+ if ( !stricmp( findData.cFileName, ".." ) )
+ continue;
+
+ char fileName[MAX_PATH];
+ strcpy( fileName, sourcePath );
+ strcat( fileName, findData.cFileName );
+
+ int j = fileList.AddToTail();
+ fileList[j].fileName.Set( fileName );
+ struct stat statbuf;
+ if ( stat( fileName, &statbuf ) )
+#ifdef OSX
+ fileList[j].timeWrite = statbuf.st_mtimespec.tv_sec;
+#else
+ fileList[j].timeWrite = statbuf.st_mtime;
+#endif
+ else
+ fileList[j].timeWrite = 0;
+ }
+ while ( !FindNextFile( h, &findData ) );
+
+ FindClose( h );
+
+#else
+#error
+#endif
+
+
+ return fileList.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Recursively determine directory tree
+//-----------------------------------------------------------------------------
+void CScriptLib::RecurseFileTree_r( const char* pDirPath, int depth, CUtlVector< CUtlString > &dirList )
+{
+ // recurse from source directory, get directories only
+ CUtlVector< fileList_t > fileList;
+ int dirCount = GetFileList( pDirPath, "\\", fileList );
+ if ( !dirCount )
+ {
+ // add directory name to search tree
+ int j = dirList.AddToTail();
+ dirList[j].Set( pDirPath );
+ return;
+ }
+
+ for ( int i=0; i<dirCount; i++ )
+ {
+ // form new path name, recurse into
+ RecurseFileTree_r( fileList[i].fileName.String(), depth+1, dirList );
+ }
+
+ int j = dirList.AddToTail();
+ dirList[j].Set( pDirPath );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Generate a list of file matching mask
+//-----------------------------------------------------------------------------
+int CScriptLib::FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList )
+{
+ char dirPath[MAX_PATH];
+ char pattern[MAX_PATH];
+ char extension[MAX_PATH];
+
+ // get path only
+ strcpy( dirPath, pFileMask );
+ V_StripFilename( dirPath );
+
+ // get pattern only
+ V_FileBase( pFileMask, pattern, sizeof( pattern ) );
+ V_ExtractFileExtension( pFileMask, extension, sizeof( extension ) );
+ if ( extension[0] )
+ {
+ strcat( pattern, "." );
+ strcat( pattern, extension );
+ }
+
+ if ( !bRecurse )
+ {
+ GetFileList( dirPath, pattern, fileList );
+ }
+ else
+ {
+ // recurse and get the tree
+ CUtlVector< fileList_t > tempList;
+ CUtlVector< CUtlString > dirList;
+ RecurseFileTree_r( dirPath, 0, dirList );
+ for ( int i=0; i<dirList.Count(); i++ )
+ {
+ // iterate each directory found
+ tempList.Purge();
+ tempList.EnsureCapacity( dirList.Count() );
+
+ GetFileList( dirList[i].String(), pattern, tempList );
+
+ int start = fileList.AddMultipleToTail( tempList.Count() );
+ for ( int j=0; j<tempList.Count(); j++ )
+ {
+ fileList[start+j] = tempList[j];
+ }
+ }
+ }
+
+ return fileList.Count();
+}
diff --git a/mp/src/utils/common/scriplib.h b/mp/src/utils/common/scriplib.h
index 6b119525..114b5563 100644
--- a/mp/src/utils/common/scriplib.h
+++ b/mp/src/utils/common/scriplib.h
@@ -1,96 +1,96 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef SCRIPLIB_H
-#define SCRIPLIB_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-enum ScriptPathMode_t
-{
- SCRIPT_USE_ABSOLUTE_PATH,
- SCRIPT_USE_RELATIVE_PATH
-};
-
-
-// scriplib.h
-
-#define MAXTOKEN 1024
-
-extern char token[MAXTOKEN];
-extern char *scriptbuffer,*script_p,*scriptend_p;
-extern int grabbed;
-extern int scriptline;
-extern qboolean endofscript;
-
-
-// If pathMode is SCRIPT_USE_ABSOLUTE_PATH, then it uses ExpandPath() on the filename before
-// trying to open it. Otherwise, it passes the filename straight into the filesystem
-// (so you can leave it as a relative path).
-void LoadScriptFile (char *filename, ScriptPathMode_t pathMode=SCRIPT_USE_ABSOLUTE_PATH);
-void ParseFromMemory (char *buffer, int size);
-
-qboolean GetToken (qboolean crossline);
-qboolean GetExprToken (qboolean crossline);
-void UnGetToken (void);
-qboolean TokenAvailable (void);
-qboolean GetTokenizerStatus( char **pFilename, int *pLine );
-bool SetCheckSingleCharTokens( bool bCheck );
-
-// SCRIPT_LOADED_CALLBACK:
-// Is called after the contents of a file is loaded.
-// pFilenameLoaded is the path of a file that got loaded.
-// pIncludedFromFileName is the name of the parent file or NULL if loaded because of "LoadScriptFile" toplevel call.
-// nIncludeLineNumber is the number of the line in the parent file with $include statement or 0 in case of "LoadScriptFile"
-typedef void ( * SCRIPT_LOADED_CALLBACK )( char const *pFilenameLoaded, char const *pIncludedFromFileName, int nIncludeLineNumber );
-
-// SetScriptLoadedCallback:
-// Sets the new callback for script loading.
-// Returns the previous callback function.
-SCRIPT_LOADED_CALLBACK SetScriptLoadedCallback( SCRIPT_LOADED_CALLBACK pfnNewScriptLoadedCallback );
-
-#include "tier1/utlstring.h"
-#include "tier1/utlvector.h"
-
-CUtlString SetSingleCharTokenList( const char *pszSingleCharTokenList );
-
-class CUtlBuffer;
-
-enum DiskWriteMode_t
-{
- WRITE_TO_DISK_NEVER,
- WRITE_TO_DISK_ALWAYS,
- WRITE_TO_DISK_UPDATE, // file must exist
-};
-
-struct fileList_t
-{
- CUtlString fileName;
- time_t timeWrite;
-};
-
-class IScriptLib
-{
-public:
- virtual bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText = false, bool bNoOpenFailureWarning = false ) = 0;
- virtual bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode ) = 0;
- virtual int FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList ) = 0;
- virtual char *MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize ) = 0;
- virtual void DeleteTemporaryFiles( const char *pFileMask ) = 0;
- virtual int CompareFileTime( const char *pFilenameA, const char *pFilenameB ) = 0;
- virtual bool DoesFileExist( const char *pFilename ) = 0;
-};
-
-extern IScriptLib *scriptlib;
-
-
-#endif // SCRIPLIB_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SCRIPLIB_H
+#define SCRIPLIB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+enum ScriptPathMode_t
+{
+ SCRIPT_USE_ABSOLUTE_PATH,
+ SCRIPT_USE_RELATIVE_PATH
+};
+
+
+// scriplib.h
+
+#define MAXTOKEN 1024
+
+extern char token[MAXTOKEN];
+extern char *scriptbuffer,*script_p,*scriptend_p;
+extern int grabbed;
+extern int scriptline;
+extern qboolean endofscript;
+
+
+// If pathMode is SCRIPT_USE_ABSOLUTE_PATH, then it uses ExpandPath() on the filename before
+// trying to open it. Otherwise, it passes the filename straight into the filesystem
+// (so you can leave it as a relative path).
+void LoadScriptFile (char *filename, ScriptPathMode_t pathMode=SCRIPT_USE_ABSOLUTE_PATH);
+void ParseFromMemory (char *buffer, int size);
+
+qboolean GetToken (qboolean crossline);
+qboolean GetExprToken (qboolean crossline);
+void UnGetToken (void);
+qboolean TokenAvailable (void);
+qboolean GetTokenizerStatus( char **pFilename, int *pLine );
+bool SetCheckSingleCharTokens( bool bCheck );
+
+// SCRIPT_LOADED_CALLBACK:
+// Is called after the contents of a file is loaded.
+// pFilenameLoaded is the path of a file that got loaded.
+// pIncludedFromFileName is the name of the parent file or NULL if loaded because of "LoadScriptFile" toplevel call.
+// nIncludeLineNumber is the number of the line in the parent file with $include statement or 0 in case of "LoadScriptFile"
+typedef void ( * SCRIPT_LOADED_CALLBACK )( char const *pFilenameLoaded, char const *pIncludedFromFileName, int nIncludeLineNumber );
+
+// SetScriptLoadedCallback:
+// Sets the new callback for script loading.
+// Returns the previous callback function.
+SCRIPT_LOADED_CALLBACK SetScriptLoadedCallback( SCRIPT_LOADED_CALLBACK pfnNewScriptLoadedCallback );
+
+#include "tier1/utlstring.h"
+#include "tier1/utlvector.h"
+
+CUtlString SetSingleCharTokenList( const char *pszSingleCharTokenList );
+
+class CUtlBuffer;
+
+enum DiskWriteMode_t
+{
+ WRITE_TO_DISK_NEVER,
+ WRITE_TO_DISK_ALWAYS,
+ WRITE_TO_DISK_UPDATE, // file must exist
+};
+
+struct fileList_t
+{
+ CUtlString fileName;
+ time_t timeWrite;
+};
+
+class IScriptLib
+{
+public:
+ virtual bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText = false, bool bNoOpenFailureWarning = false ) = 0;
+ virtual bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode ) = 0;
+ virtual int FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList ) = 0;
+ virtual char *MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize ) = 0;
+ virtual void DeleteTemporaryFiles( const char *pFileMask ) = 0;
+ virtual int CompareFileTime( const char *pFilenameA, const char *pFilenameB ) = 0;
+ virtual bool DoesFileExist( const char *pFilename ) = 0;
+};
+
+extern IScriptLib *scriptlib;
+
+
+#endif // SCRIPLIB_H
diff --git a/mp/src/utils/common/threads.cpp b/mp/src/utils/common/threads.cpp
index 344943c9..74e457a9 100644
--- a/mp/src/utils/common/threads.cpp
+++ b/mp/src/utils/common/threads.cpp
@@ -1,257 +1,257 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-//
-//-----------------------------------------------------------------------------
-// $Log: $
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#define USED
-
-#include <windows.h>
-#include "cmdlib.h"
-#define NO_THREAD_NAMES
-#include "threads.h"
-#include "pacifier.h"
-
-#define MAX_THREADS 16
-
-
-class CRunThreadsData
-{
-public:
- int m_iThread;
- void *m_pUserData;
- RunThreadsFn m_Fn;
-};
-
-CRunThreadsData g_RunThreadsData[MAX_THREADS];
-
-
-int dispatch;
-int workcount;
-qboolean pacifier;
-
-qboolean threaded;
-bool g_bLowPriorityThreads = false;
-
-HANDLE g_ThreadHandles[MAX_THREADS];
-
-
-
-/*
-=============
-GetThreadWork
-
-=============
-*/
-int GetThreadWork (void)
-{
- int r;
-
- ThreadLock ();
-
- if (dispatch == workcount)
- {
- ThreadUnlock ();
- return -1;
- }
-
- UpdatePacifier( (float)dispatch / workcount );
-
- r = dispatch;
- dispatch++;
- ThreadUnlock ();
-
- return r;
-}
-
-
-ThreadWorkerFn workfunction;
-
-void ThreadWorkerFunction( int iThread, void *pUserData )
-{
- int work;
-
- while (1)
- {
- work = GetThreadWork ();
- if (work == -1)
- break;
-
- workfunction( iThread, work );
- }
-}
-
-void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, ThreadWorkerFn func)
-{
- if (numthreads == -1)
- ThreadSetDefault ();
-
- workfunction = func;
- RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
-}
-
-
-/*
-===================================================================
-
-WIN32
-
-===================================================================
-*/
-
-int numthreads = -1;
-CRITICAL_SECTION crit;
-static int enter;
-
-
-class CCritInit
-{
-public:
- CCritInit()
- {
- InitializeCriticalSection (&crit);
- }
-} 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)
- return;
- EnterCriticalSection (&crit);
- if (enter)
- Error ("Recursive ThreadLock\n");
- enter = 1;
-}
-
-void ThreadUnlock (void)
-{
- if (!threaded)
- return;
- if (!enter)
- Error ("ThreadUnlock without lock\n");
- enter = 0;
- LeaveCriticalSection (&crit);
-}
-
-
-// This runs in the thread and dispatches a RunThreadsFn call.
-DWORD WINAPI InternalRunThreadsFn( LPVOID pParameter )
-{
- CRunThreadsData *pData = (CRunThreadsData*)pParameter;
- pData->m_Fn( pData->m_iThread, pData->m_pUserData );
- return 0;
-}
-
-
-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;
-
- DWORD dwDummy;
- g_ThreadHandles[i] = CreateThread(
- NULL, // LPSECURITY_ATTRIBUTES lpsa,
- 0, // DWORD cbStack,
- InternalRunThreadsFn, // LPTHREAD_START_ROUTINE lpStartAddr,
- &g_RunThreadsData[i], // LPVOID lpvThreadParm,
- 0, // DWORD fdwCreate,
- &dwDummy );
-
- if ( ePriority == k_eRunThreadsPriority_UseGlobalState )
- {
- if( g_bLowPriorityThreads )
- SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_LOWEST );
- }
- else if ( ePriority == k_eRunThreadsPriority_Idle )
- {
- SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_IDLE );
- }
- }
-}
-
-
-void RunThreads_End()
-{
- WaitForMultipleObjects( numthreads, g_ThreadHandles, TRUE, INFINITE );
- for ( int i=0; i < numthreads; i++ )
- CloseHandle( g_ThreadHandles[i] );
-
- threaded = false;
-}
-
-
-/*
-=============
-RunThreadsOn
-=============
-*/
-void RunThreadsOn( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData )
-{
- int start, end;
-
- start = Plat_FloatTime();
- dispatch = 0;
- workcount = workcnt;
- StartPacifier("");
- pacifier = showpacifier;
-
-#ifdef _PROFILE
- threaded = false;
- (*func)( 0 );
- return;
-#endif
-
-
- RunThreads_Start( fn, pUserData );
- RunThreads_End();
-
-
- end = Plat_FloatTime();
- if (pacifier)
- {
- EndPacifier(false);
- printf (" (%i)\n", end-start);
- }
-}
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#define USED
+
+#include <windows.h>
+#include "cmdlib.h"
+#define NO_THREAD_NAMES
+#include "threads.h"
+#include "pacifier.h"
+
+#define MAX_THREADS 16
+
+
+class CRunThreadsData
+{
+public:
+ int m_iThread;
+ void *m_pUserData;
+ RunThreadsFn m_Fn;
+};
+
+CRunThreadsData g_RunThreadsData[MAX_THREADS];
+
+
+int dispatch;
+int workcount;
+qboolean pacifier;
+
+qboolean threaded;
+bool g_bLowPriorityThreads = false;
+
+HANDLE g_ThreadHandles[MAX_THREADS];
+
+
+
+/*
+=============
+GetThreadWork
+
+=============
+*/
+int GetThreadWork (void)
+{
+ int r;
+
+ ThreadLock ();
+
+ if (dispatch == workcount)
+ {
+ ThreadUnlock ();
+ return -1;
+ }
+
+ UpdatePacifier( (float)dispatch / workcount );
+
+ r = dispatch;
+ dispatch++;
+ ThreadUnlock ();
+
+ return r;
+}
+
+
+ThreadWorkerFn workfunction;
+
+void ThreadWorkerFunction( int iThread, void *pUserData )
+{
+ int work;
+
+ while (1)
+ {
+ work = GetThreadWork ();
+ if (work == -1)
+ break;
+
+ workfunction( iThread, work );
+ }
+}
+
+void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, ThreadWorkerFn func)
+{
+ if (numthreads == -1)
+ ThreadSetDefault ();
+
+ workfunction = func;
+ RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
+}
+
+
+/*
+===================================================================
+
+WIN32
+
+===================================================================
+*/
+
+int numthreads = -1;
+CRITICAL_SECTION crit;
+static int enter;
+
+
+class CCritInit
+{
+public:
+ CCritInit()
+ {
+ InitializeCriticalSection (&crit);
+ }
+} 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)
+ return;
+ EnterCriticalSection (&crit);
+ if (enter)
+ Error ("Recursive ThreadLock\n");
+ enter = 1;
+}
+
+void ThreadUnlock (void)
+{
+ if (!threaded)
+ return;
+ if (!enter)
+ Error ("ThreadUnlock without lock\n");
+ enter = 0;
+ LeaveCriticalSection (&crit);
+}
+
+
+// This runs in the thread and dispatches a RunThreadsFn call.
+DWORD WINAPI InternalRunThreadsFn( LPVOID pParameter )
+{
+ CRunThreadsData *pData = (CRunThreadsData*)pParameter;
+ pData->m_Fn( pData->m_iThread, pData->m_pUserData );
+ return 0;
+}
+
+
+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;
+
+ DWORD dwDummy;
+ g_ThreadHandles[i] = CreateThread(
+ NULL, // LPSECURITY_ATTRIBUTES lpsa,
+ 0, // DWORD cbStack,
+ InternalRunThreadsFn, // LPTHREAD_START_ROUTINE lpStartAddr,
+ &g_RunThreadsData[i], // LPVOID lpvThreadParm,
+ 0, // DWORD fdwCreate,
+ &dwDummy );
+
+ if ( ePriority == k_eRunThreadsPriority_UseGlobalState )
+ {
+ if( g_bLowPriorityThreads )
+ SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_LOWEST );
+ }
+ else if ( ePriority == k_eRunThreadsPriority_Idle )
+ {
+ SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_IDLE );
+ }
+ }
+}
+
+
+void RunThreads_End()
+{
+ WaitForMultipleObjects( numthreads, g_ThreadHandles, TRUE, INFINITE );
+ for ( int i=0; i < numthreads; i++ )
+ CloseHandle( g_ThreadHandles[i] );
+
+ threaded = false;
+}
+
+
+/*
+=============
+RunThreadsOn
+=============
+*/
+void RunThreadsOn( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData )
+{
+ int start, end;
+
+ start = Plat_FloatTime();
+ dispatch = 0;
+ workcount = workcnt;
+ StartPacifier("");
+ pacifier = showpacifier;
+
+#ifdef _PROFILE
+ threaded = false;
+ (*func)( 0 );
+ return;
+#endif
+
+
+ RunThreads_Start( fn, pUserData );
+ RunThreads_End();
+
+
+ end = Plat_FloatTime();
+ if (pacifier)
+ {
+ EndPacifier(false);
+ printf (" (%i)\n", end-start);
+ }
+}
+
+
diff --git a/mp/src/utils/common/threads.h b/mp/src/utils/common/threads.h
index e29e9aab..0908b67a 100644
--- a/mp/src/utils/common/threads.h
+++ b/mp/src/utils/common/threads.h
@@ -1,65 +1,65 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-//
-//-----------------------------------------------------------------------------
-// $Log: $
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef THREADS_H
-#define THREADS_H
-#pragma once
-
-
-// Arrays that are indexed by thread should always be MAX_TOOL_THREADS+1
-// large so THREADINDEX_MAIN can be used from the main thread.
-#define MAX_TOOL_THREADS 16
-#define THREADINDEX_MAIN (MAX_TOOL_THREADS)
-
-
-extern int numthreads;
-
-// If set to true, then all the threads that are created are low priority.
-extern bool g_bLowPriorityThreads;
-
-typedef void (*ThreadWorkerFn)( int iThread, int iWorkItem );
-typedef void (*RunThreadsFn)( int iThread, void *pUserData );
-
-
-enum ERunThreadsPriority
-{
- k_eRunThreadsPriority_UseGlobalState=0, // Default.. uses g_bLowPriorityThreads to decide what to set the priority to.
- k_eRunThreadsPriority_Normal, // Doesn't touch thread priorities.
- k_eRunThreadsPriority_Idle // Sets threads to idle priority.
-};
-
-
-// Put the process into an idle priority class so it doesn't hog the UI.
-void SetLowPriority();
-
-void ThreadSetDefault (void);
-int GetThreadWork (void);
-
-void RunThreadsOnIndividual ( int workcnt, qboolean showpacifier, ThreadWorkerFn fn );
-
-void RunThreadsOn ( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData=NULL );
-
-// This version doesn't track work items - it just runs your function and waits for it to finish.
-void RunThreads_Start( RunThreadsFn fn, void *pUserData, ERunThreadsPriority ePriority=k_eRunThreadsPriority_UseGlobalState );
-void RunThreads_End();
-
-void ThreadLock (void);
-void ThreadUnlock (void);
-
-
-#ifndef NO_THREAD_NAMES
-#define RunThreadsOn(n,p,f) { if (p) printf("%-20s ", #f ":"); RunThreadsOn(n,p,f); }
-#define RunThreadsOnIndividual(n,p,f) { if (p) printf("%-20s ", #f ":"); RunThreadsOnIndividual(n,p,f); }
-#endif
-
-#endif // THREADS_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef THREADS_H
+#define THREADS_H
+#pragma once
+
+
+// Arrays that are indexed by thread should always be MAX_TOOL_THREADS+1
+// large so THREADINDEX_MAIN can be used from the main thread.
+#define MAX_TOOL_THREADS 16
+#define THREADINDEX_MAIN (MAX_TOOL_THREADS)
+
+
+extern int numthreads;
+
+// If set to true, then all the threads that are created are low priority.
+extern bool g_bLowPriorityThreads;
+
+typedef void (*ThreadWorkerFn)( int iThread, int iWorkItem );
+typedef void (*RunThreadsFn)( int iThread, void *pUserData );
+
+
+enum ERunThreadsPriority
+{
+ k_eRunThreadsPriority_UseGlobalState=0, // Default.. uses g_bLowPriorityThreads to decide what to set the priority to.
+ k_eRunThreadsPriority_Normal, // Doesn't touch thread priorities.
+ k_eRunThreadsPriority_Idle // Sets threads to idle priority.
+};
+
+
+// Put the process into an idle priority class so it doesn't hog the UI.
+void SetLowPriority();
+
+void ThreadSetDefault (void);
+int GetThreadWork (void);
+
+void RunThreadsOnIndividual ( int workcnt, qboolean showpacifier, ThreadWorkerFn fn );
+
+void RunThreadsOn ( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData=NULL );
+
+// This version doesn't track work items - it just runs your function and waits for it to finish.
+void RunThreads_Start( RunThreadsFn fn, void *pUserData, ERunThreadsPriority ePriority=k_eRunThreadsPriority_UseGlobalState );
+void RunThreads_End();
+
+void ThreadLock (void);
+void ThreadUnlock (void);
+
+
+#ifndef NO_THREAD_NAMES
+#define RunThreadsOn(n,p,f) { if (p) printf("%-20s ", #f ":"); RunThreadsOn(n,p,f); }
+#define RunThreadsOnIndividual(n,p,f) { if (p) printf("%-20s ", #f ":"); RunThreadsOnIndividual(n,p,f); }
+#endif
+
+#endif // THREADS_H
diff --git a/mp/src/utils/common/tools_minidump.cpp b/mp/src/utils/common/tools_minidump.cpp
index a0c84209..a7659200 100644
--- a/mp/src/utils/common/tools_minidump.cpp
+++ b/mp/src/utils/common/tools_minidump.cpp
@@ -1,61 +1,61 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include <windows.h>
-#include <dbghelp.h>
-#include "tier0/minidump.h"
-#include "tools_minidump.h"
-
-static bool g_bToolsWriteFullMinidumps = false;
-static ToolsExceptionHandler g_pCustomExceptionHandler = NULL;
-
-
-// --------------------------------------------------------------------------------- //
-// Internal helpers.
-// --------------------------------------------------------------------------------- //
-
-static LONG __stdcall ToolsExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo )
-{
- // Non VMPI workers write a minidump and show a crash dialog like normal.
- int iType = MiniDumpNormal;
- if ( g_bToolsWriteFullMinidumps )
- iType = MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory;
-
- WriteMiniDumpUsingExceptionInfo( ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo, (MINIDUMP_TYPE)iType );
- return EXCEPTION_CONTINUE_SEARCH;
-}
-
-
-static LONG __stdcall ToolsExceptionFilter_Custom( struct _EXCEPTION_POINTERS *ExceptionInfo )
-{
- // Run their custom handler.
- g_pCustomExceptionHandler( ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo );
- return EXCEPTION_EXECUTE_HANDLER; // (never gets here anyway)
-}
-
-
-// --------------------------------------------------------------------------------- //
-// Interface functions.
-// --------------------------------------------------------------------------------- //
-
-void EnableFullMinidumps( bool bFull )
-{
- g_bToolsWriteFullMinidumps = bFull;
-}
-
-
-void SetupDefaultToolsMinidumpHandler()
-{
- SetUnhandledExceptionFilter( ToolsExceptionFilter );
-}
-
-
-void SetupToolsMinidumpHandler( ToolsExceptionHandler fn )
-{
- g_pCustomExceptionHandler = fn;
- SetUnhandledExceptionFilter( ToolsExceptionFilter_Custom );
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <windows.h>
+#include <dbghelp.h>
+#include "tier0/minidump.h"
+#include "tools_minidump.h"
+
+static bool g_bToolsWriteFullMinidumps = false;
+static ToolsExceptionHandler g_pCustomExceptionHandler = NULL;
+
+
+// --------------------------------------------------------------------------------- //
+// Internal helpers.
+// --------------------------------------------------------------------------------- //
+
+static LONG __stdcall ToolsExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo )
+{
+ // Non VMPI workers write a minidump and show a crash dialog like normal.
+ int iType = MiniDumpNormal;
+ if ( g_bToolsWriteFullMinidumps )
+ iType = MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory;
+
+ WriteMiniDumpUsingExceptionInfo( ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo, (MINIDUMP_TYPE)iType );
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+
+static LONG __stdcall ToolsExceptionFilter_Custom( struct _EXCEPTION_POINTERS *ExceptionInfo )
+{
+ // Run their custom handler.
+ g_pCustomExceptionHandler( ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo );
+ return EXCEPTION_EXECUTE_HANDLER; // (never gets here anyway)
+}
+
+
+// --------------------------------------------------------------------------------- //
+// Interface functions.
+// --------------------------------------------------------------------------------- //
+
+void EnableFullMinidumps( bool bFull )
+{
+ g_bToolsWriteFullMinidumps = bFull;
+}
+
+
+void SetupDefaultToolsMinidumpHandler()
+{
+ SetUnhandledExceptionFilter( ToolsExceptionFilter );
+}
+
+
+void SetupToolsMinidumpHandler( ToolsExceptionHandler fn )
+{
+ g_pCustomExceptionHandler = fn;
+ SetUnhandledExceptionFilter( ToolsExceptionFilter_Custom );
+}
diff --git a/mp/src/utils/common/tools_minidump.h b/mp/src/utils/common/tools_minidump.h
index dfb44a9b..2e5f12cb 100644
--- a/mp/src/utils/common/tools_minidump.h
+++ b/mp/src/utils/common/tools_minidump.h
@@ -1,35 +1,35 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#ifndef TOOLS_MINIDUMP_H
-#define TOOLS_MINIDUMP_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-
-// Defaults to false. If true, it'll write larger minidump files with the contents
-// of global variables and following pointers from where the crash occurred.
-void EnableFullMinidumps( bool bFull );
-
-
-// This handler catches any crash, writes a minidump, and runs the default system
-// crash handler (which usually shows a dialog).
-void SetupDefaultToolsMinidumpHandler();
-
-
-// (Used by VMPI) - you specify your own crash handler.
-// Arguments passed to ToolsExceptionHandler
-// exceptionCode - exception code
-// pvExceptionInfo - on Win32 platform points to "struct _EXCEPTION_POINTERS"
-// otherwise NULL
-//
-typedef void (*ToolsExceptionHandler)( unsigned long exceptionCode, void *pvExceptionInfo );
-void SetupToolsMinidumpHandler( ToolsExceptionHandler fn );
-
-
-#endif // MINIDUMP_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef TOOLS_MINIDUMP_H
+#define TOOLS_MINIDUMP_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+
+// Defaults to false. If true, it'll write larger minidump files with the contents
+// of global variables and following pointers from where the crash occurred.
+void EnableFullMinidumps( bool bFull );
+
+
+// This handler catches any crash, writes a minidump, and runs the default system
+// crash handler (which usually shows a dialog).
+void SetupDefaultToolsMinidumpHandler();
+
+
+// (Used by VMPI) - you specify your own crash handler.
+// Arguments passed to ToolsExceptionHandler
+// exceptionCode - exception code
+// pvExceptionInfo - on Win32 platform points to "struct _EXCEPTION_POINTERS"
+// otherwise NULL
+//
+typedef void (*ToolsExceptionHandler)( unsigned long exceptionCode, void *pvExceptionInfo );
+void SetupToolsMinidumpHandler( ToolsExceptionHandler fn );
+
+
+#endif // MINIDUMP_H
diff --git a/mp/src/utils/common/utilmatlib.cpp b/mp/src/utils/common/utilmatlib.cpp
index 962bb3f5..f2dc49fa 100644
--- a/mp/src/utils/common/utilmatlib.cpp
+++ b/mp/src/utils/common/utilmatlib.cpp
@@ -1,184 +1,184 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-// C callable material system interface for the utils.
-
-#include "materialsystem/imaterialsystem.h"
-#include "materialsystem/imaterial.h"
-#include "materialsystem/imaterialvar.h"
-#include <cmdlib.h>
-#include "utilmatlib.h"
-#include "tier0/dbg.h"
-#include <windows.h>
-#include "filesystem.h"
-#include "materialsystem/materialsystem_config.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";
- CSysModule *materialSystemDLLHInst;
- materialSystemDLLHInst = g_pFullFileSystem->LoadModule( pDllName );
- if( !materialSystemDLLHInst )
- {
- Error( "Can't load MaterialSystem.dll\n" );
- }
-
- CreateInterfaceFn clientFactory = Sys_GetFactory( materialSystemDLLHInst );
- if ( clientFactory )
- {
- g_pMaterialSystem = (IMaterialSystem *)clientFactory( MATERIAL_SYSTEM_INTERFACE_VERSION, NULL );
- if ( !g_pMaterialSystem )
- {
- Error( "Could not get the material system interface from materialsystem.dll (" __FILE__ ")" );
- }
- }
- else
- {
- Error( "Could not find factory interface in library MaterialSystem.dll" );
- }
-
- if (!g_pMaterialSystem->Init( "shaderapiempty.dll", 0, fileSystemFactory ))
- {
- Error( "Could not start the empty shader (shaderapiempty.dll)!" );
- }
-}
-
-void InitMaterialSystem( const char *materialBaseDirPath, CreateInterfaceFn fileSystemFactory )
-{
- LoadMaterialSystemInterface( fileSystemFactory );
- MaterialSystem_Config_t config;
- g_pMaterialSystem->OverrideConfig( config, false );
-}
-
-void ShutdownMaterialSystem( )
-{
- if ( g_pMaterialSystem )
- {
- g_pMaterialSystem->Shutdown();
- g_pMaterialSystem = NULL;
- }
-}
-
-MaterialSystemMaterial_t FindMaterial( const char *materialName, bool *pFound, bool bComplain )
-{
- IMaterial *pMat = g_pMaterialSystem->FindMaterial( materialName, TEXTURE_GROUP_OTHER, bComplain );
- MaterialSystemMaterial_t matHandle = pMat;
-
- if ( pFound )
- {
- *pFound = true;
- if ( IsErrorMaterial( pMat ) )
- *pFound = false;
- }
-
- return matHandle;
-}
-
-void GetMaterialDimensions( MaterialSystemMaterial_t materialHandle, int *width, int *height )
-{
- PreviewImageRetVal_t retVal;
- ImageFormat dummyImageFormat;
- IMaterial *material = ( IMaterial * )materialHandle;
- bool translucent;
- retVal = material->GetPreviewImageProperties( width, height, &dummyImageFormat, &translucent );
- if (retVal != MATERIAL_PREVIEW_IMAGE_OK )
- {
-#if 0
- if (retVal == MATERIAL_PREVIEW_IMAGE_BAD )
- {
- Error( "problem getting preview image for %s",
- g_pMaterialSystem->GetMaterialName( materialInfo[matID].materialHandle ) );
- }
-#else
- *width = 128;
- *height = 128;
-#endif
- }
-}
-
-void GetMaterialReflectivity( MaterialSystemMaterial_t materialHandle, float *reflectivityVect )
-{
- IMaterial *material = ( IMaterial * )materialHandle;
- const IMaterialVar *reflectivityVar;
-
- bool found;
- reflectivityVar = material->FindVar( "$reflectivity", &found, false );
- if( !found )
- {
- Vector tmp;
- material->GetReflectivity( tmp );
- VectorCopy( tmp.Base(), reflectivityVect );
- }
- else
- {
- reflectivityVar->GetVecValue( reflectivityVect, 3 );
- }
-}
-
-int GetMaterialShaderPropertyBool( MaterialSystemMaterial_t materialHandle, int propID )
-{
- IMaterial *material = ( IMaterial * )materialHandle;
- switch( propID )
- {
- case UTILMATLIB_NEEDS_BUMPED_LIGHTMAPS:
- return material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
-
- case UTILMATLIB_NEEDS_LIGHTMAP:
- return material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP );
-
- default:
- Assert( 0 );
- return 0;
- }
-}
-
-int GetMaterialShaderPropertyInt( MaterialSystemMaterial_t materialHandle, int propID )
-{
- IMaterial *material = ( IMaterial * )materialHandle;
- switch( propID )
- {
- case UTILMATLIB_OPACITY:
- if (material->IsTranslucent())
- return UTILMATLIB_TRANSLUCENT;
- if (material->IsAlphaTested())
- return UTILMATLIB_ALPHATEST;
- return UTILMATLIB_OPAQUE;
-
- default:
- Assert( 0 );
- return 0;
- }
-}
-
-const char *GetMaterialVar( MaterialSystemMaterial_t materialHandle, const char *propertyName )
-{
- IMaterial *material = ( IMaterial * )materialHandle;
- IMaterialVar *var;
- bool found;
- var = material->FindVar( propertyName, &found, false );
- if( found )
- {
- return var->GetStringValue();
- }
- else
- {
- return NULL;
- }
-}
-
-const char *GetMaterialShaderName( MaterialSystemMaterial_t materialHandle )
-{
- IMaterial *material = ( IMaterial * )materialHandle;
- return material->GetShaderName();
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+// C callable material system interface for the utils.
+
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include <cmdlib.h>
+#include "utilmatlib.h"
+#include "tier0/dbg.h"
+#include <windows.h>
+#include "filesystem.h"
+#include "materialsystem/materialsystem_config.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";
+ CSysModule *materialSystemDLLHInst;
+ materialSystemDLLHInst = g_pFullFileSystem->LoadModule( pDllName );
+ if( !materialSystemDLLHInst )
+ {
+ Error( "Can't load MaterialSystem.dll\n" );
+ }
+
+ CreateInterfaceFn clientFactory = Sys_GetFactory( materialSystemDLLHInst );
+ if ( clientFactory )
+ {
+ g_pMaterialSystem = (IMaterialSystem *)clientFactory( MATERIAL_SYSTEM_INTERFACE_VERSION, NULL );
+ if ( !g_pMaterialSystem )
+ {
+ Error( "Could not get the material system interface from materialsystem.dll (" __FILE__ ")" );
+ }
+ }
+ else
+ {
+ Error( "Could not find factory interface in library MaterialSystem.dll" );
+ }
+
+ if (!g_pMaterialSystem->Init( "shaderapiempty.dll", 0, fileSystemFactory ))
+ {
+ Error( "Could not start the empty shader (shaderapiempty.dll)!" );
+ }
+}
+
+void InitMaterialSystem( const char *materialBaseDirPath, CreateInterfaceFn fileSystemFactory )
+{
+ LoadMaterialSystemInterface( fileSystemFactory );
+ MaterialSystem_Config_t config;
+ g_pMaterialSystem->OverrideConfig( config, false );
+}
+
+void ShutdownMaterialSystem( )
+{
+ if ( g_pMaterialSystem )
+ {
+ g_pMaterialSystem->Shutdown();
+ g_pMaterialSystem = NULL;
+ }
+}
+
+MaterialSystemMaterial_t FindMaterial( const char *materialName, bool *pFound, bool bComplain )
+{
+ IMaterial *pMat = g_pMaterialSystem->FindMaterial( materialName, TEXTURE_GROUP_OTHER, bComplain );
+ MaterialSystemMaterial_t matHandle = pMat;
+
+ if ( pFound )
+ {
+ *pFound = true;
+ if ( IsErrorMaterial( pMat ) )
+ *pFound = false;
+ }
+
+ return matHandle;
+}
+
+void GetMaterialDimensions( MaterialSystemMaterial_t materialHandle, int *width, int *height )
+{
+ PreviewImageRetVal_t retVal;
+ ImageFormat dummyImageFormat;
+ IMaterial *material = ( IMaterial * )materialHandle;
+ bool translucent;
+ retVal = material->GetPreviewImageProperties( width, height, &dummyImageFormat, &translucent );
+ if (retVal != MATERIAL_PREVIEW_IMAGE_OK )
+ {
+#if 0
+ if (retVal == MATERIAL_PREVIEW_IMAGE_BAD )
+ {
+ Error( "problem getting preview image for %s",
+ g_pMaterialSystem->GetMaterialName( materialInfo[matID].materialHandle ) );
+ }
+#else
+ *width = 128;
+ *height = 128;
+#endif
+ }
+}
+
+void GetMaterialReflectivity( MaterialSystemMaterial_t materialHandle, float *reflectivityVect )
+{
+ IMaterial *material = ( IMaterial * )materialHandle;
+ const IMaterialVar *reflectivityVar;
+
+ bool found;
+ reflectivityVar = material->FindVar( "$reflectivity", &found, false );
+ if( !found )
+ {
+ Vector tmp;
+ material->GetReflectivity( tmp );
+ VectorCopy( tmp.Base(), reflectivityVect );
+ }
+ else
+ {
+ reflectivityVar->GetVecValue( reflectivityVect, 3 );
+ }
+}
+
+int GetMaterialShaderPropertyBool( MaterialSystemMaterial_t materialHandle, int propID )
+{
+ IMaterial *material = ( IMaterial * )materialHandle;
+ switch( propID )
+ {
+ case UTILMATLIB_NEEDS_BUMPED_LIGHTMAPS:
+ return material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
+
+ case UTILMATLIB_NEEDS_LIGHTMAP:
+ return material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP );
+
+ default:
+ Assert( 0 );
+ return 0;
+ }
+}
+
+int GetMaterialShaderPropertyInt( MaterialSystemMaterial_t materialHandle, int propID )
+{
+ IMaterial *material = ( IMaterial * )materialHandle;
+ switch( propID )
+ {
+ case UTILMATLIB_OPACITY:
+ if (material->IsTranslucent())
+ return UTILMATLIB_TRANSLUCENT;
+ if (material->IsAlphaTested())
+ return UTILMATLIB_ALPHATEST;
+ return UTILMATLIB_OPAQUE;
+
+ default:
+ Assert( 0 );
+ return 0;
+ }
+}
+
+const char *GetMaterialVar( MaterialSystemMaterial_t materialHandle, const char *propertyName )
+{
+ IMaterial *material = ( IMaterial * )materialHandle;
+ IMaterialVar *var;
+ bool found;
+ var = material->FindVar( propertyName, &found, false );
+ if( found )
+ {
+ return var->GetStringValue();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+const char *GetMaterialShaderName( MaterialSystemMaterial_t materialHandle )
+{
+ IMaterial *material = ( IMaterial * )materialHandle;
+ return material->GetShaderName();
+}
diff --git a/mp/src/utils/common/utilmatlib.h b/mp/src/utils/common/utilmatlib.h
index f73a73d0..9d2e0b57 100644
--- a/mp/src/utils/common/utilmatlib.h
+++ b/mp/src/utils/common/utilmatlib.h
@@ -1,41 +1,41 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef UTILMATLIB_H
-#define UTILMATLIB_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-#define MATERIAL_NOT_FOUND NULL
-
-class IMaterialSystem;
-extern IMaterialSystem *g_pMaterialSystem;
-
-typedef void *MaterialSystemMaterial_t;
-
-#define UTILMATLIB_NEEDS_BUMPED_LIGHTMAPS 0
-#define UTILMATLIB_NEEDS_LIGHTMAP 1
-#define UTILMATLIB_OPACITY 2
-
-enum { UTILMATLIB_ALPHATEST = 0, UTILMATLIB_OPAQUE, UTILMATLIB_TRANSLUCENT };
-
-void InitMaterialSystem( const char *materialBaseDirPath, CreateInterfaceFn fileSystemFactory );
-void ShutdownMaterialSystem( );
-MaterialSystemMaterial_t FindMaterial( const char *materialName, bool *pFound, bool bComplain = true );
-void GetMaterialDimensions( MaterialSystemMaterial_t materialHandle, int *width, int *height );
-int GetMaterialShaderPropertyBool( MaterialSystemMaterial_t materialHandle, int propID );
-int GetMaterialShaderPropertyInt( MaterialSystemMaterial_t materialHandle, int propID );
-const char *GetMaterialVar( MaterialSystemMaterial_t materialHandle, const char *propertyName );
-void GetMaterialReflectivity( MaterialSystemMaterial_t materialHandle, float *reflectivityVect );
-const char *GetMaterialShaderName( MaterialSystemMaterial_t materialHandle );
-
-
-#endif // UTILMATLIB_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef UTILMATLIB_H
+#define UTILMATLIB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#define MATERIAL_NOT_FOUND NULL
+
+class IMaterialSystem;
+extern IMaterialSystem *g_pMaterialSystem;
+
+typedef void *MaterialSystemMaterial_t;
+
+#define UTILMATLIB_NEEDS_BUMPED_LIGHTMAPS 0
+#define UTILMATLIB_NEEDS_LIGHTMAP 1
+#define UTILMATLIB_OPACITY 2
+
+enum { UTILMATLIB_ALPHATEST = 0, UTILMATLIB_OPAQUE, UTILMATLIB_TRANSLUCENT };
+
+void InitMaterialSystem( const char *materialBaseDirPath, CreateInterfaceFn fileSystemFactory );
+void ShutdownMaterialSystem( );
+MaterialSystemMaterial_t FindMaterial( const char *materialName, bool *pFound, bool bComplain = true );
+void GetMaterialDimensions( MaterialSystemMaterial_t materialHandle, int *width, int *height );
+int GetMaterialShaderPropertyBool( MaterialSystemMaterial_t materialHandle, int propID );
+int GetMaterialShaderPropertyInt( MaterialSystemMaterial_t materialHandle, int propID );
+const char *GetMaterialVar( MaterialSystemMaterial_t materialHandle, const char *propertyName );
+void GetMaterialReflectivity( MaterialSystemMaterial_t materialHandle, float *reflectivityVect );
+const char *GetMaterialShaderName( MaterialSystemMaterial_t materialHandle );
+
+
+#endif // UTILMATLIB_H
diff --git a/mp/src/utils/common/vmpi_tools_shared.cpp b/mp/src/utils/common/vmpi_tools_shared.cpp
index c753ce11..247569f4 100644
--- a/mp/src/utils/common/vmpi_tools_shared.cpp
+++ b/mp/src/utils/common/vmpi_tools_shared.cpp
@@ -1,374 +1,374 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include <windows.h>
-#include <dbghelp.h>
-#include "vmpi.h"
-#include "cmdlib.h"
-#include "vmpi_tools_shared.h"
-#include "tier1/strtools.h"
-#include "mpi_stats.h"
-#include "iphelpers.h"
-#include "tier0/minidump.h"
-
-
-// ----------------------------------------------------------------------------- //
-// Globals.
-// ----------------------------------------------------------------------------- //
-
-static bool g_bReceivedDirectoryInfo = false; // Have we gotten the qdir info yet?
-
-static bool g_bReceivedDBInfo = false;
-static CDBInfo g_DBInfo;
-static unsigned long g_JobPrimaryID;
-
-static int g_nDisconnects = 0; // Tracks how many remote processes have disconnected ungracefully.
-
-
-// ----------------------------------------------------------------------------- //
-// Shared dispatch code.
-// ----------------------------------------------------------------------------- //
-
-bool SharedDispatch( MessageBuffer *pBuf, int iSource, int iPacketID )
-{
- char *pInPos = &pBuf->data[2];
-
- switch ( pBuf->data[1] )
- {
- case VMPI_SUBPACKETID_DIRECTORIES:
- {
- Q_strncpy( gamedir, pInPos, sizeof( gamedir ) );
- pInPos += strlen( pInPos ) + 1;
-
- Q_strncpy( qdir, pInPos, sizeof( qdir ) );
-
- g_bReceivedDirectoryInfo = true;
- }
- return true;
-
- case VMPI_SUBPACKETID_DBINFO:
- {
- g_DBInfo = *((CDBInfo*)pInPos);
- pInPos += sizeof( CDBInfo );
- g_JobPrimaryID = *((unsigned long*)pInPos);
-
- g_bReceivedDBInfo = true;
- }
- return true;
-
- case VMPI_SUBPACKETID_CRASH:
- {
- char const chCrashInfoType = *pInPos;
- pInPos += 2;
- switch ( chCrashInfoType )
- {
- case 't':
- Warning( "\nWorker '%s' dead: %s\n", VMPI_GetMachineName( iSource ), pInPos );
- break;
- case 'f':
- {
- int iFileSize = * reinterpret_cast< int const * >( pInPos );
- pInPos += sizeof( iFileSize );
-
- // Temp folder
- char const *szFolder = NULL;
- if ( !szFolder ) szFolder = getenv( "TEMP" );
- if ( !szFolder ) szFolder = getenv( "TMP" );
- if ( !szFolder ) szFolder = "c:";
-
- // Base module name
- char chModuleName[_MAX_PATH], *pModuleName = chModuleName;
- ::GetModuleFileName( NULL, chModuleName, sizeof( chModuleName ) / sizeof( chModuleName[0] ) );
-
- if ( char *pch = strrchr( chModuleName, '.' ) )
- *pch = 0;
- if ( char *pch = strrchr( chModuleName, '\\' ) )
- *pch = 0, pModuleName = pch + 1;
-
- // Current time
- time_t currTime = ::time( NULL );
- struct tm * pTime = ::localtime( &currTime );
-
- // Number of minidumps this run
- static int s_numMiniDumps = 0;
- ++ s_numMiniDumps;
-
- // Prepare the filename
- char chSaveFileName[ 2 * _MAX_PATH ] = { 0 };
- sprintf( chSaveFileName, "%s\\vmpi_%s_on_%s_%d%.2d%2d%.2d%.2d%.2d_%d.mdmp",
- szFolder,
- pModuleName,
- VMPI_GetMachineName( iSource ),
- pTime->tm_year + 1900, /* Year less 2000 */
- pTime->tm_mon + 1, /* month (0 - 11 : 0 = January) */
- pTime->tm_mday, /* day of month (1 - 31) */
- pTime->tm_hour, /* hour (0 - 23) */
- pTime->tm_min, /* minutes (0 - 59) */
- pTime->tm_sec, /* seconds (0 - 59) */
- s_numMiniDumps
- );
-
- if ( FILE *fDump = fopen( chSaveFileName, "wb" ) )
- {
- fwrite( pInPos, 1, iFileSize, fDump );
- fclose( fDump );
-
- Warning( "\nSaved worker crash minidump '%s', size %d byte(s).\n",
- chSaveFileName, iFileSize );
- }
- else
- {
- Warning( "\nReceived worker crash minidump size %d byte(s), failed to save.\n", iFileSize );
- }
- }
- break;
- }
- }
- return true;
- }
-
- return false;
-}
-
-CDispatchReg g_SharedDispatchReg( VMPI_SHARED_PACKET_ID, SharedDispatch );
-
-
-
-// ----------------------------------------------------------------------------- //
-// Module interfaces.
-// ----------------------------------------------------------------------------- //
-
-void SendQDirInfo()
-{
- char cPacketID[2] = { VMPI_SHARED_PACKET_ID, VMPI_SUBPACKETID_DIRECTORIES };
-
- MessageBuffer mb;
- mb.write( cPacketID, 2 );
- mb.write( gamedir, strlen( gamedir ) + 1 );
- mb.write( qdir, strlen( qdir ) + 1 );
-
- VMPI_SendData( mb.data, mb.getLen(), VMPI_PERSISTENT );
-}
-
-
-void RecvQDirInfo()
-{
- while ( !g_bReceivedDirectoryInfo )
- VMPI_DispatchNextMessage();
-}
-
-
-void SendDBInfo( const CDBInfo *pInfo, unsigned long jobPrimaryID )
-{
- char cPacketInfo[2] = { VMPI_SHARED_PACKET_ID, VMPI_SUBPACKETID_DBINFO };
- const void *pChunks[] = { cPacketInfo, pInfo, &jobPrimaryID };
- int chunkLengths[] = { 2, sizeof( CDBInfo ), sizeof( jobPrimaryID ) };
-
- VMPI_SendChunks( pChunks, chunkLengths, ARRAYSIZE( pChunks ), VMPI_PERSISTENT );
-}
-
-
-void RecvDBInfo( CDBInfo *pInfo, unsigned long *pJobPrimaryID )
-{
- while ( !g_bReceivedDBInfo )
- VMPI_DispatchNextMessage();
-
- *pInfo = g_DBInfo;
- *pJobPrimaryID = g_JobPrimaryID;
-}
-
-// If the file is successfully opened, read and sent returns the size of the file in bytes
-// otherwise returns 0 and nothing is sent
-int VMPI_SendFileChunk( const void *pvChunkPrefix, int lenPrefix, tchar const *ptchFileName )
-{
- HANDLE hFile = NULL;
- HANDLE hMapping = NULL;
- void const *pvMappedData = NULL;
- int iResult = 0;
-
- hFile = ::CreateFile( ptchFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
- if ( !hFile || ( hFile == INVALID_HANDLE_VALUE ) )
- goto done;
-
- hMapping = ::CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
- if ( !hMapping || ( hMapping == INVALID_HANDLE_VALUE ) )
- goto done;
-
- pvMappedData = ::MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
- if ( !pvMappedData )
- goto done;
-
- int iMappedFileSize = ::GetFileSize( hFile, NULL );
- if ( INVALID_FILE_SIZE == iMappedFileSize )
- goto done;
-
- // Send the data over VMPI
- if ( VMPI_Send3Chunks(
- pvChunkPrefix, lenPrefix,
- &iMappedFileSize, sizeof( iMappedFileSize ),
- pvMappedData, iMappedFileSize,
- VMPI_MASTER_ID ) )
- iResult = iMappedFileSize;
-
- // Fall-through for cleanup code to execute
-done:
- if ( pvMappedData )
- ::UnmapViewOfFile( pvMappedData );
-
- if ( hMapping && ( hMapping != INVALID_HANDLE_VALUE ) )
- ::CloseHandle( hMapping );
-
- if ( hFile && ( hFile != INVALID_HANDLE_VALUE ) )
- ::CloseHandle( hFile );
-
- return iResult;
-}
-
-void VMPI_HandleCrash( const char *pMessage, void *pvExceptionInfo, bool bAssert )
-{
- static LONG crashHandlerCount = 0;
- if ( InterlockedIncrement( &crashHandlerCount ) == 1 )
- {
- Msg( "\nFAILURE: '%s' (assert: %d)\n", pMessage, bAssert );
-
- // Send a message to the master.
- char crashMsg[4] = { VMPI_SHARED_PACKET_ID, VMPI_SUBPACKETID_CRASH, 't', ':' };
-
- VMPI_Send2Chunks(
- crashMsg,
- sizeof( crashMsg ),
- pMessage,
- strlen( pMessage ) + 1,
- VMPI_MASTER_ID );
-
- // Now attempt to create a minidump with the given exception information
- if ( pvExceptionInfo )
- {
- struct _EXCEPTION_POINTERS *pvExPointers = ( struct _EXCEPTION_POINTERS * ) pvExceptionInfo;
- tchar tchMinidumpFileName[_MAX_PATH] = { 0 };
- bool bSucceededWritingMinidump = WriteMiniDumpUsingExceptionInfo(
- pvExPointers->ExceptionRecord->ExceptionCode,
- pvExPointers,
- ( MINIDUMP_TYPE )( MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithProcessThreadData ),
- // ( MINIDUMP_TYPE )( MiniDumpWithDataSegs | MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithProcessThreadData | MiniDumpWithPrivateReadWriteMemory ),
- // ( MINIDUMP_TYPE )( MiniDumpNormal ),
- tchMinidumpFileName );
- if ( bSucceededWritingMinidump )
- {
- crashMsg[2] = 'f';
- VMPI_SendFileChunk( crashMsg, sizeof( crashMsg ), tchMinidumpFileName );
- ::DeleteFile( tchMinidumpFileName );
- }
- }
-
- // Let the messages go out.
- Sleep( 500 );
- }
-
- InterlockedDecrement( &crashHandlerCount );
-}
-
-
-// This is called if we crash inside our crash handler. It just terminates the process immediately.
-LONG __stdcall VMPI_SecondExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo )
-{
- TerminateProcess( GetCurrentProcess(), 2 );
- return EXCEPTION_EXECUTE_HANDLER; // (never gets here anyway)
-}
-
-
-void VMPI_ExceptionFilter( unsigned long uCode, void *pvExceptionInfo )
-{
- // This is called if we crash inside our crash handler. It just terminates the process immediately.
- SetUnhandledExceptionFilter( VMPI_SecondExceptionFilter );
-
- //DWORD code = ExceptionInfo->ExceptionRecord->ExceptionCode;
-
- #define ERR_RECORD( name ) { name, #name }
- struct
- {
- int code;
- char *pReason;
- } errors[] =
- {
- ERR_RECORD( EXCEPTION_ACCESS_VIOLATION ),
- ERR_RECORD( EXCEPTION_ARRAY_BOUNDS_EXCEEDED ),
- ERR_RECORD( EXCEPTION_BREAKPOINT ),
- ERR_RECORD( EXCEPTION_DATATYPE_MISALIGNMENT ),
- ERR_RECORD( EXCEPTION_FLT_DENORMAL_OPERAND ),
- ERR_RECORD( EXCEPTION_FLT_DIVIDE_BY_ZERO ),
- ERR_RECORD( EXCEPTION_FLT_INEXACT_RESULT ),
- ERR_RECORD( EXCEPTION_FLT_INVALID_OPERATION ),
- ERR_RECORD( EXCEPTION_FLT_OVERFLOW ),
- ERR_RECORD( EXCEPTION_FLT_STACK_CHECK ),
- ERR_RECORD( EXCEPTION_FLT_UNDERFLOW ),
- ERR_RECORD( EXCEPTION_ILLEGAL_INSTRUCTION ),
- ERR_RECORD( EXCEPTION_IN_PAGE_ERROR ),
- ERR_RECORD( EXCEPTION_INT_DIVIDE_BY_ZERO ),
- ERR_RECORD( EXCEPTION_INT_OVERFLOW ),
- ERR_RECORD( EXCEPTION_INVALID_DISPOSITION ),
- ERR_RECORD( EXCEPTION_NONCONTINUABLE_EXCEPTION ),
- ERR_RECORD( EXCEPTION_PRIV_INSTRUCTION ),
- ERR_RECORD( EXCEPTION_SINGLE_STEP ),
- ERR_RECORD( EXCEPTION_STACK_OVERFLOW ),
- ERR_RECORD( EXCEPTION_ACCESS_VIOLATION ),
- };
-
- int nErrors = sizeof( errors ) / sizeof( errors[0] );
- int i=0;
- char *pchReason = NULL;
- char chUnknownBuffer[32];
- for ( i; ( i < nErrors ) && !pchReason; i++ )
- {
- if ( errors[i].code == uCode )
- pchReason = errors[i].pReason;
- }
-
- if ( i == nErrors )
- {
- sprintf( chUnknownBuffer, "Error code 0x%08X", uCode );
- pchReason = chUnknownBuffer;
- }
-
- VMPI_HandleCrash( pchReason, pvExceptionInfo, true );
-
- TerminateProcess( GetCurrentProcess(), 1 );
-}
-
-
-void HandleMPIDisconnect( int procID, const char *pReason )
-{
- int nLiveWorkers = VMPI_GetCurrentNumberOfConnections() - g_nDisconnects - 1;
-
- // We ran into the size limit before and it wasn't readily apparent that the size limit had
- // been breached, so make sure to show errors about invalid packet sizes..
- bool bOldSuppress = g_bSuppressPrintfOutput;
- g_bSuppressPrintfOutput = ( Q_stristr( pReason, "invalid packet size" ) == 0 );
-
- Warning( "\n\n--- WARNING: lost connection to '%s' (%s).\n", VMPI_GetMachineName( procID ), pReason );
-
- if ( g_bMPIMaster )
- {
- Warning( "%d workers remain.\n\n", nLiveWorkers );
-
- ++g_nDisconnects;
- /*
- if ( VMPI_GetCurrentNumberOfConnections() - g_nDisconnects <= 1 )
- {
- Error( "All machines disconnected!" );
- }
- */
- }
- else
- {
- VMPI_HandleAutoRestart();
- Error( "Worker quitting." );
- }
-
- g_bSuppressPrintfOutput = bOldSuppress;
-}
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <windows.h>
+#include <dbghelp.h>
+#include "vmpi.h"
+#include "cmdlib.h"
+#include "vmpi_tools_shared.h"
+#include "tier1/strtools.h"
+#include "mpi_stats.h"
+#include "iphelpers.h"
+#include "tier0/minidump.h"
+
+
+// ----------------------------------------------------------------------------- //
+// Globals.
+// ----------------------------------------------------------------------------- //
+
+static bool g_bReceivedDirectoryInfo = false; // Have we gotten the qdir info yet?
+
+static bool g_bReceivedDBInfo = false;
+static CDBInfo g_DBInfo;
+static unsigned long g_JobPrimaryID;
+
+static int g_nDisconnects = 0; // Tracks how many remote processes have disconnected ungracefully.
+
+
+// ----------------------------------------------------------------------------- //
+// Shared dispatch code.
+// ----------------------------------------------------------------------------- //
+
+bool SharedDispatch( MessageBuffer *pBuf, int iSource, int iPacketID )
+{
+ char *pInPos = &pBuf->data[2];
+
+ switch ( pBuf->data[1] )
+ {
+ case VMPI_SUBPACKETID_DIRECTORIES:
+ {
+ Q_strncpy( gamedir, pInPos, sizeof( gamedir ) );
+ pInPos += strlen( pInPos ) + 1;
+
+ Q_strncpy( qdir, pInPos, sizeof( qdir ) );
+
+ g_bReceivedDirectoryInfo = true;
+ }
+ return true;
+
+ case VMPI_SUBPACKETID_DBINFO:
+ {
+ g_DBInfo = *((CDBInfo*)pInPos);
+ pInPos += sizeof( CDBInfo );
+ g_JobPrimaryID = *((unsigned long*)pInPos);
+
+ g_bReceivedDBInfo = true;
+ }
+ return true;
+
+ case VMPI_SUBPACKETID_CRASH:
+ {
+ char const chCrashInfoType = *pInPos;
+ pInPos += 2;
+ switch ( chCrashInfoType )
+ {
+ case 't':
+ Warning( "\nWorker '%s' dead: %s\n", VMPI_GetMachineName( iSource ), pInPos );
+ break;
+ case 'f':
+ {
+ int iFileSize = * reinterpret_cast< int const * >( pInPos );
+ pInPos += sizeof( iFileSize );
+
+ // Temp folder
+ char const *szFolder = NULL;
+ if ( !szFolder ) szFolder = getenv( "TEMP" );
+ if ( !szFolder ) szFolder = getenv( "TMP" );
+ if ( !szFolder ) szFolder = "c:";
+
+ // Base module name
+ char chModuleName[_MAX_PATH], *pModuleName = chModuleName;
+ ::GetModuleFileName( NULL, chModuleName, sizeof( chModuleName ) / sizeof( chModuleName[0] ) );
+
+ if ( char *pch = strrchr( chModuleName, '.' ) )
+ *pch = 0;
+ if ( char *pch = strrchr( chModuleName, '\\' ) )
+ *pch = 0, pModuleName = pch + 1;
+
+ // Current time
+ time_t currTime = ::time( NULL );
+ struct tm * pTime = ::localtime( &currTime );
+
+ // Number of minidumps this run
+ static int s_numMiniDumps = 0;
+ ++ s_numMiniDumps;
+
+ // Prepare the filename
+ char chSaveFileName[ 2 * _MAX_PATH ] = { 0 };
+ sprintf( chSaveFileName, "%s\\vmpi_%s_on_%s_%d%.2d%2d%.2d%.2d%.2d_%d.mdmp",
+ szFolder,
+ pModuleName,
+ VMPI_GetMachineName( iSource ),
+ pTime->tm_year + 1900, /* Year less 2000 */
+ pTime->tm_mon + 1, /* month (0 - 11 : 0 = January) */
+ pTime->tm_mday, /* day of month (1 - 31) */
+ pTime->tm_hour, /* hour (0 - 23) */
+ pTime->tm_min, /* minutes (0 - 59) */
+ pTime->tm_sec, /* seconds (0 - 59) */
+ s_numMiniDumps
+ );
+
+ if ( FILE *fDump = fopen( chSaveFileName, "wb" ) )
+ {
+ fwrite( pInPos, 1, iFileSize, fDump );
+ fclose( fDump );
+
+ Warning( "\nSaved worker crash minidump '%s', size %d byte(s).\n",
+ chSaveFileName, iFileSize );
+ }
+ else
+ {
+ Warning( "\nReceived worker crash minidump size %d byte(s), failed to save.\n", iFileSize );
+ }
+ }
+ break;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+CDispatchReg g_SharedDispatchReg( VMPI_SHARED_PACKET_ID, SharedDispatch );
+
+
+
+// ----------------------------------------------------------------------------- //
+// Module interfaces.
+// ----------------------------------------------------------------------------- //
+
+void SendQDirInfo()
+{
+ char cPacketID[2] = { VMPI_SHARED_PACKET_ID, VMPI_SUBPACKETID_DIRECTORIES };
+
+ MessageBuffer mb;
+ mb.write( cPacketID, 2 );
+ mb.write( gamedir, strlen( gamedir ) + 1 );
+ mb.write( qdir, strlen( qdir ) + 1 );
+
+ VMPI_SendData( mb.data, mb.getLen(), VMPI_PERSISTENT );
+}
+
+
+void RecvQDirInfo()
+{
+ while ( !g_bReceivedDirectoryInfo )
+ VMPI_DispatchNextMessage();
+}
+
+
+void SendDBInfo( const CDBInfo *pInfo, unsigned long jobPrimaryID )
+{
+ char cPacketInfo[2] = { VMPI_SHARED_PACKET_ID, VMPI_SUBPACKETID_DBINFO };
+ const void *pChunks[] = { cPacketInfo, pInfo, &jobPrimaryID };
+ int chunkLengths[] = { 2, sizeof( CDBInfo ), sizeof( jobPrimaryID ) };
+
+ VMPI_SendChunks( pChunks, chunkLengths, ARRAYSIZE( pChunks ), VMPI_PERSISTENT );
+}
+
+
+void RecvDBInfo( CDBInfo *pInfo, unsigned long *pJobPrimaryID )
+{
+ while ( !g_bReceivedDBInfo )
+ VMPI_DispatchNextMessage();
+
+ *pInfo = g_DBInfo;
+ *pJobPrimaryID = g_JobPrimaryID;
+}
+
+// If the file is successfully opened, read and sent returns the size of the file in bytes
+// otherwise returns 0 and nothing is sent
+int VMPI_SendFileChunk( const void *pvChunkPrefix, int lenPrefix, tchar const *ptchFileName )
+{
+ HANDLE hFile = NULL;
+ HANDLE hMapping = NULL;
+ void const *pvMappedData = NULL;
+ int iResult = 0;
+
+ hFile = ::CreateFile( ptchFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
+ if ( !hFile || ( hFile == INVALID_HANDLE_VALUE ) )
+ goto done;
+
+ hMapping = ::CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
+ if ( !hMapping || ( hMapping == INVALID_HANDLE_VALUE ) )
+ goto done;
+
+ pvMappedData = ::MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
+ if ( !pvMappedData )
+ goto done;
+
+ int iMappedFileSize = ::GetFileSize( hFile, NULL );
+ if ( INVALID_FILE_SIZE == iMappedFileSize )
+ goto done;
+
+ // Send the data over VMPI
+ if ( VMPI_Send3Chunks(
+ pvChunkPrefix, lenPrefix,
+ &iMappedFileSize, sizeof( iMappedFileSize ),
+ pvMappedData, iMappedFileSize,
+ VMPI_MASTER_ID ) )
+ iResult = iMappedFileSize;
+
+ // Fall-through for cleanup code to execute
+done:
+ if ( pvMappedData )
+ ::UnmapViewOfFile( pvMappedData );
+
+ if ( hMapping && ( hMapping != INVALID_HANDLE_VALUE ) )
+ ::CloseHandle( hMapping );
+
+ if ( hFile && ( hFile != INVALID_HANDLE_VALUE ) )
+ ::CloseHandle( hFile );
+
+ return iResult;
+}
+
+void VMPI_HandleCrash( const char *pMessage, void *pvExceptionInfo, bool bAssert )
+{
+ static LONG crashHandlerCount = 0;
+ if ( InterlockedIncrement( &crashHandlerCount ) == 1 )
+ {
+ Msg( "\nFAILURE: '%s' (assert: %d)\n", pMessage, bAssert );
+
+ // Send a message to the master.
+ char crashMsg[4] = { VMPI_SHARED_PACKET_ID, VMPI_SUBPACKETID_CRASH, 't', ':' };
+
+ VMPI_Send2Chunks(
+ crashMsg,
+ sizeof( crashMsg ),
+ pMessage,
+ strlen( pMessage ) + 1,
+ VMPI_MASTER_ID );
+
+ // Now attempt to create a minidump with the given exception information
+ if ( pvExceptionInfo )
+ {
+ struct _EXCEPTION_POINTERS *pvExPointers = ( struct _EXCEPTION_POINTERS * ) pvExceptionInfo;
+ tchar tchMinidumpFileName[_MAX_PATH] = { 0 };
+ bool bSucceededWritingMinidump = WriteMiniDumpUsingExceptionInfo(
+ pvExPointers->ExceptionRecord->ExceptionCode,
+ pvExPointers,
+ ( MINIDUMP_TYPE )( MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithProcessThreadData ),
+ // ( MINIDUMP_TYPE )( MiniDumpWithDataSegs | MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithProcessThreadData | MiniDumpWithPrivateReadWriteMemory ),
+ // ( MINIDUMP_TYPE )( MiniDumpNormal ),
+ tchMinidumpFileName );
+ if ( bSucceededWritingMinidump )
+ {
+ crashMsg[2] = 'f';
+ VMPI_SendFileChunk( crashMsg, sizeof( crashMsg ), tchMinidumpFileName );
+ ::DeleteFile( tchMinidumpFileName );
+ }
+ }
+
+ // Let the messages go out.
+ Sleep( 500 );
+ }
+
+ InterlockedDecrement( &crashHandlerCount );
+}
+
+
+// This is called if we crash inside our crash handler. It just terminates the process immediately.
+LONG __stdcall VMPI_SecondExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo )
+{
+ TerminateProcess( GetCurrentProcess(), 2 );
+ return EXCEPTION_EXECUTE_HANDLER; // (never gets here anyway)
+}
+
+
+void VMPI_ExceptionFilter( unsigned long uCode, void *pvExceptionInfo )
+{
+ // This is called if we crash inside our crash handler. It just terminates the process immediately.
+ SetUnhandledExceptionFilter( VMPI_SecondExceptionFilter );
+
+ //DWORD code = ExceptionInfo->ExceptionRecord->ExceptionCode;
+
+ #define ERR_RECORD( name ) { name, #name }
+ struct
+ {
+ int code;
+ char *pReason;
+ } errors[] =
+ {
+ ERR_RECORD( EXCEPTION_ACCESS_VIOLATION ),
+ ERR_RECORD( EXCEPTION_ARRAY_BOUNDS_EXCEEDED ),
+ ERR_RECORD( EXCEPTION_BREAKPOINT ),
+ ERR_RECORD( EXCEPTION_DATATYPE_MISALIGNMENT ),
+ ERR_RECORD( EXCEPTION_FLT_DENORMAL_OPERAND ),
+ ERR_RECORD( EXCEPTION_FLT_DIVIDE_BY_ZERO ),
+ ERR_RECORD( EXCEPTION_FLT_INEXACT_RESULT ),
+ ERR_RECORD( EXCEPTION_FLT_INVALID_OPERATION ),
+ ERR_RECORD( EXCEPTION_FLT_OVERFLOW ),
+ ERR_RECORD( EXCEPTION_FLT_STACK_CHECK ),
+ ERR_RECORD( EXCEPTION_FLT_UNDERFLOW ),
+ ERR_RECORD( EXCEPTION_ILLEGAL_INSTRUCTION ),
+ ERR_RECORD( EXCEPTION_IN_PAGE_ERROR ),
+ ERR_RECORD( EXCEPTION_INT_DIVIDE_BY_ZERO ),
+ ERR_RECORD( EXCEPTION_INT_OVERFLOW ),
+ ERR_RECORD( EXCEPTION_INVALID_DISPOSITION ),
+ ERR_RECORD( EXCEPTION_NONCONTINUABLE_EXCEPTION ),
+ ERR_RECORD( EXCEPTION_PRIV_INSTRUCTION ),
+ ERR_RECORD( EXCEPTION_SINGLE_STEP ),
+ ERR_RECORD( EXCEPTION_STACK_OVERFLOW ),
+ ERR_RECORD( EXCEPTION_ACCESS_VIOLATION ),
+ };
+
+ int nErrors = sizeof( errors ) / sizeof( errors[0] );
+ int i=0;
+ char *pchReason = NULL;
+ char chUnknownBuffer[32];
+ for ( i; ( i < nErrors ) && !pchReason; i++ )
+ {
+ if ( errors[i].code == uCode )
+ pchReason = errors[i].pReason;
+ }
+
+ if ( i == nErrors )
+ {
+ sprintf( chUnknownBuffer, "Error code 0x%08X", uCode );
+ pchReason = chUnknownBuffer;
+ }
+
+ VMPI_HandleCrash( pchReason, pvExceptionInfo, true );
+
+ TerminateProcess( GetCurrentProcess(), 1 );
+}
+
+
+void HandleMPIDisconnect( int procID, const char *pReason )
+{
+ int nLiveWorkers = VMPI_GetCurrentNumberOfConnections() - g_nDisconnects - 1;
+
+ // We ran into the size limit before and it wasn't readily apparent that the size limit had
+ // been breached, so make sure to show errors about invalid packet sizes..
+ bool bOldSuppress = g_bSuppressPrintfOutput;
+ g_bSuppressPrintfOutput = ( Q_stristr( pReason, "invalid packet size" ) == 0 );
+
+ Warning( "\n\n--- WARNING: lost connection to '%s' (%s).\n", VMPI_GetMachineName( procID ), pReason );
+
+ if ( g_bMPIMaster )
+ {
+ Warning( "%d workers remain.\n\n", nLiveWorkers );
+
+ ++g_nDisconnects;
+ /*
+ if ( VMPI_GetCurrentNumberOfConnections() - g_nDisconnects <= 1 )
+ {
+ Error( "All machines disconnected!" );
+ }
+ */
+ }
+ else
+ {
+ VMPI_HandleAutoRestart();
+ Error( "Worker quitting." );
+ }
+
+ g_bSuppressPrintfOutput = bOldSuppress;
+}
+
+
diff --git a/mp/src/utils/common/vmpi_tools_shared.h b/mp/src/utils/common/vmpi_tools_shared.h
index 7c22201f..980552e8 100644
--- a/mp/src/utils/common/vmpi_tools_shared.h
+++ b/mp/src/utils/common/vmpi_tools_shared.h
@@ -1,45 +1,45 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#ifndef VMPI_TOOLS_SHARED_H
-#define VMPI_TOOLS_SHARED_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-// Packet IDs.
- #define VMPI_SUBPACKETID_DIRECTORIES 0 // qdir directories.
- #define VMPI_SUBPACKETID_DBINFO 1 // MySQL database info.
- #define VMPI_SUBPACKETID_CRASH 3 // A worker saying it crashed.
- #define VMPI_SUBPACKETID_MULTICAST_ADDR 4 // Filesystem multicast address.
-
-
-class CDBInfo;
-class CIPAddr;
-
-
-// Send/receive the qdir info.
-void SendQDirInfo();
-void RecvQDirInfo();
-
-void SendDBInfo( const CDBInfo *pInfo, unsigned long jobPrimaryID );
-void RecvDBInfo( CDBInfo *pInfo, unsigned long *pJobPrimaryID );
-
-void SendMulticastIP( const CIPAddr *pAddr );
-void RecvMulticastIP( CIPAddr *pAddr );
-
-void VMPI_HandleCrash( const char *pMessage, void *pvExceptionInfo, bool bAssert );
-
-// Call this from an exception handler (set by SetUnhandledExceptionHandler).
-// uCode = ExceptionInfo->ExceptionRecord->ExceptionCode.
-// pvExceptionInfo = ExceptionInfo
-void VMPI_ExceptionFilter( unsigned long uCode, void *pvExceptionInfo );
-
-void HandleMPIDisconnect( int procID, const char *pReason );
-
-
-#endif // VMPI_TOOLS_SHARED_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef VMPI_TOOLS_SHARED_H
+#define VMPI_TOOLS_SHARED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// Packet IDs.
+ #define VMPI_SUBPACKETID_DIRECTORIES 0 // qdir directories.
+ #define VMPI_SUBPACKETID_DBINFO 1 // MySQL database info.
+ #define VMPI_SUBPACKETID_CRASH 3 // A worker saying it crashed.
+ #define VMPI_SUBPACKETID_MULTICAST_ADDR 4 // Filesystem multicast address.
+
+
+class CDBInfo;
+class CIPAddr;
+
+
+// Send/receive the qdir info.
+void SendQDirInfo();
+void RecvQDirInfo();
+
+void SendDBInfo( const CDBInfo *pInfo, unsigned long jobPrimaryID );
+void RecvDBInfo( CDBInfo *pInfo, unsigned long *pJobPrimaryID );
+
+void SendMulticastIP( const CIPAddr *pAddr );
+void RecvMulticastIP( CIPAddr *pAddr );
+
+void VMPI_HandleCrash( const char *pMessage, void *pvExceptionInfo, bool bAssert );
+
+// Call this from an exception handler (set by SetUnhandledExceptionHandler).
+// uCode = ExceptionInfo->ExceptionRecord->ExceptionCode.
+// pvExceptionInfo = ExceptionInfo
+void VMPI_ExceptionFilter( unsigned long uCode, void *pvExceptionInfo );
+
+void HandleMPIDisconnect( int procID, const char *pReason );
+
+
+#endif // VMPI_TOOLS_SHARED_H
diff --git a/mp/src/utils/common/wadlib.c b/mp/src/utils/common/wadlib.c
index 2b5bb6b1..4aff972d 100644
--- a/mp/src/utils/common/wadlib.c
+++ b/mp/src/utils/common/wadlib.c
@@ -1,334 +1,334 @@
-//========= Copyright � 1996-2005, Valve LLC, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-// wad2lib.c
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-//#include <sys/file.h>
-#include <stdarg.h>
-
-#ifdef NeXT
-#include <libc.h>
-#endif
-#include "cmdlib.h"
-#include "wadlib.h"
-#include "commonmacros.h"
-
-/*
-============================================================================
-
- WAD READING
-
-============================================================================
-*/
-
-
-lumpinfo_t *lumpinfo; // location of each lump on disk
-int numlumps;
-
-wadinfo_t header;
-FILE *wadhandle;
-
-
-/*
-====================
-W_OpenWad
-====================
-*/
-void W_OpenWad (char *filename)
-{
- lumpinfo_t *lump_p;
- unsigned i;
- int length;
-
-//
-// open the file and add to directory
-//
- wadhandle = SafeOpenRead (filename);
- SafeRead (wadhandle, &header, sizeof(header));
-
- if (!STRING_MATCHES_ID(header.identification,WAD_ID))
- Error ("Wad file %s doesn't have %s identifier\n",filename, WAD_IDNAME);
-
- header.numlumps = LittleLong(header.numlumps);
- header.infotableofs = LittleLong(header.infotableofs);
-
- numlumps = header.numlumps;
-
- length = numlumps*sizeof(lumpinfo_t);
- lumpinfo = malloc (length);
- lump_p = lumpinfo;
-
- fseek (wadhandle, header.infotableofs, SEEK_SET);
- SafeRead (wadhandle, lumpinfo, length);
-
-//
-// Fill in lumpinfo
-//
-
- for (i=0 ; i<numlumps ; i++,lump_p++)
- {
- lump_p->filepos = LittleLong(lump_p->filepos);
- lump_p->size = LittleLong(lump_p->size);
- }
-}
-
-
-
-void CleanupName (char *in, char *out)
-{
- int i;
-
- for (i=0 ; i<sizeof( ((lumpinfo_t *)0)->name ) ; i++ )
- {
- if (!in[i])
- break;
-
- out[i] = toupper(in[i]);
- }
-
- for ( ; i<sizeof( ((lumpinfo_t *)0)->name ); i++ )
- out[i] = 0;
-}
-
-
-/*
-====================
-W_CheckNumForName
-
-Returns -1 if name not found
-====================
-*/
-int W_CheckNumForName (char *name)
-{
- char cleanname[TEXTURE_NAME_LENGTH];
- int v1,v2, v3, v4;
- int i;
- lumpinfo_t *lump_p;
-
- CleanupName (name, cleanname);
-
-// make the name into four integers for easy compares
-
- v1 = *(int *)cleanname;
- v2 = *(int *)&cleanname[4];
- v3 = *(int *)&cleanname[8];
- v4 = *(int *)&cleanname[12];
-
-// find it
-
- lump_p = lumpinfo;
- for (i=0 ; i<numlumps ; i++, lump_p++)
- {
- if ( *(int *)lump_p->name == v1
- && *(int *)&lump_p->name[4] == v2
- && *(int *)&lump_p->name[8] == v3
- && *(int *)&lump_p->name[12] == v4
- && !strcmp( lump_p->name, cleanname ) )
- return i;
- }
-
- return -1;
-}
-
-
-/*
-====================
-W_GetNumForName
-
-Calls W_CheckNumForName, but bombs out if not found
-====================
-*/
-int W_GetNumForName (char *name)
-{
- int i;
-
- i = W_CheckNumForName (name);
- if (i != -1)
- return i;
-
- Error ("W_GetNumForName: %s not found!",name);
- return -1;
-}
-
-
-/*
-====================
-W_LumpLength
-
-Returns the buffer size needed to load the given lump
-====================
-*/
-int W_LumpLength (int lump)
-{
- if (lump >= numlumps)
- Error ("W_LumpLength: %i >= numlumps",lump);
- return lumpinfo[lump].size;
-}
-
-
-/*
-====================
-W_ReadLumpNum
-
-Loads the lump into the given buffer, which must be >= W_LumpLength()
-====================
-*/
-void W_ReadLumpNum (int lump, void *dest)
-{
- lumpinfo_t *l;
-
- if (lump >= numlumps)
- Error ("W_ReadLump: %i >= numlumps",lump);
- l = lumpinfo+lump;
-
- fseek (wadhandle, l->filepos, SEEK_SET);
- SafeRead (wadhandle, dest, l->size);
-}
-
-
-
-/*
-====================
-W_LoadLumpNum
-====================
-*/
-void *W_LoadLumpNum (int lump)
-{
- void *buf;
-
- if ((unsigned)lump >= numlumps)
- Error ("W_CacheLumpNum: %i >= numlumps",lump);
-
- buf = malloc (W_LumpLength (lump));
- W_ReadLumpNum (lump, buf);
-
- return buf;
-}
-
-
-/*
-====================
-W_LoadLumpName
-====================
-*/
-void *W_LoadLumpName (char *name)
-{
- return W_LoadLumpNum (W_GetNumForName(name));
-}
-
-
-/*
-===============================================================================
-
- WAD CREATION
-
-===============================================================================
-*/
-
-FILE *outwad;
-
-lumpinfo_t outinfo[4096];
-int outlumps;
-
-short (*wadshort) (short l);
-int (*wadlong) (int l);
-
-/*
-===============
-NewWad
-===============
-*/
-
-void NewWad (char *pathname, qboolean bigendien)
-{
- outwad = SafeOpenWrite (pathname);
- fseek (outwad, sizeof(wadinfo_t), SEEK_SET);
- memset (outinfo, 0, sizeof(outinfo));
-
- if (bigendien)
- {
- wadshort = BigShort;
- wadlong = BigLong;
- }
- else
- {
- wadshort = LittleShort;
- wadlong = LittleLong;
- }
-
- outlumps = 0;
-}
-
-
-/*
-===============
-AddLump
-===============
-*/
-
-void AddLump (char *name, void *buffer, int length, int type, int compress)
-{
- lumpinfo_t *info;
- int ofs;
-
- info = &outinfo[outlumps];
- outlumps++;
-
- memset (info,0,sizeof(info));
-
- strcpy (info->name, name);
- Q_strupr (info->name);
-
- ofs = ftell(outwad);
- info->filepos = wadlong(ofs);
- info->size = info->disksize = wadlong(length);
- info->type = type;
- info->compression = compress;
-
-// FIXME: do compression
-
- SafeWrite (outwad, buffer, length);
-}
-
-
-/*
-===============
-WriteWad
-===============
-*/
-
-void WriteWad (int wad3)
-{
- wadinfo_t header;
- int ofs;
-
-// write the lumpingo
- ofs = ftell(outwad);
-
- SafeWrite (outwad, outinfo, outlumps*sizeof(lumpinfo_t) );
-
-// write the header
-
-// a program will be able to tell the ednieness of a wad by the id
- ID_TO_STRING( WAD_ID, header.identification );
-
- header.numlumps = wadlong(outlumps);
- header.infotableofs = wadlong(ofs);
-
- fseek (outwad, 0, SEEK_SET);
- SafeWrite (outwad, &header, sizeof(header));
- fclose (outwad);
-}
-
-
+//========= Copyright � 1996-2005, Valve LLC, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// wad2lib.c
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+//#include <sys/file.h>
+#include <stdarg.h>
+
+#ifdef NeXT
+#include <libc.h>
+#endif
+#include "cmdlib.h"
+#include "wadlib.h"
+#include "commonmacros.h"
+
+/*
+============================================================================
+
+ WAD READING
+
+============================================================================
+*/
+
+
+lumpinfo_t *lumpinfo; // location of each lump on disk
+int numlumps;
+
+wadinfo_t header;
+FILE *wadhandle;
+
+
+/*
+====================
+W_OpenWad
+====================
+*/
+void W_OpenWad (char *filename)
+{
+ lumpinfo_t *lump_p;
+ unsigned i;
+ int length;
+
+//
+// open the file and add to directory
+//
+ wadhandle = SafeOpenRead (filename);
+ SafeRead (wadhandle, &header, sizeof(header));
+
+ if (!STRING_MATCHES_ID(header.identification,WAD_ID))
+ Error ("Wad file %s doesn't have %s identifier\n",filename, WAD_IDNAME);
+
+ header.numlumps = LittleLong(header.numlumps);
+ header.infotableofs = LittleLong(header.infotableofs);
+
+ numlumps = header.numlumps;
+
+ length = numlumps*sizeof(lumpinfo_t);
+ lumpinfo = malloc (length);
+ lump_p = lumpinfo;
+
+ fseek (wadhandle, header.infotableofs, SEEK_SET);
+ SafeRead (wadhandle, lumpinfo, length);
+
+//
+// Fill in lumpinfo
+//
+
+ for (i=0 ; i<numlumps ; i++,lump_p++)
+ {
+ lump_p->filepos = LittleLong(lump_p->filepos);
+ lump_p->size = LittleLong(lump_p->size);
+ }
+}
+
+
+
+void CleanupName (char *in, char *out)
+{
+ int i;
+
+ for (i=0 ; i<sizeof( ((lumpinfo_t *)0)->name ) ; i++ )
+ {
+ if (!in[i])
+ break;
+
+ out[i] = toupper(in[i]);
+ }
+
+ for ( ; i<sizeof( ((lumpinfo_t *)0)->name ); i++ )
+ out[i] = 0;
+}
+
+
+/*
+====================
+W_CheckNumForName
+
+Returns -1 if name not found
+====================
+*/
+int W_CheckNumForName (char *name)
+{
+ char cleanname[TEXTURE_NAME_LENGTH];
+ int v1,v2, v3, v4;
+ int i;
+ lumpinfo_t *lump_p;
+
+ CleanupName (name, cleanname);
+
+// make the name into four integers for easy compares
+
+ v1 = *(int *)cleanname;
+ v2 = *(int *)&cleanname[4];
+ v3 = *(int *)&cleanname[8];
+ v4 = *(int *)&cleanname[12];
+
+// find it
+
+ lump_p = lumpinfo;
+ for (i=0 ; i<numlumps ; i++, lump_p++)
+ {
+ if ( *(int *)lump_p->name == v1
+ && *(int *)&lump_p->name[4] == v2
+ && *(int *)&lump_p->name[8] == v3
+ && *(int *)&lump_p->name[12] == v4
+ && !strcmp( lump_p->name, cleanname ) )
+ return i;
+ }
+
+ return -1;
+}
+
+
+/*
+====================
+W_GetNumForName
+
+Calls W_CheckNumForName, but bombs out if not found
+====================
+*/
+int W_GetNumForName (char *name)
+{
+ int i;
+
+ i = W_CheckNumForName (name);
+ if (i != -1)
+ return i;
+
+ Error ("W_GetNumForName: %s not found!",name);
+ return -1;
+}
+
+
+/*
+====================
+W_LumpLength
+
+Returns the buffer size needed to load the given lump
+====================
+*/
+int W_LumpLength (int lump)
+{
+ if (lump >= numlumps)
+ Error ("W_LumpLength: %i >= numlumps",lump);
+ return lumpinfo[lump].size;
+}
+
+
+/*
+====================
+W_ReadLumpNum
+
+Loads the lump into the given buffer, which must be >= W_LumpLength()
+====================
+*/
+void W_ReadLumpNum (int lump, void *dest)
+{
+ lumpinfo_t *l;
+
+ if (lump >= numlumps)
+ Error ("W_ReadLump: %i >= numlumps",lump);
+ l = lumpinfo+lump;
+
+ fseek (wadhandle, l->filepos, SEEK_SET);
+ SafeRead (wadhandle, dest, l->size);
+}
+
+
+
+/*
+====================
+W_LoadLumpNum
+====================
+*/
+void *W_LoadLumpNum (int lump)
+{
+ void *buf;
+
+ if ((unsigned)lump >= numlumps)
+ Error ("W_CacheLumpNum: %i >= numlumps",lump);
+
+ buf = malloc (W_LumpLength (lump));
+ W_ReadLumpNum (lump, buf);
+
+ return buf;
+}
+
+
+/*
+====================
+W_LoadLumpName
+====================
+*/
+void *W_LoadLumpName (char *name)
+{
+ return W_LoadLumpNum (W_GetNumForName(name));
+}
+
+
+/*
+===============================================================================
+
+ WAD CREATION
+
+===============================================================================
+*/
+
+FILE *outwad;
+
+lumpinfo_t outinfo[4096];
+int outlumps;
+
+short (*wadshort) (short l);
+int (*wadlong) (int l);
+
+/*
+===============
+NewWad
+===============
+*/
+
+void NewWad (char *pathname, qboolean bigendien)
+{
+ outwad = SafeOpenWrite (pathname);
+ fseek (outwad, sizeof(wadinfo_t), SEEK_SET);
+ memset (outinfo, 0, sizeof(outinfo));
+
+ if (bigendien)
+ {
+ wadshort = BigShort;
+ wadlong = BigLong;
+ }
+ else
+ {
+ wadshort = LittleShort;
+ wadlong = LittleLong;
+ }
+
+ outlumps = 0;
+}
+
+
+/*
+===============
+AddLump
+===============
+*/
+
+void AddLump (char *name, void *buffer, int length, int type, int compress)
+{
+ lumpinfo_t *info;
+ int ofs;
+
+ info = &outinfo[outlumps];
+ outlumps++;
+
+ memset (info,0,sizeof(info));
+
+ strcpy (info->name, name);
+ Q_strupr (info->name);
+
+ ofs = ftell(outwad);
+ info->filepos = wadlong(ofs);
+ info->size = info->disksize = wadlong(length);
+ info->type = type;
+ info->compression = compress;
+
+// FIXME: do compression
+
+ SafeWrite (outwad, buffer, length);
+}
+
+
+/*
+===============
+WriteWad
+===============
+*/
+
+void WriteWad (int wad3)
+{
+ wadinfo_t header;
+ int ofs;
+
+// write the lumpingo
+ ofs = ftell(outwad);
+
+ SafeWrite (outwad, outinfo, outlumps*sizeof(lumpinfo_t) );
+
+// write the header
+
+// a program will be able to tell the ednieness of a wad by the id
+ ID_TO_STRING( WAD_ID, header.identification );
+
+ header.numlumps = wadlong(outlumps);
+ header.infotableofs = wadlong(ofs);
+
+ fseek (outwad, 0, SEEK_SET);
+ SafeWrite (outwad, &header, sizeof(header));
+ fclose (outwad);
+}
+
+
diff --git a/mp/src/utils/common/wadlib.h b/mp/src/utils/common/wadlib.h
index a8e4e09a..0fa12f50 100644
--- a/mp/src/utils/common/wadlib.h
+++ b/mp/src/utils/common/wadlib.h
@@ -1,46 +1,46 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-// wadlib.h
-
-//
-// wad reading
-//
-
-#define CMP_NONE 0
-#define CMP_LZSS 1
-
-#define TYP_NONE 0
-#define TYP_LABEL 1
-#define TYP_LUMPY 64 // 64 + grab command number
-
-#ifndef WADTYPES_H
-#include "wadtypes.h"
-#endif
-
-extern lumpinfo_t *lumpinfo; // location of each lump on disk
-extern int numlumps;
-extern wadinfo_t header;
-
-void W_OpenWad (char *filename);
-int W_CheckNumForName (char *name);
-int W_GetNumForName (char *name);
-int W_LumpLength (int lump);
-void W_ReadLumpNum (int lump, void *dest);
-void *W_LoadLumpNum (int lump);
-void *W_LoadLumpName (char *name);
-
-void CleanupName (char *in, char *out);
-
-//
-// wad creation
-//
-void NewWad (char *pathname, qboolean bigendien);
-void AddLump (char *name, void *buffer, int length, int type, int compress);
-void WriteWad (int wad3);
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// wadlib.h
+
+//
+// wad reading
+//
+
+#define CMP_NONE 0
+#define CMP_LZSS 1
+
+#define TYP_NONE 0
+#define TYP_LABEL 1
+#define TYP_LUMPY 64 // 64 + grab command number
+
+#ifndef WADTYPES_H
+#include "wadtypes.h"
+#endif
+
+extern lumpinfo_t *lumpinfo; // location of each lump on disk
+extern int numlumps;
+extern wadinfo_t header;
+
+void W_OpenWad (char *filename);
+int W_CheckNumForName (char *name);
+int W_GetNumForName (char *name);
+int W_LumpLength (int lump);
+void W_ReadLumpNum (int lump, void *dest);
+void *W_LoadLumpNum (int lump);
+void *W_LoadLumpName (char *name);
+
+void CleanupName (char *in, char *out);
+
+//
+// wad creation
+//
+void NewWad (char *pathname, qboolean bigendien);
+void AddLump (char *name, void *buffer, int length, int type, int compress);
+void WriteWad (int wad3);
+